1 | <h1 align="center">Precise Commits</h1>
|
2 |
|
3 | <p align="center">
|
4 | <a href="https://travis-ci.org/JamesHenry/precise-commits"><img src="https://img.shields.io/travis/JamesHenry/precise-commits.svg?style=flat-square" alt="Travis"/></a>
|
5 | <a href="https://github.com/JamesHenry/precise-commits/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/precise-commits.svg?style=flat-square" alt="GitHub license" /></a>
|
6 | <a href="https://www.npmjs.com/package/precise-commits"><img src="https://img.shields.io/npm/v/precise-commits.svg?style=flat-square" alt="NPM Version" /></a>
|
7 | <a href="https://www.npmjs.com/package/precise-commits"><img src="https://img.shields.io/npm/dt/precise-commits.svg?style=flat-square" alt="NPM Downloads" /></a>
|
8 | <a href="http://commitizen.github.io/cz-cli/"><img src="https://img.shields.io/badge/commitizen-friendly-brightgreen.svg" alt="Commitizen friendly" /></a>
|
9 | <a href="https://github.com/semantic-release/semantic-release"><img src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square" alt="semantic-release" /></a>
|
10 | </p>
|
11 |
|
12 | <br>
|
13 |
|
14 | # Why `precise-commits`?
|
15 |
|
16 | 🔎 It is simply **the most exact and least disruptive way** to add consistent code formatting (by [Prettier](https://prettier.io)) to an existing codebase.
|
17 |
|
18 | ✨ You only **reformat the exact code you have modified anyway** as part of your normal development!
|
19 |
|
20 | | Tool | Staged files | Existing commits | PR Build | Arbitrary commands | Precision |
|
21 | | ------------------- | ------------ | ---------------- | -------- | ------------------ | ------------------------------- |
|
22 | | **precise-commits** | ✅ | ✅ | ✅ | ❌ | **Individual character ranges** |
|
23 | | lint-staged | ✅ | ❌ | ❌ | ✅ | Entire File |
|
24 | | pretty-quick | ✅ | ❌ | ❌ | ❌ | Entire File |
|
25 |
|
26 | <br>
|
27 |
|
28 | # Background
|
29 |
|
30 | Implementing a new code-style in an existing codebase can be really tricky.
|
31 |
|
32 | [Prettier](https://prettier.io) is an amazing automated code formatting tool, but that does not mean that introducing it into an existing codebase is trivial.
|
33 |
|
34 | Regardless of how consistent the existing code-style might be, introducing [Prettier](https://prettier.io) will result in larger diffs, which:
|
35 |
|
36 | 1. Increases the complexity and review time burden of PRs on senior team members.
|
37 | 2. Potentially increases the amount of time it takes to complete a PR in the first place.
|
38 | 3. Can block concurrent work on the same codebase and/or result in nasty merge conflicts with outstanding feature branches.
|
39 |
|
40 | Other tools, such as `lint-staged`, made an excellent first step towards mitigating the scope of the impact of the points above, by only running linters and formatters on files which have changed.
|
41 |
|
42 | This is great for small codebases, in which the authors do not mind much that they are polluting the git history of the files they are touching, but **it is not enough**.
|
43 |
|
44 | In large and enterprise codebases (particularly those organized as monorepos), the git history of each file is really important.
|
45 |
|
46 | > If I make a change on line 10 of a 4000 line file, I shouldn't be forced to reformat all 4000s lines (thus making me the last git user to update all of them) as part of my PR.
|
47 | >
|
48 | > I should just need to reformat line 10.
|
49 |
|
50 | This is where `precise-commits` comes in!
|
51 |
|
52 | <br>
|
53 |
|
54 | # Our ideal end-goal...
|
55 |
|
56 | 1. All developers on our team develop using consistent, automated formatting as they write their code.
|
57 | e.g. Running an IDE-based plugin, such as "vscode-prettier" with "format on save" enabled.
|
58 |
|
59 | 2. Each time they commit, a precommit hook is triggered to _ensure_ that the staged code is formatted consistently.
|
60 |
|
61 | 3. Each time a Pull Request opened on our remote repo, a build is triggered on a CI server, during which the formatting
|
62 | is checked to ensure that all the files touched for that PR were formatted consistently.
|
63 |
|
64 | <br>
|
65 |
|
66 | # How `precise-commits` helps us get there...
|
67 |
|
68 | 1. All developers on our team write their code as they always have.
|
69 |
|
70 | 2. Each time they commit, a precommit hook is triggered which will run `precise-commits` on the code and ensure that **the exact code they already modified** is formatted consistently. Any untouched existing code will not be mutated.
|
71 |
|
72 | 3. Each time a Pull Request opened on our remote repo, a build is triggered on a CI server, during which `precise-commits`
|
73 | runs to ensure that all the **committed lines of code** for that PR was formatted consistently.
|
74 |
|
75 | <br>
|
76 |
|
77 | ...and after enough time has passed, **our codebase will be formatted consistently, despite us never having to disrupt our feature-building momentum!**
|
78 |
|
79 | <br>
|
80 |
|
81 | # How it works
|
82 |
|
83 | Through analyzing your staged files (or any files modified between two given commit SHAs) `precise-commits` will work out exactly what lines and characters within those files have actually been changed or added.
|
84 |
|
85 | It then uses this information to run [Prettier](https://prettier.io) in a very focused way, allowing it to only reformat what is relevant for your current work, and allowing you to keep your PRs small and explicit!
|
86 |
|
87 | <br>
|
88 |
|
89 | # Installation
|
90 |
|
91 | `precise-commits` expects `prettier` to be available as a `peerDependency`, so you will need to install this yourself as a `devDependency` of your project.
|
92 |
|
93 | ```sh
|
94 | npm install --save-dev prettier precise-commits
|
95 | ```
|
96 |
|
97 | <br>
|
98 |
|
99 | # Usage
|
100 |
|
101 | It is intended that you will run `precise-commits` as a CLI, and it will automatically pick up on any of the standard [Prettier configuration files](https://prettier.io/docs/en/configuration) you may have in your project, including [`.prettierignore`](https://prettier.io/docs/en/ignore#ignoring-files) files.
|
102 |
|
103 | ## 1. Running it manually
|
104 |
|
105 | 1. Add an npm script to your package.json, such as:
|
106 |
|
107 | ```js
|
108 | {
|
109 | //...
|
110 | "scripts": {
|
111 | "precise-commits": "precise-commits"
|
112 | }
|
113 | //...
|
114 | }
|
115 | ```
|
116 |
|
117 | 2. Execute the npm script, e.g. for the one above run:
|
118 |
|
119 | ```sh
|
120 | npm run precise-commits
|
121 | ```
|
122 |
|
123 | ## 2. "Precommit" Hook
|
124 |
|
125 | The recommended way to run `precise-commits` is as a "precommit" hook.
|
126 |
|
127 | A great tool for setting up the hook is [`husky`](https://github.com/typicode/husky). You can install and run it as follows:
|
128 |
|
129 | ```sh
|
130 | npm install --save-dev husky
|
131 | ```
|
132 |
|
133 | Update the `"scripts"` section of your `package.json`:
|
134 |
|
135 | ```js
|
136 | {
|
137 | //...
|
138 | "scripts": {
|
139 | "precise-commits": "precise-commits",
|
140 | "precommit": "npm run precise-commits"
|
141 | }
|
142 | //...
|
143 | }
|
144 | ```
|
145 |
|
146 | ## 3. As part of a PR build
|
147 |
|
148 | When running a build for your PR, you can run `precise-commits` to ensure that the author's changes are all formatted consistently.
|
149 |
|
150 | The key things you need to configure are:
|
151 |
|
152 | 1. The `--check-only` flag for `precise-commits` so that it will error out if it finds any inconsistent formatting
|
153 | 2. The `--head` and `--base` flags so that `precise-commits` knows what commits it should consider when resolving modified files. Most CI servers will have environment variables you can use to resolve these.
|
154 |
|
155 | For example, if your PR is building on [Travis](https://travis-ci.com/), your config might look like this:
|
156 |
|
157 | **.travis.yml**
|
158 |
|
159 | ```yaml
|
160 | # ... Other config options here ...
|
161 | install:
|
162 | - yarn install
|
163 | script:
|
164 | - 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then precise-commits --whitelist="src/**/*.ts" --check-only --head=$TRAVIS_PULL_REQUEST_SHA --base=$(git merge-base HEAD $TRAVIS_BRANCH); fi'
|
165 | - yarn test
|
166 | - yarn e2e
|
167 | # ... Other config options here ...
|
168 | ```
|
169 |
|
170 | <br>
|
171 |
|
172 | # CLI Configuration Options
|
173 |
|
174 | As was hinted at above, the `precise-commits` CLI supports a few different configuration options:
|
175 |
|
176 | * `--whitelist`: **[String, Default: `"*"`]**
|
177 | * Whitelist is a glob pattern ([the glob syntax from the glob module is used](https://github.com/isaacs/node-glob/blob/master/README.md#glob-primer)).
|
178 | * It is used to inform what files are considered when resolving modified files (by default all are considered).
|
179 | * Don't forget the quotes around the globs! The quotes make sure that `precise-commits` expands the globs rather than your shell.
|
180 |
|
181 | <br>
|
182 |
|
183 | * `--formatter`: **[String, Default: `"prettier"`]**
|
184 | * Currently only prettier is supported
|
185 | * If you are interested in adding support for a different formatter, all you need to do is provide an object which [implements this interface](https://github.com/JamesHenry/precise-commits/blob/master/src/precise-formatter.ts).
|
186 |
|
187 | <br>
|
188 |
|
189 | * `--check-only`: **[Boolean, Default: `false`]**
|
190 | * Only check the code formatting is consistent with the resolved config
|
191 |
|
192 | <br>
|
193 |
|
194 | * `--base`: **[String, NO DEFAULT]**
|
195 | * Base commit SHA to be used in conjunction with the `--head` flag
|
196 |
|
197 | <br>
|
198 |
|
199 | * `--head`: **[String, CONDITIONAL DEFAULT]**
|
200 | * Later commit SHA (e.g. the `HEAD` of a PR branch) to be used in conjunction with the `--base` flag
|
201 | * NOTE on conditional default: If no value is provided for `--head`, but a value is given for `--base`, it will default to checking "HEAD"
|