SDK Generation #8
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: SDK Generation | |
| # Active generator: openapi-python-client (OSS). The Speakeasy pipeline is | |
| # dormant in speakeasy_generation.yaml (free tier allows one generated SDK | |
| # per workspace; convoy.js holds that slot). | |
| # | |
| # Keeps the same workflow filename and dispatch inputs as the Speakeasy | |
| # version so the frain-dev/convoy dispatcher (speakeasy-sdk.yml) works | |
| # unchanged. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| force: | |
| # Accepted for dispatcher compatibility. Generation is deterministic | |
| # from the spec, so there is nothing to force: no diff means no PR. | |
| description: Accepted for compatibility; regeneration is always run | |
| required: false | |
| default: "false" | |
| type: string | |
| feature_branch: | |
| description: Branch for SDK changes | |
| required: false | |
| type: string | |
| schedule: | |
| - cron: "0 6 * * 1" | |
| # Serialize generations: overlapping cron/dispatch runs race on the same | |
| # branch/PR. Queue instead of cancel so a triggered regen is never dropped. | |
| concurrency: | |
| group: sdk-generation | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| generate: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| with: | |
| # Prefer a PAT: PRs opened with GITHUB_TOKEN do not trigger | |
| # pull_request workflows, so verify CI would never run on them. | |
| token: ${{ secrets.SDK_BOT_PAT || secrets.GITHUB_TOKEN }} | |
| - name: Setup Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 | |
| with: | |
| python-version: "3.11" | |
| - name: Install generator | |
| # Pin both so regeneration output is reproducible; ruff is the | |
| # generator's post-processing formatter. | |
| run: pip install openapi-python-client==0.29.0 ruff==0.15.22 | |
| - name: Regenerate client | |
| run: ./scripts/generate.sh | |
| - name: Detect changes | |
| id: diff | |
| run: | | |
| if git diff --quiet && [ -z "$(git status --porcelain)" ]; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| echo "No client changes; skipping PR." >> "$GITHUB_STEP_SUMMARY" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Prepare feature branch | |
| if: steps.diff.outputs.changed == 'true' | |
| id: branch | |
| env: | |
| # Never interpolate free-form dispatch inputs into run: directly. | |
| FEATURE_BRANCH_INPUT: ${{ inputs.feature_branch }} | |
| run: | | |
| if [ -n "$FEATURE_BRANCH_INPUT" ]; then | |
| # SDK PRs must come from a reviewable feature branch, never a | |
| # protected ref or an option-looking / metacharacter name. | |
| case "$FEATURE_BRANCH_INPUT" in | |
| main|master|release/*|-*|*[!a-zA-Z0-9._/-]*) | |
| echo "::error::Invalid feature_branch '$FEATURE_BRANCH_INPUT'" | |
| exit 1 | |
| ;; | |
| esac | |
| echo "name=$FEATURE_BRANCH_INPUT" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "name=sdk-regen-$(date -u +%Y%m%d)" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Push branch and open PR | |
| if: steps.diff.outputs.changed == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.SDK_BOT_PAT || secrets.GITHUB_TOKEN }} | |
| BRANCH: ${{ steps.branch.outputs.name }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git checkout -B "$BRANCH" | |
| git add -A | |
| git commit -m "feat: regenerate API client from OpenAPI spec" | |
| # Force push is safe: the regen branch is fully derived from main | |
| # plus this deterministic generation; any previous content is stale. | |
| git push --force origin "$BRANCH" | |
| existing=$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number // empty') | |
| if [ -z "$existing" ]; then | |
| gh pr create \ | |
| --head "$BRANCH" \ | |
| --title "feat: regenerate API client from OpenAPI spec" \ | |
| --body "Automated regeneration via openapi-python-client from \`docs/v3/openapi3.yaml\` on frain-dev/convoy main. Hand-written webhook verify (\`src/convoy/utils/\`) is untouched by the sync script." | |
| echo "Opened PR for $BRANCH" >> "$GITHUB_STEP_SUMMARY" | |
| else | |
| echo "Updated existing PR #$existing" >> "$GITHUB_STEP_SUMMARY" | |
| fi |