-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode-mower-fix-round-dispatch.yml
More file actions
157 lines (145 loc) · 7.01 KB
/
Copy pathcode-mower-fix-round-dispatch.yml
File metadata and controls
157 lines (145 loc) · 7.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# Code Mower workflow template: dispatch fix rounds when audit lanes block.
name: Code Mower fix-round dispatch
on:
pull_request:
types: [labeled]
permissions:
pull-requests: write
issues: write
concurrency:
group: code-mower-fix-round-${{ github.event.pull_request.number }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
CODE_MOWER_FIX_ROUND_RULES_JSON: "[{\"builder_label\":\"builder:cursor\",\"builder_labels\":[\"builder:cursor\",\"builder:grok-bot\"],\"builder_lane\":\"cursor\",\"mention\":\"@cursor\"}]"
CODE_MOWER_FIX_ROUND_AUDIT_LANES_JSON: "[{\"author_lane\":\"codex\",\"blocked\":\"codex-audit-blocked\",\"done\":\"codex-audit-done\",\"id\":\"codex\",\"needs\":\"needs-codex-audit\"},{\"author_lane\":\"claude\",\"blocked\":\"claude-audit-blocked\",\"done\":\"claude-audit-done\",\"id\":\"claude_audit\",\"needs\":\"needs-claude-audit\"}]"
CODE_MOWER_DISPATCH_TOKEN_ENV: "DISPATCH_TOKEN"
NEEDS_OWNER_LABEL: "needs-owner"
jobs:
dispatch:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
timeout-minutes: 5
env:
GH_TOKEN: ${{ secrets.DISPATCH_TOKEN || '' }}
PR_NUMBER: ${{ github.event.pull_request.number }}
steps:
- name: Plan fix-round dispatch
id: plan
shell: bash
run: |
set -euo pipefail
python3 - <<'PY'
import json
import os
from pathlib import Path
event = json.loads(Path(os.environ["GITHUB_EVENT_PATH"]).read_text())
pr = event["pull_request"]
event_label = (event.get("label") or {}).get("name", "")
pr_labels = {item.get("name", "") for item in pr.get("labels") or []}
audit_lanes = json.loads(os.environ["CODE_MOWER_FIX_ROUND_AUDIT_LANES_JSON"])
rules = json.loads(os.environ["CODE_MOWER_FIX_ROUND_RULES_JSON"])
def builder_labels(rule):
labels = [rule.get("builder_label", ""), *(rule.get("builder_labels") or [])]
return set(dict.fromkeys(label for label in labels if label))
audit_lane = next(
(lane for lane in audit_lanes if lane.get("blocked") == event_label),
None,
)
rule = next(
(
item
for item in rules
if builder_labels(item).intersection(pr_labels) and item.get("mention")
),
None,
)
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as out:
if not audit_lane or not rule:
print("matched=false", file=out)
raise SystemExit(0)
head_sha = pr["head"]["sha"]
marker = (
f"<!-- CODE_MOWER_FIX_ROUND:{head_sha}:"
f"{audit_lane['id']}:{rule['builder_lane']} -->"
)
print("matched=true", file=out)
print(f"audit_lane={audit_lane['id']}", file=out)
print(f"builder_lane={rule['builder_lane']}", file=out)
print(f"mention={rule['mention']}", file=out)
print(f"head_sha={head_sha}", file=out)
print(f"marker={marker}", file=out)
needs_labels = [lane["needs"] for lane in audit_lanes if lane.get("needs")]
Path(".code-mower-fix-round-needs-labels.txt").write_text(
"\n".join(needs_labels) + "\n",
encoding="utf-8",
)
PY
- name: Post fix-round mention
if: steps.plan.outputs.matched == 'true'
shell: bash
env:
AUDIT_LANE: ${{ steps.plan.outputs.audit_lane }}
BUILDER_LANE: ${{ steps.plan.outputs.builder_lane }}
FIX_ROUND_MENTION: ${{ steps.plan.outputs.mention }}
HEAD_SHA: ${{ steps.plan.outputs.head_sha }}
MARKER: ${{ steps.plan.outputs.marker }}
run: |
set -euo pipefail
if [ -z "${GH_TOKEN:-}" ]; then
echo "::error::${CODE_MOWER_DISPATCH_TOKEN_ENV} secret is missing or empty; fix-round mentions must be posted by a human-owned token"
exit 1
fi
code_mower_handle_rate_limit() {
rate_limited=false
for file in "$@"; do
if [ -s "${file}" ] && grep -qiE 'API rate limit exceeded|rate limit' "${file}"; then
rate_limited=true
fi
done
[ "${rate_limited}" = "true" ] || return 1
reset_epoch="$(gh api rate_limit --jq '.resources.core.reset // .rate.reset // ""' 2>/dev/null || true)"
if [[ "${reset_epoch}" =~ ^[0-9]+$ ]]; then
now_epoch="$(date -u +%s)"
wait_seconds=$((reset_epoch - now_epoch + 5))
reset_iso="$(date -u -d "@${reset_epoch}" "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || echo "${reset_epoch}")"
if [ "${wait_seconds}" -gt 0 ] && [ "${wait_seconds}" -le 240 ]; then
echo "::notice::GitHub API rate limit hit; backing off until ${reset_iso}."
sleep "${wait_seconds}"
else
echo "::notice::GitHub API rate limit hit; reset at ${reset_iso}; exiting cleanly so a later event can retry."
fi
else
echo "::notice::GitHub API rate limit hit; reset time unavailable; exiting cleanly so a later event can retry."
fi
return 0
}
comments_output="$(mktemp)"
comments_error="$(mktemp)"
if ! gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate -q '.[].body' >"${comments_output}" 2>"${comments_error}"; then
if code_mower_handle_rate_limit "${comments_error}" "${comments_output}"; then
exit 0
fi
cat "${comments_error}" >&2
exit 1
fi
bodies="$(cat "${comments_output}")"
if printf '%s' "${bodies}" | grep -qF -- "${MARKER}"; then
echo "fix round already dispatched for ${HEAD_SHA} (${AUDIT_LANE}/${BUILDER_LANE})"
exit 0
fi
needs_labels="$(paste -sd ', ' .code-mower-fix-round-needs-labels.txt)"
short_sha="${HEAD_SHA:0:7}"
body="${FIX_ROUND_MENTION} The **${AUDIT_LANE}** audit lane BLOCKED this PR (head ${short_sha}). Read the latest Code Mower audit comments on this PR, address every blocking finding without scope additions, push to this branch, then re-add: \`${needs_labels}\`. If a finding is wrong, reply with evidence and add \`${NEEDS_OWNER_LABEL}\`.
${MARKER}"
body_file="$(mktemp)"
printf '%s\n' "${body}" > "${body_file}"
comment_error="$(mktemp)"
if ! gh pr comment "${PR_NUMBER}" --repo "${GITHUB_REPOSITORY}" --body-file "${body_file}" 2>"${comment_error}"; then
if code_mower_handle_rate_limit "${comment_error}"; then
exit 0
fi
cat "${comment_error}" >&2
exit 1
fi
echo "dispatched fix round for #${PR_NUMBER} (${AUDIT_LANE}/${BUILDER_LANE}, ${short_sha})"