Files
RedBear-OS/local/docs/HOOKS.md
T
vasilito 99e5641127 feat: release-bump pipeline + external graphics version sync
Pipeline (3 operator asks):
- bump-release.sh: canonical orchestrator (forks + sources + external)
- upgrade-forks.sh --to=<tag>: rebase forks with diverged-mode guard
- bump-graphics-recipes.sh: map-driven group-aware graphics bumps
- check-external-versions.sh: drift checker for Qt6/KF6/Plasma/Mesa/Wayland
- refresh-fork-upstream-map.sh: append-only map updater with --check
- post-checkout-version-sync.sh + install-git-hooks.sh: opt-in branch hook
- external_version_lib.py: shared version-parsing/bumping library
- external-upstream-map.toml: ~80 external package entries
- bump-fork.sh: deprecated (REDBEAR_I_KNOW_BUMP_FORK_IS_DEPRECATED=1)
- RELEASE-BUMP-WORKFLOW.md: operator runbook

Quality fixes (8 defects from two independent audits):
- blake2b stable cache keys (was hash(), non-portable)
- atomic cache writes via os.replace
- version_sort_key pre-release demotion (was sorting after finals)
- apply_ver_transform re.error tolerance
- grep || true (pipefail abort)
- cd failure detection in upgrade-forks
- sed URL escape (injection hardening)
- refresh-fork-upstream-map last-row drop fix

Doc cleanup:
- Archive 5 obsolete plans to local/docs/archived/
- Remove 14 stale/superseded docs
- Update 18 docs to reference bump-release.sh and fix inbound links
- TOOLS.md drift fixes
2026-07-18 14:45:41 +09:00

189 lines
9.0 KiB
Markdown

