git-quality
v1.0.0
Published
A set of scripts offering a nice workflow for ensuring code quality and transforms.
Downloads
2
Readme
git-quality
A set of scripts offering a nice workflow for ensuring code quality and transforms.
Install
npm i -D CINBCUniversal/git-quality
CLI Commands
There are two CLI commands:
transform-index-and-commit
transform-index-and-commit
runs a transform script over the content of the index ("staged files") for appropriate files and commits the transformed code. The files are the content of the index, and do NOT include unstaged changes :) The passed in transform script will receive the file as a parameter, if it matches the file extension filter.
transform-index-and-commit "<script>" "<file extension filter>"
transform-index-and-commit "prettier --write" ".ts"
assert-on-head
assert-on-head
runs an assertion script on the content of HEAD. The files do NOT include unstaged/untracked changes :)
transform-index-and-commit "<script>" "<file extension filter>"
transform-index-and-commit "prettier --write" ".ts"
Example
This example uses husky to gain access to a pre-push hook.
In your project, install this lib and husky:
npm i -D husky CINBCUniversal/git-quality husky
In your package.json:
{
"scripts": {
"commit": "transform-index-and-commit 'prettier --write' '.ts'",
"prepush": "assert-on-head 'npm run test'",
"test": "jest && tslint 'src/**/*.ts' && prettier -l 'src/**/*.ts'"
}
}
This creates a script npm run commit
that can be used to transform code to be committed. It also exposes a script npm run prepush
which is applied as a git hook using husky, in this case on pre-push.
FAQ
Why make users opt-in by having to run npm run commit
rather than not just using husky with lint-staged to automatically apply the transform?
Right, with lint-staged, you could do:
+ "lint-staged": {
+ "src/**/*.{ts}": [
+ "prettier --write",
+ "git add"
+ ]
+ },
"scripts": {
+ "precommit": "lint-staged"
}
The problem is two-fold.
- Small issue: This applies the transform on the "real" file, not the file with only the staged changes applied. This means that the act of committing causes side-effects outside the scope of the files with only the staged changes applied. If you have other work in the file that you are not committing, it will also be transformed. This isn't that big of a deal, but undesired.
- Big Issue: Regardless of the transform function, lint-stage must follow it with
git add
ing the whole file. This is a big footgun. If only part of the file was staged, with this hook the act of runninggit commit
will end up adding and then subsequently commiting the entire file, implicitly and without your consent.
In order to overcome this with git-quality: the staged changes are committed, unstaged/untracked changes stashed, transform run and git added, a silent git commit ammending these changes, and then orginial changes unstashed. Because a git commit is actually used, this is the only path forward I found.
There is also something to be said, philosophically, about not overriding necessary tooling with implementation details and instead let developers own these details, offering simple scripts like npm run commit
as convenience, or directions on integrating tooling with their IDE (as could be done with this prettier use case). See the next question.
I have the opposite complaint of the first FAQ. Why would you suggest hijacking git's push command with a hook?
I am sympathetic to not hijacking neutral tooling to ensure implementation details. While commits may mark a journey, with the intention of squashing, a push typically marks completion and is the last possible catch before a PR and CI. At this point the code should be complete, and there is considerable value in tightening the feedback loop. Why move on only to have CI catch a formatting/linting/tests issue? If you are pushing incomplete work for sharing / review / saving, simply apply --no-verify.
Or, simply don't use husky with these scripts. git-quality
has no dependency / peer-dependency on husky unless you want it. Instead of prepush hook, offer a script that the developer can run at their own choosing:
"scripts": {
"test": "assert-on-head 'npm run _test'",
"_test": "jest && tslint 'src/**/*.ts' && prettier -l 'src/**/*.ts'"
}