Skip to content

Commit 654d99f

Browse files
authored
Chore: Replace Husky/Lint-staged with Lefthook (#66608)
* Switch from husky+precommit to lefthook Migrate from husky/precommit to lefthook h old husky precommit lefthook so far remove husky folder switch to new lefthook package Add postinstall script to clean up after husky preinstall to remove husky config package.json package.json package.json script v Reduce lefthook output Cleanup testing reduce output testing betterer testing betterer testing betterer testing betterer testing betterer testing betterer testing betterer skip skipping execution info small cleanup remove comment from testing clean up old husky hooks in .git/hooks path run scripts in parallel update codeowners don't auto-install lefthook install lefthook with make command fix yarn checksum * update codeowners * don't use source because it isn't available in ubuntu/debian's /bin/sh * Ensure lefthook commits files fixed by precommit hooks * add comment to lefthook.rc explaining what it does * add i18n:pseudo precommit * Don't create .husky/safe-to-delete file anymore * cleanup old lint-staged config * contribute docs * update lefthook to 1.4.8 * Move frontend encouragement docs * rewrite husky cleanup script in bash so we can run it with make * Make old husky precommit script reject commits until husky is removed * log precommit warning for everyone * fix package.json * run lefthook hooks from old husky hook * run lefthook hooks from old husky hook * comments * codeowners * codeowners
1 parent 3463dc8 commit 654d99f

14 files changed

+731
-239
lines changed

.bingo/Variables.mk

+6
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ $(JB): $(BINGO_DIR)/jb.mod
4747
@echo "(re)installing $(GOBIN)/jb-v0.5.1"
4848
@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=jb.mod -o=$(GOBIN)/jb-v0.5.1 "github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb"
4949

50+
LEFTHOOK := $(GOBIN)/lefthook-v1.4.8
51+
$(LEFTHOOK): $(BINGO_DIR)/lefthook.mod
52+
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
53+
@echo "(re)installing $(GOBIN)/lefthook-v1.4.8"
54+
@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=lefthook.mod -o=$(GOBIN)/lefthook-v1.4.8 "github.com/evilmartians/lefthook"
55+
5056
SWAGGER := $(GOBIN)/swagger-v0.30.2
5157
$(SWAGGER): $(BINGO_DIR)/swagger.mod
5258
@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.

.bingo/lefthook.mod

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
2+
3+
go 1.20
4+
5+
require github.com/evilmartians/lefthook v1.4.8

.bingo/lefthook.sum

+523
Large diffs are not rendered by default.

.bingo/variables.env

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ GOLANGCI_LINT="${GOBIN}/golangci-lint-v1.53.3"
1818

1919
JB="${GOBIN}/jb-v0.5.1"
2020

21+
LEFTHOOK="${GOBIN}/lefthook-v1.4.8"
22+
2123
SWAGGER="${GOBIN}/swagger-v0.30.2"
2224

2325
WIRE="${GOBIN}/wire-v0.5.0"

.github/CODEOWNERS

+4-1
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,6 @@ tsconfig.json @grafana/frontend-ops
335335
/.eslintignore @grafana/frontend-ops
336336
/.gitattributes @grafana/frontend-ops
337337
/.gitignore @grafana/frontend-ops
338-
/.husky/pre-commit @grafana/frontend-ops
339338
/.nvmrc @grafana/frontend-ops
340339
/.prettierignore @grafana/frontend-ops
341340
/.yarn @grafana/frontend-ops
@@ -352,6 +351,9 @@ lerna.json @grafana/frontend-ops
352351
/metadata.md @grafana/plugins-platform
353352
/stylelint.config.js @grafana/frontend-ops
354353
/tools/ @grafana/frontend-ops
354+
/lefthook.yml @grafana/frontend-ops
355+
/lefthook.rc @grafana/frontend-ops
356+
.husky/pre-commit @grafana/frontend-ops
355357

356358

357359
# public folder
@@ -493,6 +495,7 @@ lerna.json @grafana/frontend-ops
493495
/scripts/trigger_docker_build.sh @grafana/grafana-delivery
494496
/scripts/trigger_grafana_packer.sh @grafana/grafana-delivery
495497
/scripts/trigger_windows_build.sh @grafana/grafana-delivery
498+
/scripts/cleanup-husky.sh @grafana/frontend-ops
496499
/scripts/verify-repo-update/ @grafana/grafana-delivery
497500

498501
/scripts/webpack/ @grafana/frontend-ops

.husky/pre-commit

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
11
#!/bin/sh
22

3-
# Ignore husky hooks if no frontend code has been changed
4-
git diff --cached --name-only | grep -v --quiet "^pkg/" || exit 0
3+
# Catch devs who have installed lefthook, went back into the past and reinstalled husky,
4+
# then came back into lefthook-land.
5+
if [ -f ".git/hooks/pre-commit" ]; then
6+
if grep -q lefthook ".git/hooks/pre-commit"; then
7+
# Remove husky from their git config
8+
env SILENT=1 ./scripts/cleanup-husky.sh
59

6-
. "$(dirname "$0")/_/husky.sh"
10+
# And run the lefthook precommit hook instead of this
11+
./.git/hooks/pre-commit "$@"
12+
exit $?
13+
fi
14+
fi
715

8-
yarn run precommit
16+
# This precommit hook exists only for people who still have hooksPath=.husky in their git config
17+
# from when we used husky. This is intended to run only on first commit after pulling the lefthook changes.
18+
#
19+
# Either setting up lefthook, or running the clean command will unset the hooksPath git config so this
20+
# hook is no longer ran when committing.
21+
22+
echo "\n⚠️⚠️⚠️ \e[1mImportant: Pre-commit hooks are now opt-in.\e[0m ⚠️⚠️⚠️"
23+
echo "To install the new pre-commit hooks:"
24+
echo " $ \e[96mmake lefthook-install\e[0m"
25+
echo "Or, silence this message by cleaning up the old hooks"
26+
echo " $ \e[96mmake cleanup-old-git-hooks\e[0m"
27+
echo "\nPre-commit hooks will not run on this commit and it will be committed even if it contains lint errors."
28+
echo "See https://github.com/grafana/grafana/blob/main/contribute/developer-guide.md#configure-precommit-hooks for more info\n"
29+
30+
exit 0

Makefile

+12
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ validate-api-spec: $(MERGED_SPEC_TARGET) $(SWAGGER) ## Validate API spec
6262
clean-api-spec:
6363
rm -f $(SPEC_TARGET) $(MERGED_SPEC_TARGET) $(OAPI_SPEC_TARGET)
6464

65+
.PHONY: cleanup-old-git-hooks
66+
cleanup-old-git-hooks:
67+
./scripts/cleanup-husky.sh
68+
69+
.PHONY: lefthook-install
70+
lefthook-install: cleanup-old-git-hooks $(LEFTHOOK) # install lefthook for pre-commit hooks
71+
$(LEFTHOOK) install -f
72+
73+
.PHONY: lefthook-uninstall
74+
lefthook-uninstall: $(LEFTHOOK)
75+
$(LEFTHOOK) uninstall
76+
6577
##@ OpenAPI 3
6678
OAPI_SPEC_TARGET = public/openapi3.json
6779

contribute/create-pull-request.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ We know you're excited to create your first pull request. Before we get started,
88

99
- Learn how to start [Contributing to Grafana](/CONTRIBUTING.md).
1010
- Make sure your code follows the relevant [style guides](/contribute/style-guides).
11+
- It's recommened you [set up precommit hooks](/contribute/developer-guide.md) to auto-format when you commit
1112

1213
## Your first pull request
1314

contribute/developer-guide.md

+19
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,25 @@ it's as easy as running `yarn dlx @yarnpkg/sdks vscode` or `yarn dlx @yarnpkg/sd
4545

4646
More information can be found [here](https://yarnpkg.com/getting-started/editor-sdks).
4747

48+
### Configure precommit hooks
49+
50+
We use pre-commit hooks (via [lefthook](https://github.com/evilmartians/lefthook)) to lint, fix, and format code as you commit your changes. Previously the Grafana repository automatically installed these hook when you did `yarn install`, but they are now opt in for all contributors
51+
52+
Install the lefthook precommit hooks with:
53+
54+
```sh
55+
make lefthook-install
56+
```
57+
58+
To remove precommit hooks, run
59+
60+
```sh
61+
make lefthook-uninstall
62+
```
63+
64+
> [!NOTE]
65+
> Contributors working on the frontend are highly encouraged to install the precommit hooks, even if your IDE formats on save, so the `.betterer.results` file is kept up to sync.
66+
4867
## Build Grafana
4968

5069
Grafana consists of two components; the _frontend_, and the _backend_.

lefthook.rc

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This file is used by lefthook to 'expose' the bingo-installed lefthook under
2+
# the name `lefthook`, as expected by the lefthook pre-commit scripts
3+
4+
. .bingo/variables.env
5+
6+
lefthook () {
7+
${LEFTHOOK} "$@"
8+
}

lefthook.yml

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
skip_output:
2+
- meta
3+
- execution_out
4+
- skips
5+
6+
min_version: 1.4.3
7+
8+
rc: ./lefthook.rc
9+
10+
pre-commit:
11+
parallel: true
12+
commands:
13+
frontend-betterer:
14+
glob: '*.{ts,tsx}'
15+
run: yarn betterer precommit {staged_files}
16+
stage_fixed: true
17+
18+
frontend-lint:
19+
glob: '*.{js,ts,tsx}'
20+
run: |
21+
yarn eslint --ext .js,.tsx,.ts --cache --fix {staged_files}
22+
yarn prettier --write {staged_files}
23+
stage_fixed: true
24+
25+
internationalization:
26+
glob: 'public/locales/en-US/grafana.json'
27+
run: yarn i18n:pseudo
28+
stage_fixed: true
29+
30+
other-format:
31+
glob: '*.{json,scss,md,mdx}'
32+
run: yarn prettier --write {staged_files}
33+
stage_fixed: true
34+
35+
backend-format:
36+
glob: '*pkg/**/*.go'
37+
run: gofmt -w -s {staged_files}
38+
stage_fixed: true
39+
40+
cue-fix-kinds:
41+
glob: '*kinds/**/*.cue'
42+
run: make fix-cue
43+
stage_fixed: true
44+
45+
cue-fix-public:
46+
glob: '*public/app/plugins/**/**/*.cue'
47+
run: make fix-cue
48+
stage_fixed: true

package.json

-28
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
"packages:prepare": "lerna version --no-push --no-git-tag-version --force-publish --exact",
3131
"packages:pack": "mkdir -p ./npm-artifacts && lerna exec --no-private -- yarn pack --out \"../../npm-artifacts/%s-%v.tgz\"",
3232
"packages:typecheck": "lerna run typecheck",
33-
"precommit": "yarn run lint-staged",
3433
"prettier:check": "prettier --check --list-different=false --log-level=warn \"**/*.{ts,tsx,scss,md,mdx}\"",
3534
"prettier:checkDocs": "prettier --check --list-different=false --log-level=warn \"docs/**/*.md\" \"*.md\" \"packages/**/*.{ts,tsx,scss,md,mdx}\"",
3635
"prettier:write": "prettier --list-different \"**/*.{js,ts,tsx,scss,md,mdx}\" --write",
@@ -46,7 +45,6 @@
4645
"plugins:build-bundled": "find plugins-bundled -name package.json -not -path '*/node_modules/*' -execdir yarn build \\;",
4746
"watch": "yarn start -d watch,start core:start --watchTheme",
4847
"ci:test-frontend": "yarn run test:ci",
49-
"postinstall": "husky install",
5048
"i18n:clean": "rimraf public/locales/en-US/grafana.json",
5149
"i18n:extract": "yarn run i18next -c public/locales/i18next-parser.config.js 'public/**/*.{tsx,ts}' 'packages/grafana-ui/**/*.{tsx,ts}'",
5250
"i18n:compile": "echo 'no i18n compile yet, all good'",
@@ -60,30 +58,6 @@
6058
"whatsNewUrl": "https://grafana.com/docs/grafana/next/whatsnew/whats-new-in-v10-0/",
6159
"releaseNotesUrl": "https://grafana.com/docs/grafana/next/release-notes/"
6260
},
63-
"lint-staged": {
64-
"*.{ts,tsx}": [
65-
"betterer precommit"
66-
],
67-
"*.{js,ts,tsx}": [
68-
"eslint --ext .js,.tsx,.ts --cache --fix",
69-
"prettier --write"
70-
],
71-
"*.{json,scss,md,mdx}": [
72-
"prettier --write"
73-
],
74-
"*pkg/**/*.go": [
75-
"gofmt -w -s"
76-
],
77-
"*kinds/**/*.cue": [
78-
"make fix-cue"
79-
],
80-
"*public/app/plugins/**/**/*.cue": [
81-
"make fix-cue"
82-
],
83-
"./public/locales/en-US/grafana.json": [
84-
"yarn i18n:pseudo"
85-
]
86-
},
8761
"devDependencies": {
8862
"@babel/core": "7.22.9",
8963
"@babel/plugin-proposal-class-properties": "7.18.6",
@@ -206,7 +180,6 @@
206180
"html-loader": "4.2.0",
207181
"html-webpack-plugin": "5.5.3",
208182
"http-server": "14.1.1",
209-
"husky": "8.0.3",
210183
"i18next-parser": "6.6.0",
211184
"jest": "29.3.1",
212185
"jest-canvas-mock": "2.5.2",
@@ -216,7 +189,6 @@
216189
"jest-junit": "16.0.0",
217190
"jest-matcher-utils": "29.3.1",
218191
"lerna": "5.5.4",
219-
"lint-staged": "13.2.3",
220192
"mini-css-extract-plugin": "2.7.6",
221193
"msw": "1.2.2",
222194
"mutationobserver-shim": "0.3.7",

scripts/cleanup-husky.sh

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
5+
6+
# Husky modified your git config to store git hooks in the repo, so do that change
7+
currentHooksPath=$(git config core.hooksPath || true)
8+
if [[ $currentHooksPath == ".husky" ]]; then
9+
if [ -z "$SILENT" ]; then
10+
echo "Unsetting git hooks path because it was previously set to .husky."
11+
echo "If you had custom git hooks in .husky you may want to move them to .git/hooks"
12+
fi
13+
14+
git config --unset core.hooksPath
15+
fi
16+
17+
oldHuskyHookNames=(
18+
"applypatch-msg"
19+
"commit-msg"
20+
"post-applypatch"
21+
"post-checkout"
22+
"post-commit"
23+
"post-merge"
24+
"post-receive"
25+
"post-rewrite"
26+
"post-update"
27+
"pre-applypatch"
28+
"pre-auto-gc"
29+
"pre-merge-commit"
30+
"pre-push"
31+
"pre-rebase"
32+
"pre-receive"
33+
"push-to-checkout"
34+
"sendemail-validate"
35+
"update"
36+
)
37+
38+
#
39+
# Also extra-old husky dumped a bunch of hooks into .git/hooks, so check for them
40+
# and rename them so they don't run
41+
for hookName in "${oldHuskyHookNames[@]}"; do
42+
hookPath=".git/hooks/$hookName"
43+
44+
if [[ -f $hookPath ]]; then
45+
if grep -q husky "$hookPath"; then
46+
newHookPath="$hookPath.old"
47+
48+
if [ -z "$SILENT" ]; then
49+
echo "Renaming old husky hook $hookPath to $newHookPath"
50+
fi
51+
52+
mv "$hookPath" "$newHookPath" --suffix=old --backup=numbered
53+
fi
54+
fi
55+
done

0 commit comments

Comments
 (0)