Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(cli): function to turn yargs output to cliArguments #32696

Merged
merged 14 commits into from
Jan 2, 2025
Merged
1 change: 0 additions & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,4 @@ component_management:

# https://docs.codecov.com/docs/ignoring-paths
ignore:
- packages/aws-cdk/lib/parse-command-line-arguments.ts # this file is generated and some lines cannot be tested
- packages/aws-cdk/lib/cli.ts # we integ test this file
4 changes: 4 additions & 0 deletions packages/aws-cdk/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const config = {
...baseConfig.coveragePathIgnorePatterns,
// Mostly wrappers around the SDK, which get mocked in unit tests
"<rootDir>/lib/api/aws-auth/sdk.ts",
// Files generated by cli-args-gen
"<rootDir>/lib/parse-command-line-arguments.ts",
"<rootDir>/lib/cli-arguments.ts",
"<rootDir>/lib/convert-to-cli-args.ts",
],

// We have many tests here that commonly time out
Expand Down
1 change: 1 addition & 0 deletions packages/aws-cdk/lib/cli-arguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// GENERATED FROM packages/aws-cdk/lib/config.ts.
// Do not edit by hand; all changes will be overwritten at build time from the config file.
// -------------------------------------------------------------------------------------------
// istanbul ignore file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this actually do something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I forgot to yarn build aws-cdk to remove them...

/* eslint-disable @stylistic/max-len */
import { Command } from './settings';

Expand Down
242 changes: 242 additions & 0 deletions packages/aws-cdk/lib/convert-to-cli-args.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// -------------------------------------------------------------------------------------------
// GENERATED FROM packages/aws-cdk/lib/config.ts.
// Do not edit by hand; all changes will be overwritten at build time from the config file.
// -------------------------------------------------------------------------------------------
// istanbul ignore file
/* eslint-disable @stylistic/max-len */
import { CliArguments, GlobalOptions } from './cli-arguments';
import { Command } from './settings';

