mirror of
https://github.com/toddbluhm/env-cmd.git
synced 2025-12-08 18:23:33 +00:00
Merge pull request #101 from toddbluhm/add-verbos-flag
feat(flags): add --verbose flag and option
This commit is contained in:
commit
bd090e7c6b
@ -1,5 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 10.1.0 - Pending
|
||||||
|
|
||||||
|
- **Feature**: Added a new `--verbose` flag that prints additional debugging info to `console.info`
|
||||||
|
- **Change**: Updated `commander` dependency to `v4`
|
||||||
|
|
||||||
## 10.0.1
|
## 10.0.1
|
||||||
|
|
||||||
- **Fix**: Fixed bug introduced by strict equal checking for `undefined` when the value was `null`. This
|
- **Fix**: Fixed bug introduced by strict equal checking for `undefined` when the value was `null`. This
|
||||||
|
|||||||
@ -64,6 +64,7 @@ Options:
|
|||||||
--fallback Fallback to default env file path, if custom env file path not found
|
--fallback Fallback to default env file path, if custom env file path not found
|
||||||
--no-override Do not override existing environment variables
|
--no-override Do not override existing environment variables
|
||||||
--use-shell Execute the command in a new shell with the given environment
|
--use-shell Execute the command in a new shell with the given environment
|
||||||
|
--verbose Print helpful debugging information
|
||||||
-h, --help output usage information
|
-h, --help output usage information
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -186,6 +187,7 @@ A function that executes a given command in a new child process with the given e
|
|||||||
- **`options`** { `object` }
|
- **`options`** { `object` }
|
||||||
- **`noOverride`** { `boolean` }: Prevent `.env` file vars from overriding existing `process.env` vars (default: `false`)
|
- **`noOverride`** { `boolean` }: Prevent `.env` file vars from overriding existing `process.env` vars (default: `false`)
|
||||||
- **`useShell`** { `boolean` }: Runs command inside a new shell instance (default: `false`)
|
- **`useShell`** { `boolean` }: Runs command inside a new shell instance (default: `false`)
|
||||||
|
- **`verbose`** { `boolean` }: Prints extra debug logs to `console.info` (default: `false`)
|
||||||
- **Returns** { `Promise<object>` }: key is env var name and value is the env var value
|
- **Returns** { `Promise<object>` }: key is env var name and value is the env var value
|
||||||
|
|
||||||
### `GetEnvVars`
|
### `GetEnvVars`
|
||||||
@ -199,6 +201,7 @@ A function that parses environment variables from a `.env` or a `.rc` file
|
|||||||
- **`rc`** { `object` }
|
- **`rc`** { `object` }
|
||||||
- **`environments`** { `string[]` }: List of environment to read from the `.rc` file
|
- **`environments`** { `string[]` }: List of environment to read from the `.rc` file
|
||||||
- **`filePath`** { `string` }: Custom path to the `.rc` file (defaults to: `./.env-cmdrc(|.js|.json)`)
|
- **`filePath`** { `string` }: Custom path to the `.rc` file (defaults to: `./.env-cmdrc(|.js|.json)`)
|
||||||
|
- **`verbose`** { `boolean` }: Prints extra debug logs to `console.info` (default: `false`)
|
||||||
- **Returns** { `Promise<object>` }: key is env var name and value is the env var value
|
- **Returns** { `Promise<object>` }: key is env var name and value is the env var value
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|||||||
4
dist/env-cmd.js
vendored
4
dist/env-cmd.js
vendored
@ -32,7 +32,7 @@ exports.CLI = CLI;
|
|||||||
* @returns {Promise<{ [key: string]: any }>} Returns an object containing [environment variable name]: value
|
* @returns {Promise<{ [key: string]: any }>} Returns an object containing [environment variable name]: value
|
||||||
*/
|
*/
|
||||||
async function EnvCmd({ command, commandArgs, envFile, rc, options = {} }) {
|
async function EnvCmd({ command, commandArgs, envFile, rc, options = {} }) {
|
||||||
let env = await get_env_vars_1.getEnvVars({ envFile, rc });
|
let env = await get_env_vars_1.getEnvVars({ envFile, rc, verbose: options.verbose });
|
||||||
// Override the merge order if --no-override flag set
|
// Override the merge order if --no-override flag set
|
||||||
if (options.noOverride === true) {
|
if (options.noOverride === true) {
|
||||||
env = Object.assign({}, env, process.env);
|
env = Object.assign({}, env, process.env);
|
||||||
@ -48,7 +48,7 @@ async function EnvCmd({ command, commandArgs, envFile, rc, options = {} }) {
|
|||||||
env
|
env
|
||||||
});
|
});
|
||||||
// Handle any termination signals for parent and child proceses
|
// Handle any termination signals for parent and child proceses
|
||||||
const signals = new signal_termination_1.TermSignals();
|
const signals = new signal_termination_1.TermSignals({ verbose: options.verbose });
|
||||||
signals.handleUncaughtExceptions();
|
signals.handleUncaughtExceptions();
|
||||||
signals.handleTermSignals(proc);
|
signals.handleTermSignals(proc);
|
||||||
return env;
|
return env;
|
||||||
|
|||||||
6
dist/get-env-vars.d.ts
vendored
6
dist/get-env-vars.d.ts
vendored
@ -2,15 +2,17 @@ import { GetEnvVarOptions } from './types';
|
|||||||
export declare function getEnvVars(options?: GetEnvVarOptions): Promise<{
|
export declare function getEnvVars(options?: GetEnvVarOptions): Promise<{
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}>;
|
}>;
|
||||||
export declare function getEnvFile({ filePath, fallback }: {
|
export declare function getEnvFile({ filePath, fallback, verbose }: {
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
fallback?: boolean;
|
fallback?: boolean;
|
||||||
|
verbose?: boolean;
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}>;
|
}>;
|
||||||
export declare function getRCFile({ environments, filePath }: {
|
export declare function getRCFile({ environments, filePath, verbose }: {
|
||||||
environments: string[];
|
environments: string[];
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
|
verbose?: boolean;
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}>;
|
}>;
|
||||||
|
|||||||
85
dist/get-env-vars.js
vendored
85
dist/get-env-vars.js
vendored
@ -8,54 +8,103 @@ async function getEnvVars(options = {}) {
|
|||||||
options.envFile = options.envFile !== undefined ? options.envFile : {};
|
options.envFile = options.envFile !== undefined ? options.envFile : {};
|
||||||
// Check for rc file usage
|
// Check for rc file usage
|
||||||
if (options.rc !== undefined) {
|
if (options.rc !== undefined) {
|
||||||
return getRCFile({ environments: options.rc.environments, filePath: options.rc.filePath });
|
return getRCFile({
|
||||||
|
environments: options.rc.environments,
|
||||||
|
filePath: options.rc.filePath,
|
||||||
|
verbose: options.verbose
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return getEnvFile({ filePath: options.envFile.filePath, fallback: options.envFile.fallback });
|
return getEnvFile({
|
||||||
|
filePath: options.envFile.filePath,
|
||||||
|
fallback: options.envFile.fallback,
|
||||||
|
verbose: options.verbose
|
||||||
|
});
|
||||||
}
|
}
|
||||||
exports.getEnvVars = getEnvVars;
|
exports.getEnvVars = getEnvVars;
|
||||||
async function getEnvFile({ filePath, fallback }) {
|
async function getEnvFile({ filePath, fallback, verbose }) {
|
||||||
// Use env file
|
// Use env file
|
||||||
if (filePath !== undefined) {
|
if (filePath !== undefined) {
|
||||||
try {
|
try {
|
||||||
return await parse_env_file_1.getEnvFileVars(filePath);
|
const env = await parse_env_file_1.getEnvFileVars(filePath);
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Found .env file at path: ${filePath}`);
|
||||||
|
}
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Failed to find .env file at path: ${filePath}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (e) { }
|
|
||||||
if (fallback !== true) {
|
if (fallback !== true) {
|
||||||
throw new Error(`Unable to locate env file at location (${filePath})`);
|
throw new Error(`Failed to find .env file at path: ${filePath}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Use the default env file locations
|
// Use the default env file locations
|
||||||
for (const path of ENV_FILE_DEFAULT_LOCATIONS) {
|
for (const path of ENV_FILE_DEFAULT_LOCATIONS) {
|
||||||
try {
|
try {
|
||||||
return await parse_env_file_1.getEnvFileVars(path);
|
const env = await parse_env_file_1.getEnvFileVars(path);
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Found .env file at default path: ${path}`);
|
||||||
|
}
|
||||||
|
return env;
|
||||||
}
|
}
|
||||||
catch (e) { }
|
catch (e) { }
|
||||||
}
|
}
|
||||||
throw new Error(`Unable to locate env file at default locations (${ENV_FILE_DEFAULT_LOCATIONS})`);
|
const error = `Failed to find .env file at default paths: ${ENV_FILE_DEFAULT_LOCATIONS}`;
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(error);
|
||||||
|
}
|
||||||
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
exports.getEnvFile = getEnvFile;
|
exports.getEnvFile = getEnvFile;
|
||||||
async function getRCFile({ environments, filePath }) {
|
async function getRCFile({ environments, filePath, verbose }) {
|
||||||
// User provided an .rc file path
|
// User provided an .rc file path
|
||||||
if (filePath !== undefined) {
|
if (filePath !== undefined) {
|
||||||
try {
|
try {
|
||||||
return await parse_rc_file_1.getRCFileVars({ environments, filePath });
|
const env = await parse_rc_file_1.getRCFileVars({ environments, filePath });
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Found environments: ${environments} for .rc file at path: ${filePath}`);
|
||||||
|
}
|
||||||
|
return env;
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (e.name !== 'PathError')
|
if (e.name === 'PathError') {
|
||||||
console.error(e);
|
if (verbose === true) {
|
||||||
throw new Error(`Unable to locate .rc file at location (${filePath})`);
|
console.info(`Failed to find .rc file at path: ${filePath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.name === 'EnvironmentError') {
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Failed to find environments: ${environments} for .rc file at path: ${filePath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Use the default .rc file locations
|
// Use the default .rc file locations
|
||||||
for (const filePath of RC_FILE_DEFAULT_LOCATIONS) {
|
for (const path of RC_FILE_DEFAULT_LOCATIONS) {
|
||||||
try {
|
try {
|
||||||
return await parse_rc_file_1.getRCFileVars({ environments, filePath });
|
const env = await parse_rc_file_1.getRCFileVars({ environments, filePath: path });
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Found environments: ${environments} for default .rc file at path: ${path}`);
|
||||||
|
}
|
||||||
|
return env;
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (e.name !== 'PathError')
|
if (e.name === 'EnvironmentError') {
|
||||||
console.error(e);
|
const errorText = `Failed to find environments: ${environments} for .rc file at path: ${path}`;
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(errorText);
|
||||||
|
}
|
||||||
|
throw new Error(errorText);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error(`Unable to locate .rc file at default locations (${RC_FILE_DEFAULT_LOCATIONS})`);
|
const errorText = `Failed to find .rc file at default paths: ${RC_FILE_DEFAULT_LOCATIONS}`;
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(errorText);
|
||||||
|
}
|
||||||
|
throw new Error(errorText);
|
||||||
}
|
}
|
||||||
exports.getRCFile = getRCFile;
|
exports.getRCFile = getRCFile;
|
||||||
|
|||||||
11
dist/parse-args.js
vendored
11
dist/parse-args.js
vendored
@ -14,6 +14,7 @@ function parseArgs(args) {
|
|||||||
program = parseArgsUsingCommander(args.slice(0, args.indexOf(command)));
|
program = parseArgsUsingCommander(args.slice(0, args.indexOf(command)));
|
||||||
const noOverride = !program.override;
|
const noOverride = !program.override;
|
||||||
const useShell = !!program.useShell;
|
const useShell = !!program.useShell;
|
||||||
|
const verbose = !!program.verbose;
|
||||||
let rc;
|
let rc;
|
||||||
if (program.environments !== undefined && program.environments.length !== 0) {
|
if (program.environments !== undefined && program.environments.length !== 0) {
|
||||||
rc = {
|
rc = {
|
||||||
@ -28,16 +29,21 @@ function parseArgs(args) {
|
|||||||
fallback: program.fallback
|
fallback: program.fallback
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
const options = {
|
||||||
command,
|
command,
|
||||||
commandArgs,
|
commandArgs,
|
||||||
envFile,
|
envFile,
|
||||||
rc,
|
rc,
|
||||||
options: {
|
options: {
|
||||||
noOverride,
|
noOverride,
|
||||||
useShell
|
useShell,
|
||||||
|
verbose
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Options: ${JSON.stringify(options, null, 0)}`);
|
||||||
|
}
|
||||||
|
return options;
|
||||||
}
|
}
|
||||||
exports.parseArgs = parseArgs;
|
exports.parseArgs = parseArgs;
|
||||||
function parseArgsUsingCommander(args) {
|
function parseArgsUsingCommander(args) {
|
||||||
@ -51,6 +57,7 @@ function parseArgsUsingCommander(args) {
|
|||||||
.option('--fallback', 'Fallback to default env file path, if custom env file path not found')
|
.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('--no-override', 'Do not override existing environment variables')
|
||||||
.option('--use-shell', 'Execute the command in a new shell with the given environment')
|
.option('--use-shell', 'Execute the command in a new shell with the given environment')
|
||||||
|
.option('--verbose', 'Print helpful debugging information')
|
||||||
.parse(['_', '_', ...args]);
|
.parse(['_', '_', ...args]);
|
||||||
}
|
}
|
||||||
exports.parseArgsUsingCommander = parseArgsUsingCommander;
|
exports.parseArgsUsingCommander = parseArgsUsingCommander;
|
||||||
|
|||||||
4
dist/parse-env-file.js
vendored
4
dist/parse-env-file.js
vendored
@ -10,7 +10,9 @@ const REQUIRE_HOOK_EXTENSIONS = ['.json', '.js'];
|
|||||||
async function getEnvFileVars(envFilePath) {
|
async function getEnvFileVars(envFilePath) {
|
||||||
const absolutePath = utils_1.resolveEnvFilePath(envFilePath);
|
const absolutePath = utils_1.resolveEnvFilePath(envFilePath);
|
||||||
if (!fs.existsSync(absolutePath)) {
|
if (!fs.existsSync(absolutePath)) {
|
||||||
throw new Error(`Invalid env file path (${envFilePath}).`);
|
const pathError = new Error(`Invalid env file path (${envFilePath}).`);
|
||||||
|
pathError.name = 'PathError';
|
||||||
|
throw pathError;
|
||||||
}
|
}
|
||||||
// Get the file extension
|
// Get the file extension
|
||||||
const ext = path.extname(absolutePath).toLowerCase();
|
const ext = path.extname(absolutePath).toLowerCase();
|
||||||
|
|||||||
6
dist/parse-rc-file.d.ts
vendored
6
dist/parse-rc-file.d.ts
vendored
@ -7,9 +7,3 @@ export declare function getRCFileVars({ environments, filePath }: {
|
|||||||
}): Promise<{
|
}): Promise<{
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}>;
|
}>;
|
||||||
/**
|
|
||||||
* Reads and parses the .rc file
|
|
||||||
*/
|
|
||||||
export declare function parseRCFile(fileData: string): {
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
|
||||||
|
|||||||
47
dist/parse-rc-file.js
vendored
47
dist/parse-rc-file.js
vendored
@ -15,20 +15,27 @@ async function getRCFileVars({ environments, filePath }) {
|
|||||||
await statAsync(absolutePath);
|
await statAsync(absolutePath);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
const pathError = new Error('Invalid .rc file path.');
|
const pathError = new Error(`Failed to find .rc file at path: ${absolutePath}`);
|
||||||
pathError.name = 'PathError';
|
pathError.name = 'PathError';
|
||||||
throw pathError;
|
throw pathError;
|
||||||
}
|
}
|
||||||
// Get the file extension
|
// Get the file extension
|
||||||
const ext = path_1.extname(absolutePath).toLowerCase();
|
const ext = path_1.extname(absolutePath).toLowerCase();
|
||||||
let parsedData;
|
let parsedData;
|
||||||
if (ext === '.json' || ext === '.js') {
|
try {
|
||||||
const possiblePromise = require(absolutePath); /* eslint-disable-line */
|
if (ext === '.json' || ext === '.js') {
|
||||||
parsedData = utils_1.isPromise(possiblePromise) ? await possiblePromise : possiblePromise;
|
const possiblePromise = require(absolutePath); /* eslint-disable-line */
|
||||||
|
parsedData = utils_1.isPromise(possiblePromise) ? await possiblePromise : possiblePromise;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const file = await readFileAsync(absolutePath, { encoding: 'utf8' });
|
||||||
|
parsedData = JSON.parse(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
catch (e) {
|
||||||
const file = await readFileAsync(absolutePath, { encoding: 'utf8' });
|
const parseError = new Error(`Failed to parse .rc file at path: ${absolutePath}`);
|
||||||
parsedData = parseRCFile(file);
|
parseError.name = 'ParseError';
|
||||||
|
throw parseError;
|
||||||
}
|
}
|
||||||
// Parse and merge multiple rc environments together
|
// Parse and merge multiple rc environments together
|
||||||
let result = {};
|
let result = {};
|
||||||
@ -41,30 +48,10 @@ async function getRCFileVars({ environments, filePath }) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!environmentFound) {
|
if (!environmentFound) {
|
||||||
console.error(`Error:
|
const environmentError = new Error(`Failed to find environments ${environments} at .rc file location: ${absolutePath}`);
|
||||||
Could not find any environments:
|
environmentError.name = 'EnvironmentError';
|
||||||
${environments}
|
throw environmentError;
|
||||||
in .rc file:
|
|
||||||
${absolutePath}`);
|
|
||||||
throw new Error(`All environments (${environments}) are missing in in .rc file (${absolutePath}).`);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
exports.getRCFileVars = getRCFileVars;
|
exports.getRCFileVars = getRCFileVars;
|
||||||
/**
|
|
||||||
* Reads and parses the .rc file
|
|
||||||
*/
|
|
||||||
function parseRCFile(fileData) {
|
|
||||||
let data;
|
|
||||||
try {
|
|
||||||
data = JSON.parse(fileData);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`Error:
|
|
||||||
Failed to parse the .rc file.
|
|
||||||
Please make sure its a valid JSON format.`);
|
|
||||||
throw new Error('Unable to parse JSON in .rc file.');
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
exports.parseRCFile = parseRCFile;
|
|
||||||
|
|||||||
4
dist/signal-termination.d.ts
vendored
4
dist/signal-termination.d.ts
vendored
@ -2,7 +2,11 @@
|
|||||||
import { ChildProcess } from 'child_process';
|
import { ChildProcess } from 'child_process';
|
||||||
export declare class TermSignals {
|
export declare class TermSignals {
|
||||||
private readonly terminateSpawnedProcessFuncHandlers;
|
private readonly terminateSpawnedProcessFuncHandlers;
|
||||||
|
private readonly verbose;
|
||||||
_exitCalled: boolean;
|
_exitCalled: boolean;
|
||||||
|
constructor(options?: {
|
||||||
|
verbose?: boolean;
|
||||||
|
});
|
||||||
handleTermSignals(proc: ChildProcess): void;
|
handleTermSignals(proc: ChildProcess): void;
|
||||||
/**
|
/**
|
||||||
* Enables catching of unhandled exceptions
|
* Enables catching of unhandled exceptions
|
||||||
|
|||||||
11
dist/signal-termination.js
vendored
11
dist/signal-termination.js
vendored
@ -4,9 +4,11 @@ const SIGNALS_TO_HANDLE = [
|
|||||||
'SIGINT', 'SIGTERM', 'SIGHUP'
|
'SIGINT', 'SIGTERM', 'SIGHUP'
|
||||||
];
|
];
|
||||||
class TermSignals {
|
class TermSignals {
|
||||||
constructor() {
|
constructor(options = {}) {
|
||||||
this.terminateSpawnedProcessFuncHandlers = {};
|
this.terminateSpawnedProcessFuncHandlers = {};
|
||||||
|
this.verbose = false;
|
||||||
this._exitCalled = false;
|
this._exitCalled = false;
|
||||||
|
this.verbose = options.verbose === true;
|
||||||
}
|
}
|
||||||
handleTermSignals(proc) {
|
handleTermSignals(proc) {
|
||||||
// Terminate child process if parent process receives termination events
|
// Terminate child process if parent process receives termination events
|
||||||
@ -15,6 +17,9 @@ class TermSignals {
|
|||||||
(signal, code) => {
|
(signal, code) => {
|
||||||
this._removeProcessListeners();
|
this._removeProcessListeners();
|
||||||
if (!this._exitCalled) {
|
if (!this._exitCalled) {
|
||||||
|
if (this.verbose === true) {
|
||||||
|
console.info(`Parent process exited with signal: ${signal}. Terminating child process...`);
|
||||||
|
}
|
||||||
this._exitCalled = true;
|
this._exitCalled = true;
|
||||||
proc.kill(signal);
|
proc.kill(signal);
|
||||||
this._terminateProcess(code, signal);
|
this._terminateProcess(code, signal);
|
||||||
@ -28,6 +33,10 @@ class TermSignals {
|
|||||||
this._removeProcessListeners();
|
this._removeProcessListeners();
|
||||||
const convertedSignal = signal != null ? signal : undefined;
|
const convertedSignal = signal != null ? signal : undefined;
|
||||||
if (!this._exitCalled) {
|
if (!this._exitCalled) {
|
||||||
|
if (this.verbose === true) {
|
||||||
|
console.info(`Child process exited with code: ${code} and signal: ${signal}. ` +
|
||||||
|
'Terminating parent process...');
|
||||||
|
}
|
||||||
this._exitCalled = true;
|
this._exitCalled = true;
|
||||||
this._terminateProcess(code, convertedSignal);
|
this._terminateProcess(code, convertedSignal);
|
||||||
}
|
}
|
||||||
|
|||||||
2
dist/types.d.ts
vendored
2
dist/types.d.ts
vendored
@ -7,6 +7,7 @@ export interface GetEnvVarOptions {
|
|||||||
environments: string[];
|
environments: string[];
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
};
|
};
|
||||||
|
verbose?: boolean;
|
||||||
}
|
}
|
||||||
export interface EnvCmdOptions extends GetEnvVarOptions {
|
export interface EnvCmdOptions extends GetEnvVarOptions {
|
||||||
command: string;
|
command: string;
|
||||||
@ -14,5 +15,6 @@ export interface EnvCmdOptions extends GetEnvVarOptions {
|
|||||||
options?: {
|
options?: {
|
||||||
noOverride?: boolean;
|
noOverride?: boolean;
|
||||||
useShell?: boolean;
|
useShell?: boolean;
|
||||||
|
verbose?: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "env-cmd",
|
"name": "env-cmd",
|
||||||
"version": "10.0.1",
|
"version": "10.1.0",
|
||||||
"description": "Executes a command using the environment variables in an env file",
|
"description": "Executes a command using the environment variables in an env file",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
@ -47,7 +47,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/toddbluhm/env-cmd#readme",
|
"homepage": "https://github.com/toddbluhm/env-cmd#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^3.0.0",
|
"commander": "^4.0.0",
|
||||||
"cross-spawn": "^7.0.0"
|
"cross-spawn": "^7.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -63,7 +63,7 @@
|
|||||||
"sinon": "^7.0.0",
|
"sinon": "^7.0.0",
|
||||||
"ts-node": "^8.0.0",
|
"ts-node": "^8.0.0",
|
||||||
"ts-standard": "^3.0.0",
|
"ts-standard": "^3.0.0",
|
||||||
"typescript": "^3.0.0"
|
"typescript": "^3.7.0"
|
||||||
},
|
},
|
||||||
"nyc": {
|
"nyc": {
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export async function CLI (args: string[]): Promise<{ [key: string]: any }> {
|
|||||||
export async function EnvCmd (
|
export async function EnvCmd (
|
||||||
{ command, commandArgs, envFile, rc, options = {} }: EnvCmdOptions
|
{ command, commandArgs, envFile, rc, options = {} }: EnvCmdOptions
|
||||||
): Promise<{ [key: string]: any }> {
|
): Promise<{ [key: string]: any }> {
|
||||||
let env = await getEnvVars({ envFile, rc })
|
let env = await getEnvVars({ envFile, rc, verbose: options.verbose })
|
||||||
// Override the merge order if --no-override flag set
|
// Override the merge order if --no-override flag set
|
||||||
if (options.noOverride === true) {
|
if (options.noOverride === true) {
|
||||||
env = Object.assign({}, env, process.env)
|
env = Object.assign({}, env, process.env)
|
||||||
@ -51,7 +51,7 @@ export async function EnvCmd (
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Handle any termination signals for parent and child proceses
|
// Handle any termination signals for parent and child proceses
|
||||||
const signals = new TermSignals()
|
const signals = new TermSignals({ verbose: options.verbose })
|
||||||
signals.handleUncaughtExceptions()
|
signals.handleUncaughtExceptions()
|
||||||
signals.handleTermSignals(proc)
|
signals.handleTermSignals(proc)
|
||||||
|
|
||||||
|
|||||||
@ -9,55 +9,106 @@ export async function getEnvVars (options: GetEnvVarOptions = {}): Promise<{ [ke
|
|||||||
options.envFile = options.envFile !== undefined ? options.envFile : {}
|
options.envFile = options.envFile !== undefined ? options.envFile : {}
|
||||||
// Check for rc file usage
|
// Check for rc file usage
|
||||||
if (options.rc !== undefined) {
|
if (options.rc !== undefined) {
|
||||||
return getRCFile({ environments: options.rc.environments, filePath: options.rc.filePath })
|
return getRCFile({
|
||||||
|
environments: options.rc.environments,
|
||||||
|
filePath: options.rc.filePath,
|
||||||
|
verbose: options.verbose
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return getEnvFile({ filePath: options.envFile.filePath, fallback: options.envFile.fallback })
|
return getEnvFile({
|
||||||
|
filePath: options.envFile.filePath,
|
||||||
|
fallback: options.envFile.fallback,
|
||||||
|
verbose: options.verbose
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getEnvFile (
|
export async function getEnvFile (
|
||||||
{ filePath, fallback }: { filePath?: string, fallback?: boolean }
|
{ filePath, fallback, verbose }: { filePath?: string, fallback?: boolean, verbose?: boolean }
|
||||||
): Promise<{ [key: string]: any }> {
|
): Promise<{ [key: string]: any }> {
|
||||||
// Use env file
|
// Use env file
|
||||||
if (filePath !== undefined) {
|
if (filePath !== undefined) {
|
||||||
try {
|
try {
|
||||||
return await getEnvFileVars(filePath)
|
const env = await getEnvFileVars(filePath)
|
||||||
} catch (e) { }
|
if (verbose === true) {
|
||||||
|
console.info(`Found .env file at path: ${filePath}`)
|
||||||
|
}
|
||||||
|
return env
|
||||||
|
} catch (e) {
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Failed to find .env file at path: ${filePath}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
if (fallback !== true) {
|
if (fallback !== true) {
|
||||||
throw new Error(`Unable to locate env file at location (${filePath})`)
|
throw new Error(`Failed to find .env file at path: ${filePath}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the default env file locations
|
// Use the default env file locations
|
||||||
for (const path of ENV_FILE_DEFAULT_LOCATIONS) {
|
for (const path of ENV_FILE_DEFAULT_LOCATIONS) {
|
||||||
try {
|
try {
|
||||||
return await getEnvFileVars(path)
|
const env = await getEnvFileVars(path)
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Found .env file at default path: ${path}`)
|
||||||
|
}
|
||||||
|
return env
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`Unable to locate env file at default locations (${ENV_FILE_DEFAULT_LOCATIONS})`)
|
const error = `Failed to find .env file at default paths: ${ENV_FILE_DEFAULT_LOCATIONS}`
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(error)
|
||||||
|
}
|
||||||
|
throw new Error(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRCFile (
|
export async function getRCFile (
|
||||||
{ environments, filePath }: { environments: string[], filePath?: string }
|
{ environments, filePath, verbose }: { environments: string[], filePath?: string, verbose?: boolean }
|
||||||
): Promise<{ [key: string]: any }> {
|
): Promise<{ [key: string]: any }> {
|
||||||
// User provided an .rc file path
|
// User provided an .rc file path
|
||||||
if (filePath !== undefined) {
|
if (filePath !== undefined) {
|
||||||
try {
|
try {
|
||||||
return await getRCFileVars({ environments, filePath })
|
const env = await getRCFileVars({ environments, filePath })
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Found environments: ${environments} for .rc file at path: ${filePath}`)
|
||||||
|
}
|
||||||
|
return env
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.name !== 'PathError') console.error(e)
|
if (e.name === 'PathError') {
|
||||||
throw new Error(`Unable to locate .rc file at location (${filePath})`)
|
if (verbose === true) {
|
||||||
|
console.info(`Failed to find .rc file at path: ${filePath}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.name === 'EnvironmentError') {
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Failed to find environments: ${environments} for .rc file at path: ${filePath}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the default .rc file locations
|
// Use the default .rc file locations
|
||||||
for (const filePath of RC_FILE_DEFAULT_LOCATIONS) {
|
for (const path of RC_FILE_DEFAULT_LOCATIONS) {
|
||||||
try {
|
try {
|
||||||
return await getRCFileVars({ environments, filePath })
|
const env = await getRCFileVars({ environments, filePath: path })
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Found environments: ${environments} for default .rc file at path: ${path}`)
|
||||||
|
}
|
||||||
|
return env
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.name !== 'PathError') console.error(e)
|
if (e.name === 'EnvironmentError') {
|
||||||
|
const errorText = `Failed to find environments: ${environments} for .rc file at path: ${path}`
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(errorText)
|
||||||
|
}
|
||||||
|
throw new Error(errorText)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`Unable to locate .rc file at default locations (${RC_FILE_DEFAULT_LOCATIONS})`)
|
const errorText = `Failed to find .rc file at default paths: ${RC_FILE_DEFAULT_LOCATIONS}`
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(errorText)
|
||||||
|
}
|
||||||
|
throw new Error(errorText)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export function parseArgs (args: string[]): EnvCmdOptions {
|
|||||||
program = parseArgsUsingCommander(args.slice(0, args.indexOf(command)))
|
program = parseArgsUsingCommander(args.slice(0, args.indexOf(command)))
|
||||||
const noOverride = !(program.override as boolean)
|
const noOverride = !(program.override as boolean)
|
||||||
const useShell = !!(program.useShell as boolean)
|
const useShell = !!(program.useShell as boolean)
|
||||||
|
const verbose = !!(program.verbose as boolean)
|
||||||
|
|
||||||
let rc: any
|
let rc: any
|
||||||
if (program.environments !== undefined && program.environments.length !== 0) {
|
if (program.environments !== undefined && program.environments.length !== 0) {
|
||||||
@ -32,16 +33,21 @@ export function parseArgs (args: string[]): EnvCmdOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const options = {
|
||||||
command,
|
command,
|
||||||
commandArgs,
|
commandArgs,
|
||||||
envFile,
|
envFile,
|
||||||
rc,
|
rc,
|
||||||
options: {
|
options: {
|
||||||
noOverride,
|
noOverride,
|
||||||
useShell
|
useShell,
|
||||||
|
verbose
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (verbose === true) {
|
||||||
|
console.info(`Options: ${JSON.stringify(options, null, 0)}`)
|
||||||
|
}
|
||||||
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseArgsUsingCommander (args: string[]): Command {
|
export function parseArgsUsingCommander (args: string[]): Command {
|
||||||
@ -55,5 +61,6 @@ export function parseArgsUsingCommander (args: string[]): Command {
|
|||||||
.option('--fallback', 'Fallback to default env file path, if custom env file path not found')
|
.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('--no-override', 'Do not override existing environment variables')
|
||||||
.option('--use-shell', 'Execute the command in a new shell with the given environment')
|
.option('--use-shell', 'Execute the command in a new shell with the given environment')
|
||||||
|
.option('--verbose', 'Print helpful debugging information')
|
||||||
.parse(['_', '_', ...args])
|
.parse(['_', '_', ...args])
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,9 @@ const REQUIRE_HOOK_EXTENSIONS = ['.json', '.js']
|
|||||||
export async function getEnvFileVars (envFilePath: string): Promise<{ [key: string]: any }> {
|
export async function getEnvFileVars (envFilePath: string): Promise<{ [key: string]: any }> {
|
||||||
const absolutePath = resolveEnvFilePath(envFilePath)
|
const absolutePath = resolveEnvFilePath(envFilePath)
|
||||||
if (!fs.existsSync(absolutePath)) {
|
if (!fs.existsSync(absolutePath)) {
|
||||||
throw new Error(`Invalid env file path (${envFilePath}).`)
|
const pathError = new Error(`Invalid env file path (${envFilePath}).`)
|
||||||
|
pathError.name = 'PathError'
|
||||||
|
throw pathError
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the file extension
|
// Get the file extension
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export async function getRCFileVars (
|
|||||||
try {
|
try {
|
||||||
await statAsync(absolutePath)
|
await statAsync(absolutePath)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const pathError = new Error('Invalid .rc file path.')
|
const pathError = new Error(`Failed to find .rc file at path: ${absolutePath}`)
|
||||||
pathError.name = 'PathError'
|
pathError.name = 'PathError'
|
||||||
throw pathError
|
throw pathError
|
||||||
}
|
}
|
||||||
@ -25,12 +25,18 @@ export async function getRCFileVars (
|
|||||||
// Get the file extension
|
// Get the file extension
|
||||||
const ext = extname(absolutePath).toLowerCase()
|
const ext = extname(absolutePath).toLowerCase()
|
||||||
let parsedData: { [key: string]: any }
|
let parsedData: { [key: string]: any }
|
||||||
if (ext === '.json' || ext === '.js') {
|
try {
|
||||||
const possiblePromise = require(absolutePath) /* eslint-disable-line */
|
if (ext === '.json' || ext === '.js') {
|
||||||
parsedData = isPromise(possiblePromise) ? await possiblePromise : possiblePromise
|
const possiblePromise = require(absolutePath) /* eslint-disable-line */
|
||||||
} else {
|
parsedData = isPromise(possiblePromise) ? await possiblePromise : possiblePromise
|
||||||
const file = await readFileAsync(absolutePath, { encoding: 'utf8' })
|
} else {
|
||||||
parsedData = parseRCFile(file)
|
const file = await readFileAsync(absolutePath, { encoding: 'utf8' })
|
||||||
|
parsedData = JSON.parse(file)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
const parseError = new Error(`Failed to parse .rc file at path: ${absolutePath}`)
|
||||||
|
parseError.name = 'ParseError'
|
||||||
|
throw parseError
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse and merge multiple rc environments together
|
// Parse and merge multiple rc environments together
|
||||||
@ -48,29 +54,12 @@ export async function getRCFileVars (
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!environmentFound) {
|
if (!environmentFound) {
|
||||||
console.error(`Error:
|
const environmentError = new Error(
|
||||||
Could not find any environments:
|
`Failed to find environments ${environments} at .rc file location: ${absolutePath}`
|
||||||
${environments}
|
)
|
||||||
in .rc file:
|
environmentError.name = 'EnvironmentError'
|
||||||
${absolutePath}`)
|
throw environmentError
|
||||||
throw new Error(`All environments (${environments}) are missing in in .rc file (${absolutePath}).`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and parses the .rc file
|
|
||||||
*/
|
|
||||||
export function parseRCFile (fileData: string): { [key: string]: any } {
|
|
||||||
let data
|
|
||||||
try {
|
|
||||||
data = JSON.parse(fileData)
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Error:
|
|
||||||
Failed to parse the .rc file.
|
|
||||||
Please make sure its a valid JSON format.`)
|
|
||||||
throw new Error('Unable to parse JSON in .rc file.')
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|||||||
@ -6,8 +6,13 @@ const SIGNALS_TO_HANDLE: NodeJS.Signals[] = [
|
|||||||
|
|
||||||
export class TermSignals {
|
export class TermSignals {
|
||||||
private readonly terminateSpawnedProcessFuncHandlers: { [key: string]: any } = {}
|
private readonly terminateSpawnedProcessFuncHandlers: { [key: string]: any } = {}
|
||||||
|
private readonly verbose: boolean = false;
|
||||||
public _exitCalled = false
|
public _exitCalled = false
|
||||||
|
|
||||||
|
constructor (options: { verbose?: boolean } = {}) {
|
||||||
|
this.verbose = options.verbose === true
|
||||||
|
}
|
||||||
|
|
||||||
public handleTermSignals (proc: ChildProcess): void {
|
public handleTermSignals (proc: ChildProcess): void {
|
||||||
// Terminate child process if parent process receives termination events
|
// Terminate child process if parent process receives termination events
|
||||||
SIGNALS_TO_HANDLE.forEach((signal): void => {
|
SIGNALS_TO_HANDLE.forEach((signal): void => {
|
||||||
@ -15,6 +20,9 @@ export class TermSignals {
|
|||||||
(signal: any, code: any): void => {
|
(signal: any, code: any): void => {
|
||||||
this._removeProcessListeners()
|
this._removeProcessListeners()
|
||||||
if (!this._exitCalled) {
|
if (!this._exitCalled) {
|
||||||
|
if (this.verbose === true) {
|
||||||
|
console.info(`Parent process exited with signal: ${signal}. Terminating child process...`)
|
||||||
|
}
|
||||||
this._exitCalled = true
|
this._exitCalled = true
|
||||||
proc.kill(signal)
|
proc.kill(signal)
|
||||||
this._terminateProcess(code, signal)
|
this._terminateProcess(code, signal)
|
||||||
@ -29,6 +37,12 @@ export class TermSignals {
|
|||||||
this._removeProcessListeners()
|
this._removeProcessListeners()
|
||||||
const convertedSignal = signal != null ? signal : undefined
|
const convertedSignal = signal != null ? signal : undefined
|
||||||
if (!this._exitCalled) {
|
if (!this._exitCalled) {
|
||||||
|
if (this.verbose === true) {
|
||||||
|
console.info(
|
||||||
|
`Child process exited with code: ${code} and signal: ${signal}. ` +
|
||||||
|
'Terminating parent process...'
|
||||||
|
)
|
||||||
|
}
|
||||||
this._exitCalled = true
|
this._exitCalled = true
|
||||||
this._terminateProcess(code, convertedSignal)
|
this._terminateProcess(code, convertedSignal)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export interface GetEnvVarOptions {
|
|||||||
environments: string[]
|
environments: string[]
|
||||||
filePath?: string
|
filePath?: string
|
||||||
}
|
}
|
||||||
|
verbose?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EnvCmdOptions extends GetEnvVarOptions {
|
export interface EnvCmdOptions extends GetEnvVarOptions {
|
||||||
@ -15,5 +16,6 @@ export interface EnvCmdOptions extends GetEnvVarOptions {
|
|||||||
options?: {
|
options?: {
|
||||||
noOverride?: boolean
|
noOverride?: boolean
|
||||||
useShell?: boolean
|
useShell?: boolean
|
||||||
|
verbose?: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,15 +7,11 @@ import * as envFile from '../src/parse-env-file'
|
|||||||
describe('getEnvVars', (): void => {
|
describe('getEnvVars', (): void => {
|
||||||
let getRCFileVarsStub: sinon.SinonStub<any, any>
|
let getRCFileVarsStub: sinon.SinonStub<any, any>
|
||||||
let getEnvFileVarsStub: sinon.SinonStub<any, any>
|
let getEnvFileVarsStub: sinon.SinonStub<any, any>
|
||||||
let logStub: sinon.SinonStub<any, any>
|
let logInfoStub: sinon.SinonStub<any, any>
|
||||||
|
|
||||||
const pathError = new Error()
|
|
||||||
pathError.name = 'PathError'
|
|
||||||
|
|
||||||
before((): void => {
|
before((): void => {
|
||||||
getRCFileVarsStub = sinon.stub(rcFile, 'getRCFileVars')
|
getRCFileVarsStub = sinon.stub(rcFile, 'getRCFileVars')
|
||||||
getEnvFileVarsStub = sinon.stub(envFile, 'getEnvFileVars')
|
getEnvFileVarsStub = sinon.stub(envFile, 'getEnvFileVars')
|
||||||
logStub = sinon.stub(console, 'error')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
after((): void => {
|
after((): void => {
|
||||||
@ -25,9 +21,12 @@ describe('getEnvVars', (): void => {
|
|||||||
afterEach((): void => {
|
afterEach((): void => {
|
||||||
sinon.resetHistory()
|
sinon.resetHistory()
|
||||||
sinon.resetBehavior()
|
sinon.resetBehavior()
|
||||||
|
if (logInfoStub !== undefined) {
|
||||||
|
logInfoStub.restore()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse the json .rc file from the default location with the given environment',
|
it('should parse the json .rc file from the default path with the given environment',
|
||||||
async (): Promise<void> => {
|
async (): Promise<void> => {
|
||||||
getRCFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
getRCFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
const envs = await getEnvVars({ rc: { environments: ['production'] } })
|
const envs = await getEnvVars({ rc: { environments: ['production'] } })
|
||||||
@ -41,7 +40,18 @@ describe('getEnvVars', (): void => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should search all default .rc file locations', async (): Promise<void> => {
|
it('should print path of custom .rc file and environments to info for verbose',
|
||||||
|
async (): Promise<void> => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
getRCFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
|
await getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
it('should search all default .rc file paths', async (): Promise<void> => {
|
||||||
|
const pathError = new Error()
|
||||||
|
pathError.name = 'PathError'
|
||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
getRCFileVarsStub.onThirdCall().returns({ THANKS: 'FORALLTHEFISH' })
|
getRCFileVarsStub.onThirdCall().returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
const envs = await getEnvVars({ rc: { environments: ['production'] } })
|
const envs = await getEnvVars({ rc: { environments: ['production'] } })
|
||||||
@ -54,28 +64,60 @@ describe('getEnvVars', (): void => {
|
|||||||
assert.equal(getRCFileVarsStub.args[2][0].filePath, './.env-cmdrc.json')
|
assert.equal(getRCFileVarsStub.args[2][0].filePath, './.env-cmdrc.json')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should fail to find .rc file at default location', async (): Promise<void> => {
|
it('should fail to find .rc file at default path', async (): Promise<void> => {
|
||||||
|
const pathError = new Error()
|
||||||
|
pathError.name = 'PathError'
|
||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['production'] } })
|
await getEnvVars({ rc: { environments: ['production'] } })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.match(e.message, /locate \.rc/gi)
|
assert.match(e.message, /failed to find/gi)
|
||||||
|
assert.match(e.message, /\.rc file/gi)
|
||||||
|
assert.match(e.message, /default paths/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should log to error console on non-path errors', async (): Promise<void> => {
|
it('should print failure to find .rc file to info for verbose', async (): Promise<void> => {
|
||||||
getRCFileVarsStub.rejects(new Error('Non-path Error'))
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
const pathError = new Error()
|
||||||
|
pathError.name = 'PathError'
|
||||||
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['production'] } })
|
await getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.match(logStub.getCall(0).args[0].message, /non-path error/gi)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
assert.match(e.message, /locate \.rc/gi)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should find .rc file at custom path location', async (): Promise<void> => {
|
it('should fail to find environments at .rc file at default path', async (): Promise<void> => {
|
||||||
|
const environmentError = new Error('Failed to find environments: for .rc file at path:')
|
||||||
|
environmentError.name = 'EnvironmentError'
|
||||||
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
|
try {
|
||||||
|
await getEnvVars({ rc: { environments: ['bad'] } })
|
||||||
|
assert.fail('should not get here.')
|
||||||
|
} catch (e) {
|
||||||
|
assert.match(e.message, /failed to find environments/gi)
|
||||||
|
assert.match(e.message, /\.rc file at path/gi)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should print failure to find environments in .rc file to info for verbose', async (): Promise<void> => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
const environmentError = new Error('Failed to find environments: for .rc file at path:')
|
||||||
|
environmentError.name = 'EnvironmentError'
|
||||||
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
|
try {
|
||||||
|
await getEnvVars({ rc: { environments: ['bad'] }, verbose: true })
|
||||||
|
assert.fail('should not get here.')
|
||||||
|
} catch (e) {
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should find .rc file at custom path path', async (): Promise<void> => {
|
||||||
getRCFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
getRCFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
const envs = await getEnvVars({
|
const envs = await getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' }
|
rc: { environments: ['production'], filePath: '../.custom-rc' }
|
||||||
@ -89,7 +131,19 @@ describe('getEnvVars', (): void => {
|
|||||||
assert.equal(getRCFileVarsStub.args[0][0].filePath, '../.custom-rc')
|
assert.equal(getRCFileVarsStub.args[0][0].filePath, '../.custom-rc')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should fail to find .rc file at custom path location', async (): Promise<void> => {
|
it('should print custom .rc file path to info for verbose', async (): Promise<void> => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
getRCFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
|
await getEnvVars({
|
||||||
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
|
verbose: true
|
||||||
|
})
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail to find .rc file at custom path path', async (): Promise<void> => {
|
||||||
|
const pathError = new Error('Failed to find .rc file at path:')
|
||||||
|
pathError.name = 'PathError'
|
||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVars({
|
||||||
@ -97,24 +151,61 @@ describe('getEnvVars', (): void => {
|
|||||||
})
|
})
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.match(e.message, /locate \.rc/gi)
|
assert.match(e.message, /failed to find/gi)
|
||||||
|
assert.match(e.message, /\.rc file at path/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should log to error console on non-path errors', async (): Promise<void> => {
|
it('should print failure to find custom .rc file path to info for verbose', async (): Promise<void> => {
|
||||||
getRCFileVarsStub.rejects(new Error('Non-path Error'))
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
const pathError = new Error('Failed to find .rc file at path:')
|
||||||
|
pathError.name = 'PathError'
|
||||||
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' }
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
|
verbose: true
|
||||||
})
|
})
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.match(logStub.getCall(0).args[0].message, /non-path error/gi)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
assert.match(e.message, /locate \.rc/gi)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse the env file from a custom location', async (): Promise<void> => {
|
it('should fail to find environments for .rc file at custom path', async (): Promise<void> => {
|
||||||
|
const environmentError = new Error('Failed to find environments: for .rc file at path: ')
|
||||||
|
environmentError.name = 'EnvironmentError'
|
||||||
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
|
try {
|
||||||
|
await getEnvVars({
|
||||||
|
rc: { environments: ['bad'], filePath: '../.custom-rc' }
|
||||||
|
})
|
||||||
|
assert.fail('should not get here.')
|
||||||
|
} catch (e) {
|
||||||
|
assert.match(e.message, /failed to find environments/gi)
|
||||||
|
assert.match(e.message, /\.rc file at path/gi)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should print failure to find environments for custom .rc file path to info for verbose',
|
||||||
|
async (): Promise<void> => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
const environmentError = new Error('Failed to find environments: for .rc file at path: ')
|
||||||
|
environmentError.name = 'EnvironmentError'
|
||||||
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
|
try {
|
||||||
|
await getEnvVars({
|
||||||
|
rc: { environments: ['bad'], filePath: '../.custom-rc' },
|
||||||
|
verbose: true
|
||||||
|
})
|
||||||
|
assert.fail('should not get here.')
|
||||||
|
} catch (e) {
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
it('should parse the env file from a custom path', async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
const envs = await getEnvVars({ envFile: { filePath: '../.env-file' } })
|
const envs = await getEnvVars({ envFile: { filePath: '../.env-file' } })
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
@ -124,31 +215,63 @@ describe('getEnvVars', (): void => {
|
|||||||
assert.equal(getEnvFileVarsStub.args[0][0], '../.env-file')
|
assert.equal(getEnvFileVarsStub.args[0][0], '../.env-file')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should fail to find env file at custom location', async (): Promise<void> => {
|
it('should print path of .env file to info for verbose', async (): Promise<void> => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
|
await getEnvVars({ envFile: { filePath: '../.env-file' }, verbose: true })
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fail to find env file at custom path', async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.rejects('Not found.')
|
getEnvFileVarsStub.rejects('Not found.')
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ envFile: { filePath: '../.env-file' } })
|
await getEnvVars({ envFile: { filePath: '../.env-file' } })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.match(e.message, /locate env/gi)
|
assert.match(e.message, /failed to find/gi)
|
||||||
|
assert.match(e.message, /\.env file at path/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse the env file from the default location if custom ' +
|
it('should print failure to find .env file path to info for verbose', async (): Promise<void> => {
|
||||||
'location not found and fallback option provided',
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
async (): Promise<void> => {
|
getEnvFileVarsStub.rejects('Not found.')
|
||||||
getEnvFileVarsStub.onFirstCall().rejects('File not found.')
|
try {
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
await getEnvVars({ envFile: { filePath: '../.env-file' }, verbose: true })
|
||||||
const envs = await getEnvVars({ envFile: { filePath: '../.env-file', fallback: true } })
|
assert.fail('should not get here.')
|
||||||
assert.isOk(envs)
|
} catch (e) {
|
||||||
assert.lengthOf(Object.keys(envs), 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
assert.equal(envs.THANKS, 'FORALLTHEFISH')
|
}
|
||||||
assert.equal(getEnvFileVarsStub.callCount, 2)
|
})
|
||||||
assert.equal(getEnvFileVarsStub.args[1][0], './.env')
|
|
||||||
}
|
it(
|
||||||
|
'should parse the env file from the default path if custom ' +
|
||||||
|
'path not found and fallback option provided',
|
||||||
|
async (): Promise<void> => {
|
||||||
|
getEnvFileVarsStub.onFirstCall().rejects('File not found.')
|
||||||
|
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
|
const envs = await getEnvVars({ envFile: { filePath: '../.env-file', fallback: true } })
|
||||||
|
assert.isOk(envs)
|
||||||
|
assert.lengthOf(Object.keys(envs), 1)
|
||||||
|
assert.equal(envs.THANKS, 'FORALLTHEFISH')
|
||||||
|
assert.equal(getEnvFileVarsStub.callCount, 2)
|
||||||
|
assert.equal(getEnvFileVarsStub.args[1][0], './.env')
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should parse the env file from the default location', async (): Promise<void> => {
|
it(
|
||||||
|
'should print multiple times for failure to find .env file and ' +
|
||||||
|
'failure to find fallback file to infor for verbose',
|
||||||
|
async (): Promise<void> => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
getEnvFileVarsStub.onFirstCall().rejects('File not found.')
|
||||||
|
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
|
await getEnvVars({ envFile: { filePath: '../.env-file', fallback: true }, verbose: true })
|
||||||
|
assert.equal(logInfoStub.callCount, 2)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
it('should parse the env file from the default path', async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
const envs = await getEnvVars()
|
const envs = await getEnvVars()
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
@ -158,7 +281,14 @@ describe('getEnvVars', (): void => {
|
|||||||
assert.equal(getEnvFileVarsStub.args[0][0], './.env')
|
assert.equal(getEnvFileVarsStub.args[0][0], './.env')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should search all default env file locations', async (): Promise<void> => {
|
it('should print path of .env file to info for verbose', async (): Promise<void> => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
getEnvFileVarsStub.returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
|
await getEnvVars({ verbose: true })
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should search all default env file paths', async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.throws('Not found.')
|
getEnvFileVarsStub.throws('Not found.')
|
||||||
getEnvFileVarsStub.onThirdCall().returns({ THANKS: 'FORALLTHEFISH' })
|
getEnvFileVarsStub.onThirdCall().returns({ THANKS: 'FORALLTHEFISH' })
|
||||||
const envs = await getEnvVars()
|
const envs = await getEnvVars()
|
||||||
@ -167,16 +297,31 @@ describe('getEnvVars', (): void => {
|
|||||||
assert.equal(envs.THANKS, 'FORALLTHEFISH')
|
assert.equal(envs.THANKS, 'FORALLTHEFISH')
|
||||||
assert.equal(getEnvFileVarsStub.callCount, 3)
|
assert.equal(getEnvFileVarsStub.callCount, 3)
|
||||||
assert.isTrue(getEnvFileVarsStub.calledWithExactly('./.env.json'))
|
assert.isTrue(getEnvFileVarsStub.calledWithExactly('./.env.json'))
|
||||||
assert.isTrue(getEnvFileVarsStub.calledWithExactly('./.env.json'))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should fail to find env file at default location', async (): Promise<void> => {
|
it('should fail to find env file at default path', async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.rejects('Not found.')
|
getEnvFileVarsStub.rejects('Not found.')
|
||||||
try {
|
try {
|
||||||
await getEnvVars()
|
await getEnvVars()
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.match(e.message, /locate env/gi)
|
assert.match(e.message, /failed to find/gi)
|
||||||
|
assert.match(e.message, /\.env file/gi)
|
||||||
|
assert.match(e.message, /default paths/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it(
|
||||||
|
'should print failure to find .env file at default paths to info for verbose',
|
||||||
|
async (): Promise<void> => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
getEnvFileVarsStub.rejects('Not found.')
|
||||||
|
try {
|
||||||
|
await getEnvVars({ verbose: true })
|
||||||
|
assert.fail('should not get here.')
|
||||||
|
} catch (e) {
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
/* eslint @typescript-eslint/no-non-null-assertion: 0 */
|
/* eslint @typescript-eslint/no-non-null-assertion: 0 */
|
||||||
|
import * as sinon from 'sinon'
|
||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import { parseArgs } from '../src/parse-args'
|
import { parseArgs } from '../src/parse-args'
|
||||||
|
|
||||||
@ -8,6 +9,21 @@ describe('parseArgs', (): void => {
|
|||||||
const environments = ['development', 'production']
|
const environments = ['development', 'production']
|
||||||
const rcFilePath = './.env-cmdrc'
|
const rcFilePath = './.env-cmdrc'
|
||||||
const envFilePath = './.env'
|
const envFilePath = './.env'
|
||||||
|
let logInfoStub: sinon.SinonStub<any, any>
|
||||||
|
|
||||||
|
before((): void => {
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
})
|
||||||
|
|
||||||
|
after((): void => {
|
||||||
|
sinon.restore()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach((): void => {
|
||||||
|
sinon.resetHistory()
|
||||||
|
sinon.resetBehavior()
|
||||||
|
})
|
||||||
|
|
||||||
it('should parse environment value', (): 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.exists(res.rc)
|
||||||
@ -69,4 +85,10 @@ describe('parseArgs', (): void => {
|
|||||||
assert.exists(res.envFile)
|
assert.exists(res.envFile)
|
||||||
assert.isTrue(res.envFile!.fallback)
|
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])
|
||||||
|
assert.exists(res.options!.verbose)
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,30 +1,9 @@
|
|||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import { readFileSync } from 'fs'
|
import { getRCFileVars } from '../src/parse-rc-file'
|
||||||
import { getRCFileVars, parseRCFile } from '../src/parse-rc-file'
|
|
||||||
|
|
||||||
const rcFilePath = './test/test-files/.rc-test'
|
const rcFilePath = './test/test-files/.rc-test'
|
||||||
const rcJSONFilePath = './test/test-files/.rc-test.json'
|
const rcJSONFilePath = './test/test-files/.rc-test.json'
|
||||||
|
|
||||||
describe('parseRCFile', (): void => {
|
|
||||||
it('should parse an .rc file', (): void => {
|
|
||||||
const file = readFileSync(rcFilePath, { encoding: 'utf8' })
|
|
||||||
const res = parseRCFile(file)
|
|
||||||
assert.exists(res)
|
|
||||||
assert.hasAllKeys(res, ['development', 'test', 'production'])
|
|
||||||
assert.equal(res.development.ANSWER, 0)
|
|
||||||
assert.equal(res.production.THANKS, 'FOR WHAT?!')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should fail to parse an .rc file', (): void => {
|
|
||||||
try {
|
|
||||||
parseRCFile('fdsjk dsjfksdjkla')
|
|
||||||
assert.fail('Should not get here!')
|
|
||||||
} catch (e) {
|
|
||||||
assert.match(e.message, /parse/gi)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('getRCFileVars', (): void => {
|
describe('getRCFileVars', (): void => {
|
||||||
it('should parse an .rc file with the given environment', async (): Promise<void> => {
|
it('should parse an .rc file with the given environment', async (): Promise<void> => {
|
||||||
const res = await getRCFileVars({ environments: ['production'], filePath: rcFilePath })
|
const res = await getRCFileVars({ environments: ['production'], filePath: rcFilePath })
|
||||||
@ -45,6 +24,15 @@ describe('getRCFileVars', (): void => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should fail to find .rc file', async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await getRCFileVars({ environments: ['bad'], filePath: 'bad-path' })
|
||||||
|
assert.fail('Should not get here!')
|
||||||
|
} catch (e) {
|
||||||
|
assert.match(e.message, /\.rc file at path/gi)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('should fail to parse a .rc file if environment does not exist', async (): Promise<void> => {
|
it('should fail to parse a .rc file if environment does not exist', async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
await getRCFileVars({ environments: ['bad'], filePath: rcFilePath })
|
await getRCFileVars({ environments: ['bad'], filePath: rcFilePath })
|
||||||
@ -56,10 +44,10 @@ describe('getRCFileVars', (): void => {
|
|||||||
|
|
||||||
it('should fail to parse an .rc file', async (): Promise<void> => {
|
it('should fail to parse an .rc file', async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
await getRCFileVars({ environments: ['bad'], filePath: './non-existent-file' })
|
await getRCFileVars({ environments: ['bad'], filePath: './test/test-files/.rc-test-bad-format' })
|
||||||
assert.fail('Should not get here!')
|
assert.fail('Should not get here!')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.match(e.message, /path/gi)
|
assert.match(e.message, /parse/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ describe('signal-termination', (): void => {
|
|||||||
const term = new TermSignals()
|
const term = new TermSignals()
|
||||||
let logStub: sinon.SinonStub<any, any>
|
let logStub: sinon.SinonStub<any, any>
|
||||||
let processStub: sinon.SinonStub<any, any>
|
let processStub: sinon.SinonStub<any, any>
|
||||||
|
|
||||||
beforeEach((): void => {
|
beforeEach((): void => {
|
||||||
logStub = sinon.stub(console, 'error')
|
logStub = sinon.stub(console, 'error')
|
||||||
processStub = sinon.stub(process, 'exit')
|
processStub = sinon.stub(process, 'exit')
|
||||||
@ -118,9 +119,11 @@ describe('signal-termination', (): void => {
|
|||||||
let processOnceStub: sinon.SinonStub<any, any>
|
let processOnceStub: sinon.SinonStub<any, any>
|
||||||
let _removeProcessListenersStub: sinon.SinonStub<any, any>
|
let _removeProcessListenersStub: sinon.SinonStub<any, any>
|
||||||
let _terminateProcessStub: sinon.SinonStub<any, any>
|
let _terminateProcessStub: sinon.SinonStub<any, any>
|
||||||
|
let logInfoStub: sinon.SinonStub<any, any>
|
||||||
let proc: any
|
let proc: any
|
||||||
beforeEach((): void => {
|
|
||||||
term = new TermSignals()
|
function setup (verbose: boolean = false): void {
|
||||||
|
term = new TermSignals({ verbose })
|
||||||
procKillStub = sinon.stub()
|
procKillStub = sinon.stub()
|
||||||
procOnStub = sinon.stub()
|
procOnStub = sinon.stub()
|
||||||
processOnceStub = sinon.stub(process, 'once')
|
processOnceStub = sinon.stub(process, 'once')
|
||||||
@ -130,6 +133,10 @@ describe('signal-termination', (): void => {
|
|||||||
kill: procKillStub,
|
kill: procKillStub,
|
||||||
on: procOnStub
|
on: procOnStub
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach((): void => {
|
||||||
|
setup()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach((): void => {
|
afterEach((): void => {
|
||||||
@ -153,6 +160,16 @@ describe('signal-termination', (): void => {
|
|||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should print child process terminated to info for verbose', (): void => {
|
||||||
|
sinon.restore()
|
||||||
|
setup(true)
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
assert.notOk(term._exitCalled)
|
||||||
|
term.handleTermSignals(proc)
|
||||||
|
processOnceStub.args[0][1]('SIGTERM', 1)
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
})
|
||||||
|
|
||||||
it('should not terminate child process if child process termination ' +
|
it('should not terminate child process if child process termination ' +
|
||||||
'has already been called by parent', (): void => {
|
'has already been called by parent', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
@ -176,6 +193,16 @@ describe('signal-termination', (): void => {
|
|||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should print parent process terminated to info for verbose', (): void => {
|
||||||
|
sinon.restore()
|
||||||
|
setup(true)
|
||||||
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
|
assert.notOk(term._exitCalled)
|
||||||
|
term.handleTermSignals(proc)
|
||||||
|
procOnStub.args[0][1](1, 'SIGTERM')
|
||||||
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
|
})
|
||||||
|
|
||||||
it('should not terminate parent process if parent process already terminating', (): void => {
|
it('should not terminate parent process if parent process already terminating', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
|
|||||||
3
test/test-files/.rc-test-bad-format
Normal file
3
test/test-files/.rc-test-bad-format
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"development":
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user