Browse Source
- Add pre-commit and pre-push hooks for build file protection - Create comprehensive guard script for BUILDING.md validation - Add npm scripts for guard setup and testing - Integrate with existing build systemdialog-styles-unified
6 changed files with 296 additions and 0 deletions
@ -0,0 +1,40 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
# |
||||
|
# Husky Helper Script |
||||
|
# This file is sourced by all Husky hooks |
||||
|
# |
||||
|
if [ -z "$husky_skip_init" ]; then |
||||
|
debug () { |
||||
|
if [ "$HUSKY_DEBUG" = "1" ]; then |
||||
|
echo "husky (debug) - $1" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
readonly hook_name="$(basename -- "$0")" |
||||
|
debug "starting $hook_name..." |
||||
|
|
||||
|
if [ "$HUSKY" = "0" ]; then |
||||
|
debug "HUSKY env variable is set to 0, skipping hook" |
||||
|
exit 0 |
||||
|
fi |
||||
|
|
||||
|
if [ -f ~/.huskyrc ]; then |
||||
|
debug "sourcing ~/.huskyrc" |
||||
|
. ~/.huskyrc |
||||
|
fi |
||||
|
|
||||
|
readonly husky_skip_init=1 |
||||
|
export husky_skip_init |
||||
|
sh -e "$0" "$@" |
||||
|
exitCode="$?" |
||||
|
|
||||
|
if [ $exitCode != 0 ]; then |
||||
|
echo "husky - $hook_name hook exited with code $exitCode (error)" |
||||
|
fi |
||||
|
|
||||
|
if [ $exitCode = 127 ]; then |
||||
|
echo "husky - command not found in PATH=$PATH" |
||||
|
fi |
||||
|
|
||||
|
exit $exitCode |
||||
|
fi |
@ -0,0 +1,10 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
# |
||||
|
# Husky Commit Message Hook |
||||
|
# Validates commit message format using commitlint |
||||
|
# |
||||
|
. "$(dirname -- "$0")/_/husky.sh" |
||||
|
|
||||
|
# Run commitlint but don't fail the commit (|| true) |
||||
|
# This provides helpful feedback without blocking commits |
||||
|
npx commitlint --edit "$1" || true |
@ -0,0 +1,15 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
# |
||||
|
# Husky Pre-commit Hook |
||||
|
# Runs Build Architecture Guard to check staged files |
||||
|
# |
||||
|
. "$(dirname -- "$0")/_/husky.sh" |
||||
|
|
||||
|
echo "🔍 Running Build Architecture Guard (pre-commit)..." |
||||
|
bash ./scripts/build-arch-guard.sh --staged || { |
||||
|
echo |
||||
|
echo "💡 To bypass this check for emergency commits, use:" |
||||
|
echo " git commit --no-verify" |
||||
|
echo |
||||
|
exit 1 |
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
# |
||||
|
# Husky Pre-push Hook |
||||
|
# Runs Build Architecture Guard to check commits being pushed |
||||
|
# |
||||
|
. "$(dirname -- "$0")/_/husky.sh" |
||||
|
|
||||
|
echo "🔍 Running Build Architecture Guard (pre-push)..." |
||||
|
|
||||
|
# Get the remote branch we're pushing to |
||||
|
REMOTE_BRANCH="origin/$(git rev-parse --abbrev-ref HEAD)" |
||||
|
|
||||
|
# Check if remote branch exists |
||||
|
if git show-ref --verify --quiet "refs/remotes/$REMOTE_BRANCH"; then |
||||
|
RANGE="$REMOTE_BRANCH...HEAD" |
||||
|
else |
||||
|
# If remote branch doesn't exist, check last commit |
||||
|
RANGE="HEAD~1..HEAD" |
||||
|
fi |
||||
|
|
||||
|
bash ./scripts/build-arch-guard.sh --range "$RANGE" || { |
||||
|
echo |
||||
|
echo "💡 To bypass this check for emergency pushes, use:" |
||||
|
echo " git push --no-verify" |
||||
|
echo |
||||
|
exit 1 |
||||
|
} |
@ -0,0 +1,187 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
# |
||||
|
# Build Architecture Guard Script |
||||
|
# |
||||
|
# Author: Matthew Raymer |
||||
|
# Date: 2025-08-20 |
||||
|
# Purpose: Protects build-critical files by requiring BUILDING.md updates |
||||
|
# |
||||
|
# Usage: |
||||
|
# ./scripts/build-arch-guard.sh --staged # Check staged files (pre-commit) |
||||
|
# ./scripts/build-arch-guard.sh --range # Check range (pre-push) |
||||
|
# ./scripts/build-arch-guard.sh # Check working directory |
||||
|
# |
||||
|
|
||||
|
set -euo pipefail |
||||
|
|
||||
|
# Sensitive paths that require BUILDING.md updates when modified |
||||
|
SENSITIVE=( |
||||
|
"vite.config.*" |
||||
|
"scripts/**" |
||||
|
"electron/**" |
||||
|
"android/**" |
||||
|
"ios/**" |
||||
|
"sw_scripts/**" |
||||
|
"sw_combine.js" |
||||
|
"Dockerfile" |
||||
|
"docker/**" |
||||
|
"capacitor.config.ts" |
||||
|
"package.json" |
||||
|
"package-lock.json" |
||||
|
"yarn.lock" |
||||
|
"pnpm-lock.yaml" |
||||
|
) |
||||
|
|
||||
|
# Documentation files that must be updated alongside sensitive changes |
||||
|
DOCS_REQUIRED=("BUILDING.md") |
||||
|
|
||||
|
# Colors for output |
||||
|
RED='\033[0;31m' |
||||
|
GREEN='\033[0;32m' |
||||
|
YELLOW='\033[1;33m' |
||||
|
BLUE='\033[0;34m' |
||||
|
NC='\033[0m' # No Color |
||||
|
|
||||
|
log_info() { |
||||
|
echo -e "${BLUE}[guard]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_warn() { |
||||
|
echo -e "${YELLOW}[guard]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_error() { |
||||
|
echo -e "${RED}[guard]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
log_success() { |
||||
|
echo -e "${GREEN}[guard]${NC} $1" |
||||
|
} |
||||
|
|
||||
|
# Collect files based on mode |
||||
|
collect_files() { |
||||
|
if [[ "${1:-}" == "--staged" ]]; then |
||||
|
# Pre-commit: check staged files |
||||
|
git diff --name-only --cached |
||||
|
elif [[ "${1:-}" == "--range" ]]; then |
||||
|
# Pre-push: check commits being pushed |
||||
|
RANGE="${2:-HEAD~1..HEAD}" |
||||
|
git diff --name-only "$RANGE" |
||||
|
else |
||||
|
# Default: check working directory changes |
||||
|
git diff --name-only HEAD |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Check if a file matches any sensitive pattern |
||||
|
matches_sensitive() { |
||||
|
local f="$1" |
||||
|
for pat in "${SENSITIVE[@]}"; do |
||||
|
# Convert glob pattern to regex |
||||
|
local rx="^${pat//\./\.}$" |
||||
|
rx="${rx//\*\*/.*}" |
||||
|
rx="${rx//\*/[^/]*}" |
||||
|
|
||||
|
if [[ "$f" =~ $rx ]]; then |
||||
|
return 0 |
||||
|
fi |
||||
|
done |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
# Check if documentation was updated |
||||
|
check_docs_updated() { |
||||
|
local changed_files=("$@") |
||||
|
|
||||
|
for changed_file in "${changed_files[@]}"; do |
||||
|
for required_doc in "${DOCS_REQUIRED[@]}"; do |
||||
|
if [[ "$changed_file" == "$required_doc" ]]; then |
||||
|
return 0 |
||||
|
fi |
||||
|
done |
||||
|
done |
||||
|
return 1 |
||||
|
} |
||||
|
|
||||
|
# Main guard logic |
||||
|
main() { |
||||
|
local mode="${1:-}" |
||||
|
local arg="${2:-}" |
||||
|
|
||||
|
log_info "Running Build Architecture Guard..." |
||||
|
|
||||
|
# Collect changed files |
||||
|
mapfile -t changed_files < <(collect_files "$mode" "$arg") |
||||
|
|
||||
|
if [[ ${#changed_files[@]} -eq 0 ]]; then |
||||
|
log_info "No files changed, guard check passed" |
||||
|
exit 0 |
||||
|
fi |
||||
|
|
||||
|
log_info "Checking ${#changed_files[@]} changed files..." |
||||
|
|
||||
|
# Find sensitive files that were touched |
||||
|
sensitive_touched=() |
||||
|
for file in "${changed_files[@]}"; do |
||||
|
if matches_sensitive "$file"; then |
||||
|
sensitive_touched+=("$file") |
||||
|
fi |
||||
|
done |
||||
|
|
||||
|
# If no sensitive files were touched, allow the change |
||||
|
if [[ ${#sensitive_touched[@]} -eq 0 ]]; then |
||||
|
log_success "No build-sensitive files changed, guard check passed" |
||||
|
exit 0 |
||||
|
fi |
||||
|
|
||||
|
# Sensitive files were touched, log them |
||||
|
log_warn "Build-sensitive paths changed:" |
||||
|
for file in "${sensitive_touched[@]}"; do |
||||
|
echo " - $file" |
||||
|
done |
||||
|
|
||||
|
# Check if required documentation was updated |
||||
|
if check_docs_updated "${changed_files[@]}"; then |
||||
|
log_success "BUILDING.md updated alongside build changes, guard check passed" |
||||
|
exit 0 |
||||
|
else |
||||
|
log_error "Build-sensitive files changed but BUILDING.md was not updated!" |
||||
|
echo |
||||
|
echo "The following build-sensitive files were modified:" |
||||
|
for file in "${sensitive_touched[@]}"; do |
||||
|
echo " - $file" |
||||
|
done |
||||
|
echo |
||||
|
echo "When modifying build-critical files, you must also update BUILDING.md" |
||||
|
echo "to document any changes to the build process." |
||||
|
echo |
||||
|
echo "Please:" |
||||
|
echo " 1. Update BUILDING.md with relevant changes" |
||||
|
echo " 2. Stage the BUILDING.md changes: git add BUILDING.md" |
||||
|
echo " 3. Retry your commit/push" |
||||
|
echo |
||||
|
exit 2 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# Handle help flag |
||||
|
if [[ "${1:-}" =~ ^(-h|--help)$ ]]; then |
||||
|
echo "Build Architecture Guard Script" |
||||
|
echo |
||||
|
echo "Usage:" |
||||
|
echo " $0 [--staged|--range [RANGE]]" |
||||
|
echo |
||||
|
echo "Options:" |
||||
|
echo " --staged Check staged files (for pre-commit hook)" |
||||
|
echo " --range [RANGE] Check git range (for pre-push hook)" |
||||
|
echo " Default range: HEAD~1..HEAD" |
||||
|
echo " (no args) Check working directory changes" |
||||
|
echo |
||||
|
echo "Examples:" |
||||
|
echo " $0 --staged # Pre-commit check" |
||||
|
echo " $0 --range origin/main..HEAD # Pre-push check" |
||||
|
echo " $0 # Working directory check" |
||||
|
exit 0 |
||||
|
fi |
||||
|
|
||||
|
main "$@" |
Loading…
Reference in new issue