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