OverviewFilesCommitsIssuesDocsReleasesPeers

pgh / scripts / hooks / pre-commit-version-guard.sh

56 lines · bash ref:
#!/bin/sh
# pre-commit-version-guard — prevent dep-tree drift at the source.
#
# The fleet's file: workspace packages (hyper-overlay, hyper-deploy, …) are
# bundled by every app that depends on them. If a package's CONTENT changes
# without its version being bumped, two apps published before/after that commit
# ship different bytes under the SAME version → BUILD_SKEW at publish time.
#
# This hook blocks exactly that: if a commit changes any tracked file other
# than packaging metadata (package.json / package-lock.json / lockfiles), it
# must ALSO bump the version in package.json. Override with `git commit
# --no-verify` for genuine no-bump commits (docs typo, CI tweak).
#
# Installed per-repo by scripts/install-version-guard.sh.

set -e

# No package.json ⇒ nothing to guard.
[ -f package.json ] || exit 0

staged=$(git diff --cached --name-only --diff-filter=ACMR)
[ -z "$staged" ] && exit 0

# Content = anything that changes the RUNTIME tree. Mirror C's normalization:
# exclude packaging metadata, top-level dev/test/CI dirs, and docs — a change
# confined to those doesn't alter the normalized hash, so it can't skew and
# doesn't need a bump. Everything else (lib/, src/, index.js, scripts/, native)
# counts.
content=$(printf '%s\n' "$staged" \
  | grep -vE '^(package\.json|package-lock\.json|\.pgh-lock\.json|pnpm-lock\.yaml|yarn\.lock)$' \
  | grep -vE '^(test|tests|__tests__|example|examples|demo|demos|bench|benchmark|benchmarks|docs|doc|coverage|fixtures|\.github|\.circleci|\.husky)/' \
  | grep -vEi '^(readme|license|licence|changelog|history|notice|authors|contributors|copying)([.-]|$)' \
  | grep -vE '\.(md|markdown|txt)$' \
  | grep -vE '^\.(npmignore|gitignore|gitattributes|editorconfig|npmrc|nvmrc|prettierrc|prettierignore|eslintrc|eslintignore|babelrc|travis\.yml)' \
  || true)
[ -z "$content" ] && exit 0   # only metadata/dev/docs staged → no bump needed

# Did package.json's version field change vs HEAD?
old_ver=$(git show HEAD:package.json 2>/dev/null | grep '"version"' | head -1 | tr -d ' ')
new_ver=$(grep '"version"' package.json | head -1 | tr -d ' ')

if [ "$old_ver" = "$new_ver" ]; then
  pkg=$(grep '"name"' package.json | head -1 | sed 's/.*"name"[^"]*"\([^"]*\)".*/\1/')
  echo "✗ version-bump-guard: content changed in '$pkg' but the version is unchanged ($new_ver)."
  echo ""
  printf '%s\n' "$content" | sed 's/^/    /'
  echo ""
  echo "  This is a file: workspace package — shipping new bytes under an unchanged"
  echo "  version causes BUILD_SKEW across the apps that bundle it. Bump the version:"
  echo "      npm version patch --no-git-tag-version   (or edit package.json)"
  echo "  Genuinely no-op for consumers (docs/CI only)? Override: git commit --no-verify"
  exit 1
fi

exit 0