Skip to content

Sync OpenAPI client #29

Sync OpenAPI client

Sync OpenAPI client #29

Workflow file for this run

name: Sync OpenAPI client
# Daily: pull the latest OpenAPI spec, regenerate the Kotlin REST client, and
# open a PR only when the regenerated output differs from what's committed.
# Mirrors the automation in massive-com/openapi-spec-changelog.
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
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
# Cache the openapi-generator JAR (version pinned in openapitools.json)
# so we don't re-download ~30MB every run.
- name: Cache openapi-generator
uses: actions/cache@v4
with:
path: ~/.openapi-generator-cli
key: openapi-generator-7.23.0
- name: Install openapi-generator-cli
run: npm install -g @openapitools/openapi-generator-cli
# GENERATOR defaults to "native": uses openapi-generator-cli + JDK on PATH.
- 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-jvm with OpenAPI spec"
ref: ${{ env.BRANCH }}
files: |
src/
docs/
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-jvm with OpenAPI spec ($(date -u +'%Y-%m-%d'))" \
--body "Automated regeneration from \`https://api.massive.com/openapi\` via \`scripts/generate.sh\` (openapi-generator 7.23.0).
- Regenerated REST client: \`com.massive.client\` (apis, models, infrastructure, docs, tests)
- Hand-written WebSocket client (\`com.massive.client.websocket\`) preserved
- Curated \`README.md\` / \`build.gradle\` 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-jvm 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"