Skip to main content

max / makenotwork

4.6 KB · 148 lines History Blame Raw
1 #!/bin/bash
2 # CI wrapper for push-triggered builds on astra.
3 # Called by the post-receive hook on Hetzner via SSH.
4 #
5 # Pulls latest code, runs the CI suite, reports results to WAM.
6 # If tests fail on main, auto-reverts the offending commit(s) and pushes
7 # the revert — enforcing the no-regressions rule from operations.md.
8 #
9 # Location on astra: /home/max/mnw-ci/server/deploy/ci-on-push.sh
10 # Usage: ci-on-push.sh [branch_name]
11
12 set -uo pipefail
13
14 export PATH="$HOME/.cargo/bin:$PATH"
15
16 BRANCH="${1:-main}"
17 REPO_DIR="$HOME/mnw-ci"
18 SERVER_DIR="$REPO_DIR/server"
19 WAM_URL="${WAM_URL:-http://127.0.0.1:7890}"
20 START_TIME=$(date +%s)
21 LOG_FILE="$REPO_DIR/ci-latest.log"
22
23 echo "=== CI triggered for branch: $BRANCH ==="
24 echo "Started: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
25
26 # Pull latest code
27 cd "$REPO_DIR" || exit 1
28 echo "[pull] Fetching latest..."
29 git fetch origin "$BRANCH" 2>&1
30
31 # Record what we're about to test
32 OLD_HEAD=$(git rev-parse HEAD 2>/dev/null || echo "none")
33 git reset --hard "origin/$BRANCH" 2>&1
34 NEW_HEAD=$(git rev-parse HEAD)
35 COMMIT_MSG=$(git log --oneline -1)
36
37 echo "[pull] $OLD_HEAD -> $NEW_HEAD"
38 echo "[pull] $COMMIT_MSG"
39
40 # Run CI from the server directory
41 cd "$SERVER_DIR" || exit 1
42
43 export DATABASE_URL="${DATABASE_URL:-postgres:///makenotwork_staging}"
44 export TEST_DATABASE_URL="${TEST_DATABASE_URL:-postgres:///postgres}"
45 export RUST_TEST_THREADS="${RUST_TEST_THREADS:-8}"
46 export CARGO_INCREMENTAL=0
47 export RUST_BACKTRACE=1
48
49 echo "[ci] Running CI suite..."
50 CI_OUTPUT=$("$REPO_DIR/server/deploy/run-ci.sh" 2>&1) || true
51 CI_EXIT=$?
52
53 END_TIME=$(date +%s)
54 DURATION=$(( END_TIME - START_TIME ))
55
56 # Extract summary from CI output
57 PASS_COUNT=$(echo "$CI_OUTPUT" | grep -c "^ PASS" || true)
58 FAIL_COUNT=$(echo "$CI_OUTPUT" | grep -c "^ FAIL" || true)
59
60 # Save full log
61 echo "$CI_OUTPUT" > "$LOG_FILE"
62
63 # --- Handle results ---
64
65 wam_ticket() {
66 local title="$1" body="$2" priority="$3" source_ref="$4"
67 local escaped_title escaped_body
68 escaped_title=$(echo "$title" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read().strip()))' 2>/dev/null || echo "\"$title\"")
69 escaped_body=$(echo "$body" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))' 2>/dev/null || echo '""')
70 curl -sf -X POST "$WAM_URL/tickets" \
71 -H "Content-Type: application/json" \
72 -d "{\"title\": $escaped_title, \"body\": $escaped_body, \"priority\": \"$priority\", \"source\": \"ci\", \"source_ref\": \"$source_ref\"}" \
73 >/dev/null 2>&1 || echo "[warn] Failed to create WAM ticket"
74 }
75
76 if [ $CI_EXIT -eq 0 ]; then
77 # --- CI PASSED ---
78 TITLE="CI passed: $BRANCH ($PASS_COUNT steps, ${DURATION}s)"
79 BODY="Commit: $COMMIT_MSG
80 Duration: ${DURATION}s
81 Steps passed: $PASS_COUNT
82
83 All steps passed."
84
85 wam_ticket "$TITLE" "$BODY" "low" "$NEW_HEAD"
86 echo ""
87 echo "=== CI PASSED ($PASS_COUNT steps, ${DURATION}s) ==="
88 else
89 # --- CI FAILED — AUTO-REVERT ---
90 FAILED_STEPS=$(echo "$CI_OUTPUT" | grep "^ FAIL" | sed 's/^ FAIL / - /')
91
92 echo ""
93 echo "=== CI FAILED — REVERTING ==="
94 echo ""
95
96 cd "$REPO_DIR" || exit 1
97
98 # Count how many new commits since old head
99 if [ "$OLD_HEAD" = "none" ] || [ "$OLD_HEAD" = "$NEW_HEAD" ]; then
100 # Can't determine what to revert (first run or no change)
101 REVERT_STATUS="could not determine commits to revert"
102 else
103 NEW_COMMITS=$(git rev-list "$OLD_HEAD..$NEW_HEAD" --count 2>/dev/null || echo "0")
104
105 if [ "$NEW_COMMITS" -eq 1 ]; then
106 # Single commit — revert it
107 git revert --no-edit HEAD 2>&1
108 REVERT_STATUS="reverted 1 commit ($NEW_HEAD)"
109 elif [ "$NEW_COMMITS" -gt 1 ]; then
110 # Multiple commits — revert the range
111 git revert --no-edit "$OLD_HEAD..$NEW_HEAD" 2>&1
112 REVERT_STATUS="reverted $NEW_COMMITS commits ($OLD_HEAD..$NEW_HEAD)"
113 else
114 REVERT_STATUS="no new commits to revert"
115 fi
116
117 # Push the revert back to origin
118 if git push origin "$BRANCH" 2>&1; then
119 REVERT_STATUS="$REVERT_STATUS — pushed to origin"
120 else
121 REVERT_STATUS="$REVERT_STATUS — PUSH FAILED (manual intervention needed)"
122 fi
123 fi
124
125 TITLE="CI FAILED + REVERTED: $BRANCH ($FAIL_COUNT step(s) failed)"
126 BODY="Commit: $COMMIT_MSG
127 Duration: ${DURATION}s
128 Steps passed: $PASS_COUNT
129 Steps failed: $FAIL_COUNT
130
131 Failed steps:
132 $FAILED_STEPS
133
134 Revert: $REVERT_STATUS
135
136 No-regressions rule enforced automatically.
137 Fix the issue and re-push.
138
139 Last 30 lines of output:
140 $(echo "$CI_OUTPUT" | tail -30)"
141
142 wam_ticket "$TITLE" "$BODY" "critical" "$NEW_HEAD"
143 echo "Revert: $REVERT_STATUS"
144 echo ""
145 fi
146
147 exit $CI_EXIT
148