From 035fcec27c46e042a42fdf348a959e160fd3a693 Mon Sep 17 00:00:00 2001 From: zi0w Date: Sun, 25 Jan 2026 21:27:43 +0900 Subject: [PATCH 1/3] chore: add opt-in pre-commit lint --write hook --- .githooks/pre-commit | 54 ++++++++++++++++++++++++++++++++++++ .github/maintainers_guide.md | 20 +++++++++++++ 2 files changed, 74 insertions(+) create mode 100755 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 000000000..527ba178e --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,54 @@ +#!/bin/sh +set -e + +changed_paths=$(git diff --name-only --cached --diff-filter=ACMR) +if [ -z "$changed_paths" ]; then + exit 0 +fi + +repo_root=$(git rev-parse --show-toplevel 2>/dev/null) +if [ -z "$repo_root" ]; then + exit 1 +fi + +cd "$repo_root" + +packages="" +for path in $changed_paths; do + case "$path" in + packages/*/*) + pkg=${path#packages/} + pkg=${pkg%%/*} + case " $packages " in + *" $pkg "*) ;; + *) packages="$packages $pkg" ;; + esac + ;; + esac +done + +if [ -z "$packages" ]; then + exit 0 +fi + +run_lint() { + pkg_dir="$1" + pkg_json="$repo_root/$pkg_dir/package.json" + + if node -e "const p=require(process.argv[1]);process.exit(p.scripts&&p.scripts['lint:fix']?0:1)" "$pkg_json"; then + echo "[pre-commit] npm --prefix $pkg_dir run lint:fix" + npm --prefix "$pkg_dir" run lint:fix + elif node -e "const p=require(process.argv[1]);process.exit(p.scripts&&p.scripts.lint?0:1)" "$pkg_json"; then + echo "[pre-commit] npm --prefix $pkg_dir run lint -- --fix" + npm --prefix "$pkg_dir" run lint -- --fix + fi + + git add -u "$pkg_dir" +} + +for pkg in $packages; do + pkg_dir="packages/$pkg" + if [ -f "$pkg_dir/package.json" ]; then + run_lint "$pkg_dir" + fi +done diff --git a/.github/maintainers_guide.md b/.github/maintainers_guide.md index 2df2f8483..e1eeafabe 100644 --- a/.github/maintainers_guide.md +++ b/.github/maintainers_guide.md @@ -18,8 +18,28 @@ npm run lint npm test --workspace packages/web-api ``` +#### Pre-commit lint hook (optional) +We provide an opt-in Git hook that runs npm run lint from the repository root before a commit is created. + +Enable it once per clone: + +```sh +git config core.hooksPath .githooks +``` + +Disable it: + +```sh +git config --unset core.hooksPath +``` + +Notes: +- The hook runs npm run lint from the repository root. +- You can skip it with git commit --no-verify if needed. + This project has tests for individual packages as `*.spec.js` files and inside of each package's `src` directory. Also, for verifying the behavior with the real Slack server-side and developer experience with installed packages, you can run the tests amd scripts under `prod-server-integration-tests`. Refer to the README file in the directory for details. These tests are supposed to be run in the project maintainers' manual execution. They are not part of CI builds for now. + Upon opening a PR, tests are executed by GitHub Actions, our continuous integration system. GitHub Actions runs several, more granular builds in order to report on success and failure in a more targeted way. - There is one build for each package on each supported version of Node, as well as one for the integration tests on each supported version of Node. From 486177f2238682a6862b191aab531c3966dc8299 Mon Sep 17 00:00:00 2001 From: zi0w Date: Wed, 28 Jan 2026 00:09:44 +0900 Subject: [PATCH 2/3] chore: simplify pre-commit hook --- .githooks/pre-commit | 70 ++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 527ba178e..7dbea61fc 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -1,54 +1,28 @@ #!/bin/sh set -e -changed_paths=$(git diff --name-only --cached --diff-filter=ACMR) -if [ -z "$changed_paths" ]; then - exit 0 -fi +cd "$(git rev-parse --show-toplevel)" || exit 1 -repo_root=$(git rev-parse --show-toplevel 2>/dev/null) -if [ -z "$repo_root" ]; then - exit 1 -fi - -cd "$repo_root" - -packages="" -for path in $changed_paths; do - case "$path" in - packages/*/*) - pkg=${path#packages/} - pkg=${pkg%%/*} - case " $packages " in - *" $pkg "*) ;; - *) packages="$packages $pkg" ;; - esac - ;; - esac -done +pkgs=$(git diff --cached --name-only --diff-filter=ACMR -- 'packages/*/*' \ + | cut -d/ -f2 | sort -u) + +[ -z "$pkgs" ] && exit 0 + +for pkg in $pkgs; do + dir="packages/$pkg" + [ -f "$dir/package.json" ] || continue -if [ -z "$packages" ]; then - exit 0 -fi - -run_lint() { - pkg_dir="$1" - pkg_json="$repo_root/$pkg_dir/package.json" - - if node -e "const p=require(process.argv[1]);process.exit(p.scripts&&p.scripts['lint:fix']?0:1)" "$pkg_json"; then - echo "[pre-commit] npm --prefix $pkg_dir run lint:fix" - npm --prefix "$pkg_dir" run lint:fix - elif node -e "const p=require(process.argv[1]);process.exit(p.scripts&&p.scripts.lint?0:1)" "$pkg_json"; then - echo "[pre-commit] npm --prefix $pkg_dir run lint -- --fix" - npm --prefix "$pkg_dir" run lint -- --fix - fi - - git add -u "$pkg_dir" -} - -for pkg in $packages; do - pkg_dir="packages/$pkg" - if [ -f "$pkg_dir/package.json" ]; then - run_lint "$pkg_dir" - fi + echo "[pre-commit] $dir" + + out="$(npm --prefix "$dir" run -s lint:fix 2>&1)" && { git add -u "$dir"; continue; } + + echo "$out" | grep -qi 'missing script:.*lint:fix' && { + out2="$(npm --prefix "$dir" run -s lint -- --fix 2>&1)" && { git add -u "$dir"; continue; } + echo "$out2" | grep -qi 'missing script:.*lint' && { echo "[pre-commit] no lint script, skipping"; continue; } + echo "$out2" >&2 + exit 1 + } + + echo "$out" >&2 + exit 1 done From b3cea66190d3a494dd0ddc71ab3701d3495acc27 Mon Sep 17 00:00:00 2001 From: zi0w Date: Wed, 28 Jan 2026 01:37:30 +0900 Subject: [PATCH 3/3] chore: show lint output in pre-commit hook --- .githooks/pre-commit | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 7dbea61fc..39d61d96e 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -14,15 +14,20 @@ for pkg in $pkgs; do echo "[pre-commit] $dir" - out="$(npm --prefix "$dir" run -s lint:fix 2>&1)" && { git add -u "$dir"; continue; } - - echo "$out" | grep -qi 'missing script:.*lint:fix' && { - out2="$(npm --prefix "$dir" run -s lint -- --fix 2>&1)" && { git add -u "$dir"; continue; } - echo "$out2" | grep -qi 'missing script:.*lint' && { echo "[pre-commit] no lint script, skipping"; continue; } - echo "$out2" >&2 - exit 1 - } - - echo "$out" >&2 + tmp="$(mktemp)" + if npm --prefix "$dir" run lint:fix 2>&1 | tee "$tmp"; then + rm -f "$tmp" + git add -u "$dir" + continue + fi + + if grep -qi 'missing script:.*lint:fix' "$tmp"; then + rm -f "$tmp" + npm --prefix "$dir" run lint -- --fix + git add -u "$dir" + continue + fi + + rm -f "$tmp" exit 1 -done +done \ No newline at end of file