Route Sync #3
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: Route Sync | |
| # Opens a PR when the backend's canonical v2 route manifest drifts from the | |
| # vendored copy; that PR fails test_route_coverage until the matching SDK | |
| # methods + `# v2:covers` comments are added. | |
| # | |
| # Needs a cross-repo credential (the default GITHUB_TOKEN can't read the private | |
| # backend repo, and PRs it opens don't trigger CI). Use EITHER: | |
| # - a fine-grained PAT (owner TextQLLabs, repos demo2 + textql-python, | |
| # Contents: read/write, Pull requests: read/write) as secret | |
| # BACKEND_REPO_TOKEN; or | |
| # - a GitHub App (var SYNC_APP_ID + secret SYNC_APP_PRIVATE_KEY) installed on | |
| # both repos with the same permissions. | |
| # The App is preferred (no expiry); the job no-ops until one is configured. | |
| on: | |
| schedule: | |
| - cron: "0 12 * * *" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| sync: | |
| runs-on: ubuntu-latest | |
| env: | |
| BACKEND_REPO_NAME: ${{ vars.BACKEND_REPO_NAME || 'demo2' }} | |
| MANIFEST_PATH: ${{ vars.BACKEND_MANIFEST_PATH || 'compute/pkg/platform/v2/routes.manifest.json' }} | |
| # Track the PROD contract: the SDK defaults to app.textql.com, and demo2's | |
| # `main` is staging — prod is the `release` branch. Tracking `main` would | |
| # sync the SDK ahead of what prod serves. | |
| MANIFEST_REF: ${{ vars.BACKEND_MANIFEST_REF || 'release' }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Mint App token | |
| id: app-token | |
| if: ${{ vars.SYNC_APP_ID != '' }} | |
| uses: actions/create-github-app-token@v1 | |
| with: | |
| app-id: ${{ vars.SYNC_APP_ID }} | |
| private-key: ${{ secrets.SYNC_APP_PRIVATE_KEY }} | |
| repositories: | | |
| ${{ vars.BACKEND_REPO_NAME || 'demo2' }} | |
| ${{ github.event.repository.name }} | |
| - name: Resolve token | |
| id: token | |
| env: | |
| APP_TOKEN: ${{ steps.app-token.outputs.token }} | |
| PAT: ${{ secrets.BACKEND_REPO_TOKEN }} | |
| run: | | |
| tok="${APP_TOKEN:-$PAT}" | |
| if [ -z "$tok" ]; then echo "has_token=false" >> "$GITHUB_OUTPUT"; else echo "has_token=true" >> "$GITHUB_OUTPUT"; fi | |
| echo "::add-mask::$tok" | |
| echo "value=$tok" >> "$GITHUB_OUTPUT" | |
| - name: Fetch upstream manifest | |
| id: fetch | |
| if: ${{ steps.token.outputs.has_token == 'true' }} | |
| env: | |
| GH_TOKEN: ${{ steps.token.outputs.value }} | |
| run: | | |
| set -euo pipefail | |
| if ! gh api "repos/${{ github.repository_owner }}/${BACKEND_REPO_NAME}/contents/${MANIFEST_PATH}?ref=${MANIFEST_REF}" \ | |
| -H "Accept: application/vnd.github.raw" > upstream.json 2> fetch_err; then | |
| if grep -qi "not found" fetch_err; then | |
| echo "manifest not on '${MANIFEST_REF}' yet (or path moved); skipping" | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| cat fetch_err >&2 | |
| exit 1 | |
| fi | |
| changed=$(python3 -c "import json; a=set(json.load(open('upstream.json'))); b=set(json.load(open('tests/routes.manifest.json'))); print('true' if a!=b else 'false')") | |
| if [ "$changed" = "true" ]; then cp upstream.json tests/routes.manifest.json; fi | |
| echo "changed=$changed" >> "$GITHUB_OUTPUT" | |
| - name: Open PR | |
| if: ${{ steps.fetch.outputs.changed == 'true' }} | |
| uses: peter-evans/create-pull-request@v6 | |
| with: | |
| token: ${{ steps.token.outputs.value }} | |
| branch: route-sync | |
| add-paths: tests/routes.manifest.json | |
| commit-message: "chore: sync v2 route manifest from backend" | |
| title: "chore: sync v2 route manifest from backend" | |
| body: | | |
| The backend `/v2` route set changed. Add/rename the matching SDK | |
| methods and their `# v2:covers` comments until `test_route_coverage` | |
| passes. |