diff --git a/cli-program.ts b/cli-program.ts index cfaff982..aec01fb9 100644 --- a/cli-program.ts +++ b/cli-program.ts @@ -7,6 +7,7 @@ import { InitOrganizationCommand, InitPipelineCommand, PerformTasksCommand, + PrintChangeSetCommand, PrintOrganizationCommand, PrintStacksCommand, UpdateOrganizationCommand, @@ -50,6 +51,7 @@ export class CliProgram { new InitPipelineCommand(this.program); new InitOrganizationCommand(this.program); new PerformTasksCommand(this.program); + new PrintChangeSetCommand(this.program); new PrintOrganizationCommand(this.program); new PrintTasksCommand(this.program); new PrintStacksCommand(this.program); diff --git a/docs/cli-reference.md b/docs/cli-reference.md index e1f57d90..ed04d65d 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -17,6 +17,7 @@ Typing ``help`` after any command in the commandline will print documentation. - [``org-formation update``](#org-formation-update) - [``org-formation create-change-set``](#org-formation-create-change-set) - [``org-formation execute-change-set``](#org-formation-execute-change-set) + - [``org-formation print-change-set``](#org-formation-print-change-set) - [Operations on stacks](#operations-on-stacks) - [``org-formation update-stacks``](#org-formation-update-stacks) - [``org-formation validate-stacks``](#org-formation-validate-stacks) @@ -92,6 +93,12 @@ Execute a changeset by name of *changeSetName*. ``> org-formation execute-change-set change-set-name`` +### ``org-formation print-change-set`` + +Display a changeset by name of *changeSetName*. + +``> org-formation print-change-set change-set-name`` + ## Operations on stacks ### ``org-formation update-stacks`` diff --git a/src/commands/create-organization-changeset.ts b/src/commands/create-organization-changeset.ts index 190e97ed..6ecc19d6 100644 --- a/src/commands/create-organization-changeset.ts +++ b/src/commands/create-organization-changeset.ts @@ -5,6 +5,7 @@ import { ChangeSetProvider } from '~change-set/change-set-provider'; import { TemplateRoot } from '~parser/parser'; import { GlobalState } from '~util/global-state'; import { AwsUtil } from '~util/aws-util'; +import { yamlDump } from '~yaml-cfn/index'; const commandName = 'create-change-set '; const commandDescription = 'create change set that can be reviewed and executed later'; @@ -18,10 +19,16 @@ export class CreateChangeSetCommand extends BaseCliCommand', 'serialization format used when printing change set. Either json or yaml.', 'json'); } public async performCommand(command: ICreateChangeSetCommandArgs): Promise { + if (!['json', 'yaml'].includes(command.output)) { + ConsoleUtil.LogError(`Invalid output format '${command.output}'. Must be either 'json' or 'yaml'.`); + return; + } + const template = await TemplateRoot.create(command.templateFile); const state = await this.getState(command); @@ -42,8 +49,11 @@ export class CreateChangeSetCommand extends BaseCliCommand { + + public static async Perform(command: IPrintChangeSetCommandArgs): Promise { + const x = new PrintChangeSetCommand(); + await x.performCommand(command); + } + + constructor(command?: Command) { + super(command, commandName, commandDescription, 'changeSetName'); + } + + public addOptions(command: Command): void { + super.addOptions(command); + command.option('--change-set-name [change-set-name]', 'change set name'); + command.option('--output ', 'serialization format used when printing change set. Either json or yaml.', 'json'); + } + + public async performCommand(command: IPrintChangeSetCommandArgs): Promise { + if (!['json', 'yaml'].includes(command.output)) { + ConsoleUtil.LogError(`Invalid output format '${command.output}'. Must be either 'json' or 'yaml'.`); + return; + } + const changeSetName = command.changeSetName; + const stateBucketName = await BaseCliCommand.GetStateBucketName(command.stateBucketName); + const provider = new ChangeSetProvider(stateBucketName); + const changeSetObj = await provider.getChangeSet(changeSetName); + if (!changeSetObj) { + ConsoleUtil.LogError(`change set '${changeSetName}' not found.`); + return; + } + const changeSet = changeSetObj.changeSet; + + if (command.output === 'json') { + ConsoleUtil.Out(JSON.stringify(changeSet, null, 2)); + } else if (command.output === 'yaml') { + ConsoleUtil.Out(yamlDump(changeSet)); + } + + } +} + +export interface IPrintChangeSetCommandArgs extends ICommandArgs { + changeSetName?: string; + output?: 'json' | 'yaml'; +} diff --git a/test/unit-tests/commands/print-change-set.ts b/test/unit-tests/commands/print-change-set.ts new file mode 100644 index 00000000..a5b41f33 --- /dev/null +++ b/test/unit-tests/commands/print-change-set.ts @@ -0,0 +1,33 @@ +import { Command, Option } from "commander"; +import { PrintChangeSetCommand } from "~commands/print-changeset"; + +describe('when creating print change set command', () => { + let command: PrintChangeSetCommand; + let commanderCommand: Command; + let subCommanderCommand: Command; + + beforeEach(() => { + commanderCommand = new Command('root'); + command = new PrintChangeSetCommand(commanderCommand); + subCommanderCommand = commanderCommand.commands[0]; + }); + + test('print change set command is created', () => { + expect(command).toBeDefined(); + expect(subCommanderCommand).toBeDefined(); + expect(subCommanderCommand.name()).toBe('print-change-set'); + }); + + test('print change set command has description', () => { + expect(subCommanderCommand).toBeDefined(); + expect(subCommanderCommand.description()).toBeDefined(); + }); + + test('command has required output parameter with default', () => { + const opts: Option[] = subCommanderCommand.options; + const stackNameOpt = opts.find((x) => x.long === '--output'); + expect(stackNameOpt).toBeDefined(); + expect(stackNameOpt.required).toBeTruthy(); + expect(subCommanderCommand.output).toBe('yaml'); + }); +}); \ No newline at end of file