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
2 changes: 1 addition & 1 deletion .github/workflows/copilot_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: [self-hosted, codex, Linux]
timeout-minutes: 120
concurrency:
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-analysis
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-analysis
cancel-in-progress: true
permissions:
checks: write
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/copilot_pull_request_review_state.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: [self-hosted, codex, Linux]
timeout-minutes: 120
concurrency:
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-review-state
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-review-state
cancel-in-progress: true
permissions:
checks: write
Expand Down
4 changes: 2 additions & 2 deletions docs/features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ decorative media or expose configuration for it.
**Coordination policies:** issue and comment mutation workflows preserve admitted events in a workflow-local queue. Deployment mutations use a shared issue-scoped native queue. Commit and Pull Request each have a separate repository/branch latest-revision lane, so paired events cannot cancel one another.
</Info>

GitHub's native [concurrency](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency) can cancel in-progress runs when a newer one starts. Its default `queue: single` retains only one pending run; `queue: max` allows up to 100 pending jobs or workflow runs when `cancel-in-progress` is `false` or omitted. The replaceable branch jobs therefore use event-specific keys: Commit uses `copilot-push-${{ github.repository }}-${{ github.ref_name }}`; Pull Request code/lifecycle analysis uses the branch key with an `analysis` suffix; and the dedicated review-state workflow uses the same branch key with a `review-state` suffix. Each lane cancels only its own obsolete revision. Commit still synchronizes issue progress, then Bugbot performs a read-only exact-head lookup because a `push` payload does not contain PR identity. A validated open same-repository PR makes the push stop before review-context loading or agent invocation; the PR `synchronize` event exclusively owns review for that head. This prevents duplicate reviews without letting a push or review-state event cancel useful PR analysis. Branches without an open PR retain push-time Bugbot. Metadata-only `pull_request: edited` events are not subscribed because Copilot changes the PR body itself; excluding them prevents self-generated run cascades and preserves human metadata edits. Application-level head guards prevent an older run from updating a newer PR, and the next code/lifecycle run repairs any durable half-transition discovered after cancellation. Fixed workflow/job names expose analysis and review-state checks without leaking an unevaluated expression when GitHub skips bot-authored events. A separate merge-group workflow avoids a skipped duplicate on normal PRs while deliberately preserving the exact `Copilot - Pull Request` required-check context for branch-protection compatibility.
GitHub's native [concurrency](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency) can cancel in-progress runs when a newer one starts. Its default `queue: single` retains only one pending run; `queue: max` allows up to 100 pending jobs or workflow runs when `cancel-in-progress` is `false` or omitted. The replaceable event jobs therefore use event-specific keys: Commit uses `copilot-push-${{ github.repository }}-${{ github.ref_name }}`; Pull Request code/lifecycle analysis uses the repository and PR number with an `analysis` suffix; and the dedicated review-state workflow uses the same PR-number key with a `review-state` suffix. Different PRs sharing a head branch cannot cancel one another. Each PR lane cancels only its own obsolete revision. Commit still synchronizes issue progress, then Bugbot performs a read-only exact-head lookup because a `push` payload does not contain PR identity. A validated open same-repository PR makes the push stop before review-context loading or agent invocation; the PR `synchronize` event exclusively owns review for that head. This prevents duplicate reviews without letting a push or review-state event cancel useful PR analysis. Branches without an open PR retain push-time Bugbot. Metadata-only `pull_request: edited` events are not subscribed because Copilot changes the PR body itself; excluding them prevents self-generated run cascades and preserves human metadata edits. Application-level head guards prevent an older run from updating a newer PR, and the next code/lifecycle run repairs any durable half-transition discovered after cancellation. Fixed workflow/job names expose analysis and review-state checks without leaking an unevaluated expression when GitHub skips bot-authored events. A separate merge-group workflow avoids a skipped duplicate on normal PRs while deliberately preserving the exact `Copilot - Pull Request` required-check context for branch-protection compatibility.

For non-replaceable issue and comment mutations, Copilot adds an application-level queue per workflow: every started run waits for earlier active runs of that same workflow, so intermediate events are not discarded by a native concurrency group. Runs triggered by the PAT owner that would only re-trigger the normal pipeline complete before entering this queue.

