Skip to content

Commit fc1b702

Browse files
madeline-kTheRealAmazonKendra
authored andcommitted
chore(migrate): add migrate information to AWS::CDK::Metadata (#28958)
This change adds a new context key to the `cdk.json` file when an app is generated by the `cdk migrate` cli command. If the context key `"cdk-migrate"` is `true`, then that information is added to the end of the analytics string in the AWS::CDK::Metadata resource. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 5e3c3c6 commit fc1b702

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
lines changed

packages/aws-cdk-lib/core/lib/private/metadata-resource.ts

+24-9
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { Token } from '../token';
1616
export class MetadataResource extends Construct {
1717
constructor(scope: Stack, id: string) {
1818
super(scope, id);
19-
2019
const metadataServiceExists = Token.isUnresolved(scope.region) || RegionInfo.get(scope.region).cdkMetadataResourceAvailable;
2120
if (metadataServiceExists) {
2221
const resource = new CfnResource(this, 'Default', {
@@ -51,22 +50,30 @@ function makeCdkMetadataAvailableCondition() {
5150
class Trie extends Map<string, Trie> { }
5251

5352
/**
54-
* Formats a list of construct fully-qualified names (FQNs) and versions into a (possibly compressed) prefix-encoded string.
53+
* Formats the analytics string which has 3 or 4 sections separated by colons (:)
54+
*
55+
* version:encoding:constructinfo OR version:encoding:constructinfo:appinfo
5556
*
56-
* The list of ConstructInfos is logically formatted into:
57-
* ${version}!${fqn} (e.g., "1.90.0!aws-cdk-lib.Stack")
58-
* and then all of the construct-versions are grouped with common prefixes together, grouping common parts in '{}' and separating items with ','.
57+
* The constructinfo section is a list of construct fully-qualified names (FQNs)
58+
* and versions into a (possibly compressed) prefix-encoded string.
59+
*
60+
* The list of ConstructInfos is logically formatted into: ${version}!${fqn}
61+
* (e.g., "1.90.0!aws-cdk-lib.Stack") and then all of the construct-versions are
62+
* grouped with common prefixes together, grouping common parts in '{}' and
63+
* separating items with ','.
5964
*
6065
* Example:
6166
* [1.90.0!aws-cdk-lib.Stack, 1.90.0!aws-cdk-lib.Construct, 1.90.0!aws-cdk-lib.service.Resource, 0.42.1!aws-cdk-lib-experiments.NewStuff]
6267
* Becomes:
6368
* 1.90.0!aws-cdk-lib.{Stack,Construct,service.Resource},0.42.1!aws-cdk-lib-experiments.NewStuff
6469
*
65-
* The whole thing is then either included directly as plaintext as:
66-
* v2:plaintext:{prefixEncodedList}
67-
* Or is compressed and base64-encoded, and then formatted as:
70+
* The whole thing is then compressed and base64-encoded, and then formatted as:
6871
* v2:deflate64:{prefixEncodedListCompressedAndEncoded}
6972
*
73+
* The appinfo section is optional, and currently only added if the app was generated using `cdk migrate`
74+
* It is also compressed and base64-encoded. In this case, the string will be formatted as:
75+
* v2:deflate64:{prefixEncodedListCompressedAndEncoded}:{'cdk-migrate'CompressedAndEncoded}
76+
*
7077
* Exported/visible for ease of testing.
7178
*/
7279
export function formatAnalytics(infos: ConstructInfo[]) {
@@ -81,7 +88,15 @@ export function formatAnalytics(infos: ConstructInfo[]) {
8188
setGzipOperatingSystemToUnknown(compressedConstructsBuffer);
8289

8390
const compressedConstructs = compressedConstructsBuffer.toString('base64');
84-
return `v2:deflate64:${compressedConstructs}`;
91+
const analyticsString = `v2:deflate64:${compressedConstructs}`;
92+
93+
if (process.env.CDK_CONTEXT_JSON && JSON.parse(process.env.CDK_CONTEXT_JSON)['cdk-migrate']) {
94+
const compressedAppInfoBuffer = zlib.gzipSync(Buffer.from('cdk-migrate'));
95+
const compressedAppInfo = compressedAppInfoBuffer.toString('base64');
96+
analyticsString.concat(':', compressedAppInfo);
97+
}
98+
99+
return analyticsString;
85100
}
86101

87102
/**

packages/aws-cdk/lib/commands/migrate.ts

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export async function generateCdkApp(stackName: string, stack: string, language:
3838
generateOnly,
3939
workDir: resolvedOutputPath,
4040
stackName,
41+
migrate: true,
4142
});
4243

4344
let stackFileName: string;

packages/aws-cdk/lib/init.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface CliInitOptions {
2121
readonly generateOnly?: boolean;
2222
readonly workDir?: string;
2323
readonly stackName?: string;
24+
readonly migrate?: boolean;
2425
}
2526

2627
/**
@@ -51,7 +52,7 @@ export async function cliInit(options: CliInitOptions) {
5152
throw new Error('No language was selected');
5253
}
5354

54-
await initializeProject(template, options.language, canUseNetwork, generateOnly, workDir, options.stackName);
55+
await initializeProject(template, options.language, canUseNetwork, generateOnly, workDir, options.stackName, options.migrate);
5556
}
5657

5758
/**
@@ -203,6 +204,21 @@ export class InitTemplate {
203204

204205
await fs.writeJson(cdkJson, config, { spaces: 2 });
205206
}
207+
208+
public async addMigrateContext(projectDir: string) {
209+
const cdkJson = path.join(projectDir, 'cdk.json');
210+
if (!await fs.pathExists(cdkJson)) {
211+
return;
212+
}
213+
214+
const config = await fs.readJson(cdkJson);
215+
config.context = {
216+
...config.context,
217+
'cdk-migrate': true,
218+
};
219+
220+
await fs.writeJson(cdkJson, config, { spaces: 2 });
221+
}
206222
}
207223

208224
interface ProjectInfo {
@@ -271,10 +287,14 @@ async function initializeProject(
271287
generateOnly: boolean,
272288
workDir: string,
273289
stackName?: string,
290+
migrate?: boolean,
274291
) {
275292
await assertIsEmptyDirectory(workDir);
276293
print(`Applying project template ${chalk.green(template.name)} for ${chalk.blue(language)}`);
277294
await template.install(language, workDir, stackName);
295+
if (migrate) {
296+
await template.addMigrateContext(workDir);
297+
}
278298
if (await fs.pathExists('README.md')) {
279299
print(chalk.green(await fs.readFile('README.md', { encoding: 'utf-8' })));
280300
}

packages/aws-cdk/test/commands/migrate.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ describe('Migrate Function Tests', () => {
152152
expect(replacedStack).toEqual(fs.readFileSync(path.join(...stackPath, 's3-stack.ts'), 'utf8'));
153153
});
154154

155+
cliTest('generateCdkApp adds cdk-migrate key in context', async (workDir) => {
156+
const stack = generateStack(validTemplate, 'GoodTypeScript', 'typescript');
157+
await generateCdkApp('GoodTypeScript', stack, 'typescript', workDir);
158+
159+
// cdk.json exist in the correct spot
160+
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'cdk.json'))).toBeTruthy();
161+
162+
// cdk.json has "cdk-migrate" : true in context
163+
const cdkJson = fs.readJsonSync(path.join(workDir, 'GoodTypeScript', 'cdk.json'), 'utf8');
164+
expect(cdkJson.context['cdk-migrate']).toBeTruthy();
165+
});
166+
155167
cliTest('generateCdkApp generates the expected cdk app when called for python', async (workDir) => {
156168
const stack = generateStack(validTemplate, 'GoodPython', 'python');
157169
await generateCdkApp('GoodPython', stack, 'python', workDir);

0 commit comments

Comments
 (0)