Sync OpenAPI client #19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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" |