Skip to content

Commit

Permalink
chore(migrate): add migrate information to AWS::CDK::Metadata (#28958)
Browse files Browse the repository at this point in the history
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*
  • Loading branch information
madeline-k authored and TheRealAmazonKendra committed Feb 1, 2024
1 parent 5e3c3c6 commit fc1b702
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 10 deletions.
33 changes: 24 additions & 9 deletions packages/aws-cdk-lib/core/lib/private/metadata-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { Token } from '../token';
export class MetadataResource extends Construct {
constructor(scope: Stack, id: string) {
super(scope, id);

const metadataServiceExists = Token.isUnresolved(scope.region) || RegionInfo.get(scope.region).cdkMetadataResourceAvailable;
if (metadataServiceExists) {
const resource = new CfnResource(this, 'Default', {
Expand Down Expand Up @@ -51,22 +50,30 @@ function makeCdkMetadataAvailableCondition() {
class Trie extends Map<string, Trie> { }

/**
* Formats a list of construct fully-qualified names (FQNs) and versions into a (possibly compressed) prefix-encoded string.
* Formats the analytics string which has 3 or 4 sections separated by colons (:)
*
* version:encoding:constructinfo OR version:encoding:constructinfo:appinfo
*
* The list of ConstructInfos is logically formatted into:
* ${version}!${fqn} (e.g., "1.90.0!aws-cdk-lib.Stack")
* and then all of the construct-versions are grouped with common prefixes together, grouping common parts in '{}' and separating items with ','.
* The constructinfo section is a list of construct fully-qualified names (FQNs)
* and versions into a (possibly compressed) prefix-encoded string.
*
* The list of ConstructInfos is logically formatted into: ${version}!${fqn}
* (e.g., "1.90.0!aws-cdk-lib.Stack") and then all of the construct-versions are
* grouped with common prefixes together, grouping common parts in '{}' and
* separating items with ','.
*
* Example:
* [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]
* Becomes:
* 1.90.0!aws-cdk-lib.{Stack,Construct,service.Resource},0.42.1!aws-cdk-lib-experiments.NewStuff
*
* The whole thing is then either included directly as plaintext as:
* v2:plaintext:{prefixEncodedList}
* Or is compressed and base64-encoded, and then formatted as:
* The whole thing is then compressed and base64-encoded, and then formatted as:
* v2:deflate64:{prefixEncodedListCompressedAndEncoded}
*
* The appinfo section is optional, and currently only added if the app was generated using `cdk migrate`
* It is also compressed and base64-encoded. In this case, the string will be formatted as:
* v2:deflate64:{prefixEncodedListCompressedAndEncoded}:{'cdk-migrate'CompressedAndEncoded}
*
* Exported/visible for ease of testing.
*/
export function formatAnalytics(infos: ConstructInfo[]) {
Expand All @@ -81,7 +88,15 @@ export function formatAnalytics(infos: ConstructInfo[]) {
setGzipOperatingSystemToUnknown(compressedConstructsBuffer);

const compressedConstructs = compressedConstructsBuffer.toString('base64');
return `v2:deflate64:${compressedConstructs}`;
const analyticsString = `v2:deflate64:${compressedConstructs}`;

if (process.env.CDK_CONTEXT_JSON && JSON.parse(process.env.CDK_CONTEXT_JSON)['cdk-migrate']) {
const compressedAppInfoBuffer = zlib.gzipSync(Buffer.from('cdk-migrate'));
const compressedAppInfo = compressedAppInfoBuffer.toString('base64');
analyticsString.concat(':', compressedAppInfo);
}

return analyticsString;
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/aws-cdk/lib/commands/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export async function generateCdkApp(stackName: string, stack: string, language:
generateOnly,
workDir: resolvedOutputPath,
stackName,
migrate: true,
});

let stackFileName: string;
Expand Down
22 changes: 21 additions & 1 deletion packages/aws-cdk/lib/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface CliInitOptions {
readonly generateOnly?: boolean;
readonly workDir?: string;
readonly stackName?: string;
readonly migrate?: boolean;
}

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

await initializeProject(template, options.language, canUseNetwork, generateOnly, workDir, options.stackName);
await initializeProject(template, options.language, canUseNetwork, generateOnly, workDir, options.stackName, options.migrate);
}

/**
Expand Down Expand Up @@ -203,6 +204,21 @@ export class InitTemplate {

await fs.writeJson(cdkJson, config, { spaces: 2 });
}

public async addMigrateContext(projectDir: string) {
const cdkJson = path.join(projectDir, 'cdk.json');
if (!await fs.pathExists(cdkJson)) {
return;
}

const config = await fs.readJson(cdkJson);
config.context = {
...config.context,
'cdk-migrate': true,
};

await fs.writeJson(cdkJson, config, { spaces: 2 });
}
}

interface ProjectInfo {
Expand Down Expand Up @@ -271,10 +287,14 @@ async function initializeProject(
generateOnly: boolean,
workDir: string,
stackName?: string,
migrate?: boolean,
) {
await assertIsEmptyDirectory(workDir);
print(`Applying project template ${chalk.green(template.name)} for ${chalk.blue(language)}`);
await template.install(language, workDir, stackName);
if (migrate) {
await template.addMigrateContext(workDir);
}
if (await fs.pathExists('README.md')) {
print(chalk.green(await fs.readFile('README.md', { encoding: 'utf-8' })));
}
Expand Down
12 changes: 12 additions & 0 deletions packages/aws-cdk/test/commands/migrate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@ describe('Migrate Function Tests', () => {
expect(replacedStack).toEqual(fs.readFileSync(path.join(...stackPath, 's3-stack.ts'), 'utf8'));
});

cliTest('generateCdkApp adds cdk-migrate key in context', async (workDir) => {
const stack = generateStack(validTemplate, 'GoodTypeScript', 'typescript');
await generateCdkApp('GoodTypeScript', stack, 'typescript', workDir);

// cdk.json exist in the correct spot
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'cdk.json'))).toBeTruthy();

// cdk.json has "cdk-migrate" : true in context
const cdkJson = fs.readJsonSync(path.join(workDir, 'GoodTypeScript', 'cdk.json'), 'utf8');
expect(cdkJson.context['cdk-migrate']).toBeTruthy();
});

cliTest('generateCdkApp generates the expected cdk app when called for python', async (workDir) => {
const stack = generateStack(validTemplate, 'GoodPython', 'python');
await generateCdkApp('GoodPython', stack, 'python', workDir);
Expand Down

0 comments on commit fc1b702

Please sign in to comment.