-
Notifications
You must be signed in to change notification settings - Fork 216
Expand file tree
/
Copy pathagent-server-rest-api-breakage.yml
More file actions
156 lines (135 loc) · 6.5 KB
/
agent-server-rest-api-breakage.yml
File metadata and controls
156 lines (135 loc) · 6.5 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
---
name: REST API breakage checks
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
agent-server-rest-api:
name: REST API (OpenAPI)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Install workspace deps (dev)
run: uv sync --frozen --group dev
- name: Install oasdiff
run: |
curl -L https://raw.githubusercontent.com/oasdiff/oasdiff/main/install.sh | sh -s -- -b /usr/local/bin
oasdiff --version
- name: Run agent server REST API breakage check
id: api_breakage
# Let this step fail so CI is visibly red on breakage.
# Later reporting steps still run because they use if: always().
env:
REST_API_BREAKAGE_BASE_REF: ${{ github.event_name == 'pull_request' && github.base_ref || '' }}
run: |
uv run --with packaging python .github/scripts/check_agent_server_rest_api_breakage.py 2>&1 | tee api-breakage.log
exit_code=${PIPESTATUS[0]}
echo "exit_code=${exit_code}" >> "$GITHUB_OUTPUT"
exit "${exit_code}"
- name: Write REST API breakage summary
if: ${{ always() }}
env:
EXIT_CODE: ${{ steps.api_breakage.outputs.exit_code }}
IS_FORK: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }}
LOG_PATH: api-breakage.log
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
python3 <<'PY' >> "$GITHUB_STEP_SUMMARY"
import os
from pathlib import Path
exit_code = int(os.environ.get('EXIT_CODE', '0') or '0')
is_fork = os.environ.get('IS_FORK', 'false') == 'true'
run_url = os.environ['RUN_URL']
status = '✅ **PASSED**' if exit_code == 0 else '❌ **FAILED**'
print(f'## REST API breakage checks (OpenAPI) — {status}')
print()
print(f"**Result:** {status}")
if exit_code != 0:
print()
print('> ⚠️ Breaking REST API changes or policy violations detected.')
print()
if is_fork:
print(
'_Fork PR detected: sticky PR comment was skipped because '
'the GitHub token is read-only for `pull_request` workflows '
'from forks._'
)
print()
if exit_code != 0:
try:
log = Path(os.environ['LOG_PATH']).read_text()
except Exception as exc:
log = f'Unable to read log file: {exc}'
excerpt = log[:1000].replace('```', '``\\`')
print('<details><summary>Log excerpt (first 1000 characters)</summary>')
print()
print('```text')
print(excerpt)
print('```')
print()
print('</details>')
print()
print(f'[Action log]({run_url})')
PY
- name: Post REST API breakage report to PR
if: ${{ always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }}
uses: actions/github-script@v8
env:
EXIT_CODE: ${{ steps.api_breakage.outputs.exit_code }}
LOG_PATH: api-breakage.log
with:
script: |
const fs = require('fs');
const marker = '<!-- agent-server-rest-api-breakage-report -->';
const exitCode = Number(process.env.EXIT_CODE || '0');
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const status = exitCode === 0 ? '✅ **PASSED**' : '❌ **FAILED**';
let body = `${marker}\n## REST API breakage checks (OpenAPI) — ${status}\n\n**Result:** ${status}\n`;
if (exitCode !== 0) {
body += `\n> ⚠️ Breaking REST API changes or policy violations detected.\n`;
let log = '';
try {
log = fs.readFileSync(process.env.LOG_PATH, 'utf8');
} catch (e) {
log = `Unable to read log file: ${e}`;
}
const excerpt = log.slice(0, 1000).replace(/```/g, '``\\`');
body += `\n<details><summary>Log excerpt (first 1000 characters)</summary>\n\n\`\`\`text\n${excerpt}\n\`\`\`\n\n</details>\n`;
}
body += `\n[Action log](${runUrl})\n`;
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number,
per_page: 100,
});
const existing = comments.find((c) => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}