# Red Bear OS — Optional Git Hooks
This directory documents the git hooks that operators can install for
Red Bear OS. Per AGENTS.md "absolutely NEVER DELETE, NEVER IGNORE"
rule, hooks are always **opt-in** — operators explicitly choose to
install them. No hook is auto-installed.
## Available hooks (2026-07-18, Phase 4.5 + release-bump pipeline)
### post-checkout-version-sync.sh (release-bump automation, opt-in)
**File:** `local/scripts/post-checkout-version-sync.sh`
**Purpose:** When an operator switches to a release branch whose name is an
anchored semver (e.g. `0.3.1``0.3.2`), automatically synchronise every
Cat 1 (in-house) and Cat 2 (upstream fork) crate version label to match the
new branch. This is the **label-only** half of a release bump — it rewrites
the `version = "..."` fields via `sync-versions.sh --no-regen` and does
nothing else. Source upgrades and lockfile regen remain explicit operator
steps (see `local/docs/RELEASE-BUMP-WORKFLOW.md`).
**Exact guards** (any fail → silent exit 0, no mutations):
1. `$3 == 1` — branch checkouts only (file checkouts are skipped).
2. New branch name matches `^[0-9]+\.[0-9]+\.[0-9]+$` — silently skips
`master`, `submodule/*`, `recovered/*`, and detached HEAD.
3. No in-progress rebase / cherry-pick / merge (`.git/rebase-merge`,
`.git/rebase-apply`, `.git/CHERRY_PICK_HEAD`, `.git/MERGE_HEAD` all
absent).
4. `REDBEAR_NO_AUTO_SYNC` env var unset.
5. Working tree clean (`git status --porcelain` empty) — else warns to
stderr and skips.
**What this hook NEVER does:**
- No network access (no `git fetch`, no upstream lookups).
- No git mutations (no commit, no branch, no push, no stash).
- No lockfile regen (never calls `sync-versions.sh --regen`).
- No source upgrades (never rebases forks or touches `local/sources/*/`).
- Does not run on non-semver branches.
- Does not run on a dirty working tree.
- Never blocks a checkout — always exits 0, even on internal failure.
**Action when all guards pass:** reads the repo-root `Cargo.toml`
`[package] version`. If it differs from the branch version, runs
`sync-versions.sh --no-regen` (labels only) and prints the follow-up hint
pointing the operator at the explicit source-upgrade and lockfile-regen
commands. If already synced, exits silently.
**Install (operator opt-in — NEVER auto-installed):**
```bash
# Via the installer (preferred):
./local/scripts/install-git-hooks.sh # post-checkout only
./local/scripts/install-git-hooks.sh --all # + pre-push + commit-msg
# Or manually:
cp local/scripts/post-checkout-version-sync.sh .git/hooks/post-checkout
chmod +x .git/hooks/post-checkout
```
**Bypass for a single checkout:**
```bash
REDBEAR_NO_AUTO_SYNC=1 git checkout 0.3.2
```
### pre-push-checks.sh (recommended for serious operators)
**File:** `local/scripts/pre-push-checks.sh`
**Purpose:** Run 7 pre-flight checks (4 core + 3 audit checks) before every
`git push`. Closes the "silent drift" gap identified in AGENTS.md
"Daily-upstream-safe workflow".
**Checks:**
1. `sync-versions.sh --check` — Cat 0 + Cat 1 + Cat 2 versions
2. `verify-fork-versions.sh` — Cat 2 fork supremacy + content check
3. `verify-patch-content.py` — no orphan patches in `local/patches/`
4. `verify-patch-content.py --report action` — orphan-patch operator decisions
5. `verify-patch-content.py --selftest` — orphan-patch detector self-test
6. `verify-collision-detection.py` — no config-vs-package conflicts
7. `verify-collision-detection.py --selftest` — collision detector self-test
**Install:**
```bash
cp local/scripts/pre-push-checks.sh .git/hooks/pre-push
chmod +x .git/hooks/pre-push
# Or via the installer:
./local/scripts/install-git-hooks.sh --all
```
**Bypass:**
- `REDBEAR_SKIP_PRE_PUSH=1 git push` (env var)
- `git push --no-verify` (standard git bypass)
- Run with `--soft` for warn-only mode
**Why not pre-commit?** Pre-push is preferred because:
- Pre-commit would block every local commit (even non-bump commits)
- Pre-push is the right safety boundary: "before I share work with origin"
- Operators committing 5x/hour to a feature branch don't need every commit
to re-verify 4 checks; they need it on push
### Future hooks (Phase 4.5+ forward work)
- **pre-receive on the server** — gitea can run a server-side hook
that re-verifies every push. Combined with the client-side pre-push,
this is defense in depth. Implementation requires gitea admin
permission; operator-only.
- **commit-msg hook** — auto-prefix commit messages with Phase ID
(e.g., `phase 4.5: ...`) so future audits can group by phase.
Optional, helps with audit doc generation.
## How hooks relate to AGENTS.md
AGENTS.md "Daily-upstream-safe workflow" says:
> "we can sources are provisioned via provision-release.sh and
> archived in sources/redbear-<release>/ build successfully."
This means: **before any fork-upstream sync, validate the state**.
The pre-push hook is the operator-side implementation of that
check — it runs the same 4 checks that build-preflight.sh runs at
build time, but on the operator's local repository state.
## Why hooks are opt-in
Per AGENTS.md "absolutely NEVER DELETE, NEVER IGNORE" rule:
- Hooks can interfere with operator workflows (false positives block pushes)
- Some operators prefer manual run of pre-push-checks.sh
- Local hooks do not propagate (each clone must re-install)
- Some operators have multiple clones (different operator workstations)
The opt-in nature respects operator autonomy. The hook is provided
in `local/scripts/` so operators can opt in by copying it to
`.git/hooks/pre-push`.
## Audit
This directory was created in Phase 4.5 (Round 5) and extended in the
release-bump pipeline (2026-07-18). The current hook inventory is:
| Hook | File | Function |
|------|------|----------|
| post-checkout | `local/scripts/post-checkout-version-sync.sh` | Auto-sync Cat 1+2 version labels on semver branch switch (label-only, no regen) |
| pre-push | `local/scripts/pre-push-checks.sh` | Runs 7 pre-flight checks before push |
| commit-msg | `local/scripts/commit-msg` | Auto-prepends `phase X.Y:` to commit messages |
| (server-side) | (gitea admin only) | Pre-receive — defense in depth; not yet implemented |
## Installer (`install-git-hooks.sh`)
All three hooks are opt-in and can be installed individually with `cp`
(see each section above) or in one shot via the installer:
```bash
./local/scripts/install-git-hooks.sh # post-checkout only (default)
./local/scripts/install-git-hooks.sh --all # post-checkout + pre-push + commit-msg
./local/scripts/install-git-hooks.sh --uninstall # remove default set (restores .bak if present)
./local/scripts/install-git-hooks.sh --uninstall --all
```
The installer is idempotent: if a hook is already up to date it reports so
and does nothing; if an existing hook differs it backs the old one up to
`<name>.bak` (rotating older backups to `<name>.bak.1`, `.2`, …) before
overwriting. `--uninstall` reverses an install and restores the most recent
backup if one exists.
## Full Tool Inventory (Round 14)
The build system has grown organically across 9+ rounds. Here is
the complete tool inventory for reference.
| Tool | Type | Purpose | Modes |
|------|------|---------|-------|
| `patch-status.sh` | shell | Top-level consolidated report | `--brief`, `--json` |
| `sync-versions.sh` | shell | Cat 0+1+2 version sync + lockfile regen | `--check`, `--regen`, `--dry-run`, `--no-regen`, `--regen-only` |
| `verify-patch-content.sh` | shell↦py | Orphan patch detection | `--strict`, `--report action\|detail`, `--selftest` |
| `verify-fork-versions.sh` | shell | Cat 2 fork supremacy check | diverged mode; `REDBEAR_STRICT_DIVERGED_CHECK=1` |
| `verify-collision-detection.py` | python | Config [[files]] vs installs/files collision | `--strict`, `--selftest` (8 cases) |
| `pre-push-checks.sh` | shell | 7-check pre-push safety net | `--soft` for warn-only |
| `push-fork-branches.sh` | shell | Operator-reviewed fork push | `--execute` for actual push (default=print-only) |
| `unblock-base-push.sh` | shell | Base fork deadlock resolver | `path-a`, `path-b`, `path-c` for 3 operator paths |
| `commit-msg` | shell | Auto-phase-prefix hook | opt-in; install to `.git/hooks/commit-msg` |
| `build-preflight.sh` | shell | Build-time validation | Called by `build-redbear.sh` |
| `bump-release.sh` | shell | Canonical release-bump orchestrator | `--with-sources`, `--with-external`, `--check`, `--dry-run` |
| `check-external-versions.sh` | shell↦py | External desktop-stack version reporter | `--strict`, `--no-fetch`, `--json` |
| `bump-graphics-recipes.sh` | shell↦py | Map-driven external source bumper | `--dry-run`, `--no-fetch` |
| `post-checkout-version-sync.sh` | shell | Auto label-sync on semver branch switch | opt-in hook; bypass via `REDBEAR_NO_AUTO_SYNC=1` |
| `install-git-hooks.sh` | shell | Idempotent opt-in hook installer | `--all`, `--uninstall` |
All scripts are under `local/scripts/` and are designed to be
operator-friendly. Hooks are strictly opt-in per AGENTS.md
"absolutely NEVER DELETE, NEVER IGNORE" rule.