Skip to content

Commit b0be84c

Browse files
turegjorupclaude
andcommitted
Comment on PR only when api-spec drifts or changes
Adapts itk-dev/devops_itksites's two-job api-spec workflow to this repo's v2 spec layout, with one behaviour change: stay quiet when the spec is unchanged. itksites' "no changes detected" comment lands on every PR that touches src/, which is most of them; suppressing that branch removes the noise while keeping the signal — the workflow now only posts on (a) committed spec out of date with the source, (b) non-breaking spec changes (changelog), or (c) breaking spec changes (changelog + failure). --edit-last keeps the PR to one in-place comment across pushes. Pinned oasdiff-action to v0.0.44 instead of @main; path filters restrict the run to PRs that could plausibly affect the spec; the breaking-changes job depends on the export job so a drifting spec isn't compared against the base. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 200654b commit b0be84c

1 file changed

Lines changed: 122 additions & 16 deletions

File tree

.github/workflows/apispec.yaml

Lines changed: 122 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,44 @@
11
### ### Api Spec
22
###
33
### Re-exports the OpenAPI spec (`public/api-spec-v2.{yaml,json}`) from the
4-
### API Platform configuration and fails if the result differs from the
5-
### committed copy.
4+
### API Platform configuration. Posts a PR comment **only** when something
5+
### needs attention — spec drift, non-breaking changes, or breaking changes —
6+
### and stays quiet otherwise. The comment is edited in place across runs
7+
### so a PR carries at most one comment from this workflow.
68
###
79
### #### Assumptions
810
###
911
### 1. A docker compose service named `phpfpm` can be run and `bin/console`
1012
### can be run inside the `phpfpm` service.
1113
### 2. The committed `public/api-spec-v2.{yaml,json}` are kept in sync with
12-
### the API Platform config.
14+
### the API Platform configuration via `composer update-api-spec`.
1315

14-
on: pull_request
16+
on:
17+
pull_request:
18+
paths:
19+
- "src/**/*.php"
20+
- "config/**"
21+
- "composer.json"
22+
- "composer.lock"
23+
- "public/api-spec-v2.yaml"
24+
- "public/api-spec-v2.json"
25+
- "docker-compose.yml"
1526

1627
name: Api Spec
1728

1829
env:
1930
COMPOSE_USER: runner
2031

2132
jobs:
22-
apispec:
33+
api-spec-export:
34+
name: Ensure API specification is up to date
2335
runs-on: ubuntu-latest
24-
name: API Specification validation
36+
permissions:
37+
contents: read
38+
pull-requests: write
2539
steps:
2640
- name: Checkout
2741
uses: actions/checkout@v6
28-
with:
29-
fetch-depth: 2
3042

3143
- name: Cache vendor
3244
uses: actions/cache@v5
@@ -41,14 +53,108 @@ jobs:
4153
- name: Install Dependencies
4254
run: docker compose run --rm phpfpm composer install
4355

44-
- name: Export specifications (yaml)
45-
run: docker compose run --rm phpfpm bin/console api:openapi:export --yaml --output=public/api-spec-v2.yaml --no-interaction
56+
- name: Export specifications
57+
run: |
58+
docker compose run --rm phpfpm bin/console api:openapi:export --yaml --output=public/api-spec-v2.yaml --no-interaction
59+
docker compose run --rm phpfpm bin/console api:openapi:export --output=public/api-spec-v2.json --no-interaction
60+
61+
- name: Check for uncommitted changes
62+
id: git-diff-spec
63+
continue-on-error: true
64+
run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.yaml public/api-spec-v2.json
65+
66+
- name: Comment PR if spec is outdated
67+
if: steps.git-diff-spec.outcome == 'failure'
68+
env:
69+
GH_TOKEN: ${{ github.token }}
70+
run: |
71+
gh pr comment ${{ github.event.pull_request.number }} \
72+
--body "$(cat <<'EOF'
73+
## API specification not up to date
74+
75+
The committed API specification files do not match the exported output.
76+
77+
Please run the following command, then commit and push the changes:
78+
79+
```shell
80+
docker compose exec phpfpm composer update-api-spec
81+
```
82+
EOF
83+
)" \
84+
--create-if-none --edit-last
85+
86+
- name: Fail if spec is outdated
87+
if: steps.git-diff-spec.outcome == 'failure'
88+
run: exit 1
89+
90+
api-spec-breaking-changes:
91+
name: Detect breaking changes in API specification
92+
runs-on: ubuntu-latest
93+
needs: [api-spec-export]
94+
permissions:
95+
contents: read
96+
pull-requests: write
97+
steps:
98+
- name: Checkout
99+
uses: actions/checkout@v6
100+
101+
- name: Fetch base branch for comparison
102+
run: git fetch --depth=1 origin ${{ github.base_ref }}
103+
104+
- name: Detect breaking changes
105+
id: breaking
106+
continue-on-error: true
107+
uses: oasdiff/oasdiff-action/breaking@v0.0.44
108+
with:
109+
base: "origin/${{ github.base_ref }}:public/api-spec-v2.yaml"
110+
revision: "public/api-spec-v2.yaml"
111+
fail-on: ERR
112+
113+
- name: Generate changelog
114+
id: changelog
115+
continue-on-error: true
116+
uses: oasdiff/oasdiff-action/changelog@v0.0.44
117+
with:
118+
base: "origin/${{ github.base_ref }}:public/api-spec-v2.yaml"
119+
revision: "public/api-spec-v2.yaml"
120+
format: markdown
121+
output-to-file: changelog.md
122+
123+
# Stay quiet when nothing changed — neither breaking nor non-breaking.
124+
# Comments only fire on the two branches below.
46125

47-
- name: Check for changes in specifications (yaml)
48-
run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.yaml
126+
- name: Comment PR - non-breaking changes
127+
if: steps.breaking.outcome == 'success' && hashFiles('changelog.md') != ''
128+
env:
129+
GH_TOKEN: ${{ github.token }}
130+
run: |
131+
{
132+
echo "## API Specification - Non-breaking changes"
133+
echo ""
134+
cat changelog.md
135+
} > comment.md
136+
gh pr comment ${{ github.event.pull_request.number }} \
137+
--body-file comment.md \
138+
--create-if-none --edit-last
49139
50-
- name: Export specifications (json)
51-
run: docker compose run --rm phpfpm bin/console api:openapi:export --output=public/api-spec-v2.json --no-interaction
140+
- name: Comment PR - breaking changes
141+
if: steps.breaking.outcome == 'failure'
142+
env:
143+
GH_TOKEN: ${{ github.token }}
144+
run: |
145+
{
146+
echo "## API Specification - Breaking changes detected"
147+
echo ""
148+
if [ -s changelog.md ]; then
149+
cat changelog.md
150+
else
151+
echo "The breaking changes action detected incompatible changes. Review the action logs for details."
152+
fi
153+
} > comment.md
154+
gh pr comment ${{ github.event.pull_request.number }} \
155+
--body-file comment.md \
156+
--create-if-none --edit-last
52157
53-
- name: Check for changes in specifications (json)
54-
run: git diff --diff-filter=ACMRT --exit-code public/api-spec-v2.json
158+
- name: Fail if breaking changes detected
159+
if: steps.breaking.outcome == 'failure'
160+
run: exit 1

0 commit comments

Comments
 (0)