fix(ci): pr-iphone-deploy no longer self-merges on its own comment
The build-deploy job posts a 'Prêt à tester' comment whose body literally contains 'Reply **LGTM** pour merger' and 'Reply **KO**' as instructions to the reviewer. wait-approval re-fetches ALL comments every 30s and greps any body for \bLGTM\b (checked before KO) — so on the first poll (~30s after deploy) the bot matched its OWN comment and squash-merged automatically, with no human review. Regressed in #6937a36 (PR #12) which tightened the regex to catch 'Tested, LGTM!' but didn't notice the bot body matched. Fix (sentinel marker + python parse, identity-agnostic so it's safe whether PR_API_TOKEN is a bot or a personal account): - build-deploy: embed <!-- tabatago:ready-to-test --> in the bot comment (HTML comment, invisible in rendered markdown, present in raw body). - wait-approval: replace the fragile grep-over-JSON with a python3 heredoc using json.loads + the existing \bLGTM\b / \bKO\b regexes. Skip any comment whose body contains the sentinel marker. Check KO BEFORE LGTM so a PR with both signals blocks (matches the existing 'KO blocks' intent). LGTM still does {"Do":"squash"}; KO still blocks; 2h timeout unchanged. Verified locally with three scenarios: bot-only -> PENDING (was LGTM before — the bug) bot + reviewer -> LGTM (squash-merge still fires) bot + KO -> KO (block still fires, even with bot LGTM in history) AGENTS.md §5 step 9, §5 pitfalls, and §8 anti-patterns updated so the doc describes the marker rule and warns against re-introducing the self-match.
This commit is contained in:
81
.github/workflows/pr-iphone-deploy.yml
vendored
81
.github/workflows/pr-iphone-deploy.yml
vendored
@@ -172,10 +172,16 @@ jobs:
|
||||
run: |
|
||||
PR="${{ github.event.pull_request.number }}"
|
||||
REPO="${{ github.repository }}"
|
||||
# The HTML comment is invisible in Gitea's rendered markdown but is
|
||||
# present in the raw body — wait-approval uses it as a sentinel to
|
||||
# skip THIS bot comment when scanning for LGTM/KO (otherwise the
|
||||
# instruction text "Reply LGTM pour merger" would self-trigger a
|
||||
# merge ~30s after deploy). DO NOT remove or reword without also
|
||||
# updating the scanner in the wait-approval job.
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token ${GT_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"body\":\"## 📱 Prêt à tester !\\n\\nL'app est déployée sur l'iPhone (devicectl).\\n\\n- Teste les changements\\n- Reply **LGTM** pour merger\\n- Reply **KO** pour bloquer\"}" \
|
||||
-d "{\"body\":\"## 📱 Prêt à tester !\\n\\nL'app est déployée sur l'iPhone (devicectl).\\n\\n<!-- tabatago:ready-to-test -->\\n\\n- Teste les changements\\n- Reply **LGTM** pour merger\\n- Reply **KO** pour bloquer\"}" \
|
||||
"${GITEA_URL}/api/v1/repos/${REPO}/issues/${PR}/comments"
|
||||
|
||||
wait-approval:
|
||||
@@ -202,6 +208,19 @@ jobs:
|
||||
# Re-fetch ALL comments each cycle (not since_id) so we also catch
|
||||
# edits — e.g. a reviewer changing "KO" → "LGTM". Negligible cost for
|
||||
# PRs with <50 comments.
|
||||
#
|
||||
# Parsing is done with python3 (preinstalled on the macOS runner and
|
||||
# already used by scripts/ci-status.py) rather than grep over raw JSON:
|
||||
# - the bot's "Ready to test" comment body literally contains the
|
||||
# words LGTM/KO as instructions to the reviewer, so any naive
|
||||
# body grep would self-match and auto-merge ~30s after deploy.
|
||||
# We skip it via the <!-- tabatago:ready-to-test --> sentinel
|
||||
# embedded by the build-deploy job;
|
||||
# - json.loads avoids false matches when the literal "body" key or
|
||||
# trigger words appear inside another string field.
|
||||
# KO is checked BEFORE LGTM so a PR with both signals blocks (matches
|
||||
# the existing "KO blocks" intent — a reviewer who flip-flops shouldn't
|
||||
# merge just because an older LGTM is still in the history).
|
||||
|
||||
while [ $TRIES -lt $MAX ]; do
|
||||
sleep 30
|
||||
@@ -210,23 +229,51 @@ jobs:
|
||||
COMMENTS=$(curl -s -H "Authorization: token ${GT_TOKEN}" \
|
||||
"${API}/issues/${PR}/comments?limit=50&page=1")
|
||||
|
||||
# Match LGTM/KO anywhere in the body (with a word boundary so "KOM"
|
||||
# or "LGTMX" don't trigger). Case-insensitive.
|
||||
if echo "$COMMENTS" | grep -qiE '"body":[[:space:]]*"[^"]*\bLGTM\b'; then
|
||||
echo "✅ LGTM reçu ! Squash-merge..."
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token ${GT_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"Do\":\"squash\"}" \
|
||||
"${API}/pulls/${PR}/merge"
|
||||
echo "✅ Mergée (squash)."
|
||||
exit 0
|
||||
fi
|
||||
DECISION=$(python3 - "$COMMENTS" <<'PY'
|
||||
import json, re, sys
|
||||
MARKER = "<!-- tabatago:ready-to-test -->"
|
||||
try:
|
||||
comments = json.loads(sys.argv[1] or "[]")
|
||||
except Exception:
|
||||
comments = []
|
||||
lgtm = re.compile(r"\bLGTM\b", re.IGNORECASE)
|
||||
ko = re.compile(r"\bKO\b", re.IGNORECASE)
|
||||
hit_lgtm = hit_ko = False
|
||||
for c in comments:
|
||||
body = c.get("body") or ""
|
||||
if MARKER in body:
|
||||
# Skip the bot's own "Ready to test" comment — its body mentions
|
||||
# LGTM/KO as instructions and would otherwise self-trigger.
|
||||
continue
|
||||
if ko.search(body):
|
||||
hit_ko = True
|
||||
if lgtm.search(body):
|
||||
hit_lgtm = True
|
||||
if hit_ko:
|
||||
print("KO")
|
||||
elif hit_lgtm:
|
||||
print("LGTM")
|
||||
else:
|
||||
print("PENDING")
|
||||
PY
|
||||
)
|
||||
|
||||
if echo "$COMMENTS" | grep -qiE '"body":[[:space:]]*"[^"]*\bKO\b'; then
|
||||
echo "❌ KO reçu. Bloquée."
|
||||
exit 1
|
||||
fi
|
||||
case "$DECISION" in
|
||||
LGTM)
|
||||
echo "✅ LGTM reçu ! Squash-merge..."
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token ${GT_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"Do\":\"squash\"}" \
|
||||
"${API}/pulls/${PR}/merge"
|
||||
echo "✅ Mergée (squash)."
|
||||
exit 0
|
||||
;;
|
||||
KO)
|
||||
echo "❌ KO reçu. Bloquée."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ $((TRIES % 4)) -eq 0 ]; then
|
||||
echo " ⏳ ... (${TRIES}/240, $(date +%H:%M))"
|
||||
|
||||
Reference in New Issue
Block a user