diff --git a/.github/workflows/release-please-reusable.yml b/.github/workflows/release-please-reusable.yml index a3da862..43d041d 100644 --- a/.github/workflows/release-please-reusable.yml +++ b/.github/workflows/release-please-reusable.yml @@ -116,6 +116,22 @@ jobs: permissions: contents: write pull-requests: write + # Serialize runs within the caller's repo. Unserialized, overlapping runs + # (a burst of merges, or one push GitHub delivers twice) each build a + # release commit, and the slower one fails updating the release branch + # ref. The group is repo-wide, not per-ref, because release-please always + # targets the default branch. `queue: max` keeps every run waiting its + # turn; without it GitHub keeps one pending run and cancels it when a + # newer one queues, which shows as a failed check on that commit. A + # caller that declares a group of this name deadlocks with this job. + concurrency: + group: release-please-reusable + queue: max + cancel-in-progress: false + # Bound a hung run: it holds the concurrency group, so no later run in + # the repo can start until it ends. The slowest caller's job takes just + # under five minutes. + timeout-minutes: 30 # Hoist credentials to job env so step-level `if:` can read them — GitHub # allows the `env` context in step `if:` only when env is defined at the # workflow or job level, and the `secrets` context isn't allowed in `if:` diff --git a/README.md b/README.md index 432770d..67c9220 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,8 @@ jobs: Treat `body`, `pr`, `prs` and `name` as untrusted text: they come from commit messages and PR titles. Pass them to a script through `env:` — never interpolate them directly into a `run:` block. +The job runs in a repo-wide `release-please-reusable` concurrency group with `queue: max` and without `cancel-in-progress`, so overlapping pushes (a burst of merges, or a single push GitHub delivers twice) wait their turn instead of racing to update the release PR branch. Each queued run reads the branch's current HEAD, so a run that starts after its commit has been overtaken finds nothing left to do. The job times out after 30 minutes so a hung run cannot hold the group indefinitely. Don't declare a concurrency group of the same name in the caller; caller and callee would deadlock on it. + Inputs: | Name | Type | Default | Description |