diff --git a/src/commands/runtime/action/create.js b/src/commands/runtime/action/create.js index 75aac90e..8f3e6537 100644 --- a/src/commands/runtime/action/create.js +++ b/src/commands/runtime/action/create.js @@ -28,6 +28,7 @@ class ActionCreate extends RuntimeBaseCommand { let annotationParams const webAction = flags.web ? flags.web.toLowerCase() : false const webSecure = flags['web-secure'] ? flags['web-secure'].toLowerCase() : false + const method = this.isUpdate() ? 'update' : 'create' try { // sanity check web secure must have web truthy @@ -41,7 +42,7 @@ class ActionCreate extends RuntimeBaseCommand { throw (new Error(ActionCreate.errorMessages.sequenceWithDocker)) } else if (flags.docker && flags.kind) { throw (new Error(ActionCreate.errorMessages.kindWithDocker)) - } else if (!args.actionPath && !flags.sequence && !flags.docker && !this.isUpdate()) { + } else if (!flags.copy && !args.actionPath && !flags.sequence && !flags.docker && !this.isUpdate()) { throw (new Error(ActionCreate.errorMessages.missingKind)) } @@ -94,6 +95,9 @@ class ActionCreate extends RuntimeBaseCommand { } else { exec = createComponentsfromSequence(sequenceAction) } + } else if (flags.copy) { + const ow = await this.wsk() + return await this.syncAction(ow, name, null, flags, method) } if (flags.docker) { @@ -112,7 +116,7 @@ class ActionCreate extends RuntimeBaseCommand { envParams = createKeyValueArrayFromFile(flags['env-file']) } - // merge parametes and environemtn variables + // merge parameters and environment variables if (envParams) { envParams = envParams.map(e => ({ ...e, init: true })) if (paramsAction) { @@ -178,22 +182,42 @@ class ActionCreate extends RuntimeBaseCommand { } const options = { name } - if (exec) options.exec = exec - if (limits) options.limits = limits - if (paramsAction) options.parameters = paramsAction - if (annotationParams) options.annotations = annotationParams - - const ow = await this.wsk() - const method = this.isUpdate() ? 'update' : 'create' - const result = await ow.actions[method]({ name, action: options }) - if (flags.json) { - this.logJSON('', result) + if (exec) { + options.exec = exec + } + if (limits) { + options.limits = limits } + if (paramsAction) { + options.parameters = paramsAction + } + if (annotationParams) { + options.annotations = annotationParams + } + const ow = await this.wsk() + await this.syncAction(ow, name, options, flags, method) } catch (err) { - const method = this.isUpdate() ? 'update' : 'create' this.handleError(`failed to ${method} the action`, err) } } + + /** @private + * @param {OpenwhiskClient} ow + * @param {string} actionName + * @param {object} actionData + * @param {object} flags + * @param {'update' | 'create'} method + * */ + async syncAction (ow, actionName, actionData, flags, method) { + let action = actionData + if (flags.copy) { + action = await ow.actions.get(flags.copy) + } + const result = await ow.actions[method]({ name: actionName, action }) + if (flags.json) { + this.logJSON('', result) + } + } } ActionCreate.args = [ @@ -213,6 +237,9 @@ ActionCreate.flags = { description: 'parameter values in KEY VALUE format', // help description for flag multiple: true // allow setting this flag multiple times }), + copy: flags.string({ + description: 'copy an existing action' // help description for flag + }), env: flags.string({ char: 'e', description: 'environment values in KEY VALUE format', // help description for flag diff --git a/test/commands/runtime/action/create.test.js b/test/commands/runtime/action/create.test.js index 438553cd..93704e07 100644 --- a/test/commands/runtime/action/create.test.js +++ b/test/commands/runtime/action/create.test.js @@ -16,6 +16,7 @@ const RuntimeBaseCommand = require('../../../../src/RuntimeBaseCommand.js') const RuntimeLib = require('@adobe/aio-lib-runtime') const rtUtils = RuntimeLib.utils const rtAction = 'actions.create' +const rtActionGet = 'actions.get' test('exports', async () => { expect(typeof TheCommand).toEqual('function') @@ -47,6 +48,7 @@ test('flags', async () => { expect(TheCommand.flags['annotation-file'].char).toBe('A') expect(typeof TheCommand.flags['annotation-file']).toBe('object') expect(typeof TheCommand.flags.sequence).toBe('object') + expect(typeof TheCommand.flags.copy).toBe('object') }) test('args', async () => { @@ -878,5 +880,20 @@ describe('instance methods', () => { }) }) }) + + test('aio runtime:action:create newAction --copy oldAction', () => { + const oldActionJson = require('../../../__fixtures__/action/get.json') + const cmdGet = rtLib.mockResolvedFixture(rtActionGet, 'action/get.json') + const cmdCreate = rtLib.mockResolved(rtAction, { fake: '' }) + const name = 'oldAction' + const newAction = 'newAction' + command.argv = [newAction, '--copy', name] + return command.run() + .then(() => { + expect(cmdGet).toHaveBeenCalledWith(name) + expect(cmdCreate).toHaveBeenCalledWith({ name: newAction, action: oldActionJson }) + expect(stdout.output).toMatch('') + }) + }) }) })