mirror of
https://github.com/boshu2/agentops.git
synced 2026-09-14 15:08:13 +08:00
feat(gate): add --two-pass mode and default local scope to head
Two-pass mode runs pass 1 (--fast --scope head --fail-fast, blocking) then pass 2 (--scope upstream --accumulate, advisory WARN not FAIL). Local pushes now default to --scope head (~3s) instead of upstream; CI keeps upstream. Override with PRE_PUSH_GO_SCOPE=upstream. Closes soc-7c3v
This commit is contained in:
@@ -107,8 +107,15 @@ NC='\033[0m'
|
||||
|
||||
errors=0
|
||||
skipped=0
|
||||
SCOPE="${PRE_PUSH_GO_SCOPE:-upstream}"
|
||||
SCOPE_EXPLICIT=false
|
||||
if [[ -n "${PRE_PUSH_GO_SCOPE:-}" ]]; then
|
||||
SCOPE="$PRE_PUSH_GO_SCOPE"
|
||||
SCOPE_EXPLICIT=true
|
||||
else
|
||||
SCOPE="upstream"
|
||||
fi
|
||||
FAST_MODE=false
|
||||
TWO_PASS=false
|
||||
FAIL_FAST_SETTING="${PRE_PUSH_FAIL_FAST:-auto}"
|
||||
FAIL_FAST_EFFECTIVE=false
|
||||
FAIL_FAST_PENDING=false
|
||||
@@ -148,6 +155,15 @@ cleanup_hash_snapshot() {
|
||||
}
|
||||
blocked_exit() {
|
||||
echo ""
|
||||
if truthy "${_PRE_PUSH_ADVISORY:-0}"; then
|
||||
if [[ "$FAST_MODE" == "true" ]]; then
|
||||
echo -e "${YELLOW}pre-push gate (fast, advisory): $errors issues found ($skipped skipped)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}pre-push gate (advisory): $errors issues found${NC}"
|
||||
fi
|
||||
cleanup_hash_snapshot
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$FAST_MODE" == "true" ]]; then
|
||||
echo -e "${RED}pre-push gate (fast): BLOCKED ($errors failures, $skipped skipped)${NC}"
|
||||
else
|
||||
@@ -157,7 +173,11 @@ blocked_exit() {
|
||||
exit 1
|
||||
}
|
||||
fail() {
|
||||
echo -e "${RED}FAIL${NC} $1"
|
||||
if truthy "${_PRE_PUSH_ADVISORY:-0}"; then
|
||||
echo -e "${YELLOW}WARN${NC} $1 (advisory)"
|
||||
else
|
||||
echo -e "${RED}FAIL${NC} $1"
|
||||
fi
|
||||
errors=$((errors + 1))
|
||||
if [[ "${FAIL_FAST_EFFECTIVE:-false}" == "true" ]]; then
|
||||
FAIL_FAST_PENDING=true
|
||||
@@ -181,15 +201,19 @@ run_hash_snapshot() {
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: scripts/pre-push-gate.sh [--fast] [--scope auto|upstream|staged|worktree|head]
|
||||
scripts/pre-push-gate.sh --two-pass
|
||||
|
||||
Options:
|
||||
--fast Only run checks relevant to changed files
|
||||
--scope How to determine changed files (default: upstream)
|
||||
--scope How to determine changed files (default: head local, upstream CI)
|
||||
--fail-fast Stop after first blocking failure
|
||||
--accumulate Continue after failures and report all blocking failures
|
||||
--two-pass Pass 1: --fast --scope head --fail-fast (blocking)
|
||||
Pass 2: --scope upstream --accumulate (advisory, WARN not FAIL)
|
||||
|
||||
Environment:
|
||||
PRE_PUSH_FAIL_FAST=0|1|auto default auto: enabled for local --fast, off in CI
|
||||
PRE_PUSH_TWO_PASS=1 enable two-pass mode via env
|
||||
PRE_PUSH_RUN_EVAL=1 run eval canaries even when eval files did not change
|
||||
PRE_PUSH_STRICT_EVAL=1 make local fast eval canaries blocking
|
||||
PRE_PUSH_AGENT_HEALTH=1 run local fast AgentOps health/ratchet checks
|
||||
@@ -198,6 +222,10 @@ Environment:
|
||||
EOF
|
||||
}
|
||||
|
||||
if truthy "${PRE_PUSH_TWO_PASS:-0}"; then
|
||||
TWO_PASS=true
|
||||
fi
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--fast)
|
||||
@@ -206,6 +234,7 @@ while [[ $# -gt 0 ]]; do
|
||||
;;
|
||||
--scope)
|
||||
SCOPE="${2:-}"
|
||||
SCOPE_EXPLICIT=true
|
||||
shift 2
|
||||
;;
|
||||
--fail-fast)
|
||||
@@ -216,6 +245,10 @@ while [[ $# -gt 0 ]]; do
|
||||
FAIL_FAST_SETTING=0
|
||||
shift
|
||||
;;
|
||||
--two-pass)
|
||||
TWO_PASS=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
@@ -228,6 +261,10 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$SCOPE_EXPLICIT" != "true" ]] && ! is_ci_env; then
|
||||
SCOPE="head"
|
||||
fi
|
||||
|
||||
case "$SCOPE" in
|
||||
auto|upstream|staged|worktree|head) ;;
|
||||
*)
|
||||
@@ -245,6 +282,28 @@ elif truthy "$FAIL_FAST_SETTING"; then
|
||||
FAIL_FAST_EFFECTIVE=true
|
||||
fi
|
||||
|
||||
# --- Two-pass mode: re-invoke as pass 1 (blocking) + pass 2 (advisory) ---
|
||||
if [[ "$TWO_PASS" == "true" ]]; then
|
||||
SELF="$SCRIPT_DIR/pre-push-gate.sh"
|
||||
echo "=== Two-pass mode ==="
|
||||
echo ""
|
||||
echo "--- Pass 1: HEAD commit (blocking) ---"
|
||||
set +e
|
||||
PRE_PUSH_TWO_PASS=0 "$SELF" --fast --scope head --fail-fast
|
||||
pass1_rc=$?
|
||||
set -e
|
||||
if [[ $pass1_rc -ne 0 ]]; then
|
||||
echo ""
|
||||
echo -e "${RED}--- Pass 1: FAILED (blocking) ---${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}--- Pass 1: PASSED ---${NC}"
|
||||
echo ""
|
||||
echo "--- Pass 2: upstream range (advisory) ---"
|
||||
_PRE_PUSH_ADVISORY=1 PRE_PUSH_TWO_PASS=0 "$SELF" --scope upstream --accumulate || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
collect_all_changed() {
|
||||
case "$SCOPE" in
|
||||
upstream)
|
||||
@@ -1516,6 +1575,14 @@ fi
|
||||
maybe_fail_fast
|
||||
echo ""
|
||||
if [[ $errors -gt 0 ]]; then
|
||||
if truthy "${_PRE_PUSH_ADVISORY:-0}"; then
|
||||
if [[ "$FAST_MODE" == "true" ]]; then
|
||||
echo -e "${YELLOW}pre-push gate (fast, advisory): $errors issues found ($skipped skipped)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}pre-push gate (advisory): $errors issues found${NC}"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$FAST_MODE" == "true" ]]; then
|
||||
echo -e "${RED}pre-push gate (fast): BLOCKED ($errors failures, $skipped skipped)${NC}"
|
||||
else
|
||||
|
||||
@@ -1168,3 +1168,158 @@ GIT
|
||||
run grep -q 'check-test-home-isolation\.sh' "$SCRIPT"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# soc-7c3v: two-pass mode tests
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@test "pre-push-gate.sh --two-pass re-invokes with pass 1 (head) and pass 2 (upstream)" {
|
||||
cat > "$MOCK_BIN/git" <<'GIT'
|
||||
#!/usr/bin/env bash
|
||||
if [[ "$*" == *"diff --name-only"* ]]; then echo ""; fi
|
||||
if [[ "$*" == *"rev-parse"* ]]; then echo "/tmp"; fi
|
||||
if [[ "$*" == *"show --name-only"* ]]; then echo ""; fi
|
||||
exit 0
|
||||
GIT
|
||||
chmod +x "$MOCK_BIN/git"
|
||||
|
||||
cd "$FAKE_REPO"
|
||||
export PATH="$MOCK_BIN:$PATH"
|
||||
|
||||
run env -u CI -u GITHUB_ACTIONS bash "$GATE" --two-pass
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Two-pass mode"* ]]
|
||||
[[ "$output" == *"Pass 1"* ]]
|
||||
[[ "$output" == *"Pass 2"* ]]
|
||||
}
|
||||
|
||||
@test "pre-push-gate.sh --two-pass exits 0 when pass 2 has advisory failures" {
|
||||
# Pass 1 (head scope) sees no changes → passes.
|
||||
# Pass 2 (upstream scope) sees a go build failure → advisory, still exit 0.
|
||||
cat > "$MOCK_BIN/git" <<'GIT'
|
||||
#!/usr/bin/env bash
|
||||
if [[ "$*" == *"show --name-only"* ]]; then echo ""; exit 0; fi
|
||||
if [[ "$*" == *"diff --name-only"* && "$*" == *"upstream"* ]]; then echo "cli/main.go"; exit 0; fi
|
||||
if [[ "$*" == *"diff --name-only"* ]]; then echo ""; fi
|
||||
if [[ "$*" == *"rev-parse"* ]]; then echo "/tmp"; fi
|
||||
exit 0
|
||||
GIT
|
||||
chmod +x "$MOCK_BIN/git"
|
||||
cat > "$MOCK_BIN/go" <<'GO'
|
||||
#!/usr/bin/env bash
|
||||
exit 1
|
||||
GO
|
||||
chmod +x "$MOCK_BIN/go"
|
||||
|
||||
cd "$FAKE_REPO"
|
||||
export PATH="$MOCK_BIN:$PATH"
|
||||
|
||||
run env -u CI -u GITHUB_ACTIONS bash "$GATE" --two-pass
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Pass 1: PASSED"* ]]
|
||||
[[ "$output" == *"advisory"* ]]
|
||||
}
|
||||
|
||||
@test "pre-push-gate.sh --two-pass exits 1 when pass 1 fails" {
|
||||
# Pass 1 (head scope) sees a go build failure → blocking, exit 1.
|
||||
cat > "$MOCK_BIN/git" <<'GIT'
|
||||
#!/usr/bin/env bash
|
||||
if [[ "$*" == *"show --name-only"* ]]; then echo "cli/main.go"; exit 0; fi
|
||||
if [[ "$*" == *"diff --name-only"* ]]; then echo "cli/main.go"; fi
|
||||
if [[ "$*" == *"rev-parse"* ]]; then echo "/tmp"; fi
|
||||
exit 0
|
||||
GIT
|
||||
chmod +x "$MOCK_BIN/git"
|
||||
cat > "$MOCK_BIN/go" <<'GO'
|
||||
#!/usr/bin/env bash
|
||||
exit 1
|
||||
GO
|
||||
chmod +x "$MOCK_BIN/go"
|
||||
|
||||
cd "$FAKE_REPO"
|
||||
export PATH="$MOCK_BIN:$PATH"
|
||||
|
||||
run env -u CI -u GITHUB_ACTIONS bash "$GATE" --two-pass
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Pass 1: FAILED (blocking)"* ]]
|
||||
}
|
||||
|
||||
@test "pre-push-gate.sh PRE_PUSH_TWO_PASS=1 enables two-pass via env" {
|
||||
cat > "$MOCK_BIN/git" <<'GIT'
|
||||
#!/usr/bin/env bash
|
||||
if [[ "$*" == *"diff --name-only"* ]]; then echo ""; fi
|
||||
if [[ "$*" == *"rev-parse"* ]]; then echo "/tmp"; fi
|
||||
if [[ "$*" == *"show --name-only"* ]]; then echo ""; fi
|
||||
exit 0
|
||||
GIT
|
||||
chmod +x "$MOCK_BIN/git"
|
||||
|
||||
cd "$FAKE_REPO"
|
||||
export PATH="$MOCK_BIN:$PATH"
|
||||
|
||||
run env -u CI -u GITHUB_ACTIONS PRE_PUSH_TWO_PASS=1 bash "$GATE"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Two-pass mode"* ]]
|
||||
}
|
||||
|
||||
@test "pre-push-gate.sh defaults to --scope head locally (not CI)" {
|
||||
run grep -q 'SCOPE_EXPLICIT' "$SCRIPT"
|
||||
[ "$status" -eq 0 ]
|
||||
run grep -q 'SCOPE="head"' "$SCRIPT"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "pre-push-gate.sh keeps --scope upstream in CI" {
|
||||
cat > "$MOCK_BIN/git" <<'GIT'
|
||||
#!/usr/bin/env bash
|
||||
if [[ "$*" == *"diff --name-only"* ]]; then echo ""; fi
|
||||
if [[ "$*" == *"rev-parse"* ]]; then echo "/tmp"; fi
|
||||
exit 0
|
||||
GIT
|
||||
chmod +x "$MOCK_BIN/git"
|
||||
|
||||
cd "$FAKE_REPO"
|
||||
export PATH="$MOCK_BIN:$PATH"
|
||||
|
||||
run env CI=true bash "$GATE" --fast
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "pre-push-gate.sh PRE_PUSH_GO_SCOPE overrides local default" {
|
||||
cat > "$MOCK_BIN/git" <<'GIT'
|
||||
#!/usr/bin/env bash
|
||||
if [[ "$*" == *"diff --name-only"* ]]; then echo ""; fi
|
||||
if [[ "$*" == *"rev-parse"* ]]; then echo "/tmp"; fi
|
||||
exit 0
|
||||
GIT
|
||||
chmod +x "$MOCK_BIN/git"
|
||||
|
||||
cd "$FAKE_REPO"
|
||||
export PATH="$MOCK_BIN:$PATH"
|
||||
|
||||
run env -u CI -u GITHUB_ACTIONS PRE_PUSH_GO_SCOPE=upstream bash "$GATE" --fast
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "pre-push-gate.sh advisory mode prints WARN not FAIL" {
|
||||
cat > "$MOCK_BIN/git" <<'GIT'
|
||||
#!/usr/bin/env bash
|
||||
if [[ "$*" == *"diff --name-only"* ]]; then echo "cli/main.go"; fi
|
||||
if [[ "$*" == *"rev-parse"* ]]; then echo "/tmp"; fi
|
||||
exit 0
|
||||
GIT
|
||||
chmod +x "$MOCK_BIN/git"
|
||||
cat > "$MOCK_BIN/go" <<'GO'
|
||||
#!/usr/bin/env bash
|
||||
exit 1
|
||||
GO
|
||||
chmod +x "$MOCK_BIN/go"
|
||||
|
||||
cd "$FAKE_REPO"
|
||||
export PATH="$MOCK_BIN:$PATH"
|
||||
|
||||
run env -u CI -u GITHUB_ACTIONS _PRE_PUSH_ADVISORY=1 bash "$GATE" --scope upstream
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"WARN"* ]]
|
||||
[[ "$output" == *"advisory"* ]]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user