feat: add archeflow-rollback.sh for post-merge test failure auto-revert
This commit is contained in:
61
lib/archeflow-rollback.sh
Executable file
61
lib/archeflow-rollback.sh
Executable file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# archeflow-rollback.sh — Auto-revert a merge that fails post-merge tests.
|
||||||
|
#
|
||||||
|
# Usage: archeflow-rollback.sh <run_id> [--test-cmd <cmd>]
|
||||||
|
#
|
||||||
|
# If --test-cmd not provided, reads test_command from .archeflow/config.yaml.
|
||||||
|
# Returns 0 if tests pass, 1 if tests fail (merge reverted).
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
RUN_ID="${1:?Usage: archeflow-rollback.sh <run_id> [--test-cmd <cmd>]}"
|
||||||
|
shift
|
||||||
|
|
||||||
|
# Parse optional --test-cmd
|
||||||
|
TEST_CMD=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--test-cmd) TEST_CMD="$2"; shift 2 ;;
|
||||||
|
*) echo "Unknown option: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Read test_command from config if not provided
|
||||||
|
if [[ -z "$TEST_CMD" ]]; then
|
||||||
|
if [[ -f ".archeflow/config.yaml" ]]; then
|
||||||
|
TEST_CMD=$(grep -E "^test_command:" .archeflow/config.yaml | sed 's/^test_command:\s*//' | tr -d '"' || true)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$TEST_CMD" ]]; then
|
||||||
|
echo "ERROR: No test command specified (use --test-cmd or set test_command in .archeflow/config.yaml)" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify HEAD is an ArcheFlow merge
|
||||||
|
HEAD_MSG=$(git log -1 --format=%s HEAD)
|
||||||
|
if [[ "$HEAD_MSG" != *"$RUN_ID"* ]] && [[ "$HEAD_MSG" != *"archeflow"* ]]; then
|
||||||
|
echo "WARNING: HEAD commit does not appear to be an ArcheFlow merge: $HEAD_MSG" >&2
|
||||||
|
echo "Proceeding anyway..." >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Running post-merge tests: $TEST_CMD"
|
||||||
|
|
||||||
|
if timeout 300 bash -c "$TEST_CMD"; then
|
||||||
|
echo "Tests passed — merge is good."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Tests FAILED — reverting merge..."
|
||||||
|
git revert --no-edit HEAD
|
||||||
|
|
||||||
|
# Emit event if event script exists
|
||||||
|
if [[ -x "$SCRIPT_DIR/archeflow-event.sh" ]]; then
|
||||||
|
"$SCRIPT_DIR/archeflow-event.sh" "$RUN_ID" decision act "" \
|
||||||
|
"{\"what\":\"post_merge_test\",\"chosen\":\"revert\",\"rationale\":\"test suite failed after merge\"}" ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
REVERT_HASH=$(git rev-parse --short HEAD)
|
||||||
|
echo "Merge reverted (commit: $REVERT_HASH). Tests must pass before re-merging."
|
||||||
|
exit 1
|
||||||
@@ -219,6 +219,32 @@ The helper script reads this config if it exists. All values have sensible defau
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Post-Merge Rollback
|
||||||
|
|
||||||
|
After merging, the run skill validates the merge by running the project's test suite. If tests fail, the merge is automatically reverted.
|
||||||
|
|
||||||
|
### Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./lib/archeflow-rollback.sh <run_id> [--test-cmd <cmd>]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Behavior:**
|
||||||
|
1. Reads `test_command` from `.archeflow/config.yaml` (or uses `--test-cmd` override)
|
||||||
|
2. Runs the test suite with a 5-minute timeout
|
||||||
|
3. If tests pass: exits 0 (merge is good)
|
||||||
|
4. If tests fail: runs `git revert --no-edit HEAD`, emits a `decision` event, exits 1
|
||||||
|
5. Verifies HEAD is an ArcheFlow merge commit before reverting (warning if not, proceeds anyway)
|
||||||
|
|
||||||
|
**Integration with run skill:** Called in section 4c (All Approved) after `archeflow-git.sh merge`. If it returns non-zero, the orchestrator cycles back with "integration test failure" feedback or reports to the user if max cycles are reached.
|
||||||
|
|
||||||
|
**Configuration:** Set `test_command` in `.archeflow/config.yaml`:
|
||||||
|
```yaml
|
||||||
|
test_command: "npm test" # or "pytest", "cargo test", etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Safety Rules
|
## Safety Rules
|
||||||
|
|
||||||
These rules are inherited from `archeflow:orchestration` and reinforced here:
|
These rules are inherited from `archeflow:orchestration` and reinforced here:
|
||||||
|
|||||||
@@ -380,21 +380,11 @@ If all reviewers approved (and completion criteria met, if defined):
|
|||||||
./lib/archeflow-git.sh merge "$RUN_ID" --no-ff
|
./lib/archeflow-git.sh merge "$RUN_ID" --no-ff
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Post-merge test validation:**
|
4. **Post-merge test validation** (using the auto-rollback script):
|
||||||
```bash
|
```bash
|
||||||
# Read test_command from config
|
# Run tests and auto-revert if they fail
|
||||||
TEST_CMD=$(grep -E "^test_command:" .archeflow/config.yaml | sed 's/^test_command:\s*//' | tr -d '"' || true)
|
if ! ./lib/archeflow-rollback.sh "$RUN_ID"; then
|
||||||
|
# Rollback script already reverted HEAD and emitted decision event
|
||||||
if [[ -n "$TEST_CMD" ]]; then
|
|
||||||
echo "Running post-merge tests: $TEST_CMD"
|
|
||||||
if ! bash -c "$TEST_CMD"; then
|
|
||||||
echo "Post-merge tests FAILED — reverting merge..."
|
|
||||||
git revert --no-edit HEAD
|
|
||||||
|
|
||||||
# Emit decision event for the revert
|
|
||||||
./lib/archeflow-event.sh "$RUN_ID" decision act "" \
|
|
||||||
'{"what":"post_merge_test","chosen":"revert","rationale":"test suite failed after merge"}' "$SEQ_CHECK_TO_ACT"
|
|
||||||
|
|
||||||
# If cycles remain, cycle back with integration test failure feedback
|
# If cycles remain, cycle back with integration test failure feedback
|
||||||
if [[ "$CYCLE" -lt "$MAX_CYCLES" ]]; then
|
if [[ "$CYCLE" -lt "$MAX_CYCLES" ]]; then
|
||||||
echo "Cycling back with integration test failure feedback..."
|
echo "Cycling back with integration test failure feedback..."
|
||||||
@@ -405,7 +395,6 @@ If all reviewers approved (and completion criteria met, if defined):
|
|||||||
# Continue to step 4e (Max Cycles Reached)
|
# Continue to step 4e (Max Cycles Reached)
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Clean up worktree:**
|
5. **Clean up worktree:**
|
||||||
|
|||||||
Reference in New Issue
Block a user