Skip to content

feat: identify the VASP that custodies a crypto wallet account #437

feat: identify the VASP that custodies a crypto wallet account

feat: identify the VASP that custodies a crypto wallet account #437

name: OpenAPI Breaking Changes
on:
pull_request:
branches: [ main ]
paths:
- 'openapi.yaml'
- 'openapi/**'
workflow_dispatch:
permissions:
contents: read
pull-requests: write
issues: write
jobs:
detect:
name: Detect breaking changes
runs-on: ubuntu-latest
steps:
- name: Checkout base spec
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.sha }}
path: base
- name: Checkout head spec
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: head
- name: Install oasdiff
env:
OASDIFF_VERSION: 1.16.0
OASDIFF_SHA256: 2f424431c441a85e2d73ff884609f55c98c283ca2ce3d88537a7a029379dd521
run: |
curl -fsSL \
"https://github.com/oasdiff/oasdiff/releases/download/v${OASDIFF_VERSION}/oasdiff_${OASDIFF_VERSION}_linux_amd64.tar.gz" \
-o /tmp/oasdiff.tgz
echo "${OASDIFF_SHA256} /tmp/oasdiff.tgz" | sha256sum -c -
tar -xzf /tmp/oasdiff.tgz -C /tmp oasdiff
sudo mv /tmp/oasdiff /usr/local/bin/oasdiff
oasdiff --version
- name: Run oasdiff breaking
id: oasdiff
run: |
set +e
oasdiff breaking \
base/openapi.yaml head/openapi.yaml \
--format markdown \
--fail-on ERR > breaking.md
status=$?
# The markdown format prints every finding with a :warning: marker, so it
# cannot be filtered by severity; singleline prefixes each with its level.
oasdiff breaking \
base/openapi.yaml head/openapi.yaml \
--format singleline \
--fail-on ERR > breaking.txt
singleline_status=$?
set -e
# Both runs diff the same specs with the same --fail-on, so their exit codes
# must agree; anything above 1 is a crash rather than a finding.
if [ "$status" -gt 1 ] || [ "$singleline_status" -ne "$status" ]; then
echo "::error::oasdiff exited with $status (markdown) / $singleline_status (singleline)"
exit 1
fi
echo "status=$status" >> "$GITHUB_OUTPUT"
if [ "$status" -ne 0 ] && [ -s breaking.md ]; then
echo "has_breaking=true" >> "$GITHUB_OUTPUT"
else
echo "has_breaking=false" >> "$GITHUB_OUTPUT"
fi
- name: Build comment body
if: steps.oasdiff.outputs.has_breaking == 'true'
env:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
# GitHub rejects a comment body over 65536 characters, and one change to a
# shared schema yields a finding per inheriting subschema per endpoint.
MAX_ERRORS=100
MAX_WARNINGS=25
MAX_BODY=64000
errors=$(grep -c '^error ' breaking.txt || true)
warnings=$(grep -c '^warning ' breaking.txt || true)
# `error at head/openapi.yaml, in API GET /quotes added …` -> `- `GET /quotes` — added …`
fmt() { sed 's/^\(error\|warning\) at [^,]*, in API \([A-Z]* [^ ]*\) /- `\2` — /'; }
{
echo '## :warning: Breaking OpenAPI changes detected'
echo ''
echo "\`oasdiff\` reports **$errors error / $warnings warning** changes to \`openapi.yaml\`."
echo 'This PR will need approval from an API reviewer before merge.'
echo ''
echo "### Errors ($errors)"
echo ''
grep -m "$MAX_ERRORS" '^error ' breaking.txt | fmt
if [ "$errors" -gt "$MAX_ERRORS" ]; then
echo "- _…and $((errors - MAX_ERRORS)) more errors._"
fi
if [ "$warnings" -gt 0 ]; then
echo ''
echo "### Warnings ($warnings)"
echo ''
echo '<details><summary>Show sample</summary>'
echo ''
grep -m "$MAX_WARNINGS" '^warning ' breaking.txt | fmt
if [ "$warnings" -gt "$MAX_WARNINGS" ]; then
echo "- _…and $((warnings - MAX_WARNINGS)) more warnings._"
fi
echo ''
echo '</details>'
fi
echo ''
echo '---'
echo "_Detected by [oasdiff](https://github.com/oasdiff/oasdiff). Full report: [job summary]($RUN_URL) or the \`oasdiff-report\` artifact._"
} > comment.md
if [ "$(wc -c < comment.md)" -gt "$MAX_BODY" ]; then
# Trim on line boundaries so a multi-byte character is never split.
LC_ALL=C awk -v max="$MAX_BODY" '{ n += length($0) + 1; if (n > max) exit } 1' \
comment.md > comment.trimmed
printf '\n_Comment truncated. Full report: [job summary](%s)._\n' "$RUN_URL" >> comment.trimmed
mv comment.trimmed comment.md
fi
- name: Publish full report to job summary
if: steps.oasdiff.outputs.has_breaking == 'true'
run: |
# The step summary is capped at 1 MiB.
{
echo '## oasdiff breaking changes'
echo ''
head -c 900000 breaking.md
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload full report
if: steps.oasdiff.outputs.has_breaking == 'true'
uses: actions/upload-artifact@v4
with:
name: oasdiff-report
path: |
breaking.md
breaking.txt
- name: Ensure breaking-change label exists
if: steps.oasdiff.outputs.has_breaking == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
run: |
gh label create "breaking-change" \
--color B60205 \
--description "Introduces a breaking change to the OpenAPI spec" \
2>/dev/null || true
- name: Add breaking-change label
if: steps.oasdiff.outputs.has_breaking == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: gh pr edit "$PR_NUMBER" --add-label "breaking-change"
- name: Remove breaking-change label if previously set
if: steps.oasdiff.outputs.has_breaking == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: gh pr edit "$PR_NUMBER" --remove-label "breaking-change" || true
- name: Upsert PR comment (breaking)
if: steps.oasdiff.outputs.has_breaking == 'true'
uses: marocchino/sticky-pull-request-comment@v2
with:
header: oasdiff-breaking-changes
path: comment.md
- name: Clear PR comment (no breaking)
if: steps.oasdiff.outputs.has_breaking == 'false'
uses: marocchino/sticky-pull-request-comment@v2
with:
header: oasdiff-breaking-changes
delete: true