-
Notifications
You must be signed in to change notification settings - Fork 0
89 lines (78 loc) · 3.52 KB
/
drift-to-issue.yml
File metadata and controls
89 lines (78 loc) · 3.52 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
name: Drift to issue
# When a Harness drift sensor fails on main (or on the nightly schedule),
# open or update a single tracking GitHub issue per sensor. This stops
# drift signals from rotting in CI logs — they become actionable work
# items instead. Closes the steering-loop arrow: sensor fires → issue
# exists → human decides whether to fix or accept the drift.
#
# Only fires on main / scheduled runs, not on PRs (the in-PR annotation
# from harness.yml is enough there — we don't want every PR to open
# issues).
on:
workflow_run:
workflows: ['Harness']
types: [completed]
branches: [main]
permissions:
contents: read
issues: write
jobs:
open-or-update-issue:
# No workflow-level conclusion check: Harness jobs use
# `continue-on-error: true`, which means the workflow itself concludes
# `success` even when individual sensors fail. We inspect job-level
# conclusions inside the Python loop below — jobs that pass are a no-op.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Find failed jobs and (re)open issues
env:
GH_TOKEN: ${{ github.token }}
RUN_ID: ${{ github.event.workflow_run.id }}
RUN_URL: ${{ github.event.workflow_run.html_url }}
run: |
set -euo pipefail
jobs_json=$(gh api "repos/${{ github.repository }}/actions/runs/${RUN_ID}/jobs" --paginate)
# For each failed job, ensure a single open tracking issue
# exists. Title format `[harness-drift] <job name>` makes
# updates idempotent.
echo "$jobs_json" | python3 - <<'PY'
import json, os, subprocess, sys
jobs = json.loads(sys.stdin.read())["jobs"]
run_url = os.environ["RUN_URL"]
for job in jobs:
if job["conclusion"] != "failure":
continue
name = job["name"]
title = f"[harness-drift] {name}"
body = (
f"The harness drift sensor `{name}` failed on `main`.\n\n"
f"Run: {run_url}\n\n"
"This issue is automatically opened by `.github/workflows/drift-to-issue.yml`.\n"
"It's a *tracking* issue — the sensor will keep firing until either:\n"
" - the underlying drift is resolved (close this issue), or\n"
" - the sensor is intentionally disabled (remove the job from `harness.yml`).\n\n"
"Repeat failures update this same issue rather than opening duplicates."
)
search = subprocess.run(
["gh", "issue", "list", "--state", "open", "--label", "harness-drift",
"--search", f'in:title "{title}"', "--json", "number,title"],
capture_output=True, text=True, check=True,
)
existing = [i for i in json.loads(search.stdout) if i["title"] == title]
if existing:
num = existing[0]["number"]
subprocess.run(
["gh", "issue", "comment", str(num), "--body",
f"Sensor fired again. Run: {run_url}"],
check=True,
)
print(f"updated #{num}: {title}")
else:
subprocess.run(
["gh", "issue", "create", "--title", title, "--body", body,
"--label", "harness-drift"],
check=True,
)
print(f"opened: {title}")
PY