Skip to content

Commit cafe40b

Browse files
committed
normalize default value
1 parent e3a58da commit cafe40b

File tree

3 files changed

+122
-14
lines changed

3 files changed

+122
-14
lines changed

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

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,29 +1276,46 @@ export class Toolkit extends CloudAssemblySourceBuilder {
12761276
/**
12771277
* Retrieve feature flag information from the cloud assembly
12781278
*/
1279-
12801279
public async flags(cx: ICloudAssemblySource): Promise<FeatureFlag[]> {
12811280
this.requireUnstableFeature('flags');
12821281

12831282
const ioHelper = asIoHelper(this.ioHost, 'flags');
12841283
await using assembly = await assemblyFromSource(ioHelper, cx);
1285-
const artifacts = assembly.cloudAssembly.manifest.artifacts;
1284+
const artifacts = Object.values(assembly.cloudAssembly.manifest.artifacts!);
1285+
const featureFlagReports = artifacts.filter(a => a.type === ArtifactType.FEATURE_FLAG_REPORT);
1286+
1287+
const flags = featureFlagReports.flatMap(report => {
1288+
const properties = report.properties as FeatureFlagReportProperties;
1289+
const moduleName = properties.module;
1290+
1291+
const flagsWithUnconfiguredBehavesLike = Object.entries(properties.flags)
1292+
.filter(([_, flagInfo]) => flagInfo.unconfiguredBehavesLike != undefined);
12861293

1287-
return Object.values(artifacts!)
1288-
.filter(a => a.type === ArtifactType.FEATURE_FLAG_REPORT)
1289-
.flatMap(report => {
1290-
const properties = report.properties as FeatureFlagReportProperties;
1291-
const moduleName = properties.module;
1294+
const shouldIncludeUnconfiguredBehavesLike = flagsWithUnconfiguredBehavesLike.length > 0;
12921295

1293-
return Object.entries(properties.flags).map(([flagName, flagInfo]) => ({
1296+
return Object.entries(properties.flags).map(([flagName, flagInfo]) => {
1297+
const baseFlag = {
12941298
module: moduleName,
12951299
name: flagName,
12961300
recommendedValue: flagInfo.recommendedValue,
12971301
userValue: flagInfo.userValue ?? undefined,
12981302
explanation: flagInfo.explanation ?? '',
1299-
unconfiguredBehavesLike: flagInfo.unconfiguredBehavesLike,
1300-
}));
1303+
};
1304+
1305+
if (shouldIncludeUnconfiguredBehavesLike) {
1306+
return {
1307+
...baseFlag,
1308+
unconfiguredBehavesLike: {
1309+
v2: flagInfo.unconfiguredBehavesLike?.v2 === true ? true : false,
1310+
},
1311+
};
1312+
}
1313+
1314+
return baseFlag;
13011315
});
1316+
});
1317+
1318+
return flags;
13021319
}
13031320

13041321
private requireUnstableFeature(requestedFeature: UnstableFeature) {

packages/aws-cdk/lib/commands/flag-operations.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export async function handleFlags(flagData: FeatureFlag[], ioHelper: IoHelper, o
8787
default: true,
8888
unconfigured: true,
8989
};
90-
await setMultipleFlags(params);
90+
await checkDefaultBehavior(params);
9191
} else if (answer == FlagsMenuOptions.MODIFY_SPECIFIC_FLAG) {
9292
await setFlag(params, true);
9393
} else if (answer == FlagsMenuOptions.EXIT) {
@@ -167,8 +167,7 @@ export async function handleFlags(flagData: FeatureFlag[], ioHelper: IoHelper, o
167167
}
168168

169169
if (options.set && options.all && options.default) {
170-
await setMultipleFlags(params);
171-
return;
170+
await checkDefaultBehavior(params);
172171
}
173172

174173
if (options.set && options.unconfigured && options.recommended) {
@@ -177,9 +176,23 @@ export async function handleFlags(flagData: FeatureFlag[], ioHelper: IoHelper, o
177176
}
178177

179178
if (options.set && options.unconfigured && options.default) {
179+
await checkDefaultBehavior(params);
180+
}
181+
}
182+
183+
/**
184+
* Checks if the `unconfiguredBehavesLike` field is populated
185+
*
186+
* @returns true if --default options can be run
187+
*/
188+
async function checkDefaultBehavior(params: FlagOperationsParams) {
189+
const { flagData, ioHelper } = params;
190+
if (flagData[0].unconfiguredBehavesLike) {
180191
await setMultipleFlags(params);
181192
return;
182193
}
194+
await ioHelper.defaults.error('The --default options are not compatible with the AWS CDK library used by your application. Please upgrade to 2.212.0 or above.');
195+
return;
183196
}
184197

185198
async function setFlag(params: FlagOperationsParams, interactive?: boolean) {

packages/aws-cdk/test/commands/flag-operations.test.ts

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,65 @@ describe('modifyValues', () => {
572572
});
573573
});
574574

575+
describe('checkDefaultBehavior', () => {
576+
test('calls setMultipleFlags when unconfiguredBehavesLike is present', async () => {
577+
const flagsWithUnconfiguredBehavior: FeatureFlag[] = [
578+
{
579+
module: 'aws-cdk-lib',
580+
name: '@aws-cdk/core:testFlag',
581+
recommendedValue: 'true',
582+
userValue: undefined,
583+
explanation: 'Test flag',
584+
unconfiguredBehavesLike: { v2: 'true' },
585+
},
586+
];
587+
588+
const cdkJsonPath = await createCdkJsonFile({});
589+
setupMockToolkitForPrototyping(mockToolkit);
590+
591+
const requestResponseSpy = jest.spyOn(ioHelper, 'requestResponse');
592+
requestResponseSpy.mockResolvedValue(true);
593+
594+
const options: FlagsOptions = {
595+
set: true,
596+
all: true,
597+
default: true,
598+
};
599+
600+
await handleFlags(flagsWithUnconfiguredBehavior, ioHelper, options, mockToolkit);
601+
602+
expect(mockToolkit.fromCdkApp).toHaveBeenCalled();
603+
expect(mockToolkit.synth).toHaveBeenCalled();
604+
605+
await cleanupCdkJsonFile(cdkJsonPath);
606+
requestResponseSpy.mockRestore();
607+
});
608+
609+
test('shows error when unconfiguredBehavesLike is not present', async () => {
610+
const flagsWithoutUnconfiguredBehavior: FeatureFlag[] = [
611+
{
612+
module: 'aws-cdk-lib',
613+
name: '@aws-cdk/core:testFlag',
614+
recommendedValue: 'true',
615+
userValue: undefined,
616+
explanation: 'Test flag',
617+
},
618+
];
619+
620+
const options: FlagsOptions = {
621+
set: true,
622+
all: true,
623+
default: true,
624+
};
625+
626+
await handleFlags(flagsWithoutUnconfiguredBehavior, ioHelper, options, mockToolkit);
627+
628+
const plainTextOutput = output();
629+
expect(plainTextOutput).toContain('The --default options are not compatible with the AWS CDK library used by your application.');
630+
expect(mockToolkit.fromCdkApp).not.toHaveBeenCalled();
631+
});
632+
});
633+
575634
describe('interactive prompts lead to the correct function calls', () => {
576635
beforeEach(() => {
577636
setupMockToolkitForPrototyping(mockToolkit);
@@ -654,11 +713,30 @@ describe('interactive prompts lead to the correct function calls', () => {
654713
const requestResponseSpy = jest.spyOn(ioHelper, 'requestResponse');
655714
requestResponseSpy.mockResolvedValue(true);
656715

716+
const flagsWithUnconfiguredBehavior: FeatureFlag[] = [
717+
{
718+
module: 'aws-cdk-lib',
719+
name: '@aws-cdk/core:testFlag',
720+
recommendedValue: 'true',
721+
userValue: 'false',
722+
explanation: 'Test flag for unit tests',
723+
unconfiguredBehavesLike: { v2: 'true' },
724+
},
725+
{
726+
module: 'aws-cdk-lib',
727+
name: '@aws-cdk/s3:anotherFlag',
728+
recommendedValue: 'false',
729+
userValue: undefined,
730+
explanation: 'Another test flag',
731+
unconfiguredBehavesLike: { v2: 'false' },
732+
},
733+
];
734+
657735
const options: FlagsOptions = {
658736
interactive: true,
659737
};
660738

661-
await handleFlags(mockFlagsData, ioHelper, options, mockToolkit);
739+
await handleFlags(flagsWithUnconfiguredBehavior, ioHelper, options, mockToolkit);
662740

663741
expect(mockToolkit.fromCdkApp).toHaveBeenCalledTimes(2);
664742
expect(mockToolkit.synth).toHaveBeenCalledTimes(2);

0 commit comments

Comments
 (0)