-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
626453e
commit f09f53f
Showing
6 changed files
with
329 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#! /usr/bin/env node | ||
|
||
import * as commands from './commands'; | ||
const command = process.argv[2]; | ||
const args = process.argv.slice(3); | ||
|
||
const hasHelpFlag = args.includes('--help') || args.includes('-h'); | ||
if (hasHelpFlag) { | ||
commands.help(); | ||
process.exit(0); | ||
} | ||
|
||
switch (command) { | ||
case 'start': | ||
if (hasHelpFlag) { | ||
commands.help('start'); | ||
} else { | ||
handle(commands.start(args)); | ||
} | ||
break; | ||
case 'run': | ||
if (hasHelpFlag) { | ||
commands.help('run'); | ||
} else { | ||
handle(commands.run(args)); | ||
} | ||
break; | ||
case 'stop': | ||
if (hasHelpFlag) { | ||
commands.help('stop'); | ||
} else { | ||
handle(commands.stop(args)); | ||
} | ||
break; | ||
case 'help': | ||
commands.help(args[0]); | ||
break; | ||
default: | ||
commands.help(); | ||
if (!hasHelpFlag) { | ||
console.error( | ||
`Unexpected command ${command}, expected one of "start" or "help"`, | ||
); | ||
process.exit(1); | ||
} | ||
break; | ||
} | ||
|
||
function handle(v: Promise<number>) { | ||
if (!v) { | ||
process.exit(0); | ||
} | ||
v.then( | ||
(value) => { | ||
process.exit(value); | ||
}, | ||
(ex) => { | ||
console.error(ex.stack || ex); | ||
process.exit(1); | ||
}, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
import ms = require('ms'); | ||
import {parse, startChain, param} from 'parameter-reducers'; | ||
import * as ta from 'type-assertions'; | ||
import {getPgConfigSync} from '@databases/pg-config'; | ||
import getDatabase, {Options, killDatabase} from '.'; | ||
import {execBuffered, spawnBuffered} from 'modern-spawn'; | ||
|
||
const seconds = <TName extends string>(keys: string[], name: TName) => { | ||
return param.parsedString(keys, name, (str, key) => { | ||
if (/^\d+$/.test(str)) { | ||
return {valid: true, value: parseInt(str, 10)}; | ||
} | ||
try { | ||
const value = ms(str); | ||
if (value !== undefined) { | ||
return {valid: true, value: Math.round(value / 1000)}; | ||
} | ||
} catch (ex) { | ||
// return default error message | ||
} | ||
return { | ||
valid: false, | ||
reason: `Expected ${key} to be a valid number of seconds`, | ||
}; | ||
}); | ||
}; | ||
|
||
const params = startChain() | ||
.addParam(param.flag(['-d', '--debug'], 'debug')) | ||
.addParam(param.string(['--image'], 'image')) | ||
.addParam(param.string(['--containerName'], 'containerName')) | ||
.addParam(param.integer(['-p', '--externalPort'], 'externalPort')) | ||
.addParam(seconds(['--connectTimeout'], 'connectTimeoutSeconds')) | ||
.addParam(param.flag(['-r', '--refresh'], 'refreshImage')) | ||
|
||
.addParam(param.string(['--user'], 'pgUser')) | ||
.addParam(param.string(['--db'], 'pgDb')); | ||
|
||
async function runMigrationsAndAddToEnv(databaseURL: string, debug?: boolean) { | ||
const config = getPgConfigSync(); | ||
|
||
const DEFAULT_ENV_VAR = | ||
process.env.MYSQL_TEST_ENV_VAR || | ||
config.connectionStringEnvironmentVariable; | ||
process.env[DEFAULT_ENV_VAR] = databaseURL; | ||
|
||
const migrationsScript = process.env.MYSQL_TEST_MIGRATIONS_SCRIPT | ||
? process.env.MYSQL_TEST_MIGRATIONS_SCRIPT.split(' ') | ||
: config.test.migrationsScript; | ||
if (migrationsScript) { | ||
console.warn('Running pg migrations'); | ||
if (typeof migrationsScript === 'string') { | ||
await execBuffered(migrationsScript, { | ||
debug: debug || config.test.debug || false, | ||
}).getResult(); | ||
} else { | ||
await spawnBuffered(migrationsScript[0], migrationsScript.slice(1), { | ||
debug: debug || config.test.debug || false, | ||
}).getResult(); | ||
} | ||
} | ||
} | ||
|
||
export async function start(args: string[]) { | ||
const parseResult = parse(params, args); | ||
if (!parseResult.valid) { | ||
console.error(parseResult.reason); | ||
return 1; | ||
} | ||
if (parseResult.rest.length) { | ||
console.error(`Unexpected option ${parseResult.rest[0]}`); | ||
return 1; | ||
} | ||
ta.assert< | ||
ta.Equal< | ||
Pick< | ||
Partial<Options>, | ||
| 'debug' | ||
| 'image' | ||
| 'containerName' | ||
| 'externalPort' | ||
| 'connectTimeoutSeconds' | ||
| 'refreshImage' | ||
| 'pgUser' | ||
| 'pgDb' | ||
> & {environmentVariable?: string}, | ||
typeof parseResult.parsed | ||
> | ||
>(); | ||
const {databaseURL} = await getDatabase({ | ||
...parseResult.parsed, | ||
detached: true, | ||
}); | ||
|
||
await runMigrationsAndAddToEnv(databaseURL, parseResult.parsed.debug); | ||
|
||
console.info(databaseURL); | ||
return 0; | ||
} | ||
|
||
export async function run(args: string[]) { | ||
const parseResult = parse(params, args); | ||
if (!parseResult.valid) { | ||
console.error(parseResult.reason); | ||
return 1; | ||
} | ||
const rest = | ||
parseResult.rest[0] === '--' ? parseResult.rest.slice(1) : parseResult.rest; | ||
if (!rest.length) { | ||
console.error(`You must specify a command to run`); | ||
return 1; | ||
} | ||
const {databaseURL, kill} = await getDatabase({ | ||
...parseResult.parsed, | ||
detached: true, | ||
}); | ||
|
||
await runMigrationsAndAddToEnv(databaseURL, parseResult.parsed.debug); | ||
|
||
await spawnBuffered(parseResult.rest[0], parseResult.rest.slice(1), { | ||
debug: true, | ||
}); | ||
|
||
await kill(); | ||
|
||
return 0; | ||
} | ||
|
||
const stopParams = startChain() | ||
.addParam(param.flag(['-d', '--debug'], 'debug')) | ||
.addParam(param.string(['--containerName'], 'containerName')); | ||
export async function stop(args: string[]) { | ||
const parseResult = parse(stopParams, args); | ||
if (!parseResult.valid) { | ||
console.error(parseResult.reason); | ||
return 1; | ||
} | ||
if (parseResult.rest.length) { | ||
console.error(`Unexpected option ${parseResult.rest[0]}`); | ||
return 1; | ||
} | ||
ta.assert< | ||
ta.Equal< | ||
Pick<Partial<Options>, 'debug' | 'containerName'>, | ||
typeof parseResult.parsed | ||
> | ||
>(); | ||
await killDatabase({ | ||
...parseResult.parsed, | ||
detached: true, | ||
}); | ||
return 0; | ||
} | ||
|
||
// prettier-ignore | ||
export function help(command?: string) { | ||
switch (command) { | ||
case 'start': | ||
console.info(`usage: pg-test start [-h] ...`); | ||
console.info(``); | ||
console.info(`Start temporary databases for running tests, using docker`); | ||
console.info(``); | ||
console.info(`Optional arguments:`); | ||
console.info(` -d, --debug Print all the output of child commands.`); | ||
console.info(` --image <string> Override the MySQL docker image.`); | ||
console.info(` --containerName <string> Specify a custom name for the container.`); | ||
console.info(` -p, --externalPort <integer> Specify the port to run on.`); | ||
console.info(` --connectTimeout <seconds> How long should we allow for the container`); | ||
console.info(` to start. You can specify a raw number in`); | ||
console.info(` seconds, or a time string like "1 minute"`); | ||
console.info(` -r, --refresh Update the cached docker conatiner`); | ||
console.info(` -user <string> The pg user`); | ||
console.info(` -password <string> The pg password`); | ||
console.info(` -db <string> The pg database`); | ||
console.info(` -h, --help Show this help message and exit.`); | ||
break; | ||
case 'run': | ||
console.info(`usage: pg-test run <options> your-command`); | ||
console.info(``); | ||
console.info(`Run your command with a MySQL database that is disposed of when your command exits`); | ||
console.info(``); | ||
console.info(`Optional arguments:`); | ||
console.info(` -d, --debug Print all the output of child commands.`); | ||
console.info(` --image <string> Override the Postgres docker image.`); | ||
console.info(` --containerName <string> Specify a custom name for the container.`); | ||
console.info(` -p, --externalPort <integer> Specify the port to run on.`); | ||
console.info(` --connectTimeout <seconds> How long should we allow for the container`); | ||
console.info(` to start. You can specify a raw number in`); | ||
console.info(` seconds, or a time string like "1 minute"`); | ||
console.info(` -r, --refresh Update the cached docker conatiner`); | ||
console.info(` -user <string> The postgres user`); | ||
console.info(` -db <string> The postgres database`); | ||
console.info(` -h, --help Show this help message and exit.`); | ||
break; | ||
case 'stop': | ||
console.info(`usage: pg-test stop [-h] ...`); | ||
console.info(``); | ||
console.info(`Stop temporary databases created via pg-test start`); | ||
console.info(``); | ||
console.info(`Optional arguments:`); | ||
console.info(` -d, --debug Print all the output of child commands.`); | ||
console.info(` --containerName <string> Specify a custom name for the container.`); | ||
break; | ||
default: | ||
console.info(`usage: pg-test <command> [-h] ...`); | ||
console.info(``); | ||
console.info(`Start temporary databases for running tests using docker`); | ||
console.info(``); | ||
console.info(`Commands`); | ||
console.info(` start Starts a Postgres database`); | ||
console.info(` run Run a command with a Postgres database that is disposed of at the end`); | ||
console.info(` stop Stops a Postgres database`); | ||
console.info(` help Print documentation for commands`); | ||
console.info(``); | ||
console.info(`Optional arguments:`); | ||
console.info(` -h, --help Show this help message and exit.`); | ||
console.info(``); | ||
console.info(`For detailed help about a specific command, use: pg-test help <command>`); | ||
break; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters