Skip to content

Commit 4981ff8

Browse files
authored
Merge pull request #889 from adobe/cext-5368/minimal-db-provisioning
Cext 5368/minimal db provisioning
2 parents 204066c + 8972415 commit 4981ff8

2 files changed

Lines changed: 170 additions & 0 deletions

File tree

src/commands/app/deploy.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ class Deploy extends BuildCommand {
209209
this.error(err)
210210
}
211211

212+
// provision database if configured
213+
if (config.manifest?.full?.database?.['auto-provision'] === true) {
214+
await this.provisionDatabase(config, spinner, flags)
215+
}
216+
212217
if (flags.actions) {
213218
if (config.app.hasBackend) {
214219
let filterEntities
@@ -305,6 +310,35 @@ class Deploy extends BuildCommand {
305310
}
306311
}
307312

313+
async provisionDatabase (config, spinner, flags) {
314+
const region = config.manifest?.full?.database?.region
315+
const args = ['--yes']
316+
317+
if (region) {
318+
args.unshift('--region', region)
319+
}
320+
321+
const message = region ? `Deploying database in region '${region}'` : 'Deploying database in default region'
322+
323+
try {
324+
spinner.start(message)
325+
326+
if (flags.verbose) {
327+
const commandStr = region ? `aio app db provision --region ${region} --yes` : 'aio app db provision --yes'
328+
spinner.info(chalk.dim(`Running: ${commandStr}`))
329+
spinner.start(message)
330+
}
331+
332+
await this.config.runCommand('app:db:provision', args)
333+
334+
const successMessage = region ? `Deployed database for application in region '${region}'` : 'Deployed database for application'
335+
spinner.succeed(chalk.green(successMessage))
336+
} catch (error) {
337+
spinner.fail(chalk.red('Database deployment failed'))
338+
throw error
339+
}
340+
}
341+
308342
async publishExtensionPoints (deployConfigs, aioConfig, force) {
309343
const libConsoleCLI = await this.getLibConsoleCLI()
310344

test/commands/app/deploy.test.js

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const helpersActual = jest.requireActual('../../../src/lib/app-helper.js')
1818
const authHelpersActual = jest.requireActual('../../../src/lib/auth-helper')
1919

2020
const open = require('open')
21+
const ora = require('ora')
2122
const mockBundleFunc = jest.fn()
2223

2324
jest.mock('../../../src/lib/app-helper.js')
@@ -206,6 +207,7 @@ beforeEach(() => {
206207
command = new TheCommand([])
207208
command.error = jest.fn()
208209
command.log = jest.fn()
210+
command.warn = jest.fn()
209211
command.appConfig = cloneDeep(mockConfigData)
210212
command.appConfig.actions = { dist: 'actions' }
211213
command.appConfig.web.distProd = 'dist'
@@ -1762,3 +1764,137 @@ describe('run', () => {
17621764
expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1)
17631765
})
17641766
})
1767+
1768+
describe('database provisioning', () => {
1769+
// Helper functions for unit tests
1770+
const createDatabaseConfig = (region = null) => ({
1771+
manifest: {
1772+
full: {
1773+
database: {
1774+
...(region && { region })
1775+
}
1776+
}
1777+
}
1778+
})
1779+
1780+
const runProvisionTest = async (config, flags, mockResult) => {
1781+
const spinner = ora()
1782+
1783+
if (mockResult instanceof Error) {
1784+
command.config.runCommand.mockRejectedValueOnce(mockResult)
1785+
} else {
1786+
command.config.runCommand.mockResolvedValueOnce(mockResult)
1787+
}
1788+
1789+
return {
1790+
result: await command.provisionDatabase(config, spinner, flags).catch(e => { throw e }),
1791+
spinner
1792+
}
1793+
}
1794+
1795+
test('should provision database when auto-provision is true', async () => {
1796+
const appConfigWithDb = createAppConfig({
1797+
...command.appConfig,
1798+
manifest: {
1799+
full: {
1800+
database: {
1801+
'auto-provision': true,
1802+
region: 'emea'
1803+
}
1804+
}
1805+
}
1806+
})
1807+
1808+
command.getAppExtConfigs.mockResolvedValueOnce(appConfigWithDb)
1809+
command.config.runCommand.mockResolvedValue()
1810+
1811+
await command.run()
1812+
1813+
expect(command.error).toHaveBeenCalledTimes(0)
1814+
expect(command.config.runCommand).toHaveBeenCalledWith('app:db:provision', ['--region', 'emea', '--yes'])
1815+
expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1)
1816+
expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1)
1817+
expect(command.log).toHaveBeenCalledWith(
1818+
expect.stringContaining('Successful deployment 🏄')
1819+
)
1820+
})
1821+
1822+
test('should not provision database when auto-provision is false', async () => {
1823+
const appConfigWithoutDb = createAppConfig({
1824+
...command.appConfig,
1825+
manifest: {
1826+
full: {
1827+
database: {
1828+
'auto-provision': false
1829+
}
1830+
}
1831+
}
1832+
})
1833+
1834+
command.getAppExtConfigs.mockResolvedValueOnce(appConfigWithoutDb)
1835+
1836+
await command.run()
1837+
1838+
expect(command.error).toHaveBeenCalledTimes(0)
1839+
expect(command.config.runCommand).not.toHaveBeenCalledWith('app:db:provision', expect.anything())
1840+
expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1)
1841+
expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1)
1842+
expect(command.log).toHaveBeenCalledWith(
1843+
expect.stringContaining('Successful deployment 🏄')
1844+
)
1845+
})
1846+
1847+
// tests for provisionDatabase method behavior
1848+
test('should run provision command correctly with region', async () => {
1849+
const config = createDatabaseConfig('emea')
1850+
const flags = { verbose: false }
1851+
1852+
const { spinner } = await runProvisionTest(config, flags)
1853+
1854+
expect(spinner.start).toHaveBeenCalledWith('Deploying database in region \'emea\'')
1855+
expect(command.config.runCommand).toHaveBeenCalledWith('app:db:provision', ['--region', 'emea', '--yes'])
1856+
expect(spinner.succeed).toHaveBeenCalledWith(expect.stringContaining('Deployed database for application in region \'emea\''))
1857+
})
1858+
1859+
test('should run provision command correctly without region', async () => {
1860+
const config = createDatabaseConfig()
1861+
const flags = { verbose: false }
1862+
1863+
const { spinner } = await runProvisionTest(config, flags)
1864+
1865+
expect(spinner.start).toHaveBeenCalledWith('Deploying database in default region')
1866+
expect(command.config.runCommand).toHaveBeenCalledWith('app:db:provision', ['--yes'])
1867+
expect(spinner.succeed).toHaveBeenCalledWith(expect.stringContaining('Deployed database for application'))
1868+
})
1869+
1870+
test('should show verbose output with region', async () => {
1871+
const config = createDatabaseConfig('amer')
1872+
const flags = { verbose: true }
1873+
1874+
const { spinner } = await runProvisionTest(config, flags)
1875+
1876+
expect(spinner.info).toHaveBeenCalledWith(expect.stringContaining('Running: aio app db provision --region amer --yes'))
1877+
expect(spinner.start).toHaveBeenCalledTimes(2) // Once initially, once after verbose info
1878+
expect(spinner.succeed).toHaveBeenCalledWith(expect.stringContaining('Deployed database for application in region \'amer\''))
1879+
})
1880+
1881+
test('should show verbose output without region', async () => {
1882+
const config = createDatabaseConfig()
1883+
const flags = { verbose: true }
1884+
1885+
const { spinner } = await runProvisionTest(config, flags)
1886+
1887+
expect(spinner.info).toHaveBeenCalledWith(expect.stringContaining('Running: aio app db provision --yes'))
1888+
expect(spinner.start).toHaveBeenCalledTimes(2) // Once initially, once after verbose info
1889+
expect(spinner.succeed).toHaveBeenCalledWith(expect.stringContaining('Deployed database for application'))
1890+
})
1891+
1892+
test('should handle provision command failure', async () => {
1893+
const config = createDatabaseConfig('amer')
1894+
const flags = { verbose: false }
1895+
const error = new Error('Database provision failed')
1896+
1897+
await expect(runProvisionTest(config, flags, error))
1898+
.rejects.toThrow('Database provision failed')
1899+
})
1900+
})

0 commit comments

Comments
 (0)