diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml index fdacecbdf4..7629dffb82 100644 --- a/.github/workflows/ai-moderator.lock.yml +++ b/.github/workflows/ai-moderator.lock.yml @@ -46,7 +46,7 @@ name: "AI Moderator" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" + group: "gh-aw-${{ github.workflow }}" run-name: "AI Moderator" diff --git a/.github/workflows/auto-triage-issues.lock.yml b/.github/workflows/auto-triage-issues.lock.yml index 9d34e93bc6..152c81d6db 100644 --- a/.github/workflows/auto-triage-issues.lock.yml +++ b/.github/workflows/auto-triage-issues.lock.yml @@ -42,7 +42,7 @@ name: "Auto-Triage Issues" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" + group: "gh-aw-${{ github.workflow }}" run-name: "Auto-Triage Issues" diff --git a/.github/workflows/bot-detection.lock.yml b/.github/workflows/bot-detection.lock.yml index 797818d822..5412561c9d 100644 --- a/.github/workflows/bot-detection.lock.yml +++ b/.github/workflows/bot-detection.lock.yml @@ -46,7 +46,7 @@ name: "Bot Detection Agent 🔍🤖" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}" + group: "gh-aw-${{ github.workflow }}" cancel-in-progress: true run-name: "Bot Detection Agent 🔍🤖" diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 646c1b069b..c33965cedb 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -43,7 +43,7 @@ name: "Changeset Generator" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" + group: "gh-aw-${{ github.workflow }}" cancel-in-progress: true run-name: "Changeset Generator" diff --git a/.github/workflows/example-custom-error-patterns.lock.yml b/.github/workflows/example-custom-error-patterns.lock.yml index 890c0df337..2a6e470601 100644 --- a/.github/workflows/example-custom-error-patterns.lock.yml +++ b/.github/workflows/example-custom-error-patterns.lock.yml @@ -35,7 +35,7 @@ name: "Example: Custom Error Patterns" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" + group: "gh-aw-${{ github.workflow }}" run-name: "Example: Custom Error Patterns" diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 95fc93f444..a6cc6666cb 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -37,7 +37,7 @@ name: "Issue Classifier" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" + group: "gh-aw-${{ github.workflow }}" run-name: "Issue Classifier" diff --git a/.github/workflows/security-compliance.lock.yml b/.github/workflows/security-compliance.lock.yml index a16cc985a0..d31493313b 100644 --- a/.github/workflows/security-compliance.lock.yml +++ b/.github/workflows/security-compliance.lock.yml @@ -46,7 +46,7 @@ name: "Security Compliance Campaign" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" + group: "gh-aw-${{ github.workflow }}" run-name: "Security Compliance Campaign" diff --git a/.github/workflows/test-dispatcher.lock.yml b/.github/workflows/test-dispatcher.lock.yml index 5a036e6e88..2e3ab8e216 100644 --- a/.github/workflows/test-dispatcher.lock.yml +++ b/.github/workflows/test-dispatcher.lock.yml @@ -32,7 +32,7 @@ name: "Test Dispatcher Workflow" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" + group: "gh-aw-${{ github.workflow }}" run-name: "Test Dispatcher Workflow" diff --git a/.github/workflows/workflow-generator.lock.yml b/.github/workflows/workflow-generator.lock.yml index 010f60e827..86ad82d43e 100644 --- a/.github/workflows/workflow-generator.lock.yml +++ b/.github/workflows/workflow-generator.lock.yml @@ -37,7 +37,7 @@ name: "Workflow Generator" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" + group: "gh-aw-${{ github.workflow }}" run-name: "Workflow Generator" diff --git a/docs/src/content/docs/reference/concurrency.md b/docs/src/content/docs/reference/concurrency.md index 3f1ad90c74..d4c61dbab6 100644 --- a/docs/src/content/docs/reference/concurrency.md +++ b/docs/src/content/docs/reference/concurrency.md @@ -15,10 +15,12 @@ Workflow-level concurrency groups include the workflow name plus context-specifi | Trigger Type | Concurrency Group | Cancel In Progress | |--------------|-------------------|-------------------| -| Issues | `gh-aw-${{ github.workflow }}-${{ issue.number }}` | No | -| Pull Requests | `gh-aw-${{ github.workflow }}-${{ pr.number \|\| ref }}` | Yes (new commits cancel outdated runs) | -| Push | `gh-aw-${{ github.workflow }}-${{ github.ref }}` | No | +| Issues | `gh-aw-${{ github.workflow }}` | No | +| Pull Requests | `gh-aw-${{ github.workflow }}` | Yes (new commits cancel outdated runs) | +| Push | `gh-aw-${{ github.workflow }}` | No | +| Discussions | `gh-aw-${{ github.workflow }}` | No | | Schedule/Other | `gh-aw-${{ github.workflow }}` | No | +| Command Triggers | `gh-aw-${{ github.workflow }}-${{ issue.number \|\| pr.number }}` | No | This ensures workflows on different issues, PRs, or branches run concurrently without interference. diff --git a/pkg/workflow/concurrency.go b/pkg/workflow/concurrency.go index c79452ceaa..9318d4e670 100644 --- a/pkg/workflow/concurrency.go +++ b/pkg/workflow/concurrency.go @@ -132,28 +132,8 @@ func buildConcurrencyGroupKeys(workflowData *WorkflowData, isCommandTrigger bool if isCommandTrigger { // For command workflows: use issue/PR number keys = append(keys, "${{ github.event.issue.number || github.event.pull_request.number }}") - } else if isPullRequestWorkflow(workflowData.On) && isIssueWorkflow(workflowData.On) { - // Mixed workflows with both issue and PR triggers: use issue/PR number - keys = append(keys, "${{ github.event.issue.number || github.event.pull_request.number }}") - } else if isPullRequestWorkflow(workflowData.On) && isDiscussionWorkflow(workflowData.On) { - // Mixed workflows with PR and discussion triggers: use PR/discussion number - keys = append(keys, "${{ github.event.pull_request.number || github.event.discussion.number }}") - } else if isIssueWorkflow(workflowData.On) && isDiscussionWorkflow(workflowData.On) { - // Mixed workflows with issue and discussion triggers: use issue/discussion number - keys = append(keys, "${{ github.event.issue.number || github.event.discussion.number }}") - } else if isPullRequestWorkflow(workflowData.On) { - // Pure PR workflows: use PR number if available, otherwise fall back to ref for compatibility - keys = append(keys, "${{ github.event.pull_request.number || github.ref }}") - } else if isIssueWorkflow(workflowData.On) { - // Issue workflows: use issue number - keys = append(keys, "${{ github.event.issue.number }}") - } else if isDiscussionWorkflow(workflowData.On) { - // Discussion workflows: use discussion number - keys = append(keys, "${{ github.event.discussion.number }}") - } else if isPushWorkflow(workflowData.On) { - // Push workflows: use ref to differentiate between branches - keys = append(keys, "${{ github.ref }}") } + // All other workflows: sequentialize per workflow (no event-specific keys) return keys } diff --git a/pkg/workflow/concurrency_test.go b/pkg/workflow/concurrency_test.go index cbdd136ec2..3fe27f6983 100644 --- a/pkg/workflow/concurrency_test.go +++ b/pkg/workflow/concurrency_test.go @@ -26,7 +26,7 @@ func TestConcurrencyRules(t *testing.T) { description string }{ { - name: "PR workflow should have dynamic concurrency with cancel", + name: "PR workflow should be sequentialized per workflow with cancel", frontmatter: `--- on: pull_request: @@ -37,10 +37,10 @@ tools: ---`, filename: "pr-workflow.md", expectedConcurrency: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" + group: "gh-aw-${{ github.workflow }}" cancel-in-progress: true`, shouldHaveCancel: true, - description: "PR workflows should use dynamic concurrency with PR number and cancellation", + description: "PR workflows are sequentialized per workflow with cancellation", }, { name: "command workflow should have dynamic concurrency without cancel", @@ -75,7 +75,7 @@ tools: description: "Regular workflows should use static concurrency without cancellation", }, { - name: "push workflow should use dynamic concurrency with ref", + name: "push workflow should be sequentialized per workflow", frontmatter: `--- on: push: @@ -86,12 +86,12 @@ tools: ---`, filename: "push-workflow.md", expectedConcurrency: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.ref }}"`, + group: "gh-aw-${{ github.workflow }}"`, shouldHaveCancel: false, - description: "Push workflows should use dynamic concurrency with github.ref", + description: "Push workflows are sequentialized per workflow", }, { - name: "issue workflow should have dynamic concurrency with issue number", + name: "issue workflow should be sequentialized per workflow", frontmatter: `--- on: issues: @@ -102,9 +102,9 @@ tools: ---`, filename: "issue-workflow.md", expectedConcurrency: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}"`, + group: "gh-aw-${{ github.workflow }}"`, shouldHaveCancel: false, - description: "Issue workflows use global concurrency with engine ID and slot", + description: "Issue workflows are sequentialized per workflow (no issue number)", }, } @@ -158,7 +158,7 @@ func TestGenerateConcurrencyConfig(t *testing.T) { description string }{ { - name: "PR workflow should have dynamic concurrency with cancel and PR number", + name: "PR workflow should be sequentialized per workflow", workflowData: &WorkflowData{ On: `on: pull_request: @@ -167,9 +167,9 @@ func TestGenerateConcurrencyConfig(t *testing.T) { }, isAliasTrigger: false, expected: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" + group: "gh-aw-${{ github.workflow }}" cancel-in-progress: true`, - description: "PR workflows should use PR number or ref with cancellation", + description: "PR workflows are sequentialized per workflow with cancellation", }, { name: "Alias workflow should have dynamic concurrency without cancel", @@ -185,7 +185,7 @@ func TestGenerateConcurrencyConfig(t *testing.T) { description: "Alias workflows should use dynamic concurrency with ref but without cancellation", }, { - name: "Push workflow should have dynamic concurrency with ref", + name: "Push workflow should be sequentialized per workflow", workflowData: &WorkflowData{ On: `on: push: @@ -194,8 +194,8 @@ func TestGenerateConcurrencyConfig(t *testing.T) { }, isAliasTrigger: false, expected: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.ref }}"`, - description: "Push workflows should use github.ref without cancellation", + group: "gh-aw-${{ github.workflow }}"`, + description: "Push workflows are sequentialized per workflow", }, { name: "Regular workflow should use static concurrency without cancel", @@ -211,7 +211,7 @@ func TestGenerateConcurrencyConfig(t *testing.T) { description: "Regular workflows should use static concurrency without cancellation", }, { - name: "Issue workflow should have dynamic concurrency with issue number", + name: "Issue workflow should be sequentialized per workflow", workflowData: &WorkflowData{ On: `on: issues: @@ -220,11 +220,11 @@ func TestGenerateConcurrencyConfig(t *testing.T) { }, isAliasTrigger: false, expected: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}"`, - description: "Issue workflows should use issue number without cancellation", + group: "gh-aw-${{ github.workflow }}"`, + description: "Issue workflows are sequentialized per workflow (no issue number)", }, { - name: "Issue comment workflow should have dynamic concurrency with issue number", + name: "Issue comment workflow should be sequentialized per workflow", workflowData: &WorkflowData{ On: `on: issue_comment: @@ -233,11 +233,11 @@ func TestGenerateConcurrencyConfig(t *testing.T) { }, isAliasTrigger: false, expected: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}"`, - description: "Issue comment workflows should use issue number without cancellation", + group: "gh-aw-${{ github.workflow }}"`, + description: "Issue comment workflows are sequentialized per workflow (no issue number)", }, { - name: "Mixed issue and PR workflow should have dynamic concurrency with issue/PR number", + name: "Mixed issue and PR workflow should be sequentialized per workflow", workflowData: &WorkflowData{ On: `on: issues: @@ -248,12 +248,12 @@ func TestGenerateConcurrencyConfig(t *testing.T) { }, isAliasTrigger: false, expected: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}" + group: "gh-aw-${{ github.workflow }}" cancel-in-progress: true`, - description: "Mixed workflows should use issue/PR number with cancellation enabled", + description: "Mixed workflows are sequentialized per workflow with cancellation", }, { - name: "Discussion workflow should have dynamic concurrency with discussion number", + name: "Discussion workflow should be sequentialized per workflow", workflowData: &WorkflowData{ On: `on: discussion: @@ -262,11 +262,11 @@ func TestGenerateConcurrencyConfig(t *testing.T) { }, isAliasTrigger: false, expected: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.discussion.number }}"`, - description: "Discussion workflows should use discussion number without cancellation", + group: "gh-aw-${{ github.workflow }}"`, + description: "Discussion workflows are sequentialized per workflow (no discussion number)", }, { - name: "Mixed issue and discussion workflow should have dynamic concurrency with issue/discussion number", + name: "Mixed issue and discussion workflow should be sequentialized per workflow", workflowData: &WorkflowData{ On: `on: issues: @@ -277,8 +277,8 @@ func TestGenerateConcurrencyConfig(t *testing.T) { }, isAliasTrigger: false, expected: `concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.discussion.number }}"`, - description: "Mixed issue and discussion workflows should use issue/discussion number without cancellation", + group: "gh-aw-${{ github.workflow }}"`, + description: "Mixed issue and discussion workflows are sequentialized per workflow", }, { name: "Existing concurrency should not be overridden", @@ -639,29 +639,29 @@ func TestBuildConcurrencyGroupKeys(t *testing.T) { description: "Alias workflows should use issue/PR number", }, { - name: "Pure PR workflow should include PR number", + name: "Pure PR workflow should NOT include PR number", workflowData: &WorkflowData{ On: `on: pull_request: types: [opened, synchronize]`, }, isAliasTrigger: false, - expected: []string{"gh-aw", "${{ github.workflow }}", "${{ github.event.pull_request.number || github.ref }}"}, - description: "Pure PR workflows should use PR number", + expected: []string{"gh-aw", "${{ github.workflow }}"}, + description: "Pure PR workflows are sequentialized per workflow", }, { - name: "Pure issue workflow should include issue number", + name: "Pure issue workflow should NOT include issue number", workflowData: &WorkflowData{ On: `on: issues: types: [opened, edited]`, }, isAliasTrigger: false, - expected: []string{"gh-aw", "${{ github.workflow }}", "${{ github.event.issue.number }}"}, - description: "Pure issue workflows should use issue number", + expected: []string{"gh-aw", "${{ github.workflow }}"}, + description: "Pure issue workflows are sequentialized per workflow", }, { - name: "Mixed issue and PR workflow should include issue/PR number", + name: "Mixed issue and PR workflow should NOT include issue/PR number", workflowData: &WorkflowData{ On: `on: issues: @@ -670,22 +670,22 @@ func TestBuildConcurrencyGroupKeys(t *testing.T) { types: [opened, synchronize]`, }, isAliasTrigger: false, - expected: []string{"gh-aw", "${{ github.workflow }}", "${{ github.event.issue.number || github.event.pull_request.number }}"}, - description: "Mixed workflows should use issue/PR number", + expected: []string{"gh-aw", "${{ github.workflow }}"}, + description: "Mixed workflows are sequentialized per workflow", }, { - name: "Pure discussion workflow should include discussion number", + name: "Pure discussion workflow should NOT include discussion number", workflowData: &WorkflowData{ On: `on: discussion: types: [created, edited]`, }, isAliasTrigger: false, - expected: []string{"gh-aw", "${{ github.workflow }}", "${{ github.event.discussion.number }}"}, - description: "Pure discussion workflows should use discussion number", + expected: []string{"gh-aw", "${{ github.workflow }}"}, + description: "Pure discussion workflows are sequentialized per workflow", }, { - name: "Mixed issue and discussion workflow should include issue/discussion number", + name: "Mixed issue and discussion workflow should NOT include issue/discussion number", workflowData: &WorkflowData{ On: `on: issues: @@ -694,22 +694,22 @@ func TestBuildConcurrencyGroupKeys(t *testing.T) { types: [created, edited]`, }, isAliasTrigger: false, - expected: []string{"gh-aw", "${{ github.workflow }}", "${{ github.event.issue.number || github.event.discussion.number }}"}, - description: "Mixed issue and discussion workflows should use issue/discussion number", + expected: []string{"gh-aw", "${{ github.workflow }}"}, + description: "Mixed issue and discussion workflows are sequentialized per workflow", }, { - name: "Push workflow should include github.ref", + name: "Push workflow should NOT include github.ref", workflowData: &WorkflowData{ On: `on: push: branches: [main]`, }, isAliasTrigger: false, - expected: []string{"gh-aw", "${{ github.workflow }}", "${{ github.ref }}"}, - description: "Push workflows should use github.ref", + expected: []string{"gh-aw", "${{ github.workflow }}"}, + description: "Push workflows are sequentialized per workflow", }, { - name: "Mixed push and PR workflow should use PR logic (PR takes priority)", + name: "Mixed push and PR workflow should be sequentialized per workflow", workflowData: &WorkflowData{ On: `on: push: @@ -718,8 +718,8 @@ func TestBuildConcurrencyGroupKeys(t *testing.T) { types: [opened, synchronize]`, }, isAliasTrigger: false, - expected: []string{"gh-aw", "${{ github.workflow }}", "${{ github.event.pull_request.number || github.ref }}"}, - description: "Mixed push+PR workflows should use PR logic since PR is checked first", + expected: []string{"gh-aw", "${{ github.workflow }}"}, + description: "Mixed push+PR workflows are sequentialized per workflow", }, { name: "Other workflow should not include additional keys",