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
16 changes: 4 additions & 12 deletions .github/workflows/gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,16 @@ on:
types: [opened, synchronize, reopened, edited]
push:
branches: [main]
workflow_call:
inputs:
ref:
description: Commit to gate. upstream-sync passes its sync commit and merges only after this run passes.
type: string
required: true
# upstream-sync dispatches this on its sync branch. A dispatched run reports `gate`, `smoke`, and
# `statechart` under the same names as a pull request run, so the main ruleset's required checks
# cover bot syncs too. A reusable call would report `gate / gate` and never satisfy them.
workflow_dispatch:

jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.4
Expand Down Expand Up @@ -59,8 +55,6 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.4
Expand Down Expand Up @@ -93,8 +87,6 @@ jobs:
working-directory: plugins/pstack/skills/statechart/scripts
steps:
- uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
- uses: actions/setup-node@v7
with:
node-version: 22
Expand Down
30 changes: 24 additions & 6 deletions .github/workflows/upstream-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
outputs:
pr: ${{ steps.build.outputs.pr }}
sha: ${{ steps.build.outputs.sha }}
branch: ${{ steps.build.outputs.branch }}
env:
GH_TOKEN: ${{ github.token }}
steps:
Expand Down Expand Up @@ -110,22 +111,39 @@ jobs:
pr=$(gh pr create --base main --head "sync/upstream-$SHORT" \
--title "sync: upstream pstack $SHORT ($version)" --body-file "$RUNNER_TEMP/body.md" | tail -n1)
if [ "$code" -eq 0 ] && [ "$gate" -eq 0 ]; then
printf 'pr=%s\nsha=%s\n' "$pr" "$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
printf 'pr=%s\nsha=%s\nbranch=%s\n' "$pr" "$(git rev-parse HEAD)" "sync/upstream-$SHORT" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "left $pr open for a human: sync exit $code, gate exit $gate"
exit 1

# A merge made with github.token starts no push run on main, so this job is the only full gate a
# sync gets. A red gate skips the merge and leaves the PR open for a human.
# sync gets. It dispatches gate.yml on the sync branch rather than calling it: the dispatched run
# puts `gate`, `smoke`, and `statechart` on the sync commit, which the main ruleset requires before
# any merge. A red gate fails this job, skips the merge, and leaves the PR open for a human.
gate:
needs: sync
if: needs.sync.outputs.sha != ''
runs-on: ubuntu-latest
permissions:
contents: read
uses: ./.github/workflows/gate.yml
with:
ref: ${{ needs.sync.outputs.sha }}
actions: write
env:
GH_TOKEN: ${{ github.token }}
SHA: ${{ needs.sync.outputs.sha }}
BRANCH: ${{ needs.sync.outputs.branch }}
steps:
- run: |
gh workflow run gate.yml --repo "$GITHUB_REPOSITORY" --ref "$BRANCH"
id=""
for _ in $(seq 1 30); do
id=$(gh run list --repo "$GITHUB_REPOSITORY" --workflow gate.yml --event workflow_dispatch \
--branch "$BRANCH" --json databaseId,headSha \
--jq "[.[] | select(.headSha == \"$SHA\")][0].databaseId // empty")
[ -n "$id" ] && break
sleep 10
done
[ -n "$id" ] || { echo "no gate run appeared for $SHA on $BRANCH" >&2; exit 1; }
gh run watch "$id" --repo "$GITHUB_REPOSITORY" --exit-status --interval 30

merge:
needs: [sync, gate]
Expand Down
8 changes: 6 additions & 2 deletions PORTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,12 @@ bash omp-port/check-port.sh "" "$(gh api 'repos/cursor/plugins/commits?path=psta
The gate runs as its own workflow, `gate.yml`, on every pull request and on every push to `main`.
Neither trigger gated the two syncs the bot merged, #19 and #32. Each PR got a `pull_request` run
that ended with no jobs a second after the merge, and the merge, made with `github.token`, started
no `push` run. So `upstream-sync` calls `gate.yml` itself, as a reusable workflow on the sync
commit, and its `merge` job runs only after that call passes. A sync that fails the build,
no `push` run. So `upstream-sync` dispatches `gate.yml` on the sync branch and its `merge` job runs
only after that run passes. A dispatch, unlike a reusable call, reports the checks as `gate`,
`smoke`, and `statechart` on the sync commit. The `main` ruleset requires exactly those three, and a
personal repository cannot exempt the GitHub Actions bot from a ruleset, so a reusable call's
`gate / gate` names would leave every bot merge blocked. The ruleset also requires a pull request
for every change to `main` and forbids force-pushes and deletion. A sync that fails the build,
`check-port.sh`, or `gate.yml` stays open for a human, and later runs stop at the open-PR guard
until someone resolves it.

Expand Down
Loading