Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add --check CLI option #64

Merged
merged 5 commits into from May 20, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -101,6 +101,10 @@ Outputs the name of each file right before it is proccessed. This can be useful

Prevent `git commit` if any files are fixed.

### `--check`

Check that files are correctly formatted, but don't format them. This is useful on CI to verify that all changed files in the current branch were correctly formatted.

<!-- Undocumented = Unsupported :D

### `--config`
Expand Down
13 changes: 12 additions & 1 deletion bin/pretty-quick.js
Expand Up @@ -36,7 +36,13 @@ const prettyQuickResult = prettyQuick(
console.log(`✍️ Fixing up ${chalk.bold(file)}.`);
},

onExamineFile: file => {
onCheckFile: (file, isFormatted) => {
if (!isFormatted) {
console.log(`⛔️ Check failed: ${chalk.bold(file)}`);
}
},

onProcessFile: file => {
console.log(`🔍 Examining ${chalk.bold(file)}.`);
},
})
Expand All @@ -56,5 +62,10 @@ if (prettyQuickResult.success) {
'✗ File had to be prettified and prettyQuick was set to bail mode.'
);
}
if (prettyQuickResult.errors.indexOf('CHECK_FAILED') !== -1) {
console.log(
'✗ Code style issues found in the above file(s). Forgot to run Prettier?'
);
}
process.exit(1); // ensure git hooks abort
}
20 changes: 10 additions & 10 deletions src/__tests__/scm-git.test.js
Expand Up @@ -295,24 +295,24 @@ describe('with git', () => {
});
});

test('with --verbose calls onExamineFile', () => {
const onExamineFile = jest.fn();
test('with --verbose calls onProcessFile', () => {
const onProcessFile = jest.fn();
mockGitFs();

prettyQuick('root', { since: 'banana', verbose: true, onExamineFile });
prettyQuick('root', { since: 'banana', verbose: true, onProcessFile });

expect(onExamineFile).toHaveBeenCalledWith('./foo.js');
expect(onExamineFile).toHaveBeenCalledWith('./bar.md');
expect(onProcessFile).toHaveBeenCalledWith('./foo.js');
expect(onProcessFile).toHaveBeenCalledWith('./bar.md');
});

test('without --verbose does NOT call onExamineFile', () => {
const onExamineFile = jest.fn();
test('without --verbose does NOT call onProcessFile', () => {
const onProcessFile = jest.fn();
mockGitFs();

prettyQuick('root', { since: 'banana', onExamineFile });
prettyQuick('root', { since: 'banana', onProcessFile });

expect(onExamineFile).not.toHaveBeenCalledWith('./foo.js');
expect(onExamineFile).not.toHaveBeenCalledWith('./bar.md');
expect(onProcessFile).not.toHaveBeenCalledWith('./foo.js');
expect(onProcessFile).not.toHaveBeenCalledWith('./bar.md');
});

test('ignore files matching patterns from the repositories root .prettierignore', () => {
Expand Down
20 changes: 10 additions & 10 deletions src/__tests__/scm-hg.test.js
Expand Up @@ -196,22 +196,22 @@ describe('with hg', () => {
});
});

test('with --verbose calls onExamineFile', () => {
const onExamineFile = jest.fn();
test('with --verbose calls onProcessFile', () => {
const onProcessFile = jest.fn();
mockHgFs();
prettyQuick('root', { since: 'banana', verbose: true, onExamineFile });
prettyQuick('root', { since: 'banana', verbose: true, onProcessFile });

expect(onExamineFile).toHaveBeenCalledWith('./foo.js');
expect(onExamineFile).toHaveBeenCalledWith('./bar.md');
expect(onProcessFile).toHaveBeenCalledWith('./foo.js');
expect(onProcessFile).toHaveBeenCalledWith('./bar.md');
});

test('without --verbose does NOT call onExamineFile', () => {
const onExamineFile = jest.fn();
test('without --verbose does NOT call onProcessFile', () => {
const onProcessFile = jest.fn();
mockHgFs();
prettyQuick('root', { since: 'banana', onExamineFile });
prettyQuick('root', { since: 'banana', onProcessFile });

expect(onExamineFile).not.toHaveBeenCalledWith('./foo.js');
expect(onExamineFile).not.toHaveBeenCalledWith('./bar.md');
expect(onProcessFile).not.toHaveBeenCalledWith('./foo.js');
expect(onProcessFile).not.toHaveBeenCalledWith('./bar.md');
});

test('ignore files matching patterns from the repositories root .prettierignore', () => {
Expand Down
27 changes: 0 additions & 27 deletions src/formatFiles.js

This file was deleted.

17 changes: 13 additions & 4 deletions src/index.js
@@ -1,5 +1,5 @@
import scms from './scms';
import formatFiles from './formatFiles';
import processFiles from './processFiles';
import createIgnorer from './createIgnorer';
import createMatcher from './createMatcher';
import isSupportedExtension from './isSupportedExtension';
Expand All @@ -14,12 +14,14 @@ export default (
restage = true,
branch,
bail,
check,
verbose,
onFoundSinceRevision,
onFoundChangedFiles,
onPartiallyStagedFile,
onProcessFile,
onCheckFile,
onWriteFile,
onExamineFile,
smably marked this conversation as resolved.
Show resolved Hide resolved
} = {}
) => {
const scm = scms(currentDirectory);
Expand Down Expand Up @@ -60,7 +62,8 @@ export default (

const failReasons = new Set();

formatFiles(directory, changedFiles, {
processFiles(directory, changedFiles, {
check,
config,
onWriteFile: file => {
onWriteFile && onWriteFile(file);
Expand All @@ -76,7 +79,13 @@ export default (
}
}
},
onExamineFile: verbose && onExamineFile,
onCheckFile: (file, isFormatted) => {
onCheckFile && onCheckFile(file, isFormatted);
if (!isFormatted) {
failReasons.add('CHECK_FAILED');
}
},
onProcessFile: verbose && onProcessFile,
});

return {
Expand Down
36 changes: 36 additions & 0 deletions src/processFiles.js
@@ -0,0 +1,36 @@
import { readFileSync, writeFileSync } from 'fs';
import * as prettier from 'prettier';
import { join } from 'path';

export default (
directory,
files,
{ check, config, onProcessFile, onCheckFile, onWriteFile } = {}
) => {
for (const relative of files) {
onProcessFile && onProcessFile(relative);
const file = join(directory, relative);
const options = Object.assign(
{},
prettier.resolveConfig.sync(file, {
config,
editorconfig: true,
}),
{ filepath: file }
);
const input = readFileSync(file, 'utf8');

if (check) {
const isFormatted = prettier.check(input, options);
onCheckFile && onCheckFile(relative, isFormatted);
continue;
}

const output = prettier.format(input, options);

if (output !== input) {
writeFileSync(file, output);
onWriteFile && onWriteFile(relative);
}
}
};