diff --git a/bun.lockb b/bun.lockb index 7e49573..dd856b3 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/fly.js b/fly.js index 74b6fb3..16446d1 100755 --- a/fly.js +++ b/fly.js @@ -15,6 +15,10 @@ GDF.extend(class extends GDF { // create volume for sqlite3 if (this.sqlite3) this.flyMakeVolume() + if (this.sqlite3 && this.setupScriptType === 'dbsetup') { + this.flySetCmd() + } + // setup swap if (this.options.swap != null) this.flySetSwap() @@ -22,7 +26,10 @@ GDF.extend(class extends GDF { if (this.litefs) this.flyAttachConsul(this.flyApp) // set secrets, healthcheck for remix apps - if (this.remix) { + if (this.shopify) { + this.flyShopifyEnv(this.flyApp) + this.flyShopifyConfig(this.flyApp) + } else if (this.remix) { this.flyRemixSecrets(this.flyApp) this.flyHealthCheck('/healthcheck') } @@ -62,7 +69,7 @@ GDF.extend(class extends GDF { this.flyToml = fs.readFileSync(this.flyTomlFile, 'utf-8') // parse app name from fly.toml - this.flyApp = this.flyToml.match(/^app\s*=\s*"?([-\w]+)"?/m)?.[1] + this.flyApp = this.flyToml.match(/^app\s*=\s*["']?([-\w]+)["']?/m)?.[1] // see if flyctl is in the path const paths = (process.env.PATH || '') @@ -159,6 +166,27 @@ GDF.extend(class extends GDF { } } + // override command in fly.toml to include dbsetup.js + flySetCmd() { + if (this.flyToml.includes('[processes]')) return + + let cmd = this.startCommand + + const dockerfile = fs.readFileSync('Dockerfile', 'utf8') + + const match = dockerfile.match(/^\s*CMD\s+(\[.*\]|".*")/mi) + if (match) { + try { + cmd = JSON.parse(match[1]) + } catch { } + } + + if (Array.isArray(cmd)) cmd = cmd.join(' ') + cmd = `${this.bun ? 'bun' : 'node'} ./dbsetup.js ${cmd}` + this.flyToml += `\n[processes]\n app = ${JSON.stringify(cmd)}\n` + fs.writeFileSync(this.flyTomlFile, this.flyToml) + } + // add volume to fly.toml and create it if app exists flyAttachConsul(app) { if (!app) return @@ -283,6 +311,57 @@ GDF.extend(class extends GDF { }) } + // set environment and secrets for Shopify apps + flyShopifyEnv(app) { + let toml = '' + if (fs.existsSync('shopify.app.toml')) { + toml = fs.readFileSync('shopify.app.toml', 'utf-8') + } + + if (!toml.includes('client_id')) { + this.setExit(42) + console.log(`${chalk.bold.red('shopify.app.toml')} is not complete; run ${chalk.bold.blue('shopify app config create')} first.`) + return + } + + const env = { + PORT: 3000, + SHOPIFY_APP_URL: `https://${app}.fly.dev` + } + + try { + console.log(`${chalk.bold.green('execute'.padStart(11))} shopify app env show`) + const stdout = execSync('shopify app env show', { encoding: 'utf8' }) + for (const match of stdout.matchAll(/^\s*(\w+)=(.*)/mg)) { + if (match[1] === 'SHOPIFY_API_SECRET') { + console.log(`${chalk.bold.green('execute'.padStart(11))} flyctl secrets set SHOPIFY_API_SECRET`) + execSync(`${this.flyctl} secrets set SHOPIFY_API_SECRET=${match[2]} --app ${app}`, { stdio: 'inherit' }) + } else { + env[match[1]] = match[2] + } + } + } catch { } + + if (this.flyToml.includes('[env]')) return + this.flyToml += '\n[env]\n' + Object.entries(env).map(([key, value]) => ` ${key} = ${JSON.stringify(value)}`).join('\n') + '\n' + fs.writeFileSync(this.flyTomlFile, this.flyToml) + } + + // update config for Shopify apps + flyShopifyConfig(app) { + const original = fs.readFileSync('shopify.app.toml', 'utf-8') + const url = `https://${app}.fly.dev` + const config = original.replaceAll(/"https:\/\/[-\w.]+/g, '"' + url) + .replace(/(redirect_urls\s*=\s*\[).*?\]/s, + `$1\n "${url}/auth/callback",\n "${url}/auth/shopify/callback",\n "${url}/api/auth/callback"\n]`) + if (original !== config) { + console.log(`${chalk.bold.green('update'.padStart(11, ' '))} shopify.app.toml`) + fs.writeFileSync('shopify.app.toml', config) + console.log(`${chalk.bold.green('execute'.padStart(11))} shopify app deploy --force`) + execSync('shopify app deploy --force', { stdio: 'inherit' }) + } + } + // prep for deployment via GitHub actions, including setting up a staging app flyGitHubPrep() { const deploy = fs.readFileSync('.github/workflows/deploy.yml', 'utf-8') diff --git a/gdf.js b/gdf.js index 5f25176..c625ae9 100755 --- a/gdf.js +++ b/gdf.js @@ -82,6 +82,9 @@ export class GDF { // exit code #exitCode = 0 + // dockerfile exists at the time of invocation + #dockerfileExists = false + get variant() { return this.options.alpine ? 'alpine' : 'slim' } @@ -147,6 +150,11 @@ export class GDF { this.#pj.dependencies?.['@remix-run/node']) } + // Does this application use shopify? + get shopify() { + return fs.existsSync(path.join(this._appdir, 'shopify.app.toml')) + } + // Is this an EpicStack application? get epicStack() { return !!this.#pj['epic-stack'] @@ -633,6 +641,10 @@ export class GDF { modules.push('@sveltejs/adapter-node') } + if (this.litestream && !this.#pj.dependencies?.['@flydotio/litestream']) { + modules.push('@flydotio/litestream') + } + if (modules.length === 0) return const add = this.packager === 'npm' ? 'install' : 'add' for (const module of modules) { @@ -934,6 +946,7 @@ export class GDF { this.options = options this._appdir = appdir this.#pj = JSON.parse(fs.readFileSync(path.join(appdir, 'package.json'), 'utf-8')) + this.#dockerfileExists = fs.existsSync(path.join(appdir, 'Dockerfile')) // backwards compatibility with previous definition of --build=defer if (options.build === 'defer') { @@ -967,7 +980,11 @@ export class GDF { } if (this.entrypoint) { - templates['docker-entrypoint.ejs'] = `${this.configDir}docker-entrypoint.js` + if (!this.#dockerfileExists || this.options.force) { + templates['docker-entrypoint.ejs'] = `${this.configDir}docker-entrypoint.js` + } else if (this.setupScriptType === 'dbsetup') { + templates['docker-entrypoint.ejs'] = `${this.configDir}dbsetup.js` + } } if (this.litefs) { @@ -984,9 +1001,9 @@ export class GDF { } for (const [template, filename] of Object.entries(templates)) { - const dest = await this.#writeTemplateFile(template, filename) + await this.#writeTemplateFile(template, filename) - if (template === 'docker-entrypoint.ejs') fs.chmodSync(dest, 0o755) + if (template === 'docker-entrypoint.ejs') fs.chmodSync(path.join(this._appdir, filename), 0o755) } // ensure that there is a dockerignore file @@ -1028,7 +1045,11 @@ export class GDF { runner.apply(this) } - process.exit(this.#exitCode) + if (this.#exitCode) process.exit(this.#exitCode) + } + + get setupScriptType() { + return (this.options.skip && this.#dockerfileExists) ? 'dbsetup' : 'docker' } setExit(code) { @@ -1046,6 +1067,9 @@ export class GDF { if (current === proposed) { console.log(`${chalk.bold.blue('identical'.padStart(11))} ${name}`) return dest + } else if (this.options.skip) { + console.log(`${chalk.bold.yellow('skip'.padStart(11))} ${name}`) + return current } let prompt diff --git a/index.js b/index.js index 3256609..b90302f 100755 --- a/index.js +++ b/index.js @@ -89,6 +89,10 @@ const options = yargs((hideBin(process.argv))) describe: 'expose port', type: 'integer' }) + .option('skip', { + describe: 'skip overwrite of existing files', + type: 'boolean' + }) .option('swap', { alias: 's', describe: 'allocate swap space (eg. 1G, 1GiB, 1024M)', @@ -334,4 +338,6 @@ if (pj) { } } +if (options.force) options.skip = false + new GDF().run(process.cwd(), { ...defaults, ...options }) diff --git a/package-lock.json b/package-lock.json index 29e7251..4fa2115 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "@flydotio/dockerfile", - "version": "0.5.9", + "version": "0.6.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@flydotio/dockerfile", - "version": "0.5.9", + "version": "0.6.1", "license": "MIT", "dependencies": { + "@flydotio/litestream": "^1.0.1", "@sveltejs/adapter-node": "^5.2.11", "chalk": "^5.3.0", "diff": "^5.2.0", @@ -516,6 +517,88 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@flydotio/litestream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@flydotio/litestream/-/litestream-1.0.1.tgz", + "integrity": "sha512-hGIR37D1o8+AKcHa0PmdOG7dPm1RQsFQE3cqgt2udQVo3Q0NI5ruarLeaFWTFB6l+hjs97Xdlt0TgEufxLTzaQ==", + "license": "MIT", + "bin": { + "litestream": "index.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@flydotio/litestream-darwin-arm64": "1.0.1", + "@flydotio/litestream-darwin-x64": "1.0.1", + "@flydotio/litestream-linux-arm64": "1.0.1", + "@flydotio/litestream-linux-x64": "1.0.1" + } + }, + "node_modules/@flydotio/litestream-darwin-arm64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@flydotio/litestream-darwin-arm64/-/litestream-darwin-arm64-1.0.1.tgz", + "integrity": "sha512-LI663pEbO1RZzzkqDbXen6UIDeOBkGJqfyl8FGm4Y+zbcKiLQhopuQLMs4BHlWelGMb2ZnwpcpM+OcimoDhqHA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@flydotio/litestream-darwin-x64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@flydotio/litestream-darwin-x64/-/litestream-darwin-x64-1.0.1.tgz", + "integrity": "sha512-AecPpC1mu5QJ12+UWEaeCZbtNbde+t7qqgxrIYEZ+ZmrfgvCmsuZIqz67/IuRtaXTzr0COKD/uv9KRHIx+xHsQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@flydotio/litestream-linux-arm64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@flydotio/litestream-linux-arm64/-/litestream-linux-arm64-1.0.1.tgz", + "integrity": "sha512-/kukXjY+8xnAVUY3ywZIHIrW2gmKg5dXFVmSR/IQtdEwWZrKqdJ77fbK4u9bkacZqf94xn9jej8Cr4sToy6gNg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@flydotio/litestream-linux-x64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@flydotio/litestream-linux-x64/-/litestream-linux-x64-1.0.1.tgz", + "integrity": "sha512-zmcAR8q2TNiAsWRSWscrN+r4NNQ+FwfatKhcE3G/YticNSkNyIhtCTlvXxIyOG+E+UWa+j441cjbmb7p83JPEw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", diff --git a/package.json b/package.json index 27b5acb..1326f39 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "node": ">=16.0.0" }, "dependencies": { + "@flydotio/litestream": "^1.0.1", "@sveltejs/adapter-node": "^5.2.11", "chalk": "^5.3.0", "diff": "^5.2.0", diff --git a/templates/docker-entrypoint.ejs b/templates/docker-entrypoint.ejs index 9271ca6..e49d326 100755 --- a/templates/docker-entrypoint.ejs +++ b/templates/docker-entrypoint.ejs @@ -42,76 +42,98 @@ if (process.env.DATABASE_URL) { } <% } -%> +<% n = typeModule ? 0 : 1 -%> +<% if (!typeModule) { -%> ;(async() => { +<% } -%> <% if (options.swap && !flySetup()) { -%> -<%= tab(1) %>// allocate swap space -<%= tab(1) %>await exec('fallocate -l <%= options.swap %> /swapfile') -<%= tab(1) %>await exec('chmod 0600 /swapfile') -<%= tab(1) %>await exec('mkswap /swapfile') -<%= tab(1) %>writeFileSync('/proc/sys/vm/swappiness', '10') -<%= tab(1) %>await exec('swapon /swapfile') -<%= tab(1) %>writeFileSync('/proc/sys/vm/overcommit_memory', '1') +<%= tab(n) %>// allocate swap space +<%= tab(n) %>await exec('fallocate -l <%= options.swap %> /swapfile') +<%= tab(n) %>await exec('chmod 0600 /swapfile') +<%= tab(n) %>await exec('mkswap /swapfile') +<%= tab(n) %>writeFileSync('/proc/sys/vm/swappiness', '10') +<%= tab(n) %>await exec('swapon /swapfile') +<%= tab(n) %>writeFileSync('/proc/sys/vm/overcommit_memory', '1') <% } -%> <% if (prisma || (build && options.deferBuild) || nextjsGeneration) { -%> +<% if (setupScriptType == 'docker') { -%> <% if (prisma && sqlite3) { -%> -<%= tab(1) %>// If running the web server then migrate existing database +<%= tab(n) %>// If running the web server then migrate existing database <% } else { -%> -<%= tab(1) %>// If running the web server then prerender pages +<%= tab(n) %>// If running the web server then prerender pages <% } -%> -<%= tab(1) %>if (process.argv.slice(2).join(' ') === '<%- +<%= tab(n) %>if (process.argv.slice(-<%= + Array.isArray(startCommand) ? startCommand.length : startCommand.split(" ").length + %>).join(' ') === '<%- Array.isArray(startCommand) ? startCommand.join(" ") : startCommand %>'<% if (litefs) { %> && process.env.FLY_REGION === process.env.PRIMARY_REGION<% } %>) { +<% n++ -%> +<% } -%> <% if (prisma) { -%> <% if (prismaFile) { -%> -<%= tab(2) %><%= nuxtjs ? 'let' : 'const' %> source = path.resolve('<%- prismaFile %>') -<%= tab(2) %>const target = '/data/' + path.basename(source) -<%= tab(2) %>if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) +<%= tab(n) %>// place Sqlite3 database on volume +<%= tab(n) %><%= nuxtjs ? 'let' : 'const' %> source = path.resolve('<%- prismaFile %>') +<%= tab(n) %>const target = '/data/' + path.basename(source) +<%= tab(n) %>if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) <% if (nuxtjs) { -%> -<%= tab(2) %>source = path.resolve('./.output/server', '<%- prismaFile %>') -<%= tab(2) %>if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) +<%= tab(n) %>source = path.resolve('./.output/server', '<%- prismaFile %>') +<%= tab(n) %>if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) <% } -%> <% } else if (prismaSeed && sqlite3 && prismaEnv) { -%> -<%= tab(2) %>const url = new URL(process.env.<%= prismaEnv %>) -<%= tab(2) %>const target = url.protocol === 'file:' && url.pathname -<%= tab(2) %><%= litestream ? 'let' : 'const' %> newDb = target && !fs.existsSync(target) +<%= tab(n) %>const url = new URL(process.env.<%= prismaEnv %>) +<%= tab(n) %>const target = url.protocol === 'file:' && url.pathname +<% if (litestream && sqlite3 && (prismaFile || prismaEnv)) { -%> + +<%= tab(n) %>// restore database if not present and replica exists <% } -%> -<% if (prismaFile && prismaSeed && sqlite3) { -%> -<%= tab(2) %><%= litestream ? 'let' : 'const' %> newDb = !fs.existsSync(target) <% } -%> -<% if (litestream && prismaSeed && sqlite3 && (prismaFile || prismaEnv)) { -%> -<%= tab(2) %>if (newDb && process.env.BUCKET_NAME) { -<%= tab(3) %>await exec(`litestream restore -config litestream.yml -if-replica-exists ${target}`) -<%= tab(3) %>newDb = !fs.existsSync(target) -<%= tab(2) %>} +<% if (sqlite3 && (prismaSeed || litestream) && (prismaFile || prismaEnv)) { -%> +<%= tab(n) %><%= litestream && prismaSeed && sqlite3 ? 'let' : 'const' %> newDb = <%- !prismaFile ? 'target && ' : '' %>!fs.existsSync(target) +<% } -%> +<% if (litestream && sqlite3 && (prismaFile || prismaEnv)) { -%> +<%= tab(n) %>if (newDb && process.env.BUCKET_NAME) { +<%= tab(n+1) %>await exec(`<% if (setupScriptType == 'dbsetup') { %>npx <% } %>litestream restore -config litestream.yml -if-replica-exists ${target}`) +<% if (prismaSeed && sqlite3 && (prismaFile || prismaEnv)) { -%> +<%= tab(n+1) %>newDb = !fs.existsSync(target) +<% } -%> +<%= tab(n) %>} <% } -%> <% if (sqlite3) { -%> -<%= tab(2) %>await exec('<%= npx %> prisma migrate deploy') +<% if (prismaFile) { -%> + +<%= tab(n) %>// prepare database +<% } -%> +<%= tab(n) %>await exec('<%= npx %> prisma migrate deploy') <% } -%> <% if (prismaSeed && sqlite3 && (prismaFile || prismaEnv)) { -%> -<%= tab(2) %>if (newDb) await exec('npx prisma db seed') +<%= tab(n) %>if (newDb) await exec('npx prisma db seed') <% } -%> <% } -%> <% if (nextjsGeneration) { -%> -<%= tab(2) %>await exec('<%= npx %> next build --experimental-build-mode generate') +<%= tab(n) %>await exec('<%= npx %> next build --experimental-build-mode generate') <% } -%> <% if (build && options.deferBuild) { -%> -<%= tab(2) %>await exec('<%= packager %> run build') +<%= tab(n) %>await exec('<%= packager %> run build') +<% } -%> +<% if (setupScriptType == 'docker') { -%> +<%= tab(--n) %>} <% } -%> -<%= tab(1) %>} <% } -%> -<%= tab(1) %>// launch application +<%= tab(n) %>// launch application <% if (litestream) { -%> -<%= tab(1) %>if (process.env.BUCKET_NAME) { -<%= tab(2) %>await exec(`litestream replicate -config litestream.yml -exec ${JSON.stringify(process.argv.slice(2).join(' '))}`) -<%= tab(1) %>} else { -<%= tab(2) %>await exec(process.argv.slice(2).join(' ')) -<%= tab(1) %>} +<%= tab(n) %>if (process.env.BUCKET_NAME) { +<%= tab(n+1) %>await exec(`<% if (setupScriptType == 'dbsetup') { %>npx <% } %>litestream replicate -config litestream.yml -exec ${JSON.stringify(process.argv.slice(2).join(' '))}`) +<%= tab(n) %>} else { +<%= tab(n+1) %>await exec(process.argv.slice(2).join(' ')) +<%= tab(n) %>} <% } else { -%> -<%= tab(1) %>await exec(process.argv.slice(2).join(' ')) +<%= tab(n) %>await exec(process.argv.slice(2).join(' ')) <% } -%> +<% if (!typeModule) { -%> })() +<% } -%> <%= tab(0) %>function exec(command) { <%= tab(1) %>const child = spawn(command, { shell: true, stdio: 'inherit', env }) diff --git a/test/base/defer-build/docker-entrypoint.js b/test/base/defer-build/docker-entrypoint.js index 19674de..b1103fa 100755 --- a/test/base/defer-build/docker-entrypoint.js +++ b/test/base/defer-build/docker-entrypoint.js @@ -8,10 +8,13 @@ const env = { ...process.env } ;(async() => { // If running the web server then migrate existing database - if (process.argv.slice(2).join(' ') === 'npm run start') { + if (process.argv.slice(-3).join(' ') === 'npm run start') { + // place Sqlite3 database on volume const source = path.resolve('./dev.db') const target = '/data/' + path.basename(source) if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) + + // prepare database await exec('npx prisma migrate deploy') await exec('npm run build') } diff --git a/test/base/litestream/docker-entrypoint.js b/test/base/litestream/docker-entrypoint.js new file mode 100755 index 0000000..37dbc7a --- /dev/null +++ b/test/base/litestream/docker-entrypoint.js @@ -0,0 +1,44 @@ +#!/usr/bin/env node + +const { spawn } = require('node:child_process') +const path = require('node:path') +const fs = require('node:fs') + +const env = { ...process.env } + +;(async() => { + // If running the web server then migrate existing database + if (process.argv.slice(-3).join(' ') === 'npm run start') { + // place Sqlite3 database on volume + const source = path.resolve('./dev.db') + const target = '/data/' + path.basename(source) + if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) + const newDb = !fs.existsSync(target) + if (newDb && process.env.BUCKET_NAME) { + await exec(`litestream restore -config litestream.yml -if-replica-exists ${target}`) + } + + // prepare database + await exec('npx prisma migrate deploy') + } + + // launch application + if (process.env.BUCKET_NAME) { + await exec(`litestream replicate -config litestream.yml -exec ${JSON.stringify(process.argv.slice(2).join(' '))}`) + } else { + await exec(process.argv.slice(2).join(' ')) + } +})() + +function exec(command) { + const child = spawn(command, { shell: true, stdio: 'inherit', env }) + return new Promise((resolve, reject) => { + child.on('exit', code => { + if (code === 0) { + resolve() + } else { + reject(new Error(`${command} failed rc=${code}`)) + } + }) + }) +} diff --git a/test/base/windows/docker-entrypoint.js b/test/base/windows/docker-entrypoint.js index b52ac96..0b7e348 100755 --- a/test/base/windows/docker-entrypoint.js +++ b/test/base/windows/docker-entrypoint.js @@ -7,7 +7,7 @@ const env = { ...process.env } ;(async() => { // If running the web server then migrate existing database - if (process.argv.slice(2).join(' ') === 'npx remix-serve ./build/index.js') { + if (process.argv.slice(-3).join(' ') === 'npx remix-serve ./build/index.js') { const url = new URL(process.env.DATABASE_URL) const target = url.protocol === 'file:' && url.pathname const newDb = target && !fs.existsSync(target) diff --git a/test/frameworks/next-standalone/docker-entrypoint.js b/test/frameworks/next-standalone/docker-entrypoint.js new file mode 100755 index 0000000..91b89a3 --- /dev/null +++ b/test/frameworks/next-standalone/docker-entrypoint.js @@ -0,0 +1,28 @@ +#!/usr/bin/env node + +const { spawn } = require('node:child_process') + +const env = { ...process.env } + +;(async() => { + // If running the web server then prerender pages + if (process.argv.slice(-2).join(' ') === 'node server.js') { + await exec('npx next build --experimental-build-mode generate') + } + + // launch application + await exec(process.argv.slice(2).join(' ')) +})() + +function exec(command) { + const child = spawn(command, { shell: true, stdio: 'inherit', env }) + return new Promise((resolve, reject) => { + child.on('exit', code => { + if (code === 0) { + resolve() + } else { + reject(new Error(`${command} failed rc=${code}`)) + } + }) + }) +} diff --git a/test/frameworks/nuxt-prisma/docker-entrypoint.js b/test/frameworks/nuxt-prisma/docker-entrypoint.js index 814e38e..a638041 100755 --- a/test/frameworks/nuxt-prisma/docker-entrypoint.js +++ b/test/frameworks/nuxt-prisma/docker-entrypoint.js @@ -8,7 +8,8 @@ const env = { ...process.env } ;(async() => { // If running the web server then migrate existing database - if (process.argv.slice(2).join(' ') === 'node .output/server/index.mjs') { + if (process.argv.slice(-2).join(' ') === 'node .output/server/index.mjs') { + // place Sqlite3 database on volume let source = path.resolve('./dev.db') const target = '/data/' + path.basename(source) if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) @@ -19,6 +20,8 @@ const env = { ...process.env } await exec(`litestream restore -config litestream.yml -if-replica-exists ${target}`) newDb = !fs.existsSync(target) } + + // prepare database await exec('npx prisma migrate deploy') if (newDb) await exec('npx prisma db seed') } diff --git a/test/frameworks/remix-epic/docker-entrypoint.js b/test/frameworks/remix-epic/docker-entrypoint.js index 1216dcc..6e48f89 100755 --- a/test/frameworks/remix-epic/docker-entrypoint.js +++ b/test/frameworks/remix-epic/docker-entrypoint.js @@ -4,15 +4,13 @@ import { spawn } from 'node:child_process' const env = { ...process.env } -;(async() => { - // If running the web server then migrate existing database - if (process.argv.slice(2).join(' ') === 'npm run start' && process.env.FLY_REGION === process.env.PRIMARY_REGION) { - await exec('npx prisma migrate deploy') - } +// If running the web server then migrate existing database +if (process.argv.slice(-3).join(' ') === 'npm run start' && process.env.FLY_REGION === process.env.PRIMARY_REGION) { + await exec('npx prisma migrate deploy') +} - // launch application - await exec(process.argv.slice(2).join(' ')) -})() +// launch application +await exec(process.argv.slice(2).join(' ')) function exec(command) { const child = spawn(command, { shell: true, stdio: 'inherit', env }) diff --git a/test/frameworks/remix-indie/docker-entrypoint.js b/test/frameworks/remix-indie/docker-entrypoint.js index b52ac96..0b7e348 100755 --- a/test/frameworks/remix-indie/docker-entrypoint.js +++ b/test/frameworks/remix-indie/docker-entrypoint.js @@ -7,7 +7,7 @@ const env = { ...process.env } ;(async() => { // If running the web server then migrate existing database - if (process.argv.slice(2).join(' ') === 'npx remix-serve ./build/index.js') { + if (process.argv.slice(-3).join(' ') === 'npx remix-serve ./build/index.js') { const url = new URL(process.env.DATABASE_URL) const target = url.protocol === 'file:' && url.pathname const newDb = target && !fs.existsSync(target) diff --git a/test/frameworks/svelte-prisma/docker-entrypoint.js b/test/frameworks/svelte-prisma/docker-entrypoint.js index 1437720..533caa3 100755 --- a/test/frameworks/svelte-prisma/docker-entrypoint.js +++ b/test/frameworks/svelte-prisma/docker-entrypoint.js @@ -6,20 +6,21 @@ import fs from 'node:fs' const env = { ...process.env } -;(async() => { - // If running the web server then migrate existing database - if (process.argv.slice(2).join(' ') === 'node ./build/index.js') { - const source = path.resolve('./dev.db') - const target = '/data/' + path.basename(source) - if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) - const newDb = !fs.existsSync(target) - await exec('npx prisma migrate deploy') - if (newDb) await exec('npx prisma db seed') - } +// If running the web server then migrate existing database +if (process.argv.slice(-2).join(' ') === 'node ./build/index.js') { + // place Sqlite3 database on volume + const source = path.resolve('./dev.db') + const target = '/data/' + path.basename(source) + if (!fs.existsSync(source) && fs.existsSync('/data')) fs.symlinkSync(target, source) + const newDb = !fs.existsSync(target) - // launch application - await exec(process.argv.slice(2).join(' ')) -})() + // prepare database + await exec('npx prisma migrate deploy') + if (newDb) await exec('npx prisma db seed') +} + +// launch application +await exec(process.argv.slice(2).join(' ')) function exec(command) { const child = spawn(command, { shell: true, stdio: 'inherit', env })