Skip to content

Commit 4d4e28b

Browse files
Copilotpelikhan
andauthored
Lock in tag-scoped on.push as a valid scoped trigger (#45362)
* Initial plan * test: cover tag-scoped push validation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> * fix: clarify unscoped push branch and tag messaging Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
1 parent a8875ae commit 4d4e28b

4 files changed

Lines changed: 50 additions & 13 deletions

File tree

pkg/workflow/compiler_filters_validation.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,12 @@ func ValidateEventFilters(frontmatter map[string]any) error {
8989
}
9090

9191
// ValidatePushBranchScope ensures that any push event in the on: section specifies a
92-
// branches or branches-ignore filter. An unscoped push trigger fires on every push to
93-
// every branch, which causes unintended workflow fan-out on feature branches (the
94-
// workflows activate immediately after new lock files are first pushed to the branch,
95-
// producing zero-turn failures for every agentic workflow in the repository).
92+
// branch or tag ref filter. An unscoped push trigger fires on every push to every
93+
// branch and tag, which causes unintended workflow fan-out on feature branches (the workflows
94+
// activate immediately after new lock files are first pushed to the branch, producing
95+
// zero-turn failures for every agentic workflow in the repository).
9696
func ValidatePushBranchScope(frontmatter map[string]any) error {
97-
filterValidationLog.Print("Validating push event branch scope")
97+
filterValidationLog.Print("Validating push event branch/tag scope")
9898

9999
on, exists := frontmatter["on"]
100100
if !exists {
@@ -113,7 +113,7 @@ func ValidatePushBranchScope(frontmatter map[string]any) error {
113113

114114
// A nil push value (bare `push:` key with no sub-keys) is unscoped.
115115
if pushVal == nil {
116-
filterValidationLog.Print("ERROR: push event has no branch scope (nil push value)")
116+
filterValidationLog.Print("ERROR: push event has no branch/tag scope (nil push value)")
117117
return newUnScopedPushError()
118118
}
119119

@@ -140,9 +140,9 @@ func ValidatePushBranchScope(frontmatter map[string]any) error {
140140
func newUnScopedPushError() *WorkflowValidationError {
141141
return NewValidationError(
142142
"on.push",
143-
"push (no branch filter)",
144-
"push event must specify a 'branches', 'branches-ignore', 'tags', or 'tags-ignore' filter; an unscoped push trigger fires on every push to every branch and causes unintended workflow fan-out on feature branches",
145-
"Add a branch or tag filter to the push trigger:\n\non:\n push:\n branches:\n - main",
143+
"push (no branch or tag filter)",
144+
"push event must specify a 'branches', 'branches-ignore', 'tags', or 'tags-ignore' filter; an unscoped push trigger fires on every push to every branch and tag and causes unintended workflow fan-out on feature branches",
145+
"Add a branch or tag filter to the push trigger:\n\non:\n push:\n branches:\n - main\n\n# or for tag-based releases:\n\non:\n push:\n tags:\n - 'v*.*.*'",
146146
)
147147
}
148148

pkg/workflow/compiler_filters_validation_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,28 @@ func TestValidatePushBranchScope(t *testing.T) {
384384
},
385385
wantErr: false,
386386
},
387+
{
388+
name: "push with tags filter",
389+
frontmatter: map[string]any{
390+
"on": map[string]any{
391+
"push": map[string]any{
392+
"tags": []string{"v*.*.*"},
393+
},
394+
},
395+
},
396+
wantErr: false,
397+
},
398+
{
399+
name: "push with tags-ignore filter",
400+
frontmatter: map[string]any{
401+
"on": map[string]any{
402+
"push": map[string]any{
403+
"tags-ignore": []string{"nightly-*"},
404+
},
405+
},
406+
},
407+
wantErr: false,
408+
},
387409
{
388410
name: "push with branches and paths filter",
389411
frontmatter: map[string]any{

pkg/workflow/compiler_orchestrator_frontmatter.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,14 @@ func (c *Compiler) parseFrontmatterSection(markdownPath string) (*frontmatterPar
203203
return nil, err
204204
}
205205

206-
// Validate that push triggers are scoped to specific branches to prevent fan-out.
206+
// Validate that push triggers are scoped to specific branches or tags to prevent fan-out.
207207
// In strict mode this is an error; in non-strict mode it is downgraded to a warning.
208208
if err := ValidatePushBranchScope(frontmatterForValidation); err != nil {
209209
if c.effectiveStrictMode(frontmatterForValidation) {
210-
orchestratorFrontmatterLog.Printf("Push branch scope validation failed: %v", err)
210+
orchestratorFrontmatterLog.Printf("Push branch/tag scope validation failed: %v", err)
211211
return nil, err
212212
}
213-
orchestratorFrontmatterLog.Printf("Push branch scope warning (non-strict mode): %v", err)
213+
orchestratorFrontmatterLog.Printf("Push branch/tag scope warning (non-strict mode): %v", err)
214214
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(err.Error()))
215215
c.IncrementWarningCount()
216216
}

pkg/workflow/push_branch_scope_test.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
)
1515

1616
// TestPushBranchScopeStrictVsNonStrict verifies that an unscoped push trigger
17-
// (missing branches/branches-ignore) is an error in strict mode and a warning in non-strict mode.
17+
// (missing branch/tag ref filters) is an error in strict mode and a warning in non-strict mode.
1818
func TestPushBranchScopeStrictVsNonStrict(t *testing.T) {
1919
tests := []struct {
2020
name string
@@ -65,6 +65,21 @@ on:
6565
- main
6666
---
6767
68+
# Test Workflow
69+
`,
70+
expectError: false,
71+
expectWarning: false,
72+
},
73+
{
74+
name: "scoped push with tags in strict mode is allowed",
75+
content: `---
76+
name: Tag Scoped Push Strict
77+
on:
78+
push:
79+
tags:
80+
- 'v*.*.*'
81+
---
82+
6883
# Test Workflow
6984
`,
7085
expectError: false,

0 commit comments

Comments
 (0)