|
| 1 | +import { Command } from 'commander' |
| 2 | +import { listParameters } from '../aws.js' |
| 3 | +import { prettifyParameter } from '../utils.js' |
| 4 | +import { spawn } from 'node:child_process' |
| 5 | + |
| 6 | +const SUMMARY = 'Execute the command with the environment from SSM' |
| 7 | +const DESCRIPTION = `${SUMMARY}. |
| 8 | +This command will fetch the parameters from SSM and provide them as environment variables to the specified command. |
| 9 | +
|
| 10 | +The variable names are stripped of path prefix and uppercased. |
| 11 | +Example: parameter with path my/app/parameter becomes PARAMETER environment variable.` |
| 12 | + |
| 13 | +export function execCommand(program: Command) { |
| 14 | + program |
| 15 | + .command('exec') |
| 16 | + .summary(SUMMARY) |
| 17 | + .description(DESCRIPTION) |
| 18 | + .argument('<path>', 'SSM parameter path') |
| 19 | + .argument('<command>', 'Command to execute') |
| 20 | + .argument('[args...]', 'Arguments for the command. Use -- before command to ensure that arguments are passed correctly: ssm-secrets exec my/path -- command --argument') |
| 21 | + .option('--no-overwrite', 'Do not overwrite existing environment variables') |
| 22 | + .option( |
| 23 | + '--ignore <ignores...>', |
| 24 | + 'Do not include the parameters with the given names to environment. ' |
| 25 | + + 'The parameter names are case-sensitive and should match the name inside SSM excluding path prefix. ' |
| 26 | + + 'Example: if you want to ignore my/app/parameter1 and my/app/parameter2, use --ignore parameter1 parameter2' |
| 27 | + ) |
| 28 | + .action(async (path: string, command: string, args: string[], options: { overwrite: boolean, ignore: string[] | undefined }) => { |
| 29 | + // Normalize options |
| 30 | + const ignore = options.ignore ?? [] |
| 31 | + |
| 32 | + const ssmParameters = await listParameters(path) |
| 33 | + |
| 34 | + const filteredPrettyParams = ssmParameters |
| 35 | + .map(param => prettifyParameter(param, path)) |
| 36 | + .filter(param => param.Name !== undefined && !ignore.includes(param.Name)) |
| 37 | + |
| 38 | + const envs = Object.fromEntries(filteredPrettyParams.map(param => [param.Name?.toUpperCase(), param.Value])) |
| 39 | + |
| 40 | + // Merge into environment |
| 41 | + const env = options.overwrite |
| 42 | + ? { |
| 43 | + ...process.env, |
| 44 | + ...envs, |
| 45 | + } |
| 46 | + : { |
| 47 | + ...envs, |
| 48 | + ...process.env, |
| 49 | + } |
| 50 | + |
| 51 | + // Replace current process |
| 52 | + const child = spawn(command, args, { |
| 53 | + env, |
| 54 | + stdio: 'inherit', |
| 55 | + }) |
| 56 | + |
| 57 | + child.on('exit', code => process.exit(code ?? 0)) |
| 58 | + }) |
| 59 | +} |
0 commit comments