Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rulesets): add support for PR labeled events #361

Merged
merged 9 commits into from
Apr 2, 2024
6 changes: 6 additions & 0 deletions constants/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ const (
// ActionSynchronize defines the action for the synchronizing of pull requests.
ActionSynchronize = "synchronize"

// 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"

Expand Down
3 changes: 2 additions & 1 deletion constants/allow_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const (
AllowPullSync
_ // AllowPullAssigned - Not Implemented
_ // AllowPullMilestoned - Not Implemented
_ // AllowPullLabel - Not Implemented
AllowPullLabel
_ // AllowPullLocked - Not Implemented
_ // AllowPullReady - Not Implemented
AllowPullReopen
Expand All @@ -23,4 +23,5 @@ const (
AllowSchedule
AllowPushDeleteBranch
AllowPushDeleteTag
AllowPullUnlabel
)
60 changes: 60 additions & 0 deletions library/actions/pull.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
//
//nolint:dupl // similar code to push.go

Check failure on line 3 in library/actions/pull.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] library/actions/pull.go#L3

directive `//nolint:dupl // similar code to push.go` is unused for linter "dupl" (nolintlint)
Raw output
library/actions/pull.go:3:1: directive `//nolint:dupl // similar code to push.go` is unused for linter "dupl" (nolintlint)
//nolint:dupl // similar code to push.go
^
package actions

import "github.com/go-vela/types/constants"
Expand All @@ -12,6 +12,8 @@
Edited *bool `json:"edited"`
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.
Expand All @@ -20,6 +22,8 @@
a.SetSynchronize(mask&constants.AllowPullSync > 0)
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
}
Expand All @@ -44,6 +48,14 @@
mask = mask | constants.AllowPullReopen
}

if a.GetLabeled() {
mask = mask | constants.AllowPullLabel
}

if a.GetUnlabeled() {
mask = mask | constants.AllowPullUnlabel
}

return mask
}

Expand Down Expand Up @@ -91,6 +103,28 @@
return *a.Reopened
}

// 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 Labeled field is nil
if a == nil || a.Labeled == nil {
return false
}

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
Expand Down Expand Up @@ -142,3 +176,29 @@

a.Reopened = &v
}

// SetLabeled sets the Pull Labeled field.
//
// When the provided Pull type is nil, it
// will set nothing and immediately return.
func (a *Pull) SetLabeled(v bool) {
// return if Pull type is nil
if a == nil {
return
}

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
}
22 changes: 21 additions & 1 deletion library/actions/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
}
}

Expand Down Expand Up @@ -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())
Expand All @@ -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())
}
}
}