// @ts-ignore TS6133
export function convertToCliArgs(args: any): CliArguments {
const globalOptions: GlobalOptions = {
app: args.app,
build: args.build,
context: args.context,
plugin: args.plugin,
trace: args.trace,
strict: args.strict,
lookups: args.lookups,
ignoreErrors: args.ignoreErrors,
json: args.json,
verbose: args.verbose,
debug: args.debug,
profile: args.profile,
proxy: args.proxy,
caBundlePath: args.caBundlePath,
ec2creds: args.ec2creds,
versionReporting: args.versionReporting,
pathMetadata: args.pathMetadata,
assetMetadata: args.assetMetadata,
roleArn: args.roleArn,
staging: args.staging,
output: args.output,
notices: args.notices,
noColor: args.noColor,
ci: args.ci,
unstable: args.unstable,
};
let commandOptions;
switch (args._[0] as Command) {
case 'list':
commandOptions = {
long: args.long,
showDependencies: args.showDependencies,
};
break;

case 'synthesize':
commandOptions = {
exclusively: args.exclusively,
validation: args.validation,
quiet: args.quiet,
};
break;

case 'bootstrap':
commandOptions = {
bootstrapBucketName: args.bootstrapBucketName,
bootstrapKmsKeyId: args.bootstrapKmsKeyId,
examplePermissionsBoundary: args.examplePermissionsBoundary,
customPermissionsBoundary: args.customPermissionsBoundary,
bootstrapCustomerKey: args.bootstrapCustomerKey,
qualifier: args.qualifier,
publicAccessBlockConfiguration: args.publicAccessBlockConfiguration,
tags: args.tags,
execute: args.execute,
trust: args.trust,
trustForLookup: args.trustForLookup,
cloudformationExecutionPolicies: args.cloudformationExecutionPolicies,
force: args.force,
terminationProtection: args.terminationProtection,
showTemplate: args.showTemplate,
toolkitStackName: args.toolkitStackName,
template: args.template,
previousParameters: args.previousParameters,
};
break;

case 'gc':
commandOptions = {
action: args.action,
type: args.type,
rollbackBufferDays: args.rollbackBufferDays,
createdBufferDays: args.createdBufferDays,
confirm: args.confirm,
bootstrapStackName: args.bootstrapStackName,
};
break;

case 'deploy':
commandOptions = {
all: args.all,
buildExclude: args.buildExclude,
exclusively: args.exclusively,
requireApproval: args.requireApproval,
notificationArns: args.notificationArns,
tags: args.tags,
execute: args.execute,
changeSetName: args.changeSetName,
method: args.method,
importExistingResources: args.importExistingResources,
force: args.force,
parameters: args.parameters,
outputsFile: args.outputsFile,
previousParameters: args.previousParameters,
toolkitStackName: args.toolkitStackName,
progress: args.progress,
rollback: args.rollback,
hotswap: args.hotswap,
hotswapFallback: args.hotswapFallback,
watch: args.watch,
logs: args.logs,
concurrency: args.concurrency,
assetParallelism: args.assetParallelism,
assetPrebuild: args.assetPrebuild,
ignoreNoStacks: args.ignoreNoStacks,
};
break;

case 'rollback':
commandOptions = {
all: args.all,
toolkitStackName: args.toolkitStackName,
force: args.force,
validateBootstrapVersion: args.validateBootstrapVersion,
orphan: args.orphan,
};
break;

case 'import':
commandOptions = {
execute: args.execute,
changeSetName: args.changeSetName,
toolkitStackName: args.toolkitStackName,
rollback: args.rollback,
force: args.force,
recordResourceMapping: args.recordResourceMapping,
resourceMapping: args.resourceMapping,
};
break;

case 'watch':
commandOptions = {
buildExclude: args.buildExclude,
exclusively: args.exclusively,
changeSetName: args.changeSetName,
force: args.force,
toolkitStackName: args.toolkitStackName,
progress: args.progress,
rollback: args.rollback,
hotswap: args.hotswap,
hotswapFallback: args.hotswapFallback,
logs: args.logs,
concurrency: args.concurrency,
};
break;

case 'destroy':
commandOptions = {
all: args.all,
exclusively: args.exclusively,
force: args.force,
};
break;

case 'diff':
commandOptions = {
exclusively: args.exclusively,
contextLines: args.contextLines,
template: args.template,
strict: args.strict,
securityOnly: args.securityOnly,
fail: args.fail,
processed: args.processed,
quiet: args.quiet,
changeSet: args.changeSet,
};
break;

case 'metadata':
commandOptions = {};
break;

case 'acknowledge':
commandOptions = {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at our current for this command I see:

case 'ack':
return cli.acknowledge(args.ID);

Should this PR also handle positional arguments? I would expect we have a strongly typed args.acknowledge.id or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. A big part of my refactor is to make sure we don't have to use args, argv, and configuration.settings everywhere and instead just have 1 object with arguments.

Currently those positional arguments are found in index 1 and beyond on argv._: argv._: [Command, ...string]

It will be a bit awkward to figure out the right way to deal with that, which I would like to do in a separate PR.

break;

case 'notices':
commandOptions = {
unacknowledged: args.unacknowledged,
};
break;

case 'init':
commandOptions = {
language: args.language,
list: args.list,
generateOnly: args.generateOnly,
};
break;

case 'migrate':
commandOptions = {
stackName: args.stackName,
language: args.language,
account: args.account,
region: args.region,
fromPath: args.fromPath,
fromStack: args.fromStack,
outputPath: args.outputPath,
fromScan: args.fromScan,
filter: args.filter,
compress: args.compress,
};
break;

case 'context':
commandOptions = {
reset: args.reset,
force: args.force,
clear: args.clear,
};
break;

case 'docs':
commandOptions = {
browser: args.browser,
};
break;

case 'doctor':
commandOptions = {};
break;
}
const cliArguments: CliArguments = {
_: args._,
globalOptions,
[args._[0]]: commandOptions,
};

return cliArguments;
}
1 change: 1 addition & 0 deletions packages/aws-cdk/lib/parse-command-line-arguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// GENERATED FROM packages/aws-cdk/lib/config.ts.
// Do not edit by hand; all changes will be overwritten at build time from the config file.
// -------------------------------------------------------------------------------------------
// istanbul ignore file
/* eslint-disable @stylistic/max-len */
import { Argv } from 'yargs';
import * as helpers from './util/yargs-helpers';
Expand Down
5 changes: 3 additions & 2 deletions packages/aws-cdk/scripts/cli-args-gen.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as fs from 'fs';
// eslint-disable-next-line import/no-extraneous-dependencies
import { renderYargs, renderCliType } from '@aws-cdk/cli-args-gen';
import { renderYargs, renderCliArgsType, renderCliArgsFunc } from '@aws-cdk/cli-args-gen';
import { makeConfig, YARGS_HELPERS } from '../lib/config';

async function main() {
fs.writeFileSync('./lib/parse-command-line-arguments.ts', await renderYargs(await makeConfig(), YARGS_HELPERS));
fs.writeFileSync('./lib/cli-arguments.ts', await renderCliType(await makeConfig()));
fs.writeFileSync('./lib/cli-arguments.ts', await renderCliArgsType(await makeConfig()));
kaizencc marked this conversation as resolved.
Show resolved Hide resolved
fs.writeFileSync('./lib/convert-to-cli-args.ts', await renderCliArgsFunc(await makeConfig()));
}

main().then(() => {
Expand Down
73 changes: 60 additions & 13 deletions packages/aws-cdk/test/cli-arguments.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,66 @@
import { CliArguments } from '../lib/cli-arguments';
import { Command } from '../lib/settings';
import { convertToCliArgs } from '../lib/convert-to-cli-args';
import { parseCommandLineArguments } from '../lib/parse-command-line-arguments';

// CliArguments is not being used right now, so the testing suite is rather redundant.
// This file is meant to be populated when CliArguments is used.
test('cli arguments can be used as a type', async () => {
const argv: CliArguments = {
_: [Command.DEPLOY],
test('yargs object can be converted to cli arguments', async () => {
const input = await parseCommandLineArguments(['deploy', '-R', '-v', '--ci']);

const result = convertToCliArgs(input);

expect(result).toEqual({
_: ['deploy'],
globalOptions: {
lookups: true,
app: undefined,
assetMetadata: undefined,
build: undefined,
caBundlePath: undefined,
context: [],
ignoreErrors: false,
noColor: false,
pathMetadata: undefined,
plugin: [],
profile: undefined,
proxy: undefined,
roleArn: undefined,
staging: true,
strict: undefined,
verbose: 1,
versionReporting: undefined,
ci: true,
debug: false,
ec2creds: undefined,
json: false,
verbose: false,
lookups: true,
trace: undefined,
unstable: [],
notices: undefined,
output: undefined,
},
};

expect(argv._[0]).toBe('deploy');
expect(argv.globalOptions?.lookups).toBeTruthy();
deploy: {
all: false,
assetParallelism: undefined,
assetPrebuild: true,
buildExclude: [],
changeSetName: undefined,
concurrency: 1,
execute: undefined,
exclusively: undefined,
force: false,
hotswap: undefined,
hotswapFallback: undefined,
ignoreNoStacks: false,
importExistingResources: false,
logs: true,
method: undefined,
notificationArns: undefined,
outputsFile: undefined,
parameters: [{}],
previousParameters: true,
progress: undefined,
requireApproval: undefined,
rollback: false,
tags: [],
toolkitStackName: undefined,
watch: undefined,
},
});
});
7 changes: 5 additions & 2 deletions tools/@aws-cdk/cli-args-gen/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# cli-args-gen

Generates CDK CLI configurations from the source of truth in `packages/aws-cdk/lib/config.ts`.
Currently generates `yargs` config into `packages/aws-cdk/lib/parse-command-line-arguments.ts` and
strongly-typed CLI arguments interface into `packages/aws-cdk-lib/cli-arguments.ts`.
Currently generates the following files:

- `packages/aws-cdk/lib/parse-command-line-arguments.ts`: `yargs` config.
- `packages/aws-cdk-lib/cli-arguments.ts`: strongly typed `CliArguments` interface.
- `packages/aws-cdk-lib/convert-to-cli-args.ts`: converts the `any` returned by `yargs` to `CliArguments`.

## Usage

Expand Down
Loading
Loading