Skip to content

Commit

Permalink
feat: allow specifying a custom location for config files (#122)
Browse files Browse the repository at this point in the history
Fixes #121
  • Loading branch information
alangpierce authored May 13, 2017
1 parent edd4b2d commit 36b12e8
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 34 deletions.
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,14 @@ export a JS object with your config. Any file starting with `bulk-decaffeinate`
and ending with `.config.js` will be counted, and multiple config files may
exist at once. If there are multiple config files, they are merged, with
alphabetically-later config file names taking precedence over
alphabetically-earlier files. Many config options can also be specified
directly as CLI arguments, with CLI arguments taking precedence over any config
file setting.
alphabetically-earlier files.

Alternatively, you may specify the config file location using the `--config`
option, e.g. `bulk-decaffeinate --config ../bulk-decaffeinate.config.js` to use
a config file one level up in the directory structure.

Many config options can also be specified directly as CLI arguments, with CLI
arguments taking precedence over any config file setting.

Here's an example config file:

Expand Down
29 changes: 17 additions & 12 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,42 @@ export default function () {
of its subdirectories.
land: Create a merge commit with all commits generated by bulk-decaffeinate.`)
.action(commandArg => command = commandArg)
.option('-c, --config [path]',
`The config file to use. This arg may be specified multiple
times. If unspecified, files like bulk-decaffeinate.config.js will
be discovered and used.`,
(arg, args) => {args.push(arg); return args;}, [])
.option('-f, --file [path]',
`An absolute or relative path to decaffeinate. This arg may be
specified multiple times.`,
specified multiple times.`,
(arg, args) => {args.push(arg); return args;}, [])
.option('-p, --path-file [path]',
`A file containing the paths of .coffee files to decaffeinate, one
path per line. Paths can be either absolute or relative to the
current working directory.`)
path per line. Paths can be either absolute or relative to the
current working directory.`)
.option('-d, --dir [path]',
`A directory containing files to decaffeinate. All .coffee files in
any subdirectory of this directory are considered for decaffeinate.`)
any subdirectory of this directory are considered for decaffeinate.`)
.option('--allow-invalid-constructors',
`If specified, the --allow-invalid-constructors arg is added when
invoking decaffeinate.`)
invoking decaffeinate.`)
.option('--land-base [revision]',
`The git revision to use as the base commit when running the "land"
command. If none is specified, bulk-decaffeinate tries to use the
first auto-generated commit in recent history.`)
command. If none is specified, bulk-decaffeinate tries to use the
first auto-generated commit in recent history.`)
.option('--skip-verify',
`If specified, skips the initial verification step when running the
"convert" command.`)
"convert" command.`)
.option('--decaffeinate-path [path]',
`The path to the decaffeinate binary. If none is specified, it will
be automatically discovered from node_modules and then from the
PATH.`)
be automatically discovered from node_modules and then from the
PATH.`)
.option('--jscodeshift-path [path]',
`The path to the jscodeshift binary. If none is specified, it will be
automatically discovered from node_modules and then from the PATH.`)
automatically discovered from node_modules and then from the PATH.`)
.option('--eslint-path [path]',
`The path to the eslint binary. If none is specified, it will be
automatically discovered from node_modules and then from the PATH.`)
automatically discovered from node_modules and then from the PATH.`)
.parse(process.argv);

runCommand(command);
Expand Down
34 changes: 22 additions & 12 deletions src/config/resolveConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ import execLive from '../util/execLive';
export default async function resolveConfig(commander) {
let config = {};

let currentDirFiles = await readdir('.');
currentDirFiles.sort();
for (let filename of currentDirFiles) {
config = await applyPossibleConfig(filename, config);
if (commander.config && commander.config.length > 0) {
for (let filename of commander.config) {
config = applyConfig(filename, config);
}
} else {
let currentDirFiles = await readdir('.');
currentDirFiles.sort();
for (let filename of currentDirFiles) {
config = await applyPossibleConfig(filename, config);
}
}
config = getCLIParamsConfig(config, commander);
return {
Expand Down Expand Up @@ -47,20 +53,24 @@ async function applyPossibleConfig(filename, config) {
return config;
}

let filePath = resolve(filename);
if (filename.endsWith('.config.js')) {
try {
let newConfig = requireUncached(filePath);
return Object.assign(config, newConfig);
} catch (e) {
throw new CLIError(
`Error reading file ${filePath}. Make sure it is a valid JS file.`);
}
return applyConfig(filename, config);
} else {
return config;
}
}

function applyConfig(filename, config) {
let filePath = resolve(filename);
try {
let newConfig = requireUncached(filePath);
return Object.assign(config, newConfig);
} catch (e) {
throw new CLIError(
`Error reading file ${filePath}. Make sure it is a valid JS file.`);
}
}

/**
* Fill in a configuration from the CLI arguments.
*/
Expand Down
22 changes: 22 additions & 0 deletions test/bulk-decaffeinate-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import assert from 'assert';
import { readFile } from 'mz/fs';

import {
assertFileContents,
assertFileIncludes,
assertIncludes,
initGitRepo,
runCli,
runCliExpectSuccess,
runWithTemplateDir,
} from './test-util';

Expand All @@ -18,6 +21,25 @@ describe('basic CLI', () => {
});
});

describe('config', () => {
it('allows explicitly-specified config files', async function() {
await runWithTemplateDir('custom-config-location', async function() {
await initGitRepo();
await runCliExpectSuccess(
'convert --config configDir1/config.js --config configDir2/otherConfig.js');
await assertFileContents('./A.ts', `\
/* Automatically-added prefix. */
/* eslint-disable
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
const A = 1;
`);
});
});
});

describe('check', () => {
it('discovers and runs files', async function() {
let {stdout} = await runCli('check -d test/examples/simple-success');
Expand Down
8 changes: 1 addition & 7 deletions test/convert-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,12 @@ import {
assertIncludes,
initGitRepo,
runCli,
runCliExpectSuccess,
runCliExpectError,
runWithTemplateDir,
} from './test-util';

describe('convert', () => {
async function runCliExpectSuccess(command) {
let {stdout, stderr} = await runCli(command);
assert(stderr.length === 0, `Nonempty stderr. stderr:\n${stderr}\n\nstdout:\n${stdout}`);
assertIncludes(stdout, 'Successfully ran decaffeinate');
return {stdout, stderr};
}

it('generates git commits converting the files', async function() {
await runWithTemplateDir('simple-success', async function() {
await initGitRepo();
Expand Down
1 change: 1 addition & 0 deletions test/examples/custom-config-location/A.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A = 1
3 changes: 3 additions & 0 deletions test/examples/custom-config-location/configDir1/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
codePrefix: '/* Automatically-added prefix. */\n',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
outputFileExtension: 'ts',
};
7 changes: 7 additions & 0 deletions test/test-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ export async function runCli(args) {
return {stdout, stderr};
}

export async function runCliExpectSuccess(command) {
let {stdout, stderr} = await runCli(command);
assert(stderr.length === 0, `Nonempty stderr. stderr:\n${stderr}\n\nstdout:\n${stdout}`);
assertIncludes(stdout, 'Successfully ran decaffeinate');
return {stdout, stderr};
}

export async function runCliExpectError(args) {
try {
await runCli(args);
Expand Down

0 comments on commit 36b12e8

Please sign in to comment.