Expand All @@ -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()
Expand All @@ -123,6 +141,8 @@ func testPull() *Pull {
pr.SetSynchronize(true)
pr.SetEdited(false)
pr.SetReopened(true)
pr.SetLabeled(false)
pr.SetUnlabeled(true)

return pr
}
1 change: 1 addition & 0 deletions library/actions/push_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ func testMask() int64 {
constants.AllowPullOpen |
constants.AllowPullSync |
constants.AllowPullReopen |
constants.AllowPullUnlabel |
constants.AllowDeployCreate |
constants.AllowCommentCreate |
constants.AllowSchedule,
Expand Down
12 changes: 12 additions & 0 deletions library/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ func (e *Events) Allowed(event, action string) bool {
allowed = e.GetPullRequest().GetEdited()
case constants.EventPull + ":" + constants.ActionReopened:
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:
Expand Down Expand Up @@ -102,6 +106,14 @@ func (e *Events) List() []string {
eventSlice = append(eventSlice, constants.EventPull+":"+constants.ActionReopened)
}

if e.GetPullRequest().GetLabeled() {
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)
}
Expand Down
10 changes: 10 additions & 0 deletions library/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -130,6 +131,7 @@ func TestLibrary_Events_List(t *testing.T) {

wantTwo := []string{
"pull_request:edited",
"pull_request:labeled",
"deployment",
"comment:edited",
"delete:tag",
Expand Down Expand Up @@ -158,6 +160,7 @@ func TestLibrary_Events_NewEventsFromMask_ToDatabase(t *testing.T) {
constants.AllowPullOpen |
constants.AllowPullSync |
constants.AllowPullReopen |
constants.AllowPullUnlabel |
constants.AllowCommentCreate |
constants.AllowSchedule,
)
Expand All @@ -166,6 +169,7 @@ func TestLibrary_Events_NewEventsFromMask_ToDatabase(t *testing.T) {
constants.AllowPushDeleteTag |
constants.AllowPullEdit |
constants.AllowCommentEdit |
constants.AllowPullLabel |
constants.AllowDeployCreate,
)

Expand Down Expand Up @@ -210,6 +214,8 @@ func TestLibrary_Events_Allowed(t *testing.T) {
{event: "pull_request", action: "synchronize", want: true},
{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},
Expand Down Expand Up @@ -249,6 +255,8 @@ func testEvents() (*Events, *Events) {
Synchronize: &tBool,
Edited: &fBool,
Reopened: &tBool,
Labeled: &fBool,
Unlabeled: &tBool,
},
Deployment: &actions.Deploy{
Created: &fBool,
Expand All @@ -274,6 +282,8 @@ func testEvents() (*Events, *Events) {
Synchronize: &fBool,
Edited: &tBool,
Reopened: &fBool,
Labeled: &tBool,
Unlabeled: &fBool,
},
Deployment: &actions.Deploy{
Created: &tBool,
Expand Down
4 changes: 2 additions & 2 deletions library/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
14 changes: 11 additions & 3 deletions pipeline/ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type (
Status Ruletype `json:"status,omitempty" yaml:"status,omitempty"`
Tag Ruletype `json:"tag,omitempty" yaml:"tag,omitempty"`
Target Ruletype `json:"target,omitempty" yaml:"target,omitempty"`
Label Ruletype `json:"label,omitempty" yaml:"label,omitempty"`
Parallel bool `json:"-" yaml:"-"`
}

Expand All @@ -57,6 +58,7 @@ type (
Status string `json:"status,omitempty" yaml:"status,omitempty"`
Tag string `json:"tag,omitempty" yaml:"tag,omitempty"`
Target string `json:"target,omitempty" yaml:"target,omitempty"`
Label string `json:"label,omitempty" yaml:"label,omitempty"`
wsan3 marked this conversation as resolved.
Show resolved Hide resolved
Parallel bool `json:"-" yaml:"-"`
}
)
Expand Down Expand Up @@ -111,7 +113,8 @@ func (r *Rules) Empty() bool {
len(r.Repo) == 0 &&
len(r.Status) == 0 &&
len(r.Tag) == 0 &&
len(r.Target) == 0 {
len(r.Target) == 0 &&
len(r.Label) == 0 {
return true
}

Expand Down Expand Up @@ -261,10 +264,15 @@ func matches(r *Rules, from *RuleData, matcher, path, logic string) (bool, error
return false, err
}

matchLabel, err := r.Label.Match(from.Label, matcher, logic)
if err != nil {
return false, err
}

switch logic {
case constants.OperatorAnd:
return (matchBranch && matchComment && matchEvent && matchPath && matchRepo && matchTag && matchTarget && status), nil
return (matchBranch && matchComment && matchEvent && matchPath && matchRepo && matchTag && matchTarget && matchLabel && status), nil
default:
return (matchBranch || matchComment || matchEvent || matchPath || matchRepo || matchTag || matchTarget || status), nil
return (matchBranch || matchComment || matchEvent || matchPath || matchRepo || matchTag || matchTarget || matchLabel || status), nil
}
}
26 changes: 22 additions & 4 deletions pipeline/ruleset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,14 +425,20 @@ func TestPipeline_Rules_Match(t *testing.T) {
},
{
rules: &Rules{Event: []string{"push", "pull_request"}, Tag: []string{"release/*"}},
data: &RuleData{Branch: "main", Event: "push", Repo: "octocat/hello-world", Status: "pending", Tag: "release/*", Target: ""},
data: &RuleData{Branch: "main", Event: "tag", Repo: "octocat/hello-world", Status: "pending", Tag: "refs/heads/main", Target: ""},
operator: "or",
want: false,
},
{
rules: &Rules{Event: []string{"pull_request:labeled"}, Label: []string{"enhancement", "documentation"}},
data: &RuleData{Branch: "main", Event: "pull_request:labeled", Repo: "octocat/hello-world", Status: "pending", Label: "documentation"},
operator: "and",
want: true,
},
{
rules: &Rules{Event: []string{"push", "pull_request"}, Tag: []string{"release/*"}},
data: &RuleData{Branch: "main", Event: "tag", Repo: "octocat/hello-world", Status: "pending", Tag: "refs/heads/main", Target: ""},
operator: "or",
rules: &Rules{Event: []string{"pull_request:labeled"}, Label: []string{"enhancement", "documentation"}},
data: &RuleData{Branch: "main", Event: "pull_request:labeled", Repo: "octocat/hello-world", Status: "pending", Label: "support"},
operator: "and",
want: false,
},
}
Expand Down Expand Up @@ -490,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},
Expand Down Expand Up @@ -525,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
Expand Down Expand Up @@ -572,6 +584,9 @@ func TestPipeline_Ruletype_MatchOr(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 regexp matcher
{matcher: "regexp", rule: []string{}, pattern: "main", want: false},
{matcher: "regexp", rule: []string{}, pattern: "push", want: false},
Expand Down Expand Up @@ -599,6 +614,9 @@ func TestPipeline_Ruletype_MatchOr(t *testing.T) {
// Target with regexp 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
Expand Down
Loading
Loading