diff --git a/constants/action.go b/constants/action.go index 4a7f5210..2f37b804 100644 --- a/constants/action.go +++ b/constants/action.go @@ -22,9 +22,12 @@ const ( // ActionSynchronize defines the action for the synchronizing of pull requests. ActionSynchronize = "synchronize" - // ActionLabeled defines the action for the labelin of pull requests. + // ActionLabeled defines the action for the labeling of pull requests. ActionLabeled = "labeled" + // ActionUnlabeled defines the action for the unlabeling of pull requests. + ActionUnlabeled = "unlabeled" + // ActionTransferred defines the action for transferring repository ownership. ActionTransferred = "transferred" diff --git a/constants/allow_events.go b/constants/allow_events.go index 34124f03..5df53926 100644 --- a/constants/allow_events.go +++ b/constants/allow_events.go @@ -23,4 +23,5 @@ const ( AllowSchedule AllowPushDeleteBranch AllowPushDeleteTag + AllowPullUnlabel ) diff --git a/library/actions/pull.go b/library/actions/pull.go index 1bcae12c..8e0063b1 100644 --- a/library/actions/pull.go +++ b/library/actions/pull.go @@ -13,6 +13,7 @@ type Pull struct { Synchronize *bool `json:"synchronize"` Reopened *bool `json:"reopened"` Labeled *bool `json:"labeled"` + Unlabeled *bool `json:"unlabeled"` } // FromMask returns the Pull type resulting from the provided integer mask. @@ -22,6 +23,7 @@ func (a *Pull) FromMask(mask int64) *Pull { a.SetEdited(mask&constants.AllowPullEdit > 0) a.SetReopened(mask&constants.AllowPullReopen > 0) a.SetLabeled(mask&constants.AllowPullLabel > 0) + a.SetUnlabeled(mask&constants.AllowPullUnlabel > 0) return a } @@ -50,6 +52,10 @@ func (a *Pull) ToMask() int64 { mask = mask | constants.AllowPullLabel } + if a.GetUnlabeled() { + mask = mask | constants.AllowPullUnlabel + } + return mask } @@ -100,7 +106,7 @@ func (a *Pull) GetReopened() bool { // GetLabeled returns the Labeled field from the provided Pull. If the object is nil, // or the field within the object is nil, it returns the zero value instead. func (a *Pull) GetLabeled() bool { - // return zero value if Pull type or Reopened field is nil + // return zero value if Pull type or Labeled field is nil if a == nil || a.Labeled == nil { return false } @@ -108,6 +114,17 @@ func (a *Pull) GetLabeled() bool { return *a.Labeled } +// GetUnlabeled returns the Unlabeled field from the provided Pull. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (a *Pull) GetUnlabeled() bool { + // return zero value if Pull type or Unlabeled field is nil + if a == nil || a.Unlabeled == nil { + return false + } + + return *a.Unlabeled +} + // SetOpened sets the Pull Opened field. // // When the provided Pull type is nil, it @@ -160,7 +177,7 @@ func (a *Pull) SetReopened(v bool) { a.Reopened = &v } -// GetLabeled sets the Pull Labeled field. +// SetLabeled sets the Pull Labeled field. // // When the provided Pull type is nil, it // will set nothing and immediately return. @@ -172,3 +189,16 @@ func (a *Pull) SetLabeled(v bool) { a.Labeled = &v } + +// SetUnlabeled sets the Pull Unlabeled field. +// +// When the provided Pull type is nil, it +// will set nothing and immediately return. +func (a *Pull) SetUnlabeled(v bool) { + // return if Pull type is nil + if a == nil { + return + } + + a.Unlabeled = &v +} diff --git a/library/actions/pull_test.go b/library/actions/pull_test.go index 2819c9eb..f4c815b5 100644 --- a/library/actions/pull_test.go +++ b/library/actions/pull_test.go @@ -42,6 +42,14 @@ func TestLibrary_Pull_Getters(t *testing.T) { if test.actions.GetReopened() != test.want.GetReopened() { t.Errorf("GetReopened is %v, want %v", test.actions.GetReopened(), test.want.GetReopened()) } + + if test.actions.GetLabeled() != test.want.GetLabeled() { + t.Errorf("GetLabeled is %v, want %v", test.actions.GetLabeled(), test.want.GetLabeled()) + } + + if test.actions.GetUnlabeled() != test.want.GetUnlabeled() { + t.Errorf("GetUnlabeled is %v, want %v", test.actions.GetUnlabeled(), test.want.GetUnlabeled()) + } } } @@ -70,6 +78,8 @@ func TestLibrary_Pull_Setters(t *testing.T) { test.actions.SetSynchronize(test.want.GetSynchronize()) test.actions.SetEdited(test.want.GetEdited()) test.actions.SetReopened(test.want.GetReopened()) + test.actions.SetLabeled(test.want.GetLabeled()) + test.actions.SetUnlabeled(test.want.GetUnlabeled()) if test.actions.GetOpened() != test.want.GetOpened() { t.Errorf("SetOpened is %v, want %v", test.actions.GetOpened(), test.want.GetOpened()) @@ -86,6 +96,14 @@ func TestLibrary_Pull_Setters(t *testing.T) { if test.actions.GetReopened() != test.want.GetReopened() { t.Errorf("SetReopened is %v, want %v", test.actions.GetReopened(), test.want.GetReopened()) } + + if test.actions.GetLabeled() != test.want.GetLabeled() { + t.Errorf("SetLabeled is %v, want %v", test.actions.GetLabeled(), test.want.GetLabeled()) + } + + if test.actions.GetUnlabeled() != test.want.GetUnlabeled() { + t.Errorf("SetUnlabeled is %v, want %v", test.actions.GetUnlabeled(), test.want.GetUnlabeled()) + } } } @@ -107,7 +125,7 @@ func TestLibrary_Pull_ToMask(t *testing.T) { // setup types actions := testPull() - want := int64(constants.AllowPullOpen | constants.AllowPullSync | constants.AllowPullReopen) + want := int64(constants.AllowPullOpen | constants.AllowPullSync | constants.AllowPullReopen | constants.AllowPullUnlabel) // run test got := actions.ToMask() @@ -124,6 +142,7 @@ func testPull() *Pull { pr.SetEdited(false) pr.SetReopened(true) pr.SetLabeled(false) + pr.SetUnlabeled(true) return pr } diff --git a/library/actions/push_test.go b/library/actions/push_test.go index 330444ba..b0cfba47 100644 --- a/library/actions/push_test.go +++ b/library/actions/push_test.go @@ -128,6 +128,7 @@ func testMask() int64 { constants.AllowPullOpen | constants.AllowPullSync | constants.AllowPullReopen | + constants.AllowPullUnlabel | constants.AllowDeployCreate | constants.AllowCommentCreate | constants.AllowSchedule, diff --git a/library/events.go b/library/events.go index 94262c19..372182b0 100644 --- a/library/events.go +++ b/library/events.go @@ -60,6 +60,8 @@ func (e *Events) Allowed(event, action string) bool { allowed = e.GetPullRequest().GetReopened() case constants.EventPull + ":" + constants.ActionLabeled: allowed = e.GetPullRequest().GetLabeled() + case constants.EventPull + ":" + constants.ActionUnlabeled: + allowed = e.GetPullRequest().GetUnlabeled() case constants.EventTag: allowed = e.GetPush().GetTag() case constants.EventComment + ":" + constants.ActionCreated: @@ -108,6 +110,10 @@ func (e *Events) List() []string { eventSlice = append(eventSlice, constants.EventPull+":"+constants.ActionLabeled) } + if e.GetPullRequest().GetUnlabeled() { + eventSlice = append(eventSlice, constants.EventPull+":"+constants.ActionUnlabeled) + } + if e.GetPush().GetTag() { eventSlice = append(eventSlice, constants.EventTag) } diff --git a/library/events_test.go b/library/events_test.go index fb6d81db..1f3bfbbe 100644 --- a/library/events_test.go +++ b/library/events_test.go @@ -122,6 +122,7 @@ func TestLibrary_Events_List(t *testing.T) { "pull_request:opened", "pull_request:synchronize", "pull_request:reopened", + "pull_request:unlabeled", "tag", "comment:created", "schedule", @@ -159,6 +160,7 @@ func TestLibrary_Events_NewEventsFromMask_ToDatabase(t *testing.T) { constants.AllowPullOpen | constants.AllowPullSync | constants.AllowPullReopen | + constants.AllowPullUnlabel | constants.AllowCommentCreate | constants.AllowSchedule, ) @@ -213,6 +215,7 @@ func TestLibrary_Events_Allowed(t *testing.T) { {event: "pull_request", action: "edited", want: false}, {event: "pull_request", action: "reopened", want: true}, {event: "pull_request", action: "labeled", want: false}, + {event: "pull_request", action: "unlabeled", want: true}, {event: "deployment", want: false}, {event: "comment", action: "created", want: true}, {event: "comment", action: "edited", want: false}, @@ -253,6 +256,7 @@ func testEvents() (*Events, *Events) { Edited: &fBool, Reopened: &tBool, Labeled: &fBool, + Unlabeled: &tBool, }, Deployment: &actions.Deploy{ Created: &fBool, @@ -279,6 +283,7 @@ func testEvents() (*Events, *Events) { Edited: &tBool, Reopened: &fBool, Labeled: &tBool, + Unlabeled: &fBool, }, Deployment: &actions.Deploy{ Created: &tBool, diff --git a/library/repo_test.go b/library/repo_test.go index 2f2684cd..3892b85c 100644 --- a/library/repo_test.go +++ b/library/repo_test.go @@ -20,7 +20,7 @@ func TestLibrary_Repo_Environment(t *testing.T) { "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "true", "VELA_REPO_ALLOW_TAG": "false", - "VELA_REPO_ALLOW_EVENTS": "push,pull_request:opened,pull_request:synchronize,pull_request:reopened,tag,comment:created,schedule,delete:branch", + "VELA_REPO_ALLOW_EVENTS": "push,pull_request:opened,pull_request:synchronize,pull_request:reopened,pull_request:unlabeled,tag,comment:created,schedule,delete:branch", "VELA_REPO_BRANCH": "main", "VELA_REPO_TOPICS": "cloud,security", "VELA_REPO_BUILD_LIMIT": "10", @@ -41,7 +41,7 @@ func TestLibrary_Repo_Environment(t *testing.T) { "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "true", "REPOSITORY_ALLOW_TAG": "false", - "REPOSITORY_ALLOW_EVENTS": "push,pull_request:opened,pull_request:synchronize,pull_request:reopened,tag,comment:created,schedule,delete:branch", + "REPOSITORY_ALLOW_EVENTS": "push,pull_request:opened,pull_request:synchronize,pull_request:reopened,pull_request:unlabeled,tag,comment:created,schedule,delete:branch", "REPOSITORY_BRANCH": "main", "REPOSITORY_CLONE": "https://github.com/github/octocat.git", "REPOSITORY_FULL_NAME": "github/octocat", diff --git a/pipeline/ruleset_test.go b/pipeline/ruleset_test.go index d7e88b88..0b435a23 100644 --- a/pipeline/ruleset_test.go +++ b/pipeline/ruleset_test.go @@ -496,6 +496,9 @@ func TestPipeline_Ruletype_MatchAnd(t *testing.T) { // Target with filepath matcher {matcher: "filepath", rule: []string{"production"}, pattern: "production", want: true}, {matcher: "filepath", rule: []string{"stage"}, pattern: "production", want: false}, + // Label with filepath matcher + {matcher: "filepath", rule: []string{"enhancement", "documentation"}, pattern: "documentation", want: true}, + {matcher: "filepath", rule: []string{"enhancement", "documentation"}, pattern: "question", want: false}, // Empty with regex matcher {matcher: "regexp", rule: []string{}, pattern: "main", want: true}, {matcher: "regexp", rule: []string{}, pattern: "push", want: true}, @@ -531,6 +534,9 @@ func TestPipeline_Ruletype_MatchAnd(t *testing.T) { // Target with regex matcher {matcher: "regexp", rule: []string{"production"}, pattern: "production", want: true}, {matcher: "regexp", rule: []string{"stage"}, pattern: "production", want: false}, + // Label with regexp matcher + {matcher: "regexp", rule: []string{"enhancement", "documentation"}, pattern: "documentation", want: true}, + {matcher: "regexp", rule: []string{"enhancement", "documentation"}, pattern: "question", want: false}, } // run test diff --git a/yaml/ruleset.go b/yaml/ruleset.go index 20f6bce0..2fe23e16 100644 --- a/yaml/ruleset.go +++ b/yaml/ruleset.go @@ -30,7 +30,7 @@ type ( Status []string `yaml:"status,omitempty,flow" json:"status,omitempty" jsonschema:"enum=[failure],enum=[success],description=Limits the execution of a step to matching build statuses.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-ruleset-tag"` Tag []string `yaml:"tag,omitempty,flow" json:"tag,omitempty" jsonschema:"description=Limits the execution of a step to matching build tag references.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-ruleset-tag"` Target []string `yaml:"target,omitempty,flow" json:"target,omitempty" jsonschema:"description=Limits the execution of a step to matching build deployment targets.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-ruleset-tag"` - Label []string `yaml:"label,omitempty,flow" json:"label,omitempty" jsonschema:"description=Limits the execution of a step to matching build deployment targets.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-ruleset-tag"` + Label []string `yaml:"label,omitempty,flow" json:"label,omitempty" jsonschema:"description=Limits step execution to match on pull requests labels.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-ruleset-tag"` } ) diff --git a/yaml/ruleset_test.go b/yaml/ruleset_test.go index 06f3c676..559395ba 100644 --- a/yaml/ruleset_test.go +++ b/yaml/ruleset_test.go @@ -22,7 +22,7 @@ func TestYaml_Ruleset_ToPipeline(t *testing.T) { If: Rules{ Branch: []string{"main"}, Comment: []string{"test comment"}, - Event: []string{"push"}, + Event: []string{"push", "pull_request:labeled"}, Path: []string{"foo.txt"}, Repo: []string{"github/octocat"}, Status: []string{"success"}, @@ -48,7 +48,7 @@ func TestYaml_Ruleset_ToPipeline(t *testing.T) { If: pipeline.Rules{ Branch: []string{"main"}, Comment: []string{"test comment"}, - Event: []string{"push"}, + Event: []string{"push", "pull_request:labeled"}, Path: []string{"foo.txt"}, Repo: []string{"github/octocat"}, Status: []string{"success"}, @@ -169,7 +169,7 @@ func TestYaml_Rules_ToPipeline(t *testing.T) { rules: &Rules{ Branch: []string{"main"}, Comment: []string{"test comment"}, - Event: []string{"push"}, + Event: []string{"push", "pull_request:labeled"}, Path: []string{"foo.txt"}, Repo: []string{"github/octocat"}, Status: []string{"success"}, @@ -180,7 +180,7 @@ func TestYaml_Rules_ToPipeline(t *testing.T) { want: &pipeline.Rules{ Branch: []string{"main"}, Comment: []string{"test comment"}, - Event: []string{"push"}, + Event: []string{"push", "pull_request:labeled"}, Path: []string{"foo.txt"}, Repo: []string{"github/octocat"}, Status: []string{"success"},