Skip to content

Commit 6de56b2

Browse files
authored
refactor(toolkit-lib,cli): access default messages through IoHelper (#513)
This change is in preparation of work to have all default message go through `IoHelper` instead of using `IO.DEFAULT_XYZ`. It contains a number of clean-up and alignment changes: - `IoDefaultMessages` is now a local-only class, that is only accessed through the new `IoHelper.defaults` getter. - Removed unused usage of `IoHelper` and `IoDefaultMessages` in `DiffFormatter`. - Changed every use of `IoDefaultMessages` to `IoHelper.defaults` - Made `IoDefaultMessages` methods async to be consistent with the rest, we can `void` at the place of use if we really need to - Also fixed most of the remaining `void`'ed call-sites for the above. Only the legacy logging is now left. - Removed unused `messages.ts` file - Removed unused `trace` from `logging.ts` (and respective test) to not encourage further use --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent 33292d1 commit 6de56b2

File tree

20 files changed

+141
-343
lines changed

20 files changed

+141
-343
lines changed

packages/@aws-cdk/cloudformation-diff/lib/format.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ export function formatSecurityChanges(
6161
stream: NodeJS.WritableStream,
6262
templateDiff: TemplateDiff,
6363
logicalToPathMap: { [logicalId: string]: string } = {},
64-
context?: number) {
64+
context?: number,
65+
) {
6566
const formatter = new Formatter(stream, logicalToPathMap, templateDiff, context);
6667

6768
formatSecurityChangesWithBanner(formatter, templateDiff);

packages/@aws-cdk/toolkit-lib/lib/api/diff/diff-formatter.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import type * as cxapi from '@aws-cdk/cx-api';
1111
import * as chalk from 'chalk';
1212
import { PermissionChangeType } from '../../payloads';
1313
import type { NestedStackTemplates } from '../cloudformation';
14-
import type { IoHelper } from '../io/private';
15-
import { IoDefaultMessages } from '../io/private';
1614
import { StringWriteStream } from '../streams';
1715

1816
/**
@@ -50,11 +48,6 @@ interface FormatStackDiffOutput {
5048
* Props for the Diff Formatter
5149
*/
5250
interface DiffFormatterProps {
53-
/**
54-
* Helper for the IoHost class
55-
*/
56-
readonly ioHelper: IoHelper;
57-
5851
/**
5952
* The relevant information for the Template that is being diffed.
6053
* Includes the old/current state of the stack as well as the new state.
@@ -89,7 +82,6 @@ interface FormatStackDiffOptions {
8982
}
9083

9184
interface ReusableStackDiffOptions extends FormatStackDiffOptions {
92-
readonly ioDefaultHelper: IoDefaultMessages;
9385
}
9486

9587
/**
@@ -136,7 +128,6 @@ export interface TemplateInfo {
136128
* Class for formatting the diff output
137129
*/
138130
export class DiffFormatter {
139-
private readonly ioHelper: IoHelper;
140131
private readonly oldTemplate: any;
141132
private readonly newTemplate: cxapi.CloudFormationStackArtifact;
142133
private readonly stackName: string;
@@ -151,7 +142,6 @@ export class DiffFormatter {
151142
private _diffs: { [name: string]: TemplateDiff } = {};
152143

153144
constructor(props: DiffFormatterProps) {
154-
this.ioHelper = props.ioHelper;
155145
this.oldTemplate = props.templateInfo.oldTemplate;
156146
this.newTemplate = props.templateInfo.newTemplate;
157147
this.stackName = props.templateInfo.newTemplate.displayName ?? props.templateInfo.newTemplate.stackName;
@@ -204,15 +194,11 @@ export class DiffFormatter {
204194
* Format the stack diff
205195
*/
206196
public formatStackDiff(options: FormatStackDiffOptions = {}): FormatStackDiffOutput {
207-
const ioDefaultHelper = new IoDefaultMessages(this.ioHelper);
208197
return this.formatStackDiffHelper(
209198
this.oldTemplate,
210199
this.stackName,
211200
this.nestedStacks,
212-
{
213-
...options,
214-
ioDefaultHelper,
215-
},
201+
options,
216202
);
217203
}
218204

packages/@aws-cdk/toolkit-lib/lib/api/io/private/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@ export * from './span';
55
export * from './message-maker';
66
export * from './messages';
77
export * from './types';
8-
export * from './io-default-messages';

packages/@aws-cdk/toolkit-lib/lib/api/io/private/io-default-messages.ts

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,48 @@ import { IO } from './messages';
1010
* for the various log levels.
1111
*/
1212
export class IoDefaultMessages {
13-
constructor(private readonly ioHelper: IoHelper) {
13+
private readonly ioHelper: IoHelper;
14+
15+
constructor(ioHelper: IoHelper) {
16+
this.ioHelper = ioHelper;
1417
}
1518

16-
public notify(msg: ActionLessMessage<unknown>): Promise<void> {
19+
public async notify(msg: ActionLessMessage<unknown>): Promise<void> {
1720
return this.ioHelper.notify(msg);
1821
}
1922

20-
public requestResponse<T, U>(msg: ActionLessRequest<T, U>): Promise<U> {
23+
public async requestResponse<T, U>(msg: ActionLessRequest<T, U>): Promise<U> {
2124
return this.ioHelper.requestResponse(msg);
2225
}
2326

24-
public error(input: string, ...args: unknown[]) {
25-
this.emitMessage(IO.DEFAULT_TOOLKIT_ERROR, input, ...args);
27+
public async error(input: string, ...args: unknown[]): Promise<void> {
28+
return this.emitMessage(IO.DEFAULT_TOOLKIT_ERROR, input, ...args);
2629
}
2730

28-
public warn(input: string, ...args: unknown[]) {
29-
this.emitMessage(IO.DEFAULT_TOOLKIT_WARN, input, ...args);
31+
public async warn(input: string, ...args: unknown[]): Promise<void> {
32+
return this.emitMessage(IO.DEFAULT_TOOLKIT_WARN, input, ...args);
3033
}
3134

32-
public warning(input: string, ...args: unknown[]) {
33-
this.emitMessage(IO.DEFAULT_TOOLKIT_WARN, input, ...args);
35+
public async warning(input: string, ...args: unknown[]): Promise<void> {
36+
return this.emitMessage(IO.DEFAULT_TOOLKIT_WARN, input, ...args);
3437
}
3538

36-
public info(input: string, ...args: unknown[]) {
37-
this.emitMessage(IO.DEFAULT_TOOLKIT_INFO, input, ...args);
39+
public async info(input: string, ...args: unknown[]): Promise<void> {
40+
return this.emitMessage(IO.DEFAULT_TOOLKIT_INFO, input, ...args);
3841
}
3942

40-
public debug(input: string, ...args: unknown[]) {
41-
this.emitMessage(IO.DEFAULT_TOOLKIT_DEBUG, input, ...args);
43+
public async debug(input: string, ...args: unknown[]): Promise<void> {
44+
return this.emitMessage(IO.DEFAULT_TOOLKIT_DEBUG, input, ...args);
4245
}
4346

44-
public trace(input: string, ...args: unknown[]) {
45-
this.emitMessage(IO.DEFAULT_TOOLKIT_TRACE, input, ...args);
47+
public async trace(input: string, ...args: unknown[]): Promise<void> {
48+
return this.emitMessage(IO.DEFAULT_TOOLKIT_TRACE, input, ...args);
4649
}
4750

48-
public result(input: string, ...args: unknown[]) {
51+
public async result(input: string, ...args: unknown[]): Promise<void> {
4952
const message = args.length > 0 ? util.format(input, ...args) : input;
5053
// This is just the default "info" message but with a level of "result"
51-
void this.ioHelper.notify({
54+
return this.ioHelper.notify({
5255
time: new Date(),
5356
code: IO.DEFAULT_TOOLKIT_INFO.code,
5457
level: 'result',
@@ -57,9 +60,9 @@ export class IoDefaultMessages {
5760
});
5861
}
5962

60-
private emitMessage(maker: IoMessageMaker<void>, input: string, ...args: unknown[]) {
63+
private async emitMessage(maker: IoMessageMaker<void>, input: string, ...args: unknown[]): Promise<void> {
6164
// Format message if args are provided
6265
const message = args.length > 0 ? util.format(input, ...args) : input;
63-
void this.ioHelper.notify(maker.msg(message));
66+
return this.ioHelper.notify(maker.msg(message));
6467
}
6568
}

packages/@aws-cdk/toolkit-lib/lib/api/io/private/io-helper.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { IIoHost } from '../io-host';
22
import type { IoMessage, IoRequest } from '../io-message';
33
import type { ToolkitAction } from '../toolkit-action';
4+
import { IoDefaultMessages } from './io-default-messages';
45
import type { SpanEnd, SpanDefinition } from './span';
56
import { SpanMaker } from './span';
67

@@ -15,12 +16,18 @@ export class IoHelper implements IIoHost {
1516
return new IoHelper(ioHost, action);
1617
}
1718

19+
/**
20+
* Simplified access to emit default messages.
21+
*/
22+
public readonly defaults: IoDefaultMessages;
23+
1824
private readonly ioHost: IIoHost;
1925
private readonly action: ToolkitAction;
2026

2127
private constructor(ioHost: IIoHost, action: ToolkitAction) {
2228
this.ioHost = ioHost;
2329
this.action = action;
30+
this.defaults = new IoDefaultMessages(this);
2431
}
2532

2633
/**

packages/@aws-cdk/toolkit-lib/lib/api/notices/cached-data-source.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as fs from 'fs-extra';
22
import type { Notice, NoticeDataSource } from './types';
33
import { ToolkitError } from '../../toolkit/toolkit-error';
4-
import type { IoDefaultMessages } from '../io/private';
4+
import type { IoHelper } from '../io/private';
55

66
interface CachedNotices {
77
expiration: number;
@@ -13,7 +13,7 @@ const TIME_TO_LIVE_ERROR = 1 * 60 * 1000; // 1 minute
1313

1414
export class CachedDataSource implements NoticeDataSource {
1515
constructor(
16-
private readonly ioMessages: IoDefaultMessages,
16+
private readonly ioHelper: IoHelper,
1717
private readonly fileName: string,
1818
private readonly dataSource: NoticeDataSource,
1919
private readonly skipCache?: boolean,
@@ -31,7 +31,7 @@ export class CachedDataSource implements NoticeDataSource {
3131
try {
3232
updatedData = await this.fetchInner();
3333
} catch (e) {
34-
this.ioMessages.debug(`Could not refresh notices: ${e}`);
34+
await this.ioHelper.defaults.debug(`Could not refresh notices: ${e}`);
3535
updatedData = {
3636
expiration: Date.now() + TIME_TO_LIVE_ERROR,
3737
notices: [],
@@ -42,7 +42,7 @@ export class CachedDataSource implements NoticeDataSource {
4242
}
4343
return updatedData.notices;
4444
} else {
45-
this.ioMessages.debug(`Reading cached notices from ${this.fileName}`);
45+
await this.ioHelper.defaults.debug(`Reading cached notices from ${this.fileName}`);
4646
return data;
4747
}
4848
}
@@ -65,7 +65,7 @@ export class CachedDataSource implements NoticeDataSource {
6565
? await fs.readJSON(this.fileName) as CachedNotices
6666
: defaultValue;
6767
} catch (e) {
68-
this.ioMessages.debug(`Failed to load notices from cache: ${e}`);
68+
await this.ioHelper.defaults.debug(`Failed to load notices from cache: ${e}`);
6969
return defaultValue;
7070
}
7171
}
@@ -74,7 +74,7 @@ export class CachedDataSource implements NoticeDataSource {
7474
try {
7575
await fs.writeJSON(this.fileName, cached);
7676
} catch (e) {
77-
this.ioMessages.debug(`Failed to store notices in the cache: ${e}`);
77+
await this.ioHelper.defaults.debug(`Failed to store notices in the cache: ${e}`);
7878
}
7979
}
8080
}

packages/@aws-cdk/toolkit-lib/lib/api/notices/filter.ts

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as semver from 'semver';
2-
import { IO, type IoDefaultMessages } from '../io/private';
2+
import { IO, type IoHelper } from '../io/private';
33
import type { ConstructTreeNode } from '../tree';
44
import { loadTreeFromDir } from '../tree';
55
import type { BootstrappedEnvironment, Component, Notice } from './types';
@@ -58,13 +58,16 @@ export interface NoticesFilterFilterOptions {
5858
}
5959

6060
export class NoticesFilter {
61-
constructor(private readonly ioMessages: IoDefaultMessages) {
61+
private readonly ioHelper: IoHelper;
62+
63+
constructor(ioHelper: IoHelper) {
64+
this.ioHelper = ioHelper;
6265
}
6366

64-
public filter(options: NoticesFilterFilterOptions): FilteredNotice[] {
67+
public async filter(options: NoticesFilterFilterOptions): Promise<FilteredNotice[]> {
6568
const components = [
66-
...this.constructTreeComponents(options.outDir),
67-
...this.otherComponents(options),
69+
...(await this.constructTreeComponents(options.outDir)),
70+
...(await this.otherComponents(options)),
6871
];
6972

7073
return this.findForNamedComponents(options.data, components);
@@ -73,7 +76,25 @@ export class NoticesFilter {
7376
/**
7477
* From a set of input options, return the notices components we are searching for
7578
*/
76-
private otherComponents(options: NoticesFilterFilterOptions): ActualComponent[] {
79+
private async otherComponents(options: NoticesFilterFilterOptions): Promise<ActualComponent[]> {
80+
// Bootstrap environments
81+
let bootstrappedEnvironments = [];
82+
for (const env of options.bootstrappedEnvironments) {
83+
const semverBootstrapVersion = semver.coerce(env.bootstrapStackVersion);
84+
if (!semverBootstrapVersion) {
85+
// we don't throw because notices should never crash the cli.
86+
await this.ioHelper.defaults.warning(`While filtering notices, could not coerce bootstrap version '${env.bootstrapStackVersion}' into semver`);
87+
continue;
88+
}
89+
90+
bootstrappedEnvironments.push({
91+
name: 'bootstrap',
92+
version: `${semverBootstrapVersion}`,
93+
dynamicName: 'ENVIRONMENTS',
94+
dynamicValue: env.environment.name,
95+
});
96+
}
97+
7798
return [
7899
// CLI
79100
{
@@ -89,21 +110,7 @@ export class NoticesFilter {
89110
},
90111

91112
// Bootstrap environments
92-
...options.bootstrappedEnvironments.flatMap(env => {
93-
const semverBootstrapVersion = semver.coerce(env.bootstrapStackVersion);
94-
if (!semverBootstrapVersion) {
95-
// we don't throw because notices should never crash the cli.
96-
this.ioMessages.warning(`While filtering notices, could not coerce bootstrap version '${env.bootstrapStackVersion}' into semver`);
97-
return [];
98-
}
99-
100-
return [{
101-
name: 'bootstrap',
102-
version: `${semverBootstrapVersion}`,
103-
dynamicName: 'ENVIRONMENTS',
104-
dynamicValue: env.environment.name,
105-
}];
106-
}),
113+
...bootstrappedEnvironments,
107114
];
108115
}
109116

@@ -185,8 +192,8 @@ export class NoticesFilter {
185192
/**
186193
* Load the construct tree from the given directory and return its components
187194
*/
188-
private constructTreeComponents(manifestDir: string): ActualComponent[] {
189-
const tree = loadTreeFromDir(manifestDir, (msg: string) => void this.ioMessages.notify(IO.DEFAULT_ASSEMBLY_TRACE.msg(msg)));
195+
private async constructTreeComponents(manifestDir: string): Promise<ActualComponent[]> {
196+
const tree = await loadTreeFromDir(manifestDir, (msg: string) => this.ioHelper.notify(IO.DEFAULT_ASSEMBLY_TRACE.msg(msg)));
190197
if (!tree) {
191198
return [];
192199
}

packages/@aws-cdk/toolkit-lib/lib/api/notices/notices.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { NoticesFilter } from './filter';
99
import type { BootstrappedEnvironment, Notice, NoticeDataSource } from './types';
1010
import { WebsiteNoticeDataSource } from './web-data-source';
1111
import type { IoHelper } from '../io/private';
12-
import { IO, asIoHelper, IoDefaultMessages } from '../io/private';
12+
import { IO, asIoHelper } from '../io/private';
1313

1414
const CACHE_FILE_PATH = path.join(cdkCacheDir(), 'notices.json');
1515

@@ -102,7 +102,6 @@ export class Notices {
102102
private readonly acknowledgedIssueNumbers: Set<Number>;
103103
private readonly httpOptions: SdkHttpOptions;
104104
private readonly ioHelper: IoHelper;
105-
private readonly ioMessages: IoDefaultMessages;
106105
private readonly cliVersion: string;
107106

108107
private data: Set<Notice> = new Set();
@@ -116,7 +115,6 @@ export class Notices {
116115
this.output = props.output ?? 'cdk.out';
117116
this.httpOptions = props.httpOptions ?? {};
118117
this.ioHelper = asIoHelper(props.ioHost, 'notices' as any /* forcing a CliAction to a ToolkitAction */);
119-
this.ioMessages = new IoDefaultMessages(this.ioHelper);
120118
this.cliVersion = props.cliVersion;
121119
}
122120

@@ -144,16 +142,16 @@ export class Notices {
144142
*/
145143
public async refresh(options: NoticesRefreshOptions = {}) {
146144
const innerDataSource = options.dataSource ?? new WebsiteNoticeDataSource(this.ioHelper, this.httpOptions);
147-
const dataSource = new CachedDataSource(this.ioMessages, CACHE_FILE_PATH, innerDataSource, options.force ?? false);
145+
const dataSource = new CachedDataSource(this.ioHelper, CACHE_FILE_PATH, innerDataSource, options.force ?? false);
148146
const notices = await dataSource.fetch();
149147
this.data = new Set(notices);
150148
}
151149

152150
/**
153151
* Filter the data sourece for relevant notices
154152
*/
155-
public filter(options: NoticesDisplayOptions = {}): FilteredNotice[] {
156-
return new NoticesFilter(this.ioMessages).filter({
153+
public filter(options: NoticesDisplayOptions = {}): Promise<FilteredNotice[]> {
154+
return new NoticesFilter(this.ioHelper).filter({
157155
data: this.noticesFromData(options.includeAcknowledged ?? false),
158156
cliVersion: this.cliVersion,
159157
outDir: this.output,
@@ -165,7 +163,7 @@ export class Notices {
165163
* Display the relevant notices (unless context dictates we shouldn't).
166164
*/
167165
public async display(options: NoticesDisplayOptions = {}): Promise<void> {
168-
const filteredNotices = this.filter(options);
166+
const filteredNotices = await this.filter(options);
169167

170168
if (filteredNotices.length > 0) {
171169
await this.ioHelper.notify(IO.CDK_TOOLKIT_I0100.msg([

0 commit comments

Comments
 (0)