mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 19:43:15 +00:00
* docs(upstream-sync): add triage ledger + cherry-pick hook plan Seeds the upstream triage ledger (52 diverged commits from langchain-ai/open-swe categorized: landed/won't-merge/deferred/untriaged) and the design plan for a git-hook mechanism to keep it in sync during cherry-picks. * feat(upstream-sync): jsonl-backed triage ledger + generator CLI triage.jsonl is now the source of truth (52 rows migrated from triage.md); triage.md is generated with a do-not-edit banner. scripts/triage.py provides migrate/generate/reconcile/lookup/check-reject/set; make triage-render/check/reconcile added (triage-check is CI-safe staleness gate). Stdlib-only so git hooks can call it. * feat(upstream-sync): cherry-pick triage git hooks + git cp wrapper post-commit journals each -x pick to an untracked .git-local journal; prepare-commit-msg hard-blocks known-reject picks (commit-msg is a secondary backstop — clean picks skip it on git 2.50.1), overridable via git cp --force / SH_CHERRYPICK_ALLOW_REJECT=1 / sh.cherrypick.blockRejects=false. git-cp is the pre-apply guard + auto-reconcile. pre-push is a SHIM that re-execs the global Sea Haven security pre-push so core.hooksPath=.githooks does not shadow it; install-hooks.sh verifies that shim FIRST and refuses if it is missing. * docs(upstream-sync): correct hook plan + git cp runbook Record the verified git 2.50.1 finding that clean cherry-picks skip commit-msg, so the block lives in prepare-commit-msg; note the locked HARD-BLOCK-by-default reject policy. CHERRYPICK.md now leads with make install-hooks + git cp and explains the generated-md ledger. * chore(upstream-sync): mark #1651 landed (Bedrock family fix on gateway-routing) * docs(upstream-sync): rewrite CHERRYPICK.md as a repo-specific runbook * feat(upstream-sync): add triage.py sync + make triage-sync Discovers commits on dev..upstream/main not yet in the ledger and appends them as untriaged (PR # and subject parsed from each commit), then bumps _meta 'last synced' to the upstream tip and regenerates triage.md. Closes the discovery side of the workflow: triage-sync to pull in new work, git cp to land it. * docs(upstream-sync): move cherry-pick runbook to PR1 branch as cherry-pick-runbook.md
124 lines
3.3 KiB
Bash
Executable file
124 lines
3.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# `git cp` wrapper — the real pre-apply guard the hooks can't be.
|
|
#
|
|
# git cp <sha>... pre-check ledger, cherry-pick -x, auto-reconcile
|
|
# git cp --force <sha>... pick even known "Won't merge" SHAs (documented override)
|
|
# git cp --continue|--abort|--skip|--quit forwarded to git cherry-pick
|
|
#
|
|
# Behaviour:
|
|
# 1. Resolve requested SHAs (single, list, or A^..B range) BEFORE touching the tree.
|
|
# 2. If any is disposition "wont-merge", print SHA + reason and ABORT unless --force.
|
|
# 3. git cherry-pick -x <args> (ensures -x is present exactly once).
|
|
# 4. On success, run `scripts/triage.py reconcile` to land the picks in the ledger.
|
|
set -uo pipefail
|
|
|
|
root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
|
|
echo "git cp: not a git repository" >&2
|
|
exit 1
|
|
}
|
|
triage="$root/scripts/triage.py"
|
|
py="$(command -v python3 || command -v python 2>/dev/null)"
|
|
|
|
force=0
|
|
control=0
|
|
passthru=()
|
|
picks=()
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--force | --allow-reject)
|
|
force=1
|
|
;;
|
|
--continue | --abort | --skip | --quit)
|
|
control=1
|
|
passthru+=("$arg")
|
|
;;
|
|
-*)
|
|
passthru+=("$arg")
|
|
;;
|
|
*)
|
|
passthru+=("$arg")
|
|
picks+=("$arg")
|
|
;;
|
|
esac
|
|
done
|
|
|
|
reconcile() {
|
|
if [ -n "$py" ] && [ -f "$triage" ]; then
|
|
"$py" "$triage" reconcile
|
|
else
|
|
echo "git cp: python/triage.py unavailable — skipping auto-reconcile" >&2
|
|
fi
|
|
}
|
|
|
|
ensure_x() {
|
|
# Prepend -x unless the caller already passed it.
|
|
for a in "${passthru[@]}"; do
|
|
[ "$a" = "-x" ] && return 0
|
|
done
|
|
passthru=("-x" "${passthru[@]}")
|
|
}
|
|
|
|
# Sequencer control verbs: forward and (for --continue) reconcile whatever landed.
|
|
if [ "$control" -eq 1 ]; then
|
|
git cherry-pick "${passthru[@]}"
|
|
rc=$?
|
|
if [ "$rc" -eq 0 ]; then
|
|
reconcile
|
|
fi
|
|
exit "$rc"
|
|
fi
|
|
|
|
# Pre-apply reject check.
|
|
if [ -n "$py" ] && [ -f "$triage" ] && [ "${#picks[@]}" -gt 0 ]; then
|
|
resolved=()
|
|
for tok in "${picks[@]}"; do
|
|
if [[ "$tok" == *..* ]]; then
|
|
while IFS= read -r s; do
|
|
[ -n "$s" ] && resolved+=("$s")
|
|
done < <(git rev-list --reverse "$tok" 2>/dev/null)
|
|
else
|
|
s="$(git rev-parse --verify --quiet "${tok}^{commit}" 2>/dev/null)" && resolved+=("$s")
|
|
fi
|
|
done
|
|
|
|
rejects=()
|
|
for s in ${resolved[@]+"${resolved[@]}"}; do
|
|
reason="$("$py" "$triage" check-reject "$s" 2>/dev/null)"
|
|
if [ "$?" -eq 3 ]; then
|
|
rejects+=("${s:0:12} $reason")
|
|
fi
|
|
done
|
|
|
|
if [ "${#rejects[@]}" -gt 0 ]; then
|
|
echo "git cp: the following SHA(s) are marked \"Won't merge\" in the triage ledger:" >&2
|
|
for r in "${rejects[@]}"; do
|
|
echo " ⛔ $r" >&2
|
|
done
|
|
if [ "$force" -eq 0 ]; then
|
|
echo "" >&2
|
|
echo "Refusing to cherry-pick a known-reject. To override intentionally: git cp --force ..." >&2
|
|
exit 1
|
|
fi
|
|
echo " --force set — proceeding anyway." >&2
|
|
fi
|
|
fi
|
|
|
|
ensure_x
|
|
|
|
# --force must also satisfy the commit-msg backstop, so allow rejects through the hook too.
|
|
if [ "$force" -eq 1 ]; then
|
|
export SH_CHERRYPICK_ALLOW_REJECT=1
|
|
fi
|
|
|
|
git cherry-pick "${passthru[@]}"
|
|
rc=$?
|
|
|
|
if [ "$rc" -eq 0 ]; then
|
|
reconcile
|
|
else
|
|
echo "" >&2
|
|
echo "git cp: cherry-pick stopped (rc=$rc). Resolve, then: git cp --continue (or --abort/--skip)." >&2
|
|
echo " Landed picks are journaled; reconcile runs on --continue or via make triage-reconcile." >&2
|
|
fi
|
|
exit "$rc"
|