diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index 66ee61bb..47465c67 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -37,7 +37,7 @@ class Deploy extends BuildCommand { // if there are no extensions, then set publish to false flags.publish = flags.publish && !isStandaloneApp - let libConsoleCLI + let libConsoleCLI // <= this can be undefined later on, and it was not checked if (flags.publish) { // force login at beginning (if required) libConsoleCLI = await this.getLibConsoleCLI() @@ -158,6 +158,11 @@ class Deploy extends BuildCommand { try { const script = await runScript(config.hooks['deploy-actions']) if (!script) { + await this.config.runHook('deploy-actions', { + appConfig: config, + filterEntities: filterActions || [], + isLocalDev: false + }) deployedRuntimeEntities = await rtLib.deployActions(config, { filterEntities }, onProgress) } diff --git a/src/commands/app/run.js b/src/commands/app/run.js index a618221a..19dd0578 100644 --- a/src/commands/app/run.js +++ b/src/commands/app/run.js @@ -104,8 +104,8 @@ class Run extends BaseCommand { spinner.info(chalk.dim(`${info}`)) spinner.start() } - - const frontendUrl = await runDev(config, this.config.dataDir, runOptions, onProgress) + const inprocHook = this.config.runHook.bind(this.config) + const frontendUrl = await runDev(config, this.config.dataDir, runOptions, onProgress, inprocHook) try { await runScript(config.hooks['post-app-run']) } catch (err) { diff --git a/src/lib/actions-watcher.js b/src/lib/actions-watcher.js index 6e0e6bed..135891ff 100644 --- a/src/lib/actions-watcher.js +++ b/src/lib/actions-watcher.js @@ -61,10 +61,9 @@ module.exports = async (watcherOptions) => { * @param {Array} filterActions add filters to deploy only specified OpenWhisk actions */ async function buildAndDeploy (watcherOptions, filterActions) { - const { config, isLocal, log } = watcherOptions - + const { config, isLocal, log, inprocHook } = watcherOptions await buildActions(config, filterActions) - await deployActions(config, isLocal, log, filterActions) + await deployActions(config, isLocal, log, filterActions, inprocHook) } /** diff --git a/src/lib/deploy-actions.js b/src/lib/deploy-actions.js index fdebbd45..acd2200e 100644 --- a/src/lib/deploy-actions.js +++ b/src/lib/deploy-actions.js @@ -22,7 +22,7 @@ const { deployActions } = require('@adobe/aio-lib-runtime') * @param {boolean} filter true if a filter by built actions is desired. */ /** @private */ -module.exports = async (config, isLocalDev = false, log = () => {}, filter = false) => { +module.exports = async (config, isLocalDev = false, log = () => {}, filter = false, inprocHook) => { utils.runScript(config.hooks['pre-app-deploy']) const script = await utils.runScript(config.hooks['deploy-actions']) if (!script) { @@ -32,6 +32,14 @@ module.exports = async (config, isLocalDev = false, log = () => {}, filter = fal byBuiltActions: filter } } + if (inprocHook) { + const hookFilterEntities = Array.isArray(filter) ? filter : [] + await inprocHook('deploy-actions', { + appConfig: config, + filterEntities: hookFilterEntities, + isLocalDev + }) + } const entities = await deployActions(config, deployConfig, log) if (entities.actions) { const web = entities.actions.filter(utils.createWebExportFilter(true)) diff --git a/src/lib/run-dev.js b/src/lib/run-dev.js index 2886d181..e4e3aec2 100644 --- a/src/lib/run-dev.js +++ b/src/lib/run-dev.js @@ -30,7 +30,7 @@ const { run: logPoller } = require('./log-poller') const getPort = require('get-port') /** @private */ -async function runDev (config, dataDir, options = {}, log = () => {}) { +async function runDev (config, dataDir, options = {}, log = () => {}, inprocHook) { /* parcel bundle options */ const bundleOptions = { shouldDisableCache: true, @@ -38,6 +38,7 @@ async function runDev (config, dataDir, options = {}, log = () => {}) { shouldOptimize: false, ...options.parcel } + /* skip actions */ const skipActions = !!options.skipActions /* fetch logs for actions option */ @@ -48,6 +49,7 @@ async function runDev (config, dataDir, options = {}, log = () => {}) { const withBackend = config.app.hasBackend && !skipActions const isLocal = options.isLocal // applies only for backend const portToUse = parseInt(process.env.PORT) || SERVER_DEFAULT_PORT + const uiPort = await getPort({ port: portToUse }) if (uiPort !== portToUse) { log(`Could not use port:${portToUse}, using port:${uiPort} instead`) @@ -82,7 +84,7 @@ async function runDev (config, dataDir, options = {}, log = () => {}) { log('building actions..') await buildActions(devConfig, null, true /* force build */) - const { cleanup: watcherCleanup } = await actionsWatcher({ config: devConfig, isLocal, log }) + const { cleanup: watcherCleanup } = await actionsWatcher({ config: devConfig, isLocal, log, inprocHook }) cleanup.add(() => watcherCleanup(), 'stopping action watcher...') } @@ -121,7 +123,7 @@ async function runDev (config, dataDir, options = {}, log = () => {}) { // Deploy Phase - deploy actions if (withBackend) { log('redeploying actions..') - await deployActions(devConfig, isLocal, log, true) + await deployActions(devConfig, isLocal, log, true, inprocHook) } // Deploy Phase - serve the web UI diff --git a/test/commands/app/deploy.test.js b/test/commands/app/deploy.test.js index f114bcae..db8e0083 100644 --- a/test/commands/app/deploy.test.js +++ b/test/commands/app/deploy.test.js @@ -251,7 +251,7 @@ describe('run', () => { command.appConfig = cloneDeep(mockConfigData) command.appConfig.actions = { dist: 'actions' } command.appConfig.web.distProd = 'dist' - command.config = { runCommand: jest.fn() } + command.config = { runCommand: jest.fn(), runHook: jest.fn() } command.buildOneExt = jest.fn() command.getAppExtConfigs = jest.fn() command.getLibConsoleCLI = jest.fn(() => mockLibConsoleCLI) @@ -727,6 +727,13 @@ describe('run', () => { command.argv = [] await command.run() + expect(command.config.runHook).toHaveBeenCalledTimes(1) + expect(command.config.runHook).toHaveBeenCalledWith('deploy-actions', + expect.objectContaining({ + appConfig: expect.any(Object), + filterEntities: [], + isLocalDev: false + })) expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) expect(command.error).toHaveBeenCalledTimes(0) diff --git a/test/commands/app/run.test.js b/test/commands/app/run.test.js index fae99fa9..05c06a11 100644 --- a/test/commands/app/run.test.js +++ b/test/commands/app/run.test.js @@ -108,6 +108,7 @@ beforeEach(() => { command.error = jest.fn() command.log = jest.fn() command.config = { + runHook: jest.fn(), findCommand: jest.fn().mockReturnValue({ load: mockFindCommandLoad }), @@ -280,7 +281,7 @@ describe('run', () => { logLevel: 'warn' }), isLocal: undefined - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) }) test('app:run check if fetchLogs flag is set when calling scripts', async () => { @@ -292,7 +293,7 @@ describe('run', () => { await command.run() expect(mockRunDev).toHaveBeenCalledWith(appConfig.application, expect.any(String), expect.objectContaining({ fetchLogs: true - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) }) test('app:run with --verbose', async () => { @@ -309,7 +310,7 @@ describe('run', () => { logLevel: 'verbose' }), isLocal: undefined - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) }) test('app:run with --local', async () => { @@ -339,7 +340,7 @@ describe('run', () => { logLevel: 'verbose' }), isLocal: true - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) }) test('app:run where scripts.runDev throws', async () => { @@ -423,7 +424,7 @@ describe('run', () => { key: PRIVATE_KEY_PATH } } - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) }) test('app:run with UI and no cert files but has cert config', async () => { @@ -446,7 +447,7 @@ describe('run', () => { key: PRIVATE_KEY_PATH } } - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) expect(mockFS.ensureDir).toHaveBeenCalledWith(DEV_KEYS_DIR) expect(mockFS.writeFile).toHaveBeenCalledTimes(2) expect(mockFS.writeFile).toHaveBeenCalledWith(PUB_CERT_PATH, 'pub cert') @@ -477,7 +478,7 @@ describe('run', () => { key: PRIVATE_KEY_PATH } } - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) expect(mockFS.ensureDir).toHaveBeenCalledWith(DEV_KEYS_DIR) expect(command.config.findCommand).toHaveBeenCalledWith('certificate:generate') expect(mockFindCommandRun).toHaveBeenCalledWith([`--keyout=${PRIVATE_KEY_PATH}`, `--out=${PUB_CERT_PATH}`, '-n=DeveloperSelfSigned.cert']) @@ -515,7 +516,7 @@ describe('run', () => { key: PRIVATE_KEY_PATH } } - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) expect(mockConfig.set).toHaveBeenCalledTimes(2) expect(mockConfig.set).toHaveBeenCalledWith(CONFIG_KEY + '.privateKey', 'private key') expect(mockConfig.set).toHaveBeenCalledWith(CONFIG_KEY + '.publicCert', 'public cert') @@ -555,7 +556,7 @@ describe('run', () => { key: PRIVATE_KEY_PATH } } - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) expect(https.createServer).toHaveBeenCalledWith({ key: 'private key', cert: 'public cert' }, expect.any(Function)) expect(getPort).toHaveBeenCalledWith({ port: SERVER_DEFAULT_PORT }) expect(mockHttpsServerInstance.listen).toHaveBeenCalledWith(1111) @@ -593,7 +594,7 @@ describe('run', () => { key: PRIVATE_KEY_PATH } } - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) expect(getPort).toHaveBeenCalledWith({ port: 9999 }) expect(mockHttpsServerInstance.listen).toHaveBeenCalledWith(1111) expect(cli.open).toHaveBeenCalledWith('https://localhost:1111') @@ -632,7 +633,7 @@ describe('run', () => { key: PRIVATE_KEY_PATH } } - }), expect.any(Function)) + }), expect.any(Function), expect.any(Function)) expect(mockHttpsServerInstance.listen).toHaveBeenCalledWith(1111) expect(mockHttpsServerInstance.close).toHaveBeenCalledTimes(1) expect(cli.open).toHaveBeenCalledWith('https://localhost:1111') diff --git a/test/commands/lib/deploy-actions.test.js b/test/commands/lib/deploy-actions.test.js index a382a7fb..79b4c018 100644 --- a/test/commands/lib/deploy-actions.test.js +++ b/test/commands/lib/deploy-actions.test.js @@ -84,7 +84,48 @@ test('it should deploy actions with filter param, (coverage)', async () => { test('no deploy-actions app hook available (use inbuilt)', async () => { await deployActions({ hooks: {} }) + expect(rtDeployActions).toHaveBeenCalled() + expect(utils.runScript).toHaveBeenNthCalledWith(1, undefined) // pre-app-deploy + expect(utils.runScript).toHaveBeenNthCalledWith(2, undefined) // deploy-actions + expect(utils.runScript).toHaveBeenNthCalledWith(3, undefined) // post-app-deploy +}) + +test('call inprocHook no filter', async () => { + const mockHook = jest.fn() + await deployActions({ hooks: {} }, false, null, false, mockHook) + expect(mockHook).toHaveBeenCalledWith('deploy-actions', expect.objectContaining({ + appConfig: { hooks: {} }, + filterEntities: [], + isLocalDev: false + })) + expect(rtDeployActions).toHaveBeenCalled() + expect(utils.runScript).toHaveBeenNthCalledWith(1, undefined) // pre-app-deploy + expect(utils.runScript).toHaveBeenNthCalledWith(2, undefined) // deploy-actions + expect(utils.runScript).toHaveBeenNthCalledWith(3, undefined) // post-app-deploy +}) + +test('call inprocHook with filter : isLocalDev false', async () => { + const mockHook = jest.fn() + await deployActions({ hooks: {} }, false, null, ['boomer'], mockHook) + expect(mockHook).toHaveBeenCalledWith('deploy-actions', expect.objectContaining({ + appConfig: { hooks: {} }, + filterEntities: ['boomer'], + isLocalDev: false + })) + expect(rtDeployActions).toHaveBeenCalled() + expect(utils.runScript).toHaveBeenNthCalledWith(1, undefined) // pre-app-deploy + expect(utils.runScript).toHaveBeenNthCalledWith(2, undefined) // deploy-actions + expect(utils.runScript).toHaveBeenNthCalledWith(3, undefined) // post-app-deploy +}) +test('call inprocHook with filter : isLocalDev true', async () => { + const mockHook = jest.fn() + await deployActions({ hooks: {} }, true, null, ['action-1', 'action-2'], mockHook) + expect(mockHook).toHaveBeenCalledWith('deploy-actions', expect.objectContaining({ + appConfig: { hooks: {} }, + filterEntities: ['action-1', 'action-2'], + isLocalDev: true + })) expect(rtDeployActions).toHaveBeenCalled() expect(utils.runScript).toHaveBeenNthCalledWith(1, undefined) // pre-app-deploy expect(utils.runScript).toHaveBeenNthCalledWith(2, undefined) // deploy-actions