Add --check option (#5629)

master
Alexander Kachkaev 2018-12-19 14:03:30 +00:00 committed by Ika
parent f94f63b040
commit 711c6d78a8
22 changed files with 430 additions and 25 deletions

View File

@ -18,7 +18,7 @@ prettier.format("foo ( );", { semi: false, parser: "babylon" });
## `prettier.check(source [, options])`
`check` checks to see if the file has been formatted with Prettier given those options and returns a `Boolean`. This is similar to the `--list-different` parameter in the CLI and is useful for running Prettier in CI scenarios.
`check` checks to see if the file has been formatted with Prettier given those options and returns a `Boolean`. This is similar to the `--check` or `--list-different` parameter in the CLI and is useful for running Prettier in CI scenarios.
## `prettier.formatWithCursor(source [, options])`

View File

@ -21,6 +21,38 @@ Don't forget the quotes around the globs! The quotes make sure that Prettier exp
Prettier CLI will ignore files located in `node_modules` directory. To opt-out from this behavior use `--with-node-modules` flag.
## `--check`
When you want to check if your files are formatted, you can run Prettier with the `--check` flag (or `-c`).
This will output a human-friendly message and a list of unformatted files, if any.
```bash
prettier --check "src/**/*.js"
```
Console output if all files are formatted:
```
Checking formatting...
All matched files use Prettier code style!
```
Console output if some of the files require re-formatting:
```
Checking formatting...
src/fileA.js
src/fileB.js
Code style issues found in the above file(s). Forgot to run Prettier?
```
The command will return exit code 1 in the second case, which is helpful inside the CI pipelines.
Human-friendly status messages help project contributors react on possible problems.
To minimise the number of times `prettier --check` finds unformatted files, you may be interested in configuring a [pre-commit hook](precommit.md) in your repo.
Applying this practice will minimise the number of times the CI fails because of code formatting problems.
If you need to pipe the list of unformatted files to another command, you can use [`--list-different`](./cli.md#list-different) flag instead of `--check`.
## `--debug-check`
If you're worried that Prettier will change the correctness of your code, add `--debug-check` to the command. This will cause Prettier to print an error message if it detects that code correctness might have changed. Note that `--write` cannot be used with `--debug-check`.
@ -72,6 +104,8 @@ Another useful flag is `--list-different` (or `-l`) which prints the filenames o
prettier --single-quote --list-different "src/**/*.js"
```
You can also use [`--check`](./cli.md#check) flag, which works the same way as `--list-different`, but also prints a human-friendly summary message to stdout.
## `--no-config`
Do not look for a configuration file. The default settings will be used.

View File

@ -310,7 +310,7 @@ If you want to make sure that your git repository only contains Linux-style line
1. Set `endOfLine` option to `lf`
1. Configure [a pre-commit hook](./precommit.md) that will run Prettier
1. Configure Prettier to run in your CI pipeline (e.g. using [`prettier-check` npm package](https://www.npmjs.com/package/prettier-check))
1. Configure Prettier to run in your CI pipeline using [`--check` flag](./cli.md#check)
1. Ask Windows users to run `git config core.autocrlf false` before working on your repo so that git did not convert `LF` to `CRLF` on checkout.
Alternatively, you can add `* text=auto eol=lf` to the repo's `.gitattributes` file to achieve this.

View File

@ -70,6 +70,15 @@ const categoryOrder = [
* Note: The options below are sorted alphabetically.
*/
const options = {
check: {
type: "boolean",
category: coreOptions.CATEGORY_OUTPUT,
alias: "c",
description: dedent`
Check if the given files are formatted, print a human-friendly summary
message and paths to unformatted files (see also --list-different).
`
},
color: {
// The supports-color package (a sub sub dependency) looks directly at
// `process.argv` for `--no-color` and such-like options. The reason it is
@ -170,7 +179,7 @@ const options = {
category: coreOptions.CATEGORY_OUTPUT,
alias: "l",
description:
"Print the names of files that are different from Prettier's formatting."
"Print the names of files that are different from Prettier's formatting (see also --check)."
},
loglevel: {
type: "choice",

View File

@ -12,6 +12,11 @@ function run(args) {
context.logger.debug(`normalized argv: ${JSON.stringify(context.argv)}`);
if (context.argv["check"] && context.argv["list-different"]) {
context.logger.error("Cannot use --check and --list-different together.");
process.exit(1);
}
if (context.argv["write"] && context.argv["debug-check"]) {
context.logger.error("Cannot use --write and --debug-check together.");
process.exit(1);

View File

@ -58,7 +58,7 @@ function handleError(context, filename, error) {
readline.clearLine(process.stdout, 0);
readline.cursorTo(process.stdout, 0, null);
}
if (!context.argv["list-different"]) {
if (!context.argv["check"] && !context.argv["list-different"]) {
process.exitCode = 2;
}
context.logger.error(error.message);
@ -133,7 +133,7 @@ function writeOutput(context, result, options) {
}
function listDifferent(context, input, options, filename) {
if (!context.argv["list-different"]) {
if (!context.argv["check"] && !context.argv["list-different"]) {
return;
}
@ -441,18 +441,25 @@ function formatFiles(context) {
// before any files are actually written
const ignorer = createIgnorerFromContextOrDie(context);
let numberOfUnformattedFilesFound = 0;
if (context.argv["check"]) {
context.logger.log("Checking formatting...");
}
eachFilename(context, context.filePatterns, (filename, options) => {
const fileIgnored = ignorer.filter([filename]).length === 0;
if (
fileIgnored &&
(context.argv["debug-check"] ||
context.argv["write"] ||
context.argv["check"] ||
context.argv["list-different"])
) {
return;
}
if (context.argv["write"] && process.stdout.isTTY) {
if (process.stdout.isTTY) {
// Don't use `console.log` here since we need to replace this line.
context.logger.log(filename, { newline: false });
}
@ -496,24 +503,17 @@ function formatFiles(context) {
const isDifferent = output !== input;
if (context.argv["list-different"] && isDifferent) {
context.logger.log(filename);
if (!context.argv["write"]) {
process.exitCode = 1;
}
if (process.stdout.isTTY) {
// Remove previously printed filename to log it with duration.
readline.clearLine(process.stdout, 0);
readline.cursorTo(process.stdout, 0, null);
}
if (context.argv["write"]) {
if (process.stdout.isTTY) {
// Remove previously printed filename to log it with duration.
readline.clearLine(process.stdout, 0);
readline.cursorTo(process.stdout, 0, null);
}
// Don't write the file if it won't change in order not to invalidate
// mtime based caches.
if (isDifferent) {
if (!context.argv["list-different"]) {
if (!context.argv["check"] && !context.argv["list-different"]) {
context.logger.log(`${filename} ${Date.now() - start}ms`);
}
@ -526,7 +526,7 @@ function formatFiles(context) {
// Don't exit the process if one file failed
process.exitCode = 2;
}
} else if (!context.argv["list-different"]) {
} else if (!context.argv["check"] && !context.argv["list-different"]) {
context.logger.log(`${chalk.grey(filename)} ${Date.now() - start}ms`);
}
} else if (context.argv["debug-check"]) {
@ -535,10 +535,39 @@ function formatFiles(context) {
} else {
process.exitCode = 2;
}
} else if (!context.argv["list-different"]) {
} else if (!context.argv["check"] && !context.argv["list-different"]) {
writeOutput(context, result, options);
}
if (
(context.argv["check"] || context.argv["list-different"]) &&
isDifferent
) {
context.logger.log(filename);
numberOfUnformattedFilesFound += 1;
}
});
// Print check summary based on expected exit code
if (context.argv["check"]) {
context.logger.log(
numberOfUnformattedFilesFound === 0
? "All matched files use Prettier code style!"
: context.argv["write"]
? "Code style issues fixed in the above file(s)."
: "Code style issues found in the above file(s). Forgot to run Prettier?"
);
}
// Ensure non-zero exitCode when using --check/list-different is not combined with --write
if (
(context.argv["check"] || context.argv["list-different"]) &&
numberOfUnformattedFilesFound > 0 &&
!process.exitCode &&
!context.argv["write"]
) {
process.exitCode = 1;
}
}
function getOptionsWithOpposites(options) {

View File

@ -0,0 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`checks stdin with --check (write) 1`] = `Array []`;
exports[`checks stdin with -c (alias for --check) (write) 1`] = `Array []`;

View File

@ -4,6 +4,17 @@ exports[`checks stdin with --debug-check (write) 1`] = `Array []`;
exports[`doesn't crash when --debug-check is passed (write) 1`] = `Array []`;
exports[`should not exit non-zero for already prettified code with --debug-check + --check (stderr) 1`] = `""`;
exports[`should not exit non-zero for already prettified code with --debug-check + --check (stdout) 1`] = `
"Checking formatting...
issue-4599.js
All matched files use Prettier code style!
"
`;
exports[`should not exit non-zero for already prettified code with --debug-check + --check (write) 1`] = `Array []`;
exports[`should not exit non-zero for already prettified code with --debug-check + --list-different (stderr) 1`] = `""`;
exports[`should not exit non-zero for already prettified code with --debug-check + --list-different (stdout) 1`] = `

View File

@ -5,7 +5,7 @@ exports[`show detailed usage with --help l (alias) (stderr) 1`] = `""`;
exports[`show detailed usage with --help l (alias) (stdout) 1`] = `
"-l, --list-different
Print the names of files that are different from Prettier's formatting.
Print the names of files that are different from Prettier's formatting (see also --check).
"
`;
@ -51,7 +51,9 @@ Stdin is read if it is piped to Prettier and no files are given.
Output options:
-l, --list-different Print the names of files that are different from Prettier's formatting.
-c, --check Check if the given files are formatted, print a human-friendly summary
message and paths to unformatted files (see also --list-different).
-l, --list-different Print the names of files that are different from Prettier's formatting (see also --check).
--write Edit files in-place. (Beware!)
Format options:
@ -197,7 +199,9 @@ Stdin is read if it is piped to Prettier and no files are given.
Output options:
-l, --list-different Print the names of files that are different from Prettier's formatting.
-c, --check Check if the given files are formatted, print a human-friendly summary
message and paths to unformatted files (see also --list-different).
-l, --list-different Print the names of files that are different from Prettier's formatting (see also --check).
--write Edit files in-place. (Beware!)
Format options:
@ -296,6 +300,15 @@ Other options:
exports[`throw error and show usage with something unexpected (write) 1`] = `Array []`;
exports[`throw error with --check + --list-different (stderr) 1`] = `
"[error] Cannot use --check and --list-different together.
"
`;
exports[`throw error with --check + --list-different (stdout) 1`] = `""`;
exports[`throw error with --check + --list-different (write) 1`] = `Array []`;
exports[`throw error with --file-info + multiple files (stderr) 1`] = `
"[error] Cannot use --file-info with multiple files
"

View File

@ -31,6 +31,18 @@ Default: true
exports[`show detailed usage with --help bracket-spacing (write) 1`] = `Array []`;
exports[`show detailed usage with --help check (stderr) 1`] = `""`;
exports[`show detailed usage with --help check (stdout) 1`] = `
"-c, --check
Check if the given files are formatted, print a human-friendly summary
message and paths to unformatted files (see also --list-different).
"
`;
exports[`show detailed usage with --help check (write) 1`] = `Array []`;
exports[`show detailed usage with --help color (stderr) 1`] = `""`;
exports[`show detailed usage with --help color (stdout) 1`] = `
@ -235,7 +247,7 @@ exports[`show detailed usage with --help list-different (stderr) 1`] = `""`;
exports[`show detailed usage with --help list-different (stdout) 1`] = `
"-l, --list-different
Print the names of files that are different from Prettier's formatting.
Print the names of files that are different from Prettier's formatting (see also --check).
"
`;

View File

@ -1,5 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`--check with unknown path and no parser multiple files (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--check with unknown path and no parser multiple files (stdout) 1`] = `
"Checking formatting...
foo.js
Code style issues found in the above file(s). Forgot to run Prettier?
"
`;
exports[`--check with unknown path and no parser specific file (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--check with unknown path and no parser specific file (stdout) 1`] = `
"Checking formatting...
All matched files use Prettier code style!
"
`;
exports[`--list-different with unknown path and no parser multiple files (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
@ -10,6 +33,39 @@ exports[`--list-different with unknown path and no parser specific file (stderr)
"
`;
exports[`--write and --check with unknown path and no parser multiple files (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--write and --check with unknown path and no parser multiple files (stdout) 1`] = `
"Checking formatting...
foo.js
Code style issues fixed in the above file(s).
"
`;
exports[`--write and --check with unknown path and no parser multiple files (write) 1`] = `
Array [
Object {
"content": "foo();
",
"filename": "foo.js",
},
]
`;
exports[`--write and --check with unknown path and no parser specific file (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
`;
exports[`--write and --check with unknown path and no parser specific file (stdout) 1`] = `
"Checking formatting...
All matched files use Prettier code style!
"
`;
exports[`--write and --list-different with unknown path and no parser multiple files (stderr) 1`] = `
"[error] No parser could be inferred for file: FOO
"
@ -72,6 +128,11 @@ Array [
]
`;
exports[`stdin no path and no parser --check logs error but exits with 0 (stderr) 1`] = `
"[error] No parser and no file path given, couldn't infer a parser.
"
`;
exports[`stdin no path and no parser --list-different logs error but exits with 0 (stderr) 1`] = `
"[error] No parser and no file path given, couldn't infer a parser.
"
@ -82,6 +143,11 @@ exports[`stdin no path and no parser logs error and exits with 2 (stderr) 1`] =
"
`;
exports[`stdin with unknown path and no parser --check logs error but exits with 0 (stderr) 1`] = `
"[error] No parser could be inferred for file: foo
"
`;
exports[`stdin with unknown path and no parser --list-different logs error but exits with 0 (stderr) 1`] = `
"[error] No parser could be inferred for file: foo
"

View File

@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`checks stdin with --list-different (write) 1`] = `Array []`;
exports[`checks stdin with -l (alias for --list-different) (write) 1`] = `Array []`;

View File

@ -1,5 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`no file diffs with --check + formatted file (stderr) 1`] = `""`;
exports[`no file diffs with --check + formatted file (stderr) 2`] = `""`;
exports[`no file diffs with --check + formatted file (stdout) 1`] = `
"Checking formatting...
formatted.jsAll matched files use Prettier code style!
"
`;
exports[`no file diffs with --check + formatted file (stdout) 2`] = `
"Checking formatting...
All matched files use Prettier code style!
"
`;
exports[`no file diffs with --check + formatted file (write) 1`] = `Array []`;
exports[`no file diffs with --check + formatted file (write) 2`] = `Array []`;
exports[`no file diffs with --list-different + formatted file (stderr) 1`] = `""`;
exports[`no file diffs with --list-different + formatted file (stderr) 2`] = `""`;
@ -12,6 +32,44 @@ exports[`no file diffs with --list-different + formatted file (write) 1`] = `Arr
exports[`no file diffs with --list-different + formatted file (write) 2`] = `Array []`;
exports[`output with --check + unformatted differs when piped (stderr) 1`] = `""`;
exports[`output with --check + unformatted differs when piped (stderr) 2`] = `""`;
exports[`output with --check + unformatted differs when piped (stdout) 1`] = `
"Checking formatting...
unformatted.jsunformatted.js
Code style issues fixed in the above file(s).
"
`;
exports[`output with --check + unformatted differs when piped (stdout) 2`] = `
"Checking formatting...
unformatted.js
Code style issues fixed in the above file(s).
"
`;
exports[`output with --check + unformatted differs when piped (write) 1`] = `
Array [
Object {
"content": "var x = 1;
",
"filename": "unformatted.js",
},
]
`;
exports[`output with --check + unformatted differs when piped (write) 2`] = `
Array [
Object {
"content": "var x = 1;
",
"filename": "unformatted.js",
},
]
`;
exports[`output with --list-different + unformatted differs when piped (stderr) 1`] = `""`;
exports[`output with --list-different + unformatted differs when piped (stderr) 2`] = `""`;

View File

@ -5,7 +5,7 @@ exports[` 1`] = `
- First value
+ Second value
@@ -15,10 +15,12 @@
@@ -17,10 +17,12 @@
Defaults to avoid.
--no-bracket-spacing Do not print spaces between brackets.
--end-of-line <auto|lf|crlf|cr>

View File

@ -14,6 +14,16 @@ exports[`infers postcss parser (stdout) 1`] = `
exports[`infers postcss parser (write) 1`] = `Array []`;
exports[`infers postcss parser with --check (stderr) 1`] = `""`;
exports[`infers postcss parser with --check (stdout) 1`] = `
"Checking formatting...
All matched files use Prettier code style!
"
`;
exports[`infers postcss parser with --check (write) 1`] = `Array []`;
exports[`infers postcss parser with --list-different (stderr) 1`] = `""`;
exports[`infers postcss parser with --list-different (stdout) 1`] = `""`;

View File

@ -0,0 +1,23 @@
"use strict";
const runPrettier = require("../runPrettier");
describe("checks stdin with --check", () => {
runPrettier("cli/with-shebang", ["--check", "--parser", "babylon"], {
input: "0"
}).test({
stdout: "(stdin)\n",
stderr: "",
status: "non-zero"
});
});
describe("checks stdin with -c (alias for --check)", () => {
runPrettier("cli/with-shebang", ["-c", "--parser", "babylon"], {
input: "0"
}).test({
stdout: "(stdin)\n",
stderr: "",
status: "non-zero"
});
});

View File

@ -33,6 +33,16 @@ describe("show diff for 2+ error files with --debug-check", () => {
});
});
describe("should not exit non-zero for already prettified code with --debug-check + --check", () => {
runPrettier("cli/debug-check", [
"issue-4599.js",
"--debug-check",
"--check"
]).test({
status: 0
});
});
describe("should not exit non-zero for already prettified code with --debug-check + --list-different", () => {
runPrettier("cli/debug-check", [
"issue-4599.js",

View File

@ -56,6 +56,12 @@ describe("show warning with --help not-found (typo)", () => {
});
});
describe("throw error with --check + --list-different", () => {
runPrettier("cli", ["--check", "--list-different"]).test({
status: 1
});
});
describe("throw error with --write + --debug-check", () => {
runPrettier("cli", ["--write", "--debug-check"]).test({
status: 1

View File

@ -12,6 +12,16 @@ describe("stdin no path and no parser", () => {
});
});
describe("--check logs error but exits with 0", () => {
runPrettier("cli/infer-parser/", ["--check", "--stdin"], {
input: "foo"
}).test({
status: 0,
stdout: "",
write: []
});
});
describe("--list-different logs error but exits with 0", () => {
runPrettier("cli/infer-parser/", ["--list-different", "--stdin"], {
input: "foo"
@ -34,6 +44,18 @@ describe("stdin with unknown path and no parser", () => {
});
});
describe("--check logs error but exits with 0", () => {
runPrettier(
"cli/infer-parser/",
["--check", "--stdin", "--stdin-filepath", "foo"],
{ input: "foo" }
).test({
status: 0,
stdout: "",
write: []
});
});
describe("--list-different logs error but exits with 0", () => {
runPrettier(
"cli/infer-parser/",
@ -64,6 +86,22 @@ describe("unknown path and no parser", () => {
});
});
describe("--check with unknown path and no parser", () => {
describe("specific file", () => {
runPrettier("cli/infer-parser/", ["--check", "FOO"]).test({
status: 0,
write: []
});
});
describe("multiple files", () => {
runPrettier("cli/infer-parser/", ["--check", "*"]).test({
status: 1,
write: []
});
});
});
describe("--list-different with unknown path and no parser", () => {
describe("specific file", () => {
runPrettier("cli/infer-parser/", ["--list-different", "FOO"]).test({
@ -98,6 +136,21 @@ describe("--write with unknown path and no parser", () => {
});
});
describe("--write and --check with unknown path and no parser", () => {
describe("specific file", () => {
runPrettier("cli/infer-parser/", ["--check", "--write", "FOO"]).test({
status: 0,
write: []
});
});
describe("multiple files", () => {
runPrettier("cli/infer-parser/", ["--check", "--write", "*"]).test({
status: 0
});
});
});
describe("--write and --list-different with unknown path and no parser", () => {
describe("specific file", () => {
runPrettier("cli/infer-parser/", [

View File

@ -11,3 +11,13 @@ describe("checks stdin with --list-different", () => {
status: "non-zero"
});
});
describe("checks stdin with -l (alias for --list-different)", () => {
runPrettier("cli/with-shebang", ["-l", "--parser", "babylon"], {
input: "0"
}).test({
stdout: "(stdin)\n",
stderr: "",
status: "non-zero"
});
});

View File

@ -2,6 +2,49 @@
const runPrettier = require("../runPrettier");
describe("output with --check + unformatted differs when piped", () => {
const result0 = runPrettier(
"cli/write",
["--write", "--check", "--no-color", "unformatted.js"],
{ stdoutIsTTY: true }
).test({
status: 0
});
const result1 = runPrettier(
"cli/write",
["--write", "--check", "--no-color", "unformatted.js"],
{ stdoutIsTTY: false }
).test({
status: 0
});
expect(result0.stdout.length).toBeGreaterThan(result1.stdout.length);
expect(result0.write).toEqual(result1.write);
});
describe("no file diffs with --check + formatted file", () => {
const result0 = runPrettier(
"cli/write",
["--write", "--check", "--no-color", "formatted.js"],
{ stdoutIsTTY: true }
).test({
status: 0
});
const result1 = runPrettier(
"cli/write",
["--write", "--check", "--no-color", "formatted.js"],
{ stdoutIsTTY: false }
).test({
status: 0
});
expect(result0.stdout).not.toEqual(result1.stdout);
expect(result0.stdout.length).toBeGreaterThan(result1.stdout.length);
expect(result0.write).toEqual(result1.write);
});
describe("output with --list-different + unformatted differs when piped", () => {
const result0 = runPrettier(
"cli/write",

View File

@ -9,6 +9,12 @@ describe("infers postcss parser", () => {
});
});
describe("infers postcss parser with --check", () => {
runPrettier("cli/with-parser-inference", ["--check", "*"]).test({
status: 0
});
});
describe("infers postcss parser with --list-different", () => {
runPrettier("cli/with-parser-inference", ["--list-different", "*"]).test({
status: 0