Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/spec-drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ name: API specification drift
# replaces the vendored copy, with a summary of the changes and the list of
# conformance tests that fail against it: the to-do list for updating the
# bindings. See MAINTAINING.md.
#
# The pull request is opened with a GitHub App token, so that it triggers CI
# (pull requests opened with GITHUB_TOKEN do not) and is authored by the app's
# bot account. Configure the app with the SPEC_SYNC_APP_CLIENT_ID repository
# variable and the SPEC_SYNC_APP_PRIVATE_KEY repository secret. Without them,
# the workflow falls back to GITHUB_TOKEN.

on:
schedule:
Expand All @@ -21,6 +27,27 @@ jobs:
steps:
- uses: actions/checkout@v7

# Runs on every check, not only when the specification changed, so that
# an expired key or an uninstalled app is noticed straight away.
- uses: actions/create-github-app-token@v3
if: vars.SPEC_SYNC_APP_CLIENT_ID != ''
id: app-token
with:
client-id: ${{ vars.SPEC_SYNC_APP_CLIENT_ID }}
private-key: ${{ secrets.SPEC_SYNC_APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write

- name: Identify the app's bot account
if: steps.app-token.outcome == 'success'
id: bot
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
APP_SLUG: ${{ steps.app-token.outputs.app-slug }}
run: |
user_id="$(gh api "/users/${APP_SLUG}[bot]" --jq .id)"
echo "identity=${APP_SLUG}[bot] <${user_id}+${APP_SLUG}[bot]@users.noreply.github.com>" >> "$GITHUB_OUTPUT"

- name: Compare with the published specification
id: sync
run: |
Expand Down Expand Up @@ -76,8 +103,9 @@ jobs:
- uses: peter-evans/create-pull-request@v8
if: steps.sync.outputs.changed == 'true'
with:
# A token other than GITHUB_TOKEN lets the pull request trigger CI.
token: ${{ secrets.SPEC_SYNC_TOKEN || github.token }}
token: ${{ steps.app-token.outputs.token || github.token }}
author: ${{ steps.bot.outputs.identity || 'github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>' }}
committer: ${{ steps.bot.outputs.identity || 'github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>' }}
branch: api-spec-update
delete-branch: true
commit-message: Update the vendored TypeSafe OpenAPI specification
Expand Down
36 changes: 32 additions & 4 deletions MAINTAINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,38 @@ opens or updates the `api-spec-update` pull request. The description lists
what was added and removed, and the conformance tests that fail against the
new specification.

Pull requests opened with the default `GITHUB_TOKEN` do not trigger other
workflows. To have CI run on them, add a fine-grained personal access token
with *contents* and *pull requests* write access as the `SPEC_SYNC_TOKEN`
repository secret.
The workflow opens the pull request with a GitHub App token, so that CI runs
on it and a bot account is its author. Pull requests opened with the default
`GITHUB_TOKEN` do not trigger other workflows. Without the app, the workflow
still runs, but falls back to `GITHUB_TOKEN`, and CI has to be started by
hand (`gh workflow run ci.yml --ref api-spec-update`).

To set up the app (once):

1. Create a GitHub App owned by the `byteally` organisation (*Organization
settings → Developer settings → GitHub Apps → New GitHub App*):
- any name, such as `typesafe-sdk-spec-sync`, and the repository URL as
the homepage;
- under *Webhook*, clear *Active*;
- *Repository permissions*: *Contents* and *Pull requests*, both *Read and
write*;
- *Where can this GitHub App be installed?*: *Only on this account*.
2. On the app's page, note the *Client ID*, and under *Private keys*
generate a key. A `.pem` file downloads.
3. Install the app (*Install App* in the app's settings) on the `byteally`
organisation, for the `typesafe-sdk` repository only.
4. Store the client ID as a variable and the key as a secret:

```sh
gh variable set SPEC_SYNC_APP_CLIENT_ID --repo byteally/typesafe-sdk --body <client-id>
gh secret set SPEC_SYNC_APP_PRIVATE_KEY --repo byteally/typesafe-sdk < path/to/key.pem
```

Then delete the downloaded `.pem` file.
5. Check the setup with `gh workflow run spec-drift.yml --repo byteally/typesafe-sdk`.
The *create-github-app-token* and *Identify the app's bot account* steps
must succeed. They run on every check, so a revoked key or an uninstalled
app makes the daily run fail.

To check by hand:

Expand Down
Loading