Expand Down Expand Up @@ -221,7 +221,7 @@ jobs:
project-ids: '2,3'
```

Issue and comment mutation workflows use the application-level queue above to preserve intermediate events. Release, hotfix, and managed-PR deployment mutations use native `concurrency` with `queue: max` and `cancel-in-progress: false`, which preserves pending deployment runs and is valid GitHub Actions syntax. Without `queue: max`, native concurrency retains only one pending run and can discard intermediate mutations. See [deployment concurrency validation](/issues/deployment-orchestration#validating-queue-max) before changing generated workflows in response to a linter error. Commit and Pull Request use separate native groups with cancellation for their own replaceable branch revisions, so they cannot cancel one another. Native concurrency also remains appropriate for replaceable read-only workflows such as CI and the optional, manually dispatched RepoWise analysis.
Issue and comment mutation workflows use the application-level queue above to preserve intermediate events. Release, hotfix, and managed-PR deployment mutations use native `concurrency` with `queue: max` and `cancel-in-progress: false`, which preserves pending deployment runs and is valid GitHub Actions syntax. Without `queue: max`, native concurrency retains only one pending run and can discard intermediate mutations. See [deployment concurrency validation](/issues/deployment-orchestration#validating-queue-max) before changing generated workflows in response to a linter error. Commit and Pull Request use separate native groups with cancellation for their own replaceable branch or PR revisions, so they cannot cancel one another. Native concurrency also remains appropriate for replaceable read-only workflows such as CI and the optional, manually dispatched RepoWise analysis.

---

Expand Down
4 changes: 2 additions & 2 deletions docs/pull-requests/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
name: Copilot - Pull Request
runs-on: ubuntu-latest
concurrency:
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-analysis
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-analysis
cancel-in-progress: true
steps:
- name: Checkout Repository
Expand Down Expand Up @@ -78,7 +78,7 @@ jobs:
name: Copilot - Pull Request Review State
runs-on: ubuntu-latest
concurrency:
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-review-state
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-review-state
cancel-in-progress: true
steps:
- uses: actions/checkout@v5
Expand Down
13 changes: 11 additions & 2 deletions docs/pull-requests/workflow-setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
name: Copilot - Pull Request
runs-on: ubuntu-latest
concurrency:
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-analysis
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-analysis
cancel-in-progress: true
steps:
- name: Checkout Repository
Expand Down Expand Up @@ -120,11 +120,20 @@ jobs:
Install the shipped `copilot_pull_request_review_state.yml` alongside it. That
workflow listens only to `pull_request_review`, uses the fixed
`Copilot - Pull Request Review State` workflow/job name, and uses the same
branch key with a `review-state` suffix.
PR-number key with a `review-state` suffix.

Existing installations retain their workflow files when the `@v3` action moves.
To adopt PR-number groups, use a released CLI containing this fix and review
`copilot setup --web --update-workflows`, or apply the two group expressions in a
reviewed maintenance PR. Update analysis and review-state together and retain
project-specific setup/release customizations. No new Variable, Secret or
permission is required. Current-head checks and review remain the merge gate.

- **`token`** is required (use a fine-grained PAT with repo and project permissions; see [Authentication](/authentication)).
- **`project-ids`** is optional but needed if you want PRs linked to GitHub Project boards and moved to columns (e.g. "In Progress").
- The conditional fetch downloads only the two commit objects needed by the incremental reviewer. Keep it when `synchronize` is enabled; a full-history checkout is not required.
- Different PR numbers use independent groups even when they share a head branch
and target different bases. Repeated events retain the same PR/lane identity.
- Keep both PR-specific concurrency groups and cancellation policies exactly as
shown. A newer code/lifecycle event cancels only obsolete analysis; a newer
review event cancels only obsolete review-state observation. The Commit
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vypdev/copilot",
"version": "3.10.3",
"version": "3.10.4",
"packageManager": "pnpm@10.12.4",
"pnpm": {
"overrides": {
Expand Down
6 changes: 3 additions & 3 deletions scripts/validate-workflow-contract.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const ISOLATED_REPOWISE_VENV_NAME = 'repowise-venv-${{ github.run_id }}-${{ gith
const ISOLATED_REPOWISE_REPORT_NAME = 'repowise-report-${{ github.run_id }}-${{ github.run_attempt }}-code-health';
const CRLF_WHITESPACE = 'core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol';
const PUSH_BRANCH_CONCURRENCY_GROUP = 'copilot-push-${{ github.repository }}-${{ github.ref_name }}';
const PULL_REQUEST_ANALYSIS_CONCURRENCY_GROUP = 'copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-analysis';
const PULL_REQUEST_REVIEW_STATE_CONCURRENCY_GROUP = 'copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-review-state';
const PULL_REQUEST_ANALYSIS_CONCURRENCY_GROUP = 'copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-analysis';
const PULL_REQUEST_REVIEW_STATE_CONCURRENCY_GROUP = 'copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-review-state';
const BUGBOT_CONCURRENCY_JOBS = Object.freeze({
'copilot_commit.yml': Object.freeze({
jobId: 'copilot-commits',
Expand Down Expand Up @@ -703,7 +703,7 @@ function assertReviewConcurrency(relativeFile, workflow) {
}
if (job.concurrency?.group !== group
|| job.concurrency?.['cancel-in-progress'] !== cancelInProgress) {
throw new Error(`${relativeFile} job ${jobId} must use its workflow- and event-specific branch group, avoid cross-canceling another event owner, and cancel superseded runs within its lane.`);
throw new Error(`${relativeFile} job ${jobId} must use its workflow- and event-specific group (PR number for pull requests), avoid cross-canceling another event owner, and cancel superseded runs within its lane.`);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion setup/workflows/copilot_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 120
concurrency:
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-analysis
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-analysis
cancel-in-progress: true
permissions:
checks: write
Expand Down
2 changes: 1 addition & 1 deletion setup/workflows/copilot_pull_request_review_state.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 120
concurrency:
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}-review-state
group: copilot-pr-${{ github.repository }}-${{ github.event.pull_request.number }}-review-state
cancel-in-progress: true
permissions:
checks: write
Expand Down
Loading
Loading