From 51ae21305a2778cfdb9bc291924786f9d17be5ab Mon Sep 17 00:00:00 2001 From: Hal Eisen Date: Sun, 12 Jul 2026 08:48:59 -0700 Subject: [PATCH] ADFA-4678: Add pre-push nudge to run plugin-review skill Adds an opt-in .githooks/pre-push hook that reminds developers to run the /plugin-review skill when pushing changes to a plugin folder, so peer review isn't spent on issues the skill catches automatically. The hook detects which top-level plugin folders changed in the push range and names them; it always exits 0 (reminder only, never blocks) and stays silent for non-plugin pushes. Because git honors a single core.hooksPath, the hook is enabled per-clone via scripts/setup-hooks.sh. Documented in the README. --- .githooks/pre-push | 89 ++++++++++++++++++++++++++++++++++++++++++ README.md | 18 +++++++++ scripts/setup-hooks.sh | 19 +++++++++ 3 files changed, 126 insertions(+) create mode 100755 .githooks/pre-push create mode 100755 scripts/setup-hooks.sh diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 00000000..e69e360d --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# +# pre-push nudge (ADFA-4678) +# +# Reminds the developer to run the Code On The Go plugin-review skill +# (/plugin-review) before finishing a PR, so peer review isn't spent on +# issues the skill catches automatically. +# +# This is a NUDGE, not a gate: it always exits 0 and never blocks a push. +# +# NOTE: git only honors a single core.hooksPath. This hook lives in the repo +# but is NOT active until a contributor opts in once: +# ./scripts/setup-hooks.sh (runs: git config core.hooksPath .githooks) + +set -euo pipefail + +# A plugin folder is any top-level dir whose build.gradle.kts applies the +# plugin-builder Gradle plugin. Discover them dynamically so new plugins are +# picked up automatically. +plugin_dirs() { + local f + for f in */build.gradle.kts; do + [ -e "$f" ] || continue + if grep -q 'com.itsaky.androidide.plugins.build' "$f"; then + printf '%s\n' "${f%/build.gradle.kts}" + fi + done +} + +# Determine the set of commits being pushed. git feeds pre-push one line per +# ref on stdin: " ". +# For each pushed ref, diff its new commit against what the remote already has +# (or against origin/main when the remote branch is brand new). +zero='0000000000000000000000000000000000000000' +changed_files="" +while read -r local_ref local_sha remote_ref remote_sha; do + [ "$local_sha" = "$zero" ] && continue # branch deletion; nothing to review + + if [ "$remote_sha" = "$zero" ]; then + # New branch on the remote: compare against origin/main if we have it. + base="$(git rev-parse --verify --quiet origin/main || true)" + range="${base:+$base..}$local_sha" + else + range="$remote_sha..$local_sha" + fi + + changed_files+="$(git diff --name-only "$range" 2>/dev/null || true)"$'\n' +done + +# No stdin (e.g. manual invocation) or nothing to compare: fall back to the +# diff against origin/main so the hook is still useful when run by hand. +if [ -z "${changed_files//[$'\n\t ']/}" ]; then + base="$(git rev-parse --verify --quiet origin/main || true)" + [ -n "$base" ] && changed_files="$(git diff --name-only "$base...HEAD" 2>/dev/null || true)" +fi + +# Which plugin folders were touched? +mapfile -t all_plugins < <(plugin_dirs) +touched=() +for p in "${all_plugins[@]}"; do + if printf '%s\n' "$changed_files" | grep -q "^$p/"; then + touched+=("$p") + fi +done + +# Clean skip: docs-only / libs-only / non-plugin pushes get no noise. +[ ${#touched[@]} -eq 0 ] && exit 0 + +yellow=$'\033[33m'; bold=$'\033[1m'; reset=$'\033[0m' +{ + echo + echo "${yellow}${bold}┌───────────────────────────────────────────────────────────────┐${reset}" + echo "${yellow}${bold}│ Reminder: run the plugin-review skill before opening your PR │${reset}" + echo "${yellow}${bold}└───────────────────────────────────────────────────────────────┘${reset}" + echo " You changed these plugin folder(s):" + for p in "${touched[@]}"; do + echo " ${bold}• $p${reset}" + done + echo + echo " In Claude Code, run: ${bold}/plugin-review${reset}" + echo " It builds, audits security, and scores against the submission rubric," + echo " catching issues (resource leaks, missing manifest entries, missing" + echo " in-IDE help) that a clean build won't surface." + echo + echo " (This is a reminder only — your push is proceeding.)" + echo +} >&2 + +exit 0 diff --git a/README.md b/README.md index ce14550d..cb62dbd3 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,24 @@ cd Beepy The resulting `.cgp` file lands under the plugin's `build/plugin/` directory. Install it from inside CodeOnTheGo via the Plugin Manager. +## Git hooks + +This repo ships a `pre-push` nudge in `.githooks/` that reminds you to run the +plugin-review skill (`/plugin-review` in Claude Code) whenever you're pushing +changes to a plugin folder. Running the skill before opening a PR keeps peer +review focused on substance instead of issues the skill catches automatically +(resource leaks, missing manifest entries, missing in-IDE help). + +Git honors only a single `core.hooksPath`, so the committed hook does nothing +until you enable it once after cloning: + +```sh +./scripts/setup-hooks.sh # runs: git config core.hooksPath .githooks +``` + +The hook is a **reminder only** — it never blocks a push, and it stays quiet +when your push doesn't touch any plugin folder. + ## The `libs/` folder Every plugin depends on two jars produced by the CodeOnTheGo source tree: diff --git a/scripts/setup-hooks.sh b/scripts/setup-hooks.sh new file mode 100755 index 00000000..6a18f67a --- /dev/null +++ b/scripts/setup-hooks.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# +# One-time opt-in for this repo's git hooks (see .githooks/). +# +# git honors only a single core.hooksPath, so a committed hook does nothing +# until you point git at it. Run this once after cloning: +# +# ./scripts/setup-hooks.sh +# +set -euo pipefail + +repo_root="$(git rev-parse --show-toplevel)" +cd "$repo_root" + +git config core.hooksPath .githooks +chmod +x .githooks/* 2>/dev/null || true + +echo "core.hooksPath is now '.githooks' for this repo." +echo "The pre-push hook will remind you to run /plugin-review when you change a plugin."