Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/deploy-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,24 @@ async function deployActions (config, deployConfig = {}, logFunc) {
// checks
// a. missing credentials
utils.checkOpenWhiskCredentials(config)
// b. missing build files
// b. no packages declared (e.g. `packages: {}`, used only to trigger database
// auto-provisioning). Skip deployment entirely. Proceeding would run a full
// sync against an empty manifest, undeploying every previously-deployed entity
// for the project. Use `aio app undeploy` to intentionally remove all entities.
const packages = config.manifest.full.packages
if (Object.keys(packages).length === 0) {
log('Warning: no packages defined in the manifest, skipping deployment. Existing deployed entities are left untouched; use \'aio app undeploy\' to remove them.')
return {}
}

// c. missing build files — only required when at least one package defines actions
const dist = config.actions.dist
const hasAnyActions = Object.values(packages)
.some(pkg => Object.keys(pkg.actions || {}).length > 0)
Comment thread
iivvaannxx marked this conversation as resolved.
if (
hasAnyActions &&
(!deployConfig.filterEntities || deployConfig.filterEntities.actions) &&
(!fs.pathExistsSync(dist) || !fs.lstatSync(dist).isDirectory() || !fs.readdirSync(dist).length === 0)
(!fs.pathExistsSync(dist) || !fs.lstatSync(dist).isDirectory() || fs.readdirSync(dist).length === 0)
) {
throw new Error(`missing files in ${utils._relApp(config.root, dist)}, maybe you forgot to build your actions ?`)
}
Expand Down
4 changes: 3 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2104,7 +2104,9 @@ function replacePackagePlaceHolder (config) {
// Using custom package name.
// Set config.ow.package so that syncProject can use it as project name for annotations.
const packageNames = Object.keys(packages)
modifiedConfig.ow.package = packageNames[0]
if (packageNames.length > 0) {
modifiedConfig.ow.package = packageNames[0]
}
}
return modifiedConfig
}
Expand Down
18 changes: 18 additions & 0 deletions test/deploy.actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -577,12 +577,30 @@ test('Deploy actions should fail if there are no build files and action filter',
.rejects.toThrow('missing files in dist')
})

test('Deploy actions should fail if the build directory exists but is empty', async () => {
addSampleAppFiles()
// dist exists as a directory but contains no built actions
global.fakeFileSystem.addJson({ [global.sampleAppConfig.actions.dist]: null })
await expect(deployActions(global.sampleAppConfig))
.rejects.toThrow('missing files in dist')
})

test('Deploy actions should pass if there are no build files and filter does not include actions', async () => {
addSampleAppFiles()
runtimeLibUtils.processPackage.mockReturnValue({})
await expect(deployActions(global.sampleAppConfig, { filterEntities: { triggers: ['trigger1'] } })).resolves.toEqual({})
})

test('Deploy actions should be a no-op (no undeploy) and warn when packages: {} (empty packages)', async () => {
const emptyPackagesConfig = deepCopy(global.sampleAppConfig)
emptyPackagesConfig.manifest.full.packages = {}
const logSpy = jest.fn()
await expect(deployActions(emptyPackagesConfig, {}, logSpy)).resolves.toEqual({})
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('no packages defined'))
// must not run a full sync that would undeploy previously-deployed entities
expect(runtimeLibUtils.syncProject).not.toHaveBeenCalled()
})

// lonely
test('if actions are deployed and part of the manifest it should return their url', async () => {
addSampleAppReducedFiles()
Expand Down
40 changes: 40 additions & 0 deletions test/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3097,3 +3097,43 @@ describe('loadIMSCredentialsFromEnv', () => {
expect(result.scopes).toBe('not json')
})
})

describe('replacePackagePlaceHolder', () => {
test('leaves ow.package unchanged when packages is empty (packages: {})', () => {
const config = {
ow: { package: 'my-pkg' },
manifest: {
packagePlaceholder: '__APP_PACKAGE__',
full: { packages: {} }
}
}
const result = utils.replacePackagePlaceHolder(config)
expect(result.ow.package).toBe('my-pkg')
})

test('renames placeholder package to ow.package', () => {
const config = {
ow: { package: 'my-pkg' },
manifest: {
packagePlaceholder: '__APP_PACKAGE__',
full: { packages: { __APP_PACKAGE__: { actions: {} } } }
}
}
const result = utils.replacePackagePlaceHolder(config)
expect(result.ow.package).toBe('my-pkg')
expect(result.manifest.full.packages['my-pkg']).toBeDefined()
expect(result.manifest.full.packages.__APP_PACKAGE__).toBeUndefined()
})

test('sets ow.package to first package name when no placeholder matches', () => {
const config = {
ow: { package: 'ignored' },
manifest: {
packagePlaceholder: '__APP_PACKAGE__',
full: { packages: { 'custom-pkg': { actions: {} } } }
}
}
const result = utils.replacePackagePlaceHolder(config)
expect(result.ow.package).toBe('custom-pkg')
})
})
Loading