mirror of
https://github.com/toddbluhm/env-cmd.git
synced 2025-12-08 18:23:33 +00:00
fix(commander)!: updated code for new version
This commit is contained in:
parent
29c824674b
commit
9942f3c448
25
README.md
25
README.md
@ -30,7 +30,7 @@ ENV3=THE FISH
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": "env-cmd mocha -R spec"
|
||||
"test": "env-cmd -- mocha -R spec"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -38,7 +38,7 @@ ENV3=THE FISH
|
||||
**Terminal**
|
||||
|
||||
```sh
|
||||
./node_modules/.bin/env-cmd node index.js
|
||||
./node_modules/.bin/env-cmd -- node index.js
|
||||
```
|
||||
|
||||
### Using custom env file path
|
||||
@ -48,13 +48,13 @@ To use a custom env filename or path, pass the `-f` flag. This is a major breaki
|
||||
**Terminal**
|
||||
|
||||
```sh
|
||||
./node_modules/.bin/env-cmd -f ./custom/path/.env node index.js
|
||||
./node_modules/.bin/env-cmd -f ./custom/path/.env -- node index.js
|
||||
```
|
||||
|
||||
## 📜 Help
|
||||
|
||||
```text
|
||||
Usage: _ [options] <command> [...args]
|
||||
Usage: env-cmd [options] -- <command> [...args]
|
||||
|
||||
Options:
|
||||
-v, --version output the version number
|
||||
@ -101,10 +101,10 @@ are found.
|
||||
**Terminal**
|
||||
|
||||
```sh
|
||||
./node_modules/.bin/env-cmd -e production node index.js
|
||||
./node_modules/.bin/env-cmd -e production -- node index.js
|
||||
# Or for multiple environments (where `production` vars override `test` vars,
|
||||
# but both are included)
|
||||
./node_modules/.bin/env-cmd -e test,production node index.js
|
||||
./node_modules/.bin/env-cmd -e test,production -- node index.js
|
||||
```
|
||||
|
||||
### `--no-override` option
|
||||
@ -125,7 +125,7 @@ commands together that share the same environment variables.
|
||||
**Terminal**
|
||||
|
||||
```sh
|
||||
./node_modules/.bin/env-cmd -f ./test/.env --use-shell "npm run lint && npm test"
|
||||
./node_modules/.bin/env-cmd -f ./test/.env --use-shell -- "npm run lint && npm test"
|
||||
```
|
||||
|
||||
### Asynchronous env file support
|
||||
@ -138,7 +138,7 @@ commands together that share the same environment variables.
|
||||
**Terminal**
|
||||
|
||||
```sh
|
||||
./node_modules/.bin/env-cmd -f ./async-file.js node index.js
|
||||
./node_modules/.bin/env-cmd -f ./async-file.js -- node index.js
|
||||
```
|
||||
|
||||
### `-x` expands vars in arguments
|
||||
@ -152,14 +152,14 @@ to provide arguments to a command that are based on environment variable values
|
||||
|
||||
```sh
|
||||
# $VAR will be expanded into the env value it contains at runtime
|
||||
./node_modules/.bin/env-cmd -x node index.js --arg=\$VAR
|
||||
./node_modules/.bin/env-cmd -x -- node index.js --arg=\$VAR
|
||||
```
|
||||
|
||||
or in `package.json` (use `\\` to insert a literal backslash)
|
||||
```json
|
||||
{
|
||||
"script": {
|
||||
"start": "env-cmd -x node index.js --arg=\\$VAR"
|
||||
"start": "env-cmd -x -- node index.js --arg=\\$VAR"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -252,11 +252,6 @@ usually just easier to have a file with all the vars in them, especially for dev
|
||||
|
||||
[`cross-env`](https://github.com/kentcdodds/cross-env) - Cross platform setting of environment scripts
|
||||
|
||||
## 🎊 Special Thanks
|
||||
|
||||
Special thanks to [`cross-env`](https://github.com/kentcdodds/cross-env) for inspiration (uses the
|
||||
same `cross-spawn` lib underneath too).
|
||||
|
||||
## 📋 Contributing Guide
|
||||
|
||||
I welcome all pull requests. Please make sure you add appropriate test cases for any features
|
||||
|
||||
53
dist/parse-args.js
vendored
53
dist/parse-args.js
vendored
@ -1,4 +1,4 @@
|
||||
import * as commander from 'commander';
|
||||
import { Command } from '@commander-js/extra-typings';
|
||||
import { parseArgList } from './utils.js';
|
||||
import { default as packageJson } from '../package.json' with { type: 'json' };
|
||||
/**
|
||||
@ -7,48 +7,55 @@ import { default as packageJson } from '../package.json' with { type: 'json' };
|
||||
export function parseArgs(args) {
|
||||
// Run the initial arguments through commander in order to determine
|
||||
// which value in the args array is the `command` to execute
|
||||
let program = parseArgsUsingCommander(args);
|
||||
const program = parseArgsUsingCommander(args);
|
||||
const command = program.args[0];
|
||||
// Grab all arguments after the `command` in the args array
|
||||
const commandArgs = args.splice(args.indexOf(command) + 1);
|
||||
// Reprocess the args with the command and command arguments removed
|
||||
program = parseArgsUsingCommander(args.slice(0, args.indexOf(command)));
|
||||
// program = parseArgsUsingCommander(args.slice(0, args.indexOf(command)))
|
||||
const parsedCmdOptions = program.opts();
|
||||
// Set values for provided options
|
||||
let noOverride = false;
|
||||
// In commander `no-` negates the original value `override`
|
||||
if (program.override === false) {
|
||||
if (parsedCmdOptions.override === false) {
|
||||
noOverride = true;
|
||||
}
|
||||
let useShell = false;
|
||||
if (program.useShell === true) {
|
||||
if (parsedCmdOptions.useShell === true) {
|
||||
useShell = true;
|
||||
}
|
||||
let expandEnvs = false;
|
||||
if (program.expandEnvs === true) {
|
||||
if (parsedCmdOptions.expandEnvs === true) {
|
||||
expandEnvs = true;
|
||||
}
|
||||
let verbose = false;
|
||||
if (program.verbose === true) {
|
||||
if (parsedCmdOptions.verbose === true) {
|
||||
verbose = true;
|
||||
}
|
||||
let silent = false;
|
||||
if (program.silent === true) {
|
||||
if (parsedCmdOptions.silent === true) {
|
||||
silent = true;
|
||||
}
|
||||
let rc;
|
||||
if (program.environments !== undefined
|
||||
&& Array.isArray(program.environments)
|
||||
&& program.environments.length !== 0) {
|
||||
if (parsedCmdOptions.environments !== undefined
|
||||
&& Array.isArray(parsedCmdOptions.environments)
|
||||
&& parsedCmdOptions.environments.length !== 0) {
|
||||
rc = {
|
||||
environments: program.environments,
|
||||
filePath: program.rcFile,
|
||||
environments: parsedCmdOptions.environments,
|
||||
// if we get a boolean value assume not defined
|
||||
filePath: parsedCmdOptions.rcFile === true ?
|
||||
undefined :
|
||||
parsedCmdOptions.rcFile,
|
||||
};
|
||||
}
|
||||
let envFile;
|
||||
if (program.file !== undefined) {
|
||||
if (parsedCmdOptions.file !== undefined) {
|
||||
envFile = {
|
||||
filePath: program.file,
|
||||
fallback: program.fallback,
|
||||
// if we get a boolean value assume not defined
|
||||
filePath: parsedCmdOptions.file === true ?
|
||||
undefined :
|
||||
parsedCmdOptions.file,
|
||||
fallback: parsedCmdOptions.fallback,
|
||||
};
|
||||
}
|
||||
const options = {
|
||||
@ -70,19 +77,19 @@ export function parseArgs(args) {
|
||||
return options;
|
||||
}
|
||||
export function parseArgsUsingCommander(args) {
|
||||
const program = new commander.Command();
|
||||
return program
|
||||
return new Command('env-cmd')
|
||||
.description('CLI for executing commands using an environment from an env file.')
|
||||
.version(packageJson.version, '-v, --version')
|
||||
.usage('[options] <command> [...args]')
|
||||
.option('-e, --environments [env1,env2,...]', 'The rc file environment(s) to use', parseArgList)
|
||||
.usage('[options] -- <command> [...args]')
|
||||
.option('-e, --environments [envs...]', 'The rc file environment(s) to use', parseArgList)
|
||||
.option('-f, --file [path]', 'Custom env file path (default path: ./.env)')
|
||||
.option('-r, --rc-file [path]', 'Custom rc file path (default path: ./.env-cmdrc.(js|cjs|mjs|json)')
|
||||
.option('-x, --expand-envs', 'Replace $var in args and command with environment variables')
|
||||
.option('--fallback', 'Fallback to default env file path, if custom env file path not found')
|
||||
.option('--no-override', 'Do not override existing environment variables')
|
||||
.option('-r, --rc-file [path]', 'Custom rc file path (default path: ./.env-cmdrc(|.js|.json)')
|
||||
.option('--silent', 'Ignore any env-cmd errors and only fail on executed program failure.')
|
||||
.option('--use-shell', 'Execute the command in a new shell with the given environment')
|
||||
.option('--verbose', 'Print helpful debugging information')
|
||||
.option('-x, --expand-envs', 'Replace $var in args and command with environment variables')
|
||||
.allowUnknownOption(true)
|
||||
.parse(['_', '_', ...args]);
|
||||
.parse(['_', '_', ...args], { from: 'node' });
|
||||
}
|
||||
|
||||
20
dist/types.d.ts
vendored
20
dist/types.d.ts
vendored
@ -1,17 +1,17 @@
|
||||
import { Command } from 'commander';
|
||||
import type { Command } from '@commander-js/extra-typings';
|
||||
export type Environment = Partial<Record<string, string | number | boolean>>;
|
||||
export type RCEnvironment = Partial<Record<string, Environment>>;
|
||||
export interface CommanderOptions extends Command {
|
||||
override?: boolean;
|
||||
useShell?: boolean;
|
||||
export type CommanderOptions = Command<[], {
|
||||
environments?: true | string[];
|
||||
expandEnvs?: boolean;
|
||||
verbose?: boolean;
|
||||
silent?: boolean;
|
||||
fallback?: boolean;
|
||||
environments?: string[];
|
||||
rcFile?: string;
|
||||
file?: string;
|
||||
}
|
||||
file?: true | string;
|
||||
override?: boolean;
|
||||
rcFile?: true | string;
|
||||
silent?: boolean;
|
||||
useShell?: boolean;
|
||||
verbose?: boolean;
|
||||
}>;
|
||||
export interface RCFileOptions {
|
||||
environments: string[];
|
||||
filePath?: string;
|
||||
|
||||
@ -49,6 +49,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/toddbluhm/env-cmd#readme",
|
||||
"dependencies": {
|
||||
"@commander-js/extra-typings": "^12.1.0",
|
||||
"commander": "^12.1.0",
|
||||
"cross-spawn": "^7.0.6"
|
||||
},
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as commander from 'commander'
|
||||
import { Command } from '@commander-js/extra-typings'
|
||||
import type { EnvCmdOptions, CommanderOptions, EnvFileOptions, RCFileOptions } from './types.ts'
|
||||
import { parseArgList } from './utils.js'
|
||||
import { default as packageJson } from '../package.json' with { type: 'json' };
|
||||
@ -9,54 +9,62 @@ import { default as packageJson } from '../package.json' with { type: 'json' };
|
||||
export function parseArgs(args: string[]): EnvCmdOptions {
|
||||
// Run the initial arguments through commander in order to determine
|
||||
// which value in the args array is the `command` to execute
|
||||
let program = parseArgsUsingCommander(args)
|
||||
const program = parseArgsUsingCommander(args)
|
||||
|
||||
const command = program.args[0]
|
||||
// Grab all arguments after the `command` in the args array
|
||||
const commandArgs = args.splice(args.indexOf(command) + 1)
|
||||
|
||||
// Reprocess the args with the command and command arguments removed
|
||||
program = parseArgsUsingCommander(args.slice(0, args.indexOf(command)))
|
||||
// program = parseArgsUsingCommander(args.slice(0, args.indexOf(command)))
|
||||
|
||||
const parsedCmdOptions = program.opts()
|
||||
// Set values for provided options
|
||||
let noOverride = false
|
||||
// In commander `no-` negates the original value `override`
|
||||
if (program.override === false) {
|
||||
if (parsedCmdOptions.override === false) {
|
||||
noOverride = true
|
||||
}
|
||||
let useShell = false
|
||||
if (program.useShell === true) {
|
||||
if (parsedCmdOptions.useShell === true) {
|
||||
useShell = true
|
||||
}
|
||||
let expandEnvs = false
|
||||
if (program.expandEnvs === true) {
|
||||
if (parsedCmdOptions.expandEnvs === true) {
|
||||
expandEnvs = true
|
||||
}
|
||||
let verbose = false
|
||||
if (program.verbose === true) {
|
||||
if (parsedCmdOptions.verbose === true) {
|
||||
verbose = true
|
||||
}
|
||||
let silent = false
|
||||
if (program.silent === true) {
|
||||
if (parsedCmdOptions.silent === true) {
|
||||
silent = true
|
||||
}
|
||||
|
||||
let rc: RCFileOptions | undefined
|
||||
if (
|
||||
program.environments !== undefined
|
||||
&& Array.isArray(program.environments)
|
||||
&& program.environments.length !== 0
|
||||
parsedCmdOptions.environments !== undefined
|
||||
&& Array.isArray(parsedCmdOptions.environments)
|
||||
&& parsedCmdOptions.environments.length !== 0
|
||||
) {
|
||||
rc = {
|
||||
environments: program.environments,
|
||||
filePath: program.rcFile,
|
||||
environments: parsedCmdOptions.environments,
|
||||
// if we get a boolean value assume not defined
|
||||
filePath: parsedCmdOptions.rcFile === true ?
|
||||
undefined :
|
||||
parsedCmdOptions.rcFile,
|
||||
}
|
||||
}
|
||||
|
||||
let envFile: EnvFileOptions | undefined
|
||||
if (program.file !== undefined) {
|
||||
if (parsedCmdOptions.file !== undefined) {
|
||||
envFile = {
|
||||
filePath: program.file,
|
||||
fallback: program.fallback,
|
||||
// if we get a boolean value assume not defined
|
||||
filePath: parsedCmdOptions.file === true ?
|
||||
undefined :
|
||||
parsedCmdOptions.file,
|
||||
fallback: parsedCmdOptions.fallback,
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,19 +88,19 @@ export function parseArgs(args: string[]): EnvCmdOptions {
|
||||
}
|
||||
|
||||
export function parseArgsUsingCommander(args: string[]): CommanderOptions {
|
||||
const program = new commander.Command() as CommanderOptions
|
||||
return program
|
||||
return new Command('env-cmd')
|
||||
.description('CLI for executing commands using an environment from an env file.')
|
||||
.version(packageJson.version, '-v, --version')
|
||||
.usage('[options] <command> [...args]')
|
||||
.option('-e, --environments [env1,env2,...]', 'The rc file environment(s) to use', parseArgList)
|
||||
.usage('[options] -- <command> [...args]')
|
||||
.option('-e, --environments [envs...]', 'The rc file environment(s) to use', parseArgList)
|
||||
.option('-f, --file [path]', 'Custom env file path (default path: ./.env)')
|
||||
.option('-r, --rc-file [path]', 'Custom rc file path (default path: ./.env-cmdrc.(js|cjs|mjs|json)')
|
||||
.option('-x, --expand-envs', 'Replace $var in args and command with environment variables')
|
||||
.option('--fallback', 'Fallback to default env file path, if custom env file path not found')
|
||||
.option('--no-override', 'Do not override existing environment variables')
|
||||
.option('-r, --rc-file [path]', 'Custom rc file path (default path: ./.env-cmdrc(|.js|.json)')
|
||||
.option('--silent', 'Ignore any env-cmd errors and only fail on executed program failure.')
|
||||
.option('--use-shell', 'Execute the command in a new shell with the given environment')
|
||||
.option('--verbose', 'Print helpful debugging information')
|
||||
.option('-x, --expand-envs', 'Replace $var in args and command with environment variables')
|
||||
.allowUnknownOption(true)
|
||||
.parse(['_', '_', ...args])
|
||||
.parse(['_', '_', ...args], { from: 'node' })
|
||||
}
|
||||
|
||||
20
src/types.ts
20
src/types.ts
@ -1,21 +1,21 @@
|
||||
import { Command } from 'commander'
|
||||
import type { Command } from '@commander-js/extra-typings'
|
||||
|
||||
// Define an export type
|
||||
export type Environment = Partial<Record<string, string | number | boolean>>
|
||||
|
||||
export type RCEnvironment = Partial<Record<string, Environment>>
|
||||
|
||||
export interface CommanderOptions extends Command {
|
||||
override?: boolean // Default: false
|
||||
useShell?: boolean // Default: false
|
||||
export type CommanderOptions = Command<[], {
|
||||
environments?: true | string[]
|
||||
expandEnvs?: boolean // Default: false
|
||||
verbose?: boolean // Default: false
|
||||
silent?: boolean // Default: false
|
||||
fallback?: boolean // Default false
|
||||
environments?: string[]
|
||||
rcFile?: string
|
||||
file?: string
|
||||
}
|
||||
file?: true | string
|
||||
override?: boolean // Default: false
|
||||
rcFile?: true | string
|
||||
silent?: boolean // Default: false
|
||||
useShell?: boolean // Default: false
|
||||
verbose?: boolean // Default: false
|
||||
}>
|
||||
|
||||
export interface RCFileOptions {
|
||||
environments: string[]
|
||||
|
||||
@ -25,31 +25,31 @@ describe('parseArgs', (): void => {
|
||||
})
|
||||
|
||||
it('should parse environment value', (): void => {
|
||||
const res = parseArgs(['-e', environments[0], command])
|
||||
const res = parseArgs(['-e', environments[0], '--', command])
|
||||
assert.exists(res.rc)
|
||||
assert.sameOrderedMembers(res.rc.environments, [environments[0]])
|
||||
})
|
||||
|
||||
it('should parse multiple environment values', (): void => {
|
||||
const res = parseArgs(['-e', environments.join(','), command])
|
||||
const res = parseArgs(['-e', environments.join(','), '--', command])
|
||||
assert.exists(res.rc)
|
||||
assert.sameOrderedMembers(res.rc.environments, environments)
|
||||
})
|
||||
|
||||
it('should parse command value', (): void => {
|
||||
const res = parseArgs(['-e', environments[0], command])
|
||||
const res = parseArgs(['-e', environments[0], '--', command])
|
||||
assert.equal(res.command, command)
|
||||
})
|
||||
|
||||
it('should parse multiple command arguments', (): void => {
|
||||
const res = parseArgs(['-e', environments[0], command, ...commandArgs])
|
||||
const res = parseArgs(['-e', environments[0], '--', command, ...commandArgs])
|
||||
assert.sameOrderedMembers(res.commandArgs, commandArgs)
|
||||
})
|
||||
|
||||
it('should parse multiple command arguments even if they use the same options flags as env-cmd',
|
||||
(): void => {
|
||||
const commandFlags = ['-f', './other-file', '--use-shell', '-r']
|
||||
const res = parseArgs(['-e', environments[0], command, ...commandFlags])
|
||||
const res = parseArgs(['-e', environments[0], '--', command, ...commandFlags])
|
||||
assert.sameOrderedMembers(res.commandArgs, commandFlags)
|
||||
assert.notOk(res.options!.useShell)
|
||||
assert.notOk(res.envFile)
|
||||
@ -57,49 +57,49 @@ describe('parseArgs', (): void => {
|
||||
)
|
||||
|
||||
it('should parse override option', (): void => {
|
||||
const res = parseArgs(['-e', environments[0], '--no-override', command, ...commandArgs])
|
||||
const res = parseArgs(['-e', environments[0], '--no-override', '--', command, ...commandArgs])
|
||||
assert.exists(res.options)
|
||||
assert.isTrue(res.options.noOverride)
|
||||
})
|
||||
|
||||
it('should parse use shell option', (): void => {
|
||||
const res = parseArgs(['-e', environments[0], '--use-shell', command, ...commandArgs])
|
||||
const res = parseArgs(['-e', environments[0], '--use-shell', '--', command, ...commandArgs])
|
||||
assert.exists(res.options)
|
||||
assert.isTrue(res.options.useShell)
|
||||
})
|
||||
|
||||
it('should parse rc file path', (): void => {
|
||||
const res = parseArgs(['-e', environments[0], '-r', rcFilePath, command, ...commandArgs])
|
||||
const res = parseArgs(['-e', environments[0], '-r', rcFilePath, '--', command, ...commandArgs])
|
||||
assert.exists(res.rc)
|
||||
assert.equal(res.rc.filePath, rcFilePath)
|
||||
})
|
||||
|
||||
it('should parse env file path', (): void => {
|
||||
const res = parseArgs(['-f', envFilePath, command, ...commandArgs])
|
||||
const res = parseArgs(['-f', envFilePath, '--', command, ...commandArgs])
|
||||
assert.exists(res.envFile)
|
||||
assert.equal(res.envFile.filePath, envFilePath)
|
||||
})
|
||||
|
||||
it('should parse fallback option', (): void => {
|
||||
const res = parseArgs(['-f', envFilePath, '--fallback', command, ...commandArgs])
|
||||
const res = parseArgs(['-f', envFilePath, '--fallback', '--', command, ...commandArgs])
|
||||
assert.exists(res.envFile)
|
||||
assert.isTrue(res.envFile.fallback)
|
||||
})
|
||||
|
||||
it('should print to console.info if --verbose flag is passed', (): void => {
|
||||
const res = parseArgs(['-f', envFilePath, '--verbose', command, ...commandArgs])
|
||||
const res = parseArgs(['-f', envFilePath, '--verbose', '--', command, ...commandArgs])
|
||||
assert.exists(res.options!.verbose)
|
||||
assert.equal(logInfoStub.callCount, 1)
|
||||
})
|
||||
|
||||
it('should parse expandEnvs option', (): void => {
|
||||
const res = parseArgs(['-f', envFilePath, '-x', command, ...commandArgs])
|
||||
const res = parseArgs(['-f', envFilePath, '-x', '--', command, ...commandArgs])
|
||||
assert.exists(res.envFile)
|
||||
assert.isTrue(res.options!.expandEnvs)
|
||||
})
|
||||
|
||||
it('should parse silent option', (): void => {
|
||||
const res = parseArgs(['-f', envFilePath, '--silent', command, ...commandArgs])
|
||||
const res = parseArgs(['-f', envFilePath, '--silent', '--', command, ...commandArgs])
|
||||
assert.exists(res.envFile)
|
||||
assert.isTrue(res.options!.silent)
|
||||
})
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
module.exports = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
console.log('resolved')
|
||||
resolve({
|
||||
development: {
|
||||
THANKS: 'FOR ALL THE FISH',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user