Skip to content

Commit

Permalink
Standardize and improve exit code handling (#245)
Browse files Browse the repository at this point in the history
  • Loading branch information
sxlijin committed Dec 16, 2021
1 parent 799ed61 commit c5a8b48
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 14 deletions.
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -112,9 +112,10 @@ If a rule is passed to both `--enable` and `--disable`, it will be disabled.
`markdownlint-cli` returns one of the following exit codes:

- `0`: Program ran successfully
- `1`: Linting errors / bad parameter
- `1`: Linting errors
- `2`: Unable to write `-o`/`--output` output file
- `3`: Unable to load `-r`/`--rules` custom rule
- `4`: Unexpected error (e.g. malformed config)

## Use with pre-commit

Expand Down
34 changes: 23 additions & 11 deletions markdownlint.js
Expand Up @@ -24,6 +24,13 @@ function jsYamlSafeLoad(text) {
return require('js-yaml').load(text);
}

const exitCodes = {
lintFindings: 1,
failedToWriteOutputFile: 2,
failedToLoadCustomRules: 3,
unexpectedError: 4
};

const projectConfigFiles = [
'.markdownlint.json',
'.markdownlint.yaml',
Expand Down Expand Up @@ -61,7 +68,7 @@ function readConfiguration(userConfigFile) {
config = require('deep-extend')(config, userConfig);
} catch (error) {
console.error(`Cannot read or parse config file '${userConfigFile}': ${error.message}`);
process.exitCode = 1;
process.exitCode = exitCodes.unexpectedError;
}
}

Expand Down Expand Up @@ -160,7 +167,7 @@ function printResult(lintResult) {
// and let the program terminate normally.
// @see {@link https://nodejs.org/dist/latest-v8.x/docs/api/process.html#process_process_exit_code}
// @see {@link https://github.com/igorshubovych/markdownlint-cli/pull/29#issuecomment-343535291}
process.exitCode = 1;
process.exitCode = exitCodes.lintFindings;
}

if (options.output) {
Expand All @@ -171,7 +178,7 @@ function printResult(lintResult) {
fs.writeFileSync(options.output, lintResultString);
} catch (error) {
console.warn('Cannot write to output file ' + options.output + ': ' + error.message);
process.exitCode = 2;
process.exitCode = exitCodes.failedToWriteOutputFile;
}
} else if (lintResultString && !options.quiet) {
console.error(lintResultString);
Expand Down Expand Up @@ -239,7 +246,7 @@ function loadCustomRules(rules) {
return fileList;
} catch (error) {
console.error('Cannot load custom rule ' + rule + ': ' + error.message);
return process.exit(3);
return process.exit(exitCodes.failedToLoadCustomRules);
}
});
}
Expand Down Expand Up @@ -321,11 +328,16 @@ function lintAndPrint(stdin, files) {
printResult(lintResult);
}

if ((files.length > 0) && !options.stdin) {
lintAndPrint(null, diff);
} else if ((files.length === 0) && options.stdin && !options.fix) {
const getStdin = require('get-stdin');
getStdin().then(lintAndPrint);
} else {
program.help();
try {
if ((files.length > 0) && !options.stdin) {
lintAndPrint(null, diff);
} else if ((files.length === 0) && options.stdin && !options.fix) {
const getStdin = require('get-stdin');
getStdin().then(lintAndPrint);
} else {
program.help();
}
} catch (error) {
console.error(error);
process.exit(exitCodes.unexpectedError);
}
20 changes: 18 additions & 2 deletions test/test.js
Expand Up @@ -126,6 +126,22 @@ test('linting of incorrect Markdown file fails with absolute path', async t => {
}
});

test('linting of unreadable Markdown file fails', async t => {
const unreadablePath = '../unreadable.test.md';
fs.symlinkSync('nonexistent.dest.md', unreadablePath, 'file');

try {
await execa('../markdownlint.js',
['--config', 'test-config.json', unreadablePath],
{stripFinalNewline: false});
t.fail();
} catch (error) {
t.is(error.exitCode, 4);
} finally {
fs.unlinkSync(unreadablePath, {force: true});
}
});

test('linting of incorrect Markdown via npm run file fails with eol', async t => {
try {
await execa('npm', ['run', 'invalid'], {stripFinalNewline: false});
Expand Down Expand Up @@ -472,7 +488,7 @@ test('error on configuration file not found', async t => {
} catch (error) {
t.is(error.stdout, '');
t.regex(error.stderr, /Cannot read or parse config file 'non-existent-file-path.yaml': ENOENT: no such file or directory, open 'non-existent-file-path.yaml'/);
t.is(error.exitCode, 1);
t.is(error.exitCode, 4);
}
});

Expand All @@ -484,7 +500,7 @@ test('error on malformed YAML configuration file', async t => {
} catch (error) {
t.is(error.stdout, '');
t.regex(error.stderr, /Cannot read or parse config file 'malformed-config.yaml': Unable to parse 'malformed-config.yaml'; Unexpected token/);
t.is(error.exitCode, 1);
t.is(error.exitCode, 4);
}
});

Expand Down

0 comments on commit c5a8b48

Please sign in to comment.