Skip to content

Commit 65d2198

Browse files
committed
feat: recursive embedding of env vars in env vars
1 parent fa50d02 commit 65d2198

9 files changed

+63
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- **Upgrade**: Upgraded dependency `commander` to `5.x`
66
- **Upgrade**: Upgraded devDependencies `ts-standard`, `sinon`
77
- **Feature**: support both `$var` and `${var}` when expanding vars
8+
- **Feature**: Added support for nested env variables with the `--recursive` flag
89

910
## 10.1.0
1011

dist/env-cmd.js

+5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ async function EnvCmd({ command, commandArgs, envFile, rc, options = {} }) {
5252
// Add in the system environment variables to our environment list
5353
env = Object.assign({}, process.env, env);
5454
}
55+
if (options.recursive === true) {
56+
for (const key of Object.keys(env)) {
57+
env[key] = expand_envs_1.expandEnvs(env[key], env);
58+
}
59+
}
5560
if (options.expandEnvs === true) {
5661
command = expand_envs_1.expandEnvs(command, env);
5762
commandArgs = commandArgs.map(arg => expand_envs_1.expandEnvs(arg, env));

dist/parse-args.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ function parseArgs(args) {
3131
if (program.expandEnvs === true) {
3232
expandEnvs = true;
3333
}
34+
let recursive = false;
35+
if (program.recursive === true) {
36+
recursive = true;
37+
}
3438
let verbose = false;
3539
if (program.verbose === true) {
3640
verbose = true;
@@ -60,6 +64,7 @@ function parseArgs(args) {
6064
rc,
6165
options: {
6266
expandEnvs,
67+
recursive,
6368
noOverride,
6469
silent,
6570
useShell,
@@ -85,7 +90,8 @@ function parseArgsUsingCommander(args) {
8590
.option('--silent', 'Ignore any env-cmd errors and only fail on executed program failure.')
8691
.option('--use-shell', 'Execute the command in a new shell with the given environment')
8792
.option('--verbose', 'Print helpful debugging information')
88-
.option('-x, --expand-envs', 'Replace $var in args and command with environment variables')
93+
.option('-x, --expand-envs', 'Replace $var and $\\{var\\} in args and command with environment variables')
94+
.option('--recursive', 'Replace $var and $\\{var\\} in env file with the referenced environment variable')
8995
.allowUnknownOption(true)
9096
.parse(['_', '_', ...args]);
9197
}

dist/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface EnvCmdOptions extends Pick<GetEnvVarOptions, 'envFile' | 'rc'>
1414
commandArgs: string[];
1515
options?: {
1616
expandEnvs?: boolean;
17+
recursive?: boolean;
1718
noOverride?: boolean;
1819
silent?: boolean;
1920
useShell?: boolean;

src/env-cmd.ts

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ export async function EnvCmd (
5757
env = Object.assign({}, process.env, env)
5858
}
5959

60+
if (options.recursive === true) {
61+
for (const key of Object.keys(env)) {
62+
env[key] = expandEnvs(env[key], env)
63+
}
64+
}
65+
6066
if (options.expandEnvs === true) {
6167
command = expandEnvs(command, env)
6268
commandArgs = commandArgs.map(arg => expandEnvs(arg, env))

src/parse-args.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export function parseArgs (args: string[]): EnvCmdOptions {
3333
if (program.expandEnvs === true) {
3434
expandEnvs = true
3535
}
36+
let recursive = false
37+
if (program.recursive === true) {
38+
recursive = true
39+
}
3640
let verbose = false
3741
if (program.verbose === true) {
3842
verbose = true
@@ -65,6 +69,7 @@ export function parseArgs (args: string[]): EnvCmdOptions {
6569
rc,
6670
options: {
6771
expandEnvs,
72+
recursive,
6873
noOverride,
6974
silent,
7075
useShell,
@@ -90,7 +95,8 @@ export function parseArgsUsingCommander (args: string[]): commander.Command {
9095
.option('--silent', 'Ignore any env-cmd errors and only fail on executed program failure.')
9196
.option('--use-shell', 'Execute the command in a new shell with the given environment')
9297
.option('--verbose', 'Print helpful debugging information')
93-
.option('-x, --expand-envs', 'Replace $var in args and command with environment variables')
98+
.option('-x, --expand-envs', 'Replace $var and $\\{var\\} in args and command with environment variables')
99+
.option('--recursive', 'Replace $var and $\\{var\\} in env file with the referenced environment variable')
94100
.allowUnknownOption(true)
95101
.parse(['_', '_', ...args])
96102
}

src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface EnvCmdOptions extends Pick<GetEnvVarOptions, 'envFile' | 'rc'>
1515
commandArgs: string[]
1616
options?: {
1717
expandEnvs?: boolean
18+
recursive?: boolean
1819
noOverride?: boolean
1920
silent?: boolean
2021
useShell?: boolean

test/env-cmd.spec.ts

+29
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,35 @@ describe('EnvCmd', (): void => {
193193
}
194194
)
195195

196+
it('should spawn process with args expanded if recursive option is true',
197+
async (): Promise<void> => {
198+
getEnvVarsStub.returns({ PING: 'PONG', recursive: 'PING ${PING}' }) /* eslint-disable-line */
199+
await envCmdLib.EnvCmd({
200+
command: 'node',
201+
commandArgs: [],
202+
envFile: {
203+
filePath: './.env',
204+
fallback: true
205+
},
206+
rc: {
207+
environments: ['dev'],
208+
filePath: './.rc'
209+
},
210+
options: {
211+
recursive: true
212+
}
213+
})
214+
215+
const spawnArgs = spawnStub.args[0]
216+
217+
assert.equal(getEnvVarsStub.callCount, 1, 'getEnvVars must be called once')
218+
assert.equal(spawnStub.callCount, 1)
219+
assert.isAtLeast(expandEnvsSpy.callCount, 3, 'total number of env args')
220+
assert.equal(spawnArgs[0], 'node')
221+
assert.equal(spawnArgs[2].env.recursive, 'PING PONG')
222+
}
223+
)
224+
196225
it('should ignore errors if silent flag provided',
197226
async (): Promise<void> => {
198227
delete process.env.BOB

test/parse-args.spec.ts

+6
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ describe('parseArgs', (): void => {
9898
assert.isTrue(res.options!.expandEnvs)
9999
})
100100

101+
it('should parse recursive option', (): void => {
102+
const res = parseArgs(['-f', envFilePath, '--recursive', command, ...commandArgs])
103+
assert.exists(res.envFile)
104+
assert.isTrue(res.options!.recursive)
105+
})
106+
101107
it('should parse silent option', (): void => {
102108
const res = parseArgs(['-f', envFilePath, '--silent', command, ...commandArgs])
103109
assert.exists(res.envFile)

0 commit comments

Comments
 (0)