Skip to content

Commit a94b241

Browse files
authored
feat: add message about unconfigured feature flags when user runs cdk synth (#765)
#### Notify users about the number of unconfigured feature flags in their application and the `cdk flags` command when they run `cdk synth`. --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent 880c92c commit a94b241

File tree

4 files changed

+102
-2
lines changed

4 files changed

+102
-2
lines changed

packages/aws-cdk/lib/cli/cdk-toolkit.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
} from '../commands/migrate';
5656
import type { CloudAssembly, CloudExecutable, StackSelector } from '../cxapp';
5757
import { DefaultSelection, environmentsFromDescriptors, globEnvironmentsFromStacks, looksLikeGlob } from '../cxapp';
58+
import { OBSOLETE_FLAGS } from '../obsolete-flags';
5859
import {
5960
deserializeStructure,
6061
formatErrorMessage,
@@ -195,7 +196,7 @@ export class CdkToolkit {
195196
emojis: true,
196197
ioHost: this.ioHost,
197198
toolkitStackName: this.toolkitStackName,
198-
unstableFeatures: ['refactor'],
199+
unstableFeatures: ['refactor', 'flags'],
199200
});
200201
}
201202

@@ -1058,6 +1059,8 @@ export class CdkToolkit {
10581059
): Promise<any> {
10591060
const stacks = await this.selectStacksForDiff(stackNames, exclusively, autoValidate);
10601061

1062+
await displayFlagsMessage(this.toolkit, this.props.cloudExecutable, this.ioHost.asIoHelper());
1063+
10611064
// if we have a single stack, print it to STDOUT
10621065
if (stacks.stackCount === 1) {
10631066
if (!quiet) {
@@ -2108,6 +2111,16 @@ async function askUserConfirmation(
21082111
}
21092112
});
21102113
}
2114+
export async function displayFlagsMessage(toolkit: InternalToolkit, cloudExecutable: CloudExecutable,
2115+
ioHelper: IoHelper): Promise<void> {
2116+
let numUnconfigured = (await toolkit.flags(cloudExecutable))
2117+
.filter(flag => !OBSOLETE_FLAGS.includes(flag.name))
2118+
.filter(flag => flag.userValue === undefined).length;
2119+
2120+
if (numUnconfigured > 0) {
2121+
await ioHelper.defaults.info(`You currently have ${numUnconfigured} unconfigured feature flags that may require attention to keep your application up-to-date. Run 'cdk flags' to learn more.`);
2122+
}
2123+
}
21112124

21122125
/**
21132126
* Logger for processing stack metadata

packages/aws-cdk/lib/cli/cli.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,6 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise<n
457457
if (!configuration.settings.get(['unstable']).includes('flags')) {
458458
throw new ToolkitError('Unstable feature use: \'flags\' is unstable. It must be opted in via \'--unstable\', e.g. \'cdk flags --unstable=flags\'');
459459
}
460-
461460
const toolkit = new Toolkit({
462461
ioHost,
463462
toolkitStackName,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const OBSOLETE_FLAGS = [
2+
'@aws-cdk/core:enableStackNameDuplicates',
3+
'@aws-cdk/aws-s3:grantWriteWithoutAcl',
4+
'@aws-cdk/aws-kms:defaultKeyPolicies',
5+
];
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { Toolkit } from '@aws-cdk/toolkit-lib';
2+
import { asIoHelper } from '../../lib/api-private';
3+
import { displayFlagsMessage } from '../../lib/cli/cdk-toolkit';
4+
import { TestIoHost } from '../_helpers/io-host';
5+
6+
describe('displayFlagsMessage', () => {
7+
let ioHost: TestIoHost;
8+
let ioHelper: any;
9+
let mockToolkit: jest.Mocked<Toolkit>;
10+
let mockCloudExecutable: any;
11+
12+
beforeEach(() => {
13+
ioHost = new TestIoHost();
14+
ioHelper = asIoHelper(ioHost, 'synth');
15+
mockCloudExecutable = {};
16+
17+
mockToolkit = {
18+
flags: jest.fn(),
19+
} as any;
20+
21+
jest.spyOn(Toolkit.prototype, 'flags').mockImplementation(mockToolkit.flags);
22+
});
23+
24+
afterEach(() => {
25+
jest.restoreAllMocks();
26+
});
27+
28+
test('displays message with correct count of unconfigured flags, filtering out obsolete flags', async () => {
29+
const mockFlagsData = [
30+
{
31+
name: '@aws-cdk/core:testFlag',
32+
userValue: undefined,
33+
recommendedValue: 'true',
34+
explanation: 'Test flag',
35+
module: 'aws-cdk-lib',
36+
},
37+
{
38+
name: '@aws-cdk/s3:anotherFlag',
39+
userValue: 'false',
40+
recommendedValue: 'false',
41+
explanation: 'Another test flag',
42+
module: 'aws-cdk-lib',
43+
},
44+
{
45+
name: '@aws-cdk/core:enableStackNameDuplicates',
46+
userValue: undefined,
47+
recommendedValue: 'true',
48+
explanation: 'Obsolete flag',
49+
module: 'aws-cdk-lib',
50+
},
51+
];
52+
53+
mockToolkit.flags.mockResolvedValue(mockFlagsData);
54+
55+
await displayFlagsMessage(mockToolkit as any, mockCloudExecutable, ioHelper);
56+
57+
expect(mockToolkit.flags).toHaveBeenCalledWith(mockCloudExecutable);
58+
expect(ioHost.notifySpy).toHaveBeenCalledWith(
59+
expect.objectContaining({
60+
message: 'You currently have 1 unconfigured feature flags that may require attention to keep your application up-to-date. Run \'cdk flags\' to learn more.',
61+
level: 'info',
62+
}),
63+
);
64+
});
65+
test('does not display a message when user has no unconfigured flags', async () => {
66+
const mockFlagsData = [
67+
{
68+
name: '@aws-cdk/s3:anotherFlag',
69+
userValue: 'false',
70+
recommendedValue: 'false',
71+
explanation: 'Another test flag',
72+
module: 'aws-cdk-lib',
73+
},
74+
];
75+
mockToolkit.flags.mockResolvedValue(mockFlagsData);
76+
77+
await displayFlagsMessage(mockToolkit as any, mockCloudExecutable, ioHelper);
78+
79+
expect(mockToolkit.flags).toHaveBeenCalledWith(mockCloudExecutable);
80+
expect(ioHost.notifySpy).not.toHaveBeenCalled();
81+
});
82+
});
83+

0 commit comments

Comments
 (0)