diff --git a/schema/app.config.yaml.schema.json b/schema/app.config.yaml.schema.json index 4b764b5..6738c2a 100644 --- a/schema/app.config.yaml.schema.json +++ b/schema/app.config.yaml.schema.json @@ -96,7 +96,8 @@ "runtimeManifest": { "type": "object", "properties": { - "packages": { "$ref": "#/definitions/packages" } + "packages": { "$ref": "#/definitions/packages" }, + "database": { "$ref": "#/definitions/database" } }, "required": ["packages"] }, @@ -109,6 +110,15 @@ }, "additionalProperties": false }, + "database": { + "type": "object", + "properties": { + "auto-provision": { "type": "boolean"}, + "region": { "type": "string"} + }, + "required": ["auto-provision"], + "additionalProperties": false + }, "package": { "type": "object", "properties": { diff --git a/src/index.js b/src/index.js index 40b98cd..6a02cf4 100644 --- a/src/index.js +++ b/src/index.js @@ -637,6 +637,9 @@ async function buildSingleConfig (configName, singleUserConfig, commonConfig, in if (singleUserConfig.events) { config.events = { ...singleUserConfig.events } } + if (manifest && manifest.database) { + config.database = { ...manifest.database } + } if (commonConfig?.aio?.project) { config.project = commonConfig.aio.project } diff --git a/test/__fixtures__/app-with-database/app.config.yaml b/test/__fixtures__/app-with-database/app.config.yaml new file mode 100644 index 0000000..f5277ef --- /dev/null +++ b/test/__fixtures__/app-with-database/app.config.yaml @@ -0,0 +1,20 @@ +application: + actions: 'myactions' + runtimeManifest: + database: + auto-provision: true + region: 'emea' + packages: + my-app-package: + license: 'Apache-2.0' + actions: + action: + function: 'myactions/action.js' + web: 'yes' + runtime: 'nodejs:14' + inputs: + LOG_LEVEL: 'debug' + annotations: + final: true + require-adobe-auth: true + web: 'web-src' diff --git a/test/__fixtures__/app-with-database/myactions/action.js b/test/__fixtures__/app-with-database/myactions/action.js new file mode 100644 index 0000000..38a6e5a --- /dev/null +++ b/test/__fixtures__/app-with-database/myactions/action.js @@ -0,0 +1,10 @@ +/** + * Main action function + * @param {object} params - Action parameters + * @returns {object} Response object + */ +function main (params) { + return { msg: 'Hello world with database!' } +} + +module.exports.main = main diff --git a/test/__fixtures__/app-with-database/package.json b/test/__fixtures__/app-with-database/package.json new file mode 100644 index 0000000..8ec31ee --- /dev/null +++ b/test/__fixtures__/app-with-database/package.json @@ -0,0 +1,7 @@ +{ + "name": "app-with-database", + "version": "1.0.0", + "scripts": { + "test": "echo test" + } +} diff --git a/test/__fixtures__/app-with-database/web-src/index.html b/test/__fixtures__/app-with-database/web-src/index.html new file mode 100644 index 0000000..41631a1 --- /dev/null +++ b/test/__fixtures__/app-with-database/web-src/index.html @@ -0,0 +1,9 @@ + + + + App with Database + + +

Hello from App with Database!

+ + diff --git a/test/data-mocks/config-loader.js b/test/data-mocks/config-loader.js index 6eb135c..1dd2623 100644 --- a/test/data-mocks/config-loader.js +++ b/test/data-mocks/config-loader.js @@ -284,6 +284,73 @@ const applicationSingleConfig = { } } +const appWithDatabaseActionsFolder = winCompat(`${root}myactions`) +const applicationWithDatabaseSingleConfig = { + application: { + app: { + hasBackend: true, + hasFrontend: true, + dist: winCompat(`${root}dist/application`), + defaultHostname: 'adobeio-static.net', + hostname: 'mydomain.test', + htmlCacheDuration: '60', + jsCacheDuration: '60', + cssCacheDuration: '60', + imageCacheDuration: '60' + }, + ow, + s3: { + credsCacheFile: winCompat(`${root}.aws.tmp.creds.json`) + }, + web: { + src: winCompat(`${root}web-src`), + injectedConfig: winCompat(`${root}web-src/src/config.json`), + distDev: winCompat(`${root}dist/application/web-dev`), + distProd: winCompat(`${root}dist/application/web-prod`) + }, + manifest: { + src: 'manifest.yml', + full: { + packages: { + 'my-app-package': { + license: 'Apache-2.0', + actions: { + action: { + function: winCompat(`${appWithDatabaseActionsFolder}/action.js`), + web: 'yes', + runtime: 'nodejs:14', + inputs: { + LOG_LEVEL: 'debug' + }, + annotations: { + final: true, + 'require-adobe-auth': true + } + } + } + } + }, + database: { + 'auto-provision': true, + region: 'emea' + } + }, + packagePlaceholder: '__APP_PACKAGE__', + package: undefined + }, + actions: { + src: appWithDatabaseActionsFolder, + dist: winCompat(`${root}dist/application/actions`) + }, + tests: { + e2e: winCompat(`${root}e2e`), + unit: winCompat(`${root}test`) + }, + root: `${root}`, + name: 'application' + } +} + const legacyManifest = fullFakeRuntimeManifest(appActionsFolder, '__APP_PACKAGE__') const applicationLegacyConfig = { application: { @@ -362,6 +429,18 @@ const expectedConfigs = { }, root }, + 'app-with-database': { + all: { ...applicationWithDatabaseSingleConfig }, + implements: [ + 'application' + ], + includeIndex: appIncludeIndex, + packagejson: { + version: '1.0.0', + name: 'app-with-database' + }, + root + }, 'app-exc-nui': { all: { ...excSingleConfig, ...nuiSingleConfig, ...applicationSingleConfig }, implements: [ diff --git a/test/index.test.js b/test/index.test.js index 116ca01..040e8d9 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -46,6 +46,17 @@ describe('load config', () => { expect(config).toEqual(mockConfig) }) + test('standalone app config with database', async () => { + global.loadFixtureApp('app-with-database') + config = await appConfig.load() + expect(config.all.application.database).toEqual({ + 'auto-provision': true, + region: 'emea' + }) + expect(config.all.application.app.hasBackend).toBe(true) + expect(config.all.application.app.hasFrontend).toBe(true) + }) + test('not in an app', async () => { global.loadFixtureApp('not-in-app') await expect(appConfig.load()).rejects.toThrow(new Error('ENOENT: no such file or directory, open \'package.json\'')) @@ -1064,3 +1075,121 @@ describe('coalesce config', () => { expect(coalesced.includeIndex['application.runtimeManifest.packages.my-app-package.actions.action.function']).toEqual({ file: 'app/myactions/action.config.yaml', key: 'function' }) }) }) + +describe('database config', () => { + beforeEach(async () => { + mockAIOConfig.get.mockImplementation(k => global.fakeConfig.tvm) + process.chdir('/') + global.fakeFileSystem.clear() + libEnv.getCliEnv.mockReturnValue('prod') + }) + + test('valid database configuration', async () => { + global.fakeFileSystem.addJson({ + '/package.json': '{"name": "test-app", "version": "1.0.0"}', + '/app.config.yaml': ` +application: + runtimeManifest: + database: + auto-provision: true + region: 'emea' + packages: + my-app-package: + actions: + action: + function: 'actions/hello.js' + web: true +` + }) + const config = await appConfig.load() + expect(config.all.application.database).toEqual({ + 'auto-provision': true, + region: 'emea' + }) + }) + + test('database configuration with auto-provision true', async () => { + global.fakeFileSystem.addJson({ + '/package.json': '{"name": "test-app", "version": "1.0.0"}', + '/app.config.yaml': ` +application: + runtimeManifest: + database: + auto-provision: true + packages: + my-app-package: + actions: + action: + function: 'actions/hello.js' + web: true +` + }) + const config = await appConfig.load() + expect(config.all.application.database).toEqual({ + 'auto-provision': true + }) + }) + + test('database configuration with empty fields', async () => { + global.fakeFileSystem.addJson({ + '/package.json': '{"name": "test-app", "version": "1.0.0"}', + '/app.config.yaml': ` +application: + runtimeManifest: + database: {} + packages: + my-app-package: + actions: + action: + function: 'actions/hello.js' + web: true +` + }) + await expect(appConfig.load()).rejects.toThrow('Missing or invalid keys in app.config.yaml:') + }) + + test('database configuration validation - valid', async () => { + const validConfig = { + application: { + runtimeManifest: { + database: { + 'auto-provision': true, + region: 'apac' + }, + packages: { + 'my-app': { + actions: { + hello: { + function: 'hello.js' + } + } + } + } + } + } + } + const validation = await appConfig.validate(validConfig) + expect(validation.valid).toBe(true) + expect(validation.errors).toBe(null) + }) + + test('invalid database configuration - invalid auto-provision type', async () => { + global.fakeFileSystem.addJson({ + '/package.json': '{"name": "test-app", "version": "1.0.0"}', + '/app.config.yaml': ` +application: + runtimeManifest: + database: + auto-provision: 'invalid' + region: 'amer' + packages: + my-app-package: + actions: + action: + function: 'actions/hello.js' + web: true +` + }) + await expect(appConfig.load({})).rejects.toThrow('must be boolean') + }) +})