-
Notifications
You must be signed in to change notification settings - Fork 0
262 lines (240 loc) Β· 9.73 KB
/
Copy pathapi-spec.yml
File metadata and controls
262 lines (240 loc) Β· 9.73 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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
on:
pull_request:
paths:
- "src/**/*.php"
- "config/**"
- "composer.json"
- "composer.lock"
- "public/spec.yaml"
- "docker-compose.yml"
- "docker-compose.override.yml"
name: API Spec review
env:
COMPOSE_USER: root
jobs:
api-spec:
runs-on: ubuntu-latest
name: Ensure committed API specification is up to date
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 2
- name: Cache vendor
uses: actions/cache@v5
with:
path: vendor
key: vendor-php8.4-${{ hashFiles('composer.lock') }}
restore-keys: vendor-php8.4-
- name: Install dependencies
run: |
docker network create frontend
# The spec export only needs PHP β pull phpfpm alone and run it as a
# one-off (--no-deps skips mariadb/rabbit), not the whole stack.
docker compose pull --quiet phpfpm
docker compose run --rm --no-deps phpfpm composer install --no-interaction
- name: Export API specification
run: |
docker compose run --rm --no-deps phpfpm bin/console api:openapi:export --yaml --output=public/spec.yaml --no-interaction
- name: Check for changes in specification
id: git-diff-spec
continue-on-error: true
run: git diff --diff-filter=ACMRT --exit-code public/spec.yaml
- name: Find previous export comment
id: prev-export-comment
env:
GH_TOKEN: ${{ github.token }}
run: |
id=$(gh api \
"repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \
--paginate \
--jq '.[] | select(.body | startswith("<!-- api-spec-export -->")) | .id' \
| tail -n1)
echo "id=${id:-}" >> "$GITHUB_OUTPUT"
- name: Comment PR - spec out of date
if: steps.git-diff-spec.outcome == 'failure'
env:
GH_TOKEN: ${{ github.token }}
PREV_ID: ${{ steps.prev-export-comment.outputs.id }}
run: |
{
echo "<!-- api-spec-export -->"
echo "## π Exported API specification file not up to date"
echo ""
echo "Run \`task api:spec:export\` to export the API specification, then commit and push the changes."
} > comment.md
if [ -n "$PREV_ID" ]; then
jq -Rs '{body: .}' < comment.md \
| gh api "repos/${{ github.repository }}/issues/comments/$PREV_ID" --method PATCH --input -
else
gh pr comment ${{ github.event.pull_request.number }} --body-file comment.md
fi
# Self-heal: once the committed spec matches the export again, edit the
# previous π comment to β
instead of leaving a stale failure comment.
- name: Mark export comment resolved (when up to date)
if: steps.git-diff-spec.outcome == 'success' && steps.prev-export-comment.outputs.id != ''
env:
GH_TOKEN: ${{ github.token }}
PREV_ID: ${{ steps.prev-export-comment.outputs.id }}
run: |
{
echo "<!-- api-spec-export -->"
echo "## β
Exported API specification is up to date"
echo ""
echo "_Resolved β the committed \`public/spec.yaml\` matches the export._"
} > comment.md
jq -Rs '{body: .}' < comment.md \
| gh api "repos/${{ github.repository }}/issues/comments/$PREV_ID" --method PATCH --input -
- name: Fail job api spec is not up to date
if: steps.git-diff-spec.outcome == 'failure'
run: |
exit 1
detect-breaking-changes:
name: Detect breaking changes in API specification
runs-on: ubuntu-latest
needs: [api-spec]
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Fetch base branch for comparison
env:
BASE_REF: ${{ github.base_ref }}
run: git fetch --depth=1 origin "$BASE_REF"
# oasdiff cannot parse `headers: []` (it expects a map); normalise both specs.
- name: Sanitise specs (headers -> map)
env:
BASE_REF: ${{ github.base_ref }}
run: |
mkdir -p .api-spec-tmp
git show "origin/$BASE_REF:public/spec.yaml" | sed 's/headers: \[\]/headers: {}/g' > .api-spec-tmp/base.yaml
sed 's/headers: \[\]/headers: {}/g' public/spec.yaml > .api-spec-tmp/revision.yaml
- name: Detect breaking changes
id: breaking
continue-on-error: true
uses: oasdiff/oasdiff-action/breaking@v0.1.5
with:
base: .api-spec-tmp/base.yaml
revision: .api-spec-tmp/revision.yaml
fail-on: ERR
# Compare effective (flattened) schemas so an allOf/$ref restructure is
# not reported as removed properties. Never masks real diffs.
flatten-allof: true
# Upload to oasdiff.com to get a side-by-side review link (exposed as
# the review_url output), but suppress the action's own comment with an
# empty token β we post a single combined comment below.
review: true
github-token: ""
- name: Generate changelog
id: changelog
continue-on-error: true
uses: oasdiff/oasdiff-action/changelog@v0.1.5
with:
base: .api-spec-tmp/base.yaml
revision: .api-spec-tmp/revision.yaml
format: markdown
output-to-file: changelog.md
flatten-allof: true
# As above: keep the upload/review_url output, suppress the auto-comment.
review: true
github-token: ""
- name: Determine whether the spec changed
id: changes
run: |
# oasdiff writes "No changelog changes" (v0.1.x) / "No changes" (older)
# when the spec is unchanged; treat either as no change.
if [ -s changelog.md ] && ! grep -qiE 'no (changelog )?changes' changelog.md; then
echo "has_changes=true" >> "$GITHUB_OUTPUT"
else
echo "has_changes=false" >> "$GITHUB_OUTPUT"
fi
- name: Find previous workflow comment
id: prev-comment
env:
GH_TOKEN: ${{ github.token }}
run: |
id=$(gh api \
"repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \
--paginate \
--jq '.[] | select(.body | startswith("<!-- api-spec-workflow -->")) | .id' \
| tail -n1)
echo "id=${id:-}" >> "$GITHUB_OUTPUT"
- name: Comment PR - non-breaking changes
if: steps.breaking.outcome == 'success' && steps.changes.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ github.token }}
PREV_ID: ${{ steps.prev-comment.outputs.id }}
REVIEW_URL: ${{ steps.changelog.outputs.review_url }}
run: |
{
echo "<!-- api-spec-workflow -->"
echo "## β οΈ API specification β non-breaking changes"
echo ""
echo "<details><summary>API changes</summary>"
echo ""
cat changelog.md
echo ""
echo "</details>"
if [ -n "$REVIEW_URL" ]; then
printf '\nπ [View the full side-by-side review](%s)\n' "$REVIEW_URL"
fi
} > comment.md
if [ -n "$PREV_ID" ]; then
jq -Rs '{body: .}' < comment.md \
| gh api "repos/${{ github.repository }}/issues/comments/$PREV_ID" --method PATCH --input -
else
gh pr comment ${{ github.event.pull_request.number }} --body-file comment.md
fi
- name: Comment PR - breaking changes
if: steps.breaking.outcome == 'failure'
env:
GH_TOKEN: ${{ github.token }}
PREV_ID: ${{ steps.prev-comment.outputs.id }}
REVIEW_URL: ${{ steps.breaking.outputs.review_url }}
run: |
{
echo "<!-- api-spec-workflow -->"
echo "## π API specification β breaking changes detected"
echo ""
if [ -s changelog.md ]; then
echo "<details><summary>API changes</summary>"
echo ""
cat changelog.md
echo ""
echo "</details>"
else
echo "The breaking-changes check flagged incompatible changes. Review the workflow logs for details."
fi
if [ -n "$REVIEW_URL" ]; then
printf '\nπ [View the full side-by-side review](%s)\n' "$REVIEW_URL"
fi
} > comment.md
if [ -n "$PREV_ID" ]; then
jq -Rs '{body: .}' < comment.md \
| gh api "repos/${{ github.repository }}/issues/comments/$PREV_ID" --method PATCH --input -
else
gh pr comment ${{ github.event.pull_request.number }} --body-file comment.md
fi
- name: Mark previous comment resolved (when no changes)
if: steps.breaking.outcome == 'success' && steps.changes.outputs.has_changes == 'false' && steps.prev-comment.outputs.id != ''
env:
GH_TOKEN: ${{ github.token }}
PREV_ID: ${{ steps.prev-comment.outputs.id }}
run: |
{
echo "<!-- api-spec-workflow -->"
echo "## β
API specification"
echo ""
echo "_No changes detected on this run β previous diff resolved._"
} > comment.md
jq -Rs '{body: .}' < comment.md \
| gh api "repos/${{ github.repository }}/issues/comments/$PREV_ID" --method PATCH --input -
- name: Fail if breaking changes detected
if: steps.breaking.outcome == 'failure'
run: |
exit 1