Skip to content

Sync OpenAPI client #27

Sync OpenAPI client

Sync OpenAPI client #27

Workflow file for this run

name: Sync OpenAPI client
# Daily: pull the latest OpenAPI spec, regenerate the Go REST client with
# oapi-codegen, and open a brand-new PR only when the regenerated output differs
# from what's committed. Mirrors the automation in massive-com/client-jvm and
# massive-com/client-js (adapted to the Go toolchain).
on:
schedule:
- cron: '0 15 * * *' # 07:00 America/Vancouver
workflow_dispatch:
permissions:
contents: write
pull-requests: write
concurrency:
group: sync-openapi
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
steps:
# Mint a short-lived token for the org GitHub App. The default GITHUB_TOKEN
# can't open PRs (org policy: "Allow GitHub Actions to create and approve
# pull requests" is off). The App token isn't subject to that restriction,
# triggers required checks, and authors the PR as the app bot so a human
# can still review.
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.MASSIVE_CLIENT_LIBRARY_AUTOMATION_APP_ID }}
private-key: ${{ secrets.MASSIVE_CLIENT_LIBRARY_AUTOMATION_APP_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
persist-credentials: true
# The generator is oapi-codegen, a Go tool invoked via `go run <pkg>@<ver>`
# from scripts/generate.sh. setup-go caches the module + build cache, so the
# pinned generator is only downloaded/compiled once across runs.
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24.x'
# Node runs the spec pull (rest/scripts/pull_spec.js) and the generated-code
# post-processing (rest/scripts/fix-go-clashes.js).
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '22'
# jq is preinstalled on ubuntu-latest runners (used to pre-process the spec).
- name: Regenerate client
run: bash scripts/generate.sh
- name: Detect changes
id: diff
run: |
git add -A
if git diff --cached --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No changes — spec + generated output match what's committed."
else
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Changes detected:"
git diff --cached --stat | tail -25
fi
# A unique branch per run (date + run id) so every sync opens a brand-new
# PR and never reuses/updates a previous one.
- name: Create sync branch
if: steps.diff.outputs.changed == 'true'
run: |
BRANCH="bot/openapi-sync-$(date -u +'%Y-%m-%d')-${GITHUB_RUN_ID}"
echo "BRANCH=$BRANCH" >> "$GITHUB_ENV"
git checkout -B "$BRANCH"
- name: Commit and push
if: steps.diff.outputs.changed == 'true'
uses: iarekylew00t/verified-bot-commit@v2
with:
token: ${{ steps.app-token.outputs.token }}
message: "Sync client-go with OpenAPI spec"
ref: ${{ env.BRANCH }}
files: |
rest/
scripts/
- name: Open PR
if: steps.diff.outputs.changed == 'true'
id: pr
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
url=$(gh pr create \
--base master --head "$BRANCH" \
--title "[bot] Sync client-go with OpenAPI spec ($(date -u +'%Y-%m-%d'))" \
--body "Automated regeneration from \`https://api.massive.com/openapi\` via \`scripts/generate.sh\` (oapi-codegen v2.5.1).
- Regenerated REST client: \`rest/gen/client.gen.go\` + committed spec \`rest/scripts/openapi.json\`
- Hand-written WebSocket client (\`websocket/\`) and REST helpers (\`rest/client.go\`, \`rest/iterator.go\`) preserved
- Curated \`README.md\` / \`go.mod\` preserved
Please review the diff before merging.")
echo "url=$url" >> "$GITHUB_OUTPUT"
# Best-effort label — don't fail the run if the app lacks label perms.
gh label create automated --color ededed --description "Automated PR" --force >/dev/null 2>&1 || true
gh pr edit "$url" --add-label automated >/dev/null 2>&1 || true
- name: Notify Slack
if: steps.diff.outputs.changed == 'true'
env:
SLACK_CLIENT_LIBRARY_WEBHOOK: ${{ secrets.SLACK_CLIENT_LIBRARY_WEBHOOK }}
PR_URL: ${{ steps.pr.outputs.url }}
run: |
if [ -z "$SLACK_CLIENT_LIBRARY_WEBHOOK" ]; then
echo "No Slack webhook configured — skipping."
exit 0
fi
payload=$(jq -n --arg url "$PR_URL" --arg date "$(date -u +'%Y-%m-%d')" '{
blocks: [
{ type: "header", text: { type: "plain_text", text: ("client-go OpenAPI sync – " + $date), emoji: true } },
{ type: "section", text: { type: "mrkdwn", text: ("A new OpenAPI sync PR is ready for review:\n<" + $url + "|" + $url + ">") } }
]
}')
resp=$(curl -sS -X POST -H 'Content-type: application/json' --data "$payload" "$SLACK_CLIENT_LIBRARY_WEBHOOK")
[ "$resp" = "ok" ] && echo "✅ Slack posted" || echo "❌ Slack post failed: $resp"