diff --git a/cmd/input.go b/cmd/input.go index a7ccae84eac..fd891f2b851 100644 --- a/cmd/input.go +++ b/cmd/input.go @@ -62,6 +62,7 @@ type Input struct { useNewActionCache bool localRepository []string listOptions bool + applyEventFilters bool } func (i *Input) resolve(path string) string { diff --git a/cmd/root.go b/cmd/root.go index 50a2155990a..bd4646a61cb 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -127,6 +127,7 @@ func createRootCommand(ctx context.Context, input *Input, version string) *cobra rootCmd.PersistentFlags().BoolVarP(&input.useNewActionCache, "use-new-action-cache", "", false, "Enable using the new Action Cache for storing Actions locally") rootCmd.PersistentFlags().StringArrayVarP(&input.localRepository, "local-repository", "", []string{}, "Replaces the specified repository and ref with a local folder (e.g. https://github.com/test/test@v0=/home/act/test or test/test@v0=/home/act/test, the latter matches any hosts or protocols)") rootCmd.PersistentFlags().BoolVar(&input.listOptions, "list-options", false, "Print a json structure of compatible options") + rootCmd.PersistentFlags().BoolVar(&input.applyEventFilters, "apply-event-filters", false, "Only run workflows for an event that matches the event filters defined for the workflow.") rootCmd.SetArgs(args()) return rootCmd } @@ -444,7 +445,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str matrixes := parseMatrix(input.matrix) log.Debugf("Evaluated matrix inclusions: %v", matrixes) - planner, err := model.NewWorkflowPlanner(input.WorkflowsPath(), input.noWorkflowRecurse) + planner, err := model.NewWorkflowPlanner(input.WorkflowsPath(), input.noWorkflowRecurse, input.applyEventFilters, input.eventPath) if err != nil { return err } @@ -469,53 +470,6 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str // collect all events from loaded workflows events := planner.GetEvents() - // plan with filtered jobs - to be used for filtering only - var filterPlan *model.Plan - - // Determine the event name to be filtered - var filterEventName string - - if len(args) > 0 { - log.Debugf("Using first passed in arguments event for filtering: %s", args[0]) - filterEventName = args[0] - } else if input.autodetectEvent && len(events) > 0 && len(events[0]) > 0 { - // set default event type to first event from many available - // this way user dont have to specify the event. - log.Debugf("Using first detected workflow event for filtering: %s", events[0]) - filterEventName = events[0] - } - - var plannerErr error - if jobID != "" { - log.Debugf("Preparing plan with a job: %s", jobID) - filterPlan, plannerErr = planner.PlanJob(jobID) - } else if filterEventName != "" { - log.Debugf("Preparing plan for a event: %s", filterEventName) - filterPlan, plannerErr = planner.PlanEvent(filterEventName) - } else { - log.Debugf("Preparing plan with all jobs") - filterPlan, plannerErr = planner.PlanAll() - } - if filterPlan == nil && plannerErr != nil { - return plannerErr - } - - if list { - err = printList(filterPlan) - if err != nil { - return err - } - return plannerErr - } - - if graph { - err = drawGraph(filterPlan) - if err != nil { - return err - } - return plannerErr - } - // plan with triggered jobs var plan *model.Plan @@ -539,22 +493,44 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str } // build the plan for this run + var plannerErr error if jobID != "" { log.Debugf("Planning job: %s", jobID) - plan, plannerErr = planner.PlanJob(jobID) + plan, plannerErr = planner.PlanJob(jobID, eventName) } else { log.Debugf("Planning jobs for event: %s", eventName) plan, plannerErr = planner.PlanEvent(eventName) } if plan != nil { - if len(plan.Stages) == 0 { - plannerErr = fmt.Errorf("Could not find any stages to run. View the valid jobs with `act --list`. Use `act --help` to find how to filter by Job ID/Workflow/Event Name") + if len(plan.Stages) == 0 && !input.applyEventFilters { + plannerErr = fmt.Errorf("could not find any stages to run. View the valid jobs with `act --list`. Use `act --help` to find how to filter by Job ID/Workflow/Event Name") } } if plan == nil && plannerErr != nil { return plannerErr } + if list { + err = printList(plan) + if err != nil { + return err + } + return plannerErr + } + + if graph { + err = drawGraph(plan) + if err != nil { + return err + } + return plannerErr + } + + if len(plan.Stages) == 0 && input.applyEventFilters { + log.Info("The configured event filters caused all jobs to be skipped - if you are expecting a job to execute then check your supplied event structure against the workflow 'on' filters, or run Act without applying event filters.") + return plannerErr + } + // check to see if the main branch was defined defaultbranch, err := cmd.Flags().GetString("defaultbranch") if err != nil { @@ -635,6 +611,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str ReplaceGheActionTokenWithGithubCom: input.replaceGheActionTokenWithGithubCom, Matrix: matrixes, ContainerNetworkMode: docker_container.NetworkMode(input.networkName), + ApplyEventFilters: input.applyEventFilters, } if input.useNewActionCache || len(input.localRepository) > 0 { if input.actionOfflineMode { diff --git a/go.mod b/go.mod index fb6582fbd69..5d00d608004 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( dario.cat/mergo v1.0.1 github.com/distribution/reference v0.6.0 github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/google/go-github/v71 v71.0.0 google.golang.org/protobuf v1.36.6 ) @@ -63,6 +64,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect diff --git a/go.sum b/go.sum index 2b5aa41e0b9..77b5979b234 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,13 @@ github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeD github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v71 v71.0.0 h1:Zi16OymGKZZMm8ZliffVVJ/Q9YZreDKONCr+WUd0Z30= +github.com/google/go-github/v71 v71.0.0/go.mod h1:URZXObp2BLlMjwu0O8g4y6VBneUj2bCHgnI8FfgZ51M= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= diff --git a/pkg/artifacts/server_test.go b/pkg/artifacts/server_test.go index 0e9dca155c6..9a4fe538499 100644 --- a/pkg/artifacts/server_test.go +++ b/pkg/artifacts/server_test.go @@ -298,7 +298,7 @@ func runTestJobFile(ctx context.Context, t *testing.T, tjfi TestJobFileInfo) { runner, err := runner.New(runnerConfig) assert.Nil(t, err, tjfi.workflowPath) - planner, err := model.NewWorkflowPlanner(fullWorkflowPath, true) + planner, err := model.NewWorkflowPlanner(fullWorkflowPath, true, false, "") assert.Nil(t, err, fullWorkflowPath) plan, err := planner.PlanEvent(tjfi.eventName) diff --git a/pkg/model/planner.go b/pkg/model/planner.go index f0557ef61d7..f34c95666a9 100644 --- a/pkg/model/planner.go +++ b/pkg/model/planner.go @@ -16,9 +16,11 @@ import ( // WorkflowPlanner contains methods for creating plans type WorkflowPlanner interface { PlanEvent(eventName string) (*Plan, error) - PlanJob(jobName string) (*Plan, error) + PlanJob(jobName string, eventName string) (*Plan, error) PlanAll() (*Plan, error) GetEvents() []string + ShouldApplyEventFilters() bool + EventPath() string } // Plan contains a list of stages to run in series @@ -56,7 +58,7 @@ type WorkflowFiles struct { } // NewWorkflowPlanner will load a specific workflow, all workflows from a directory or all workflows from a directory and its subdirectories -func NewWorkflowPlanner(path string, noWorkflowRecurse bool) (WorkflowPlanner, error) { +func NewWorkflowPlanner(path string, noWorkflowRecurse bool, applyEventFilters bool, eventPath string) (WorkflowPlanner, error) { path, err := filepath.Abs(path) if err != nil { return nil, err @@ -153,11 +155,12 @@ func NewWorkflowPlanner(path string, noWorkflowRecurse bool) (WorkflowPlanner, e _ = f.Close() } } - + wp.shouldApplyEventFilters = applyEventFilters + wp.eventPath = eventPath return wp, nil } -func NewSingleWorkflowPlanner(name string, f io.Reader) (WorkflowPlanner, error) { +func NewSingleWorkflowPlanner(name string, f io.Reader, applyEventFilters bool, eventPath string) (WorkflowPlanner, error) { wp := new(workflowPlanner) log.Debugf("Reading workflow %s", name) @@ -179,7 +182,8 @@ func NewSingleWorkflowPlanner(name string, f io.Reader) (WorkflowPlanner, error) } wp.workflows = append(wp.workflows, workflow) - + wp.shouldApplyEventFilters = applyEventFilters + wp.eventPath = eventPath return wp, nil } @@ -194,7 +198,9 @@ func validateJobName(workflow *Workflow) error { } type workflowPlanner struct { - workflows []*Workflow + workflows []*Workflow + shouldApplyEventFilters bool + eventPath string } // PlanEvent builds a new list of runs to execute in parallel for an event name @@ -207,20 +213,39 @@ func (wp *workflowPlanner) PlanEvent(eventName string) (*Plan, error) { var lastErr error for _, w := range wp.workflows { - events := w.On() - if len(events) == 0 { - log.Debugf("no events found for workflow: %s", w.File) - continue - } + // the user might want the legacy behaviour so we do this in two sections + if wp.ShouldApplyEventFilters() { + // user has explicitly opted in to maybe not having a workflow run because of the event filters + if w.ShouldFilterForEvent(eventName, wp.EventPath()) { + log.Debugf("Skipping workflow %s because workflow does not have an event filter that matches this event", w.Name) + continue + } - for _, e := range events { - if e == eventName { - stages, err := createStages(w, w.GetJobIDs()...) - if err != nil { - log.Warn(err) - lastErr = err - } else { - plan.mergeStages(stages) + stages, err := createStages(w, w.GetJobIDs()...) + if err != nil { + log.Warn(err) + lastErr = err + } else { + plan.mergeStages(stages) + } + } else { + // the user wants the legacy behaviour which is that if there is a matching on event then we execute it + // even if the filters for branch/tag/path don't match + events := w.On() + if len(events) == 0 { + log.Debugf("no events found for workflow: %s", w.File) + continue + } + + for _, e := range events { + if e == eventName { + stages, err := createStages(w, w.GetJobIDs()...) + if err != nil { + log.Warn(err) + lastErr = err + } else { + plan.mergeStages(stages) + } } } } @@ -229,7 +254,7 @@ func (wp *workflowPlanner) PlanEvent(eventName string) (*Plan, error) { } // PlanJob builds a new run to execute in parallel for a job name -func (wp *workflowPlanner) PlanJob(jobName string) (*Plan, error) { +func (wp *workflowPlanner) PlanJob(jobName string, eventName string) (*Plan, error) { plan := new(Plan) if len(wp.workflows) == 0 { log.Debugf("no jobs found for workflow: %s", jobName) @@ -237,6 +262,10 @@ func (wp *workflowPlanner) PlanJob(jobName string) (*Plan, error) { var lastErr error for _, w := range wp.workflows { + if wp.ShouldApplyEventFilters() && w.ShouldFilterForEvent(eventName, wp.EventPath()) { + log.Debugf("Skipping workflow %s because workflow does not have an event filter that matches this event", w.Name) + continue + } stages, err := createStages(w, jobName) if err != nil { log.Warn(err) @@ -300,6 +329,14 @@ func (wp *workflowPlanner) GetEvents() []string { return events } +func (wp *workflowPlanner) ShouldApplyEventFilters() bool { + return wp.shouldApplyEventFilters +} + +func (wp *workflowPlanner) EventPath() string { + return wp.eventPath +} + // MaxRunNameLen determines the max name length of all jobs func (p *Plan) MaxRunNameLen() int { maxRunNameLen := 0 diff --git a/pkg/model/planner_test.go b/pkg/model/planner_test.go index 2857c2c8a3f..6c3ac1c8615 100644 --- a/pkg/model/planner_test.go +++ b/pkg/model/planner_test.go @@ -1,7 +1,9 @@ package model import ( + "fmt" "path/filepath" + "strings" "testing" log "github.com/sirupsen/logrus" @@ -14,6 +16,13 @@ type WorkflowPlanTest struct { noWorkflowRecurse bool } +type WorkflowPlanFilterTest struct { + workflow string + workflowEventPath string + shouldBeFiltered bool + errorMsg string +} + func TestPlanner(t *testing.T) { log.SetLevel(log.DebugLevel) @@ -31,7 +40,7 @@ func TestPlanner(t *testing.T) { assert.NoError(t, err, workdir) for _, table := range tables { fullWorkflowPath := filepath.Join(workdir, table.workflowPath) - _, err = NewWorkflowPlanner(fullWorkflowPath, table.noWorkflowRecurse) + _, err = NewWorkflowPlanner(fullWorkflowPath, table.noWorkflowRecurse, false, "") if table.errorMessage == "" { assert.NoError(t, err, "WorkflowPlanner should exit without any error") } else { @@ -40,6 +49,636 @@ func TestPlanner(t *testing.T) { } } +func TestPlannerPushEventFiltering(t *testing.T) { + log.SetLevel(log.DebugLevel) + + pushSimple := ` + name: test-job + on: push + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushSimple2 := ` + name: test-job + on: + - push + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushSimple3 := ` + name: test-job + on: + push: + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pullRequestSimple := ` + name: test-job + on: + pull_request: + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterBranch := ` + name: test-job + on: + push: + branches: + - refs/heads/master + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterTag := ` + name: test-job + on: + push: + tags: + - refs/tags/v1 + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterPath := ` + name: test-job + on: + push: + paths: + - test/app/** + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterPath2 := ` + name: test-job + on: + push: + paths: + - test/other/** + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterBranchTag := ` + name: test-job + on: + push: + branches: + - refs/heads/master + tags: + - refs/tags/v1 + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterBranchTagPath := ` + name: test-job + on: + push: + branches: + - refs/heads/master + tags: + - refs/tags/v1 + paths: + - test/app/** + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushDoubleFilterBranch := ` + name: test-job + on: + push: + branches: + - does/not/exist + + branches_ignore: + - does/not/exist + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushDoubleFilterTag := ` + name: test-job + on: + push: + tags: + - does/not/exist + + tags_ignore: + - does/not/exist + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushDoubleFilterPath := ` + name: test-job + on: + push: + paths: + - does/not/exist + + paths_ignore: + - does/not/exist + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterBranchIgnoreTag := ` + name: test-job + on: + push: + branches: + - 'refs/heads/*' + tags_ignore: + - '**' + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterIgnoreBranchTag := ` + name: test-job + on: + push: + branches_ignore: + - 'refs/heads/*' + tags: + - 'refs/tags/*' + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushFilterIgnorePath := ` + name: test-job + on: + push: + paths_ignore: + - test/app/** + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + tables := []WorkflowPlanFilterTest{ + {pushSimple, "", false, "Push should not be filtered"}, + {pushSimple2, "", false, "Push should not be filtered"}, + {pushSimple3, "", false, "Push should not be filtered"}, + {pullRequestSimple, "", true, "Pull request workflow for push event should be filtered when no event object passed"}, + {pullRequestSimple, "filter-events/push-master.json", true, "Pull request workflow for push event should be filtered"}, + {pushFilterBranch, "filter-events/push-master.json", false, "Branches should match so workflow should not be filtered"}, + {pushFilterBranch, "filter-events/push-foo.json", true, "Branches should not match so workflow should be filtered"}, + {pushFilterTag, "filter-events/push-tag-v1.json", false, "Tags should match so workflow should not be filtered"}, + {pushFilterTag, "filter-events/push-tag-v2.json", true, "Tags should not match so workflow should be filtered"}, + {pushFilterPath, "filter-events/push-master.json", false, "Paths should match so workflow should not be filtered"}, + {pushFilterPath2, "filter-events/push-master.json", true, "Paths should not match so workflow should be filtered"}, + {pushFilterBranchTag, "filter-events/push-master.json", false, "Branches or tags should match so workflow should not be filtered"}, + {pushFilterBranchTag, "filter-events/push-foo.json", true, "Neither branches or tags should match so workflow should be filtered"}, + {pushFilterBranchTag, "filter-events/push-tag-v1.json", false, "Branches or tags should match so workflow should not be filtered"}, + {pushFilterBranchTagPath, "filter-events/push-master.json", false, "Branches and path should match so workflow should not be filtered"}, + {pushFilterBranchTagPath, "filter-events/push-foo.json", true, "Branches don't match even though path matches so workflow should be filtered"}, + {pushFilterBranchTagPath, "filter-events/push-tag-v1.json", false, "Tag matches and path should be ignored so workflow should not be filtered"}, + {pushDoubleFilterBranch, "filter-events/push-master.json", false, "No match for event but it's malformed so workflow should not be filtered"}, + {pushDoubleFilterTag, "filter-events/push-tag-v1.json", false, "No match for event but it's malformed so workflow should not be filtered"}, + {pushDoubleFilterPath, "filter-events/push-master.json", false, "No match for event but it's malformed so workflow should not be filtered"}, + {pushFilterBranchIgnoreTag, "filter-events/push-foo.json", false, "Wildcard branch and ignore all tags so workflow should not be filtered"}, + {pushFilterBranchIgnoreTag, "filter-events/push-tag-v1.json", true, "Wildcard branch and ignore all tags so workflow should be filtered"}, + {pushFilterIgnoreBranchTag, "filter-events/push-foo.json", true, "Wildcard branch ignore and accept all tags so workflow should be filtered"}, + {pushFilterIgnoreBranchTag, "filter-events/push-tag-v2.json", false, "Wildcard branch ignore and accept all tags so workflow should not be filtered"}, + {pushFilterIgnorePath, "filter-events/push-tag-v2.json", true, "Wildcard paths ignore so workflow should be filtered"}, + } + + workdir, err := filepath.Abs("testdata") + assert.NoError(t, err, workdir) + for n, table := range tables { + fullEventPath := "" + if table.workflowEventPath != "" { + fullEventPath = filepath.Join(workdir, table.workflowEventPath) + } + planner, err := NewSingleWorkflowPlanner(fmt.Sprintf("Test %d", n+1), strings.NewReader(table.workflow), true, fullEventPath) + assert.NoError(t, err, "WorkflowPlanner should exit without any error") + + plan, err := planner.PlanEvent("push") + assert.NoError(t, err) + if table.shouldBeFiltered { + assert.Equal(t, 0, len(plan.Stages), fmt.Sprintf("%d: %s", n+1, table.errorMsg)) + } else { + assert.Equal(t, 1, len(plan.Stages), fmt.Sprintf("%d: %s", n+1, table.errorMsg)) + } + } +} + +//nolint:dupl +func TestPlannerPullRequestEventFiltering(t *testing.T) { + log.SetLevel(log.DebugLevel) + + prSimple := ` + name: test-job + on: pull_request + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prSimple2 := ` + name: test-job + on: + - pull_request + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prSimple3 := ` + name: test-job + on: + pull_request: + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushRequestSimple := ` + name: test-job + on: + push: + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prFilterBranch := ` + name: test-job + on: + pull_request: + branches: + - main + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prFilterBranchFoo := ` + name: test-job + on: + pull_request: + branches: + - foo + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prDoubleFilterBranch := ` + name: test-job + on: + pull_request: + branches: + - does/not/exist + + branches_ignore: + - does/not/exist + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prDoubleFilterPath := ` + name: test-job + on: + pull_request: + paths: + - does/not/exist + + paths_ignore: + - does/not/exist + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prFilterIgnoreBranch := ` + name: test-job + on: + pull_request: + branches_ignore: + - '*' + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prFilterPath := ` + name: test-job + on: + pull_request: + paths: + - '**' + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + tables := []WorkflowPlanFilterTest{ + {prSimple, "", false, "PR should not be filtered"}, + {prSimple2, "", false, "PR should not be filtered"}, + {prSimple3, "", false, "PR should not be filtered"}, + {pushRequestSimple, "", true, "Push workflow for PS event should be filtered when no event object passed"}, + {prFilterBranch, "filter-events/pr-opened.json", false, "Branches should match so workflow should not be filtered"}, + {prFilterBranchFoo, "filter-events/pr-opened.json", true, "Branches should not match so workflow should be filtered"}, + {prDoubleFilterBranch, "filter-events/pr-opened.json", false, "No match for event but it's malformed so workflow should not be filtered"}, + {prDoubleFilterPath, "filter-events/pr-opened.json", false, "No match for event but it's malformed so workflow should not be filtered"}, + {prFilterIgnoreBranch, "filter-events/pr-opened.json", true, "Wildcard paths ignore so workflow should be filtered"}, + {prFilterPath, "filter-events/pr-opened.json", false, "Wildcard paths set but unsupported filter so workflow should not be filtered"}, + } + + workdir, err := filepath.Abs("testdata") + assert.NoError(t, err, workdir) + for n, table := range tables { + fullEventPath := "" + if table.workflowEventPath != "" { + fullEventPath = filepath.Join(workdir, table.workflowEventPath) + } + planner, err := NewSingleWorkflowPlanner(fmt.Sprintf("Test %d", n+1), strings.NewReader(table.workflow), true, fullEventPath) + assert.NoError(t, err, "WorkflowPlanner should exit without any error") + + plan, err := planner.PlanEvent("pull_request") + assert.NoError(t, err) + if table.shouldBeFiltered { + assert.Equal(t, 0, len(plan.Stages), fmt.Sprintf("%d: %s", n+1, table.errorMsg)) + } else { + assert.Equal(t, 1, len(plan.Stages), fmt.Sprintf("%d: %s", n+1, table.errorMsg)) + } + } +} + +//nolint:dupl +func TestPlannerPullRequestTargetEventFiltering(t *testing.T) { + log.SetLevel(log.DebugLevel) + + prtSimple := ` + name: test-job + on: pull_request_target + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prtSimple2 := ` + name: test-job + on: + - pull_request_target + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prtSimple3 := ` + name: test-job + on: + pull_request_target: + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + pushRequestSimple := ` + name: test-job + on: + push: + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prtFilterBranch := ` + name: test-job + on: + pull_request_target: + branches: + - main + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prtFilterBranchFoo := ` + name: test-job + on: + pull_request_target: + branches: + - foo + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prtDoubleFilterBranch := ` + name: test-job + on: + pull_request_target: + branches: + - does/not/exist + + branches_ignore: + - does/not/exist + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prtDoubleFilterPath := ` + name: test-job + on: + pull_request_target: + paths: + - does/not/exist + + paths_ignore: + - does/not/exist + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prtFilterIgnoreBranch := ` + name: test-job + on: + pull_request_target: + branches_ignore: + - '*' + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + prtFilterPath := ` + name: test-job + on: + pull_request: + paths: + - '**' + + jobs: + a-job: + runs-on: ubuntu-latest + steps: + - run: echo hi + ` + + tables := []WorkflowPlanFilterTest{ + {prtSimple, "", false, "PR should not be filtered"}, + {prtSimple2, "", false, "PR should not be filtered"}, + {prtSimple3, "", false, "PR should not be filtered"}, + {pushRequestSimple, "", true, "Push workflow for PS event should be filtered when no event object passed"}, + {prtFilterBranch, "filter-events/pr-opened.json", false, "Branches should match so workflow should not be filtered"}, + {prtFilterBranchFoo, "filter-events/pr-opened.json", true, "Branches should not match so workflow should be filtered"}, + {prtDoubleFilterBranch, "filter-events/pr-opened.json", false, "No match for event but it's malformed so workflow should not be filtered"}, + {prtDoubleFilterPath, "filter-events/pr-opened.json", false, "No match for event but it's malformed so workflow should not be filtered"}, + {prtFilterIgnoreBranch, "filter-events/pr-opened.json", true, "Wildcard paths ignore so workflow should be filtered"}, + {prtFilterPath, "filter-events/pr-opened.json", false, "Wildcard paths set but unsupported filter so workflow should not be filtered"}, + } + + workdir, err := filepath.Abs("testdata") + assert.NoError(t, err, workdir) + for n, table := range tables { + fullEventPath := "" + if table.workflowEventPath != "" { + fullEventPath = filepath.Join(workdir, table.workflowEventPath) + } + planner, err := NewSingleWorkflowPlanner(fmt.Sprintf("Test %d", n+1), strings.NewReader(table.workflow), true, fullEventPath) + assert.NoError(t, err, "WorkflowPlanner should exit without any error") + + plan, err := planner.PlanEvent("pull_request_target") + assert.NoError(t, err) + if table.shouldBeFiltered { + assert.Equal(t, 0, len(plan.Stages), fmt.Sprintf("%d: %s", n+1, table.errorMsg)) + } else { + assert.Equal(t, 1, len(plan.Stages), fmt.Sprintf("%d: %s", n+1, table.errorMsg)) + } + } +} + func TestWorkflow(t *testing.T) { log.SetLevel(log.DebugLevel) diff --git a/pkg/model/testdata/filter-events/pr-opened.json b/pkg/model/testdata/filter-events/pr-opened.json new file mode 100644 index 00000000000..7a6a23c347c --- /dev/null +++ b/pkg/model/testdata/filter-events/pr-opened.json @@ -0,0 +1,532 @@ +{ + "action": "opened", + "number": 15, + "pull_request": { + "url": "https://api.github.com/repos/example_org/example_repo/pulls/15", + "id": 1211243938, + "node_id": "PR_0000000000000000", + "html_url": "https://github.com/example_org/example_repo/pull/15", + "diff_url": "https://github.com/example_org/example_repo/pull/15.diff", + "patch_url": "https://github.com/example_org/example_repo/pull/15.patch", + "issue_url": "https://api.github.com/repos/example_org/example_repo/issues/15", + "number": 15, + "state": "open", + "locked": false, + "title": "jdoe/example-branch", + "user": { + "login": "jdoe", + "id": 1234567, + "node_id": "MDQ6VXNlcjEyMzQ1Njc=", + "avatar_url": "https://avatars.githubusercontent.com/u/1234567?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jdoe", + "html_url": "https://github.com/jdoe", + "followers_url": "https://api.github.com/users/jdoe/followers", + "following_url": "https://api.github.com/users/jdoe/following{/other_user}", + "gists_url": "https://api.github.com/users/jdoe/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jdoe/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jdoe/subscriptions", + "organizations_url": "https://api.github.com/users/jdoe/orgs", + "repos_url": "https://api.github.com/users/jdoe/repos", + "events_url": "https://api.github.com/users/jdoe/events{/privacy}", + "received_events_url": "https://api.github.com/users/jdoe/received_events", + "type": "User", + "site_admin": false + }, + "body": "This is a test PR", + "created_at": "2023-01-20T09:03:04Z", + "updated_at": "2023-01-20T09:03:04Z", + "closed_at": null, + "merged_at": null, + "merge_commit_sha": null, + "assignee": null, + "assignees": [], + "requested_reviewers": [], + "requested_teams": [], + "labels": [], + "milestone": null, + "draft": false, + "commits_url": "https://api.github.com/repos/example_org/example_repo/pulls/15/commits", + "review_comments_url": "https://api.github.com/repos/example_org/example_repo/pulls/15/comments", + "review_comment_url": "https://api.github.com/repos/example_org/example_repo/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/example_org/example_repo/issues/15/comments", + "statuses_url": "https://api.github.com/repos/example_org/example_repo/statuses/07a6048532c799c58bf7eafdbc7d4eaf6b6bbde6", + "head": { + "label": "example_org:jdoe/example-branch", + "ref": "jdoe/example-branch", + "sha": "07a6048532c799c58bf7eafdbc7d4eaf6b6bbde6", + "user": { + "login": "example_org", + "id": 2345678, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjIzNDU2Nzg=", + "avatar_url": "https://avatars.githubusercontent.com/u/2345678?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/example_org", + "html_url": "https://github.com/example_org", + "followers_url": "https://api.github.com/users/example_org/followers", + "following_url": "https://api.github.com/users/example_org/following{/other_user}", + "gists_url": "https://api.github.com/users/example_org/gists{/gist_id}", + "starred_url": "https://api.github.com/users/example_org/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/example_org/subscriptions", + "organizations_url": "https://api.github.com/users/example_org/orgs", + "repos_url": "https://api.github.com/users/example_org/repos", + "events_url": "https://api.github.com/users/example_org/events{/privacy}", + "received_events_url": "https://api.github.com/users/example_org/received_events", + "type": "Organization", + "site_admin": false + }, + "repo": { + "id": 553972582, + "node_id": "R_kgDOIQTzZg", + "name": "example_repo", + "full_name": "example_org/example_repo", + "private": true, + "owner": { + "login": "example_org", + "id": 2345678, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjIzNDU2Nzg=", + "avatar_url": "https://avatars.githubusercontent.com/u/2345678?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/example_org", + "html_url": "https://github.com/example_org", + "followers_url": "https://api.github.com/users/example_org/followers", + "following_url": "https://api.github.com/users/example_org/following{/other_user}", + "gists_url": "https://api.github.com/users/example_org/gists{/gist_id}", + "starred_url": "https://api.github.com/users/example_org/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/example_org/subscriptions", + "organizations_url": "https://api.github.com/users/example_org/orgs", + "repos_url": "https://api.github.com/users/example_org/repos", + "events_url": "https://api.github.com/users/example_org/events{/privacy}", + "received_events_url": "https://api.github.com/users/example_org/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/example_org/example_repo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/example_org/example_repo", + "forks_url": "https://api.github.com/repos/example_org/example_repo/forks", + "keys_url": "https://api.github.com/repos/example_org/example_repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/example_org/example_repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/example_org/example_repo/teams", + "hooks_url": "https://api.github.com/repos/example_org/example_repo/hooks", + "issue_events_url": "https://api.github.com/repos/example_org/example_repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/example_org/example_repo/events", + "assignees_url": "https://api.github.com/repos/example_org/example_repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/example_org/example_repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/example_org/example_repo/tags", + "blobs_url": "https://api.github.com/repos/example_org/example_repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/example_org/example_repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/example_org/example_repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/example_org/example_repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/example_org/example_repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/example_org/example_repo/languages", + "stargazers_url": "https://api.github.com/repos/example_org/example_repo/stargazers", + "contributors_url": "https://api.github.com/repos/example_org/example_repo/contributors", + "subscribers_url": "https://api.github.com/repos/example_org/example_repo/subscribers", + "subscription_url": "https://api.github.com/repos/example_org/example_repo/subscription", + "commits_url": "https://api.github.com/repos/example_org/example_repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/example_org/example_repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/example_org/example_repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/example_org/example_repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/example_org/example_repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/example_org/example_repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/example_org/example_repo/merges", + "archive_url": "https://api.github.com/repos/example_org/example_repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/example_org/example_repo/downloads", + "issues_url": "https://api.github.com/repos/example_org/example_repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/example_org/example_repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/example_org/example_repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/example_org/example_repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/example_org/example_repo/labels{/name}", + "releases_url": "https://api.github.com/repos/example_org/example_repo/releases{/id}", + "deployments_url": "https://api.github.com/repos/example_org/example_repo/deployments", + "created_at": "2022-10-19T03:41:52Z", + "updated_at": "2022-10-23T23:12:34Z", + "pushed_at": "2023-01-20T09:03:04Z", + "git_url": "git://github.com/example_org/example_repo.git", + "ssh_url": "git@github.com:example_org/example_repo.git", + "clone_url": "https://github.com/example_org/example_repo.git", + "svn_url": "https://github.com/example_org/example_repo", + "homepage": "https://www.example.com", + "size": 642, + "stargazers_count": 1, + "watchers_count": 1, + "language": "TypeScript", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 4, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": false, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "internal", + "forks": 0, + "open_issues": 4, + "watchers": 1, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": false, + "allow_rebase_merge": false, + "allow_auto_merge": true, + "delete_branch_on_merge": false, + "allow_update_branch": true, + "use_squash_pr_title_as_default": false, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE" + } + }, + "base": { + "label": "example_org:main", + "ref": "main", + "sha": "caf87bf0162986f2874ec1b668f1d576b9f99e76", + "user": { + "login": "example_org", + "id": 2345678, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjIzNDU2Nzg=", + "avatar_url": "https://avatars.githubusercontent.com/u/2345678?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/example_org", + "html_url": "https://github.com/example_org", + "followers_url": "https://api.github.com/users/example_org/followers", + "following_url": "https://api.github.com/users/example_org/following{/other_user}", + "gists_url": "https://api.github.com/users/example_org/gists{/gist_id}", + "starred_url": "https://api.github.com/users/example_org/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/example_org/subscriptions", + "organizations_url": "https://api.github.com/users/example_org/orgs", + "repos_url": "https://api.github.com/users/example_org/repos", + "events_url": "https://api.github.com/users/example_org/events{/privacy}", + "received_events_url": "https://api.github.com/users/example_org/received_events", + "type": "Organization", + "site_admin": false + }, + "repo": { + "id": 553972582, + "node_id": "R_kgDOIQTzZg", + "name": "captain", + "full_name": "example_org/example_repo", + "private": true, + "owner": { + "login": "example_org", + "id": 2345678, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjIzNDU2Nzg=", + "avatar_url": "https://avatars.githubusercontent.com/u/2345678?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/example_org", + "html_url": "https://github.com/example_org", + "followers_url": "https://api.github.com/users/example_org/followers", + "following_url": "https://api.github.com/users/example_org/following{/other_user}", + "gists_url": "https://api.github.com/users/example_org/gists{/gist_id}", + "starred_url": "https://api.github.com/users/example_org/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/example_org/subscriptions", + "organizations_url": "https://api.github.com/users/example_org/orgs", + "repos_url": "https://api.github.com/users/example_org/repos", + "events_url": "https://api.github.com/users/example_org/events{/privacy}", + "received_events_url": "https://api.github.com/users/example_org/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/example_org/example_repo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/example_org/example_repo", + "forks_url": "https://api.github.com/repos/example_org/example_repo/forks", + "keys_url": "https://api.github.com/repos/example_org/example_repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/example_org/example_repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/example_org/example_repo/teams", + "hooks_url": "https://api.github.com/repos/example_org/example_repo/hooks", + "issue_events_url": "https://api.github.com/repos/example_org/example_repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/example_org/example_repo/events", + "assignees_url": "https://api.github.com/repos/example_org/example_repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/example_org/example_repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/example_org/example_repo/tags", + "blobs_url": "https://api.github.com/repos/example_org/example_repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/example_org/example_repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/example_org/example_repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/example_org/example_repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/example_org/example_repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/example_org/example_repo/languages", + "stargazers_url": "https://api.github.com/repos/example_org/example_repo/stargazers", + "contributors_url": "https://api.github.com/repos/example_org/example_repo/contributors", + "subscribers_url": "https://api.github.com/repos/example_org/example_repo/subscribers", + "subscription_url": "https://api.github.com/repos/example_org/example_repo/subscription", + "commits_url": "https://api.github.com/repos/example_org/example_repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/example_org/example_repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/example_org/example_repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/example_org/example_repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/example_org/example_repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/example_org/example_repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/example_org/example_repo/merges", + "archive_url": "https://api.github.com/repos/example_org/example_repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/example_org/example_repo/downloads", + "issues_url": "https://api.github.com/repos/example_org/example_repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/example_org/example_repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/example_org/example_repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/example_org/example_repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/example_org/example_repo/labels{/name}", + "releases_url": "https://api.github.com/repos/example_org/example_repo/releases{/id}", + "deployments_url": "https://api.github.com/repos/example_org/example_repo/deployments", + "created_at": "2022-10-19T03:41:52Z", + "updated_at": "2022-10-23T23:12:34Z", + "pushed_at": "2023-01-20T09:03:04Z", + "git_url": "git://github.com/example_org/example_repo.git", + "ssh_url": "git@github.com:example_org/example_repo.git", + "clone_url": "https://github.com/example_org/example_repo.git", + "svn_url": "https://github.com/example_org/example_repo", + "homepage": "https://www.example.com", + "size": 642, + "stargazers_count": 1, + "watchers_count": 1, + "language": "TypeScript", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 4, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": false, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "internal", + "forks": 0, + "open_issues": 4, + "watchers": 1, + "default_branch": "main", + "allow_squash_merge": true, + "allow_merge_commit": false, + "allow_rebase_merge": false, + "allow_auto_merge": true, + "delete_branch_on_merge": false, + "allow_update_branch": true, + "use_squash_pr_title_as_default": false, + "squash_merge_commit_message": "COMMIT_MESSAGES", + "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", + "merge_commit_message": "PR_TITLE", + "merge_commit_title": "MERGE_MESSAGE" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/example_org/example_repo/pulls/15" + }, + "html": { + "href": "https://github.com/example_org/example_repo/pull/15" + }, + "issue": { + "href": "https://api.github.com/repos/example_org/example_repo/issues/15" + }, + "comments": { + "href": "https://api.github.com/repos/example_org/example_repo/issues/15/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/example_org/example_repo/pulls/15/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/example_org/example_repo/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/example_org/example_repo/pulls/15/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/example_org/example_repo/statuses/07a6048532c799c58bf7eafdbc7d4eaf6b6bbde6" + } + }, + "author_association": "COLLABORATOR", + "auto_merge": null, + "active_lock_reason": null, + "merged": false, + "mergeable": null, + "rebaseable": null, + "mergeable_state": "unknown", + "merged_by": null, + "comments": 0, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 7, + "additions": 557, + "deletions": 45, + "changed_files": 27 + }, + "repository": { + "id": 553972582, + "node_id": "R_kgDOIQTzZg", + "name": "captain", + "full_name": "example_org/example_repo", + "private": true, + "owner": { + "login": "example_org", + "id": 2345678, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjIzNDU2Nzg=", + "avatar_url": "https://avatars.githubusercontent.com/u/2345678?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/example_org", + "html_url": "https://github.com/example_org", + "followers_url": "https://api.github.com/users/example_org/followers", + "following_url": "https://api.github.com/users/example_org/following{/other_user}", + "gists_url": "https://api.github.com/users/example_org/gists{/gist_id}", + "starred_url": "https://api.github.com/users/example_org/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/example_org/subscriptions", + "organizations_url": "https://api.github.com/users/example_org/orgs", + "repos_url": "https://api.github.com/users/example_org/repos", + "events_url": "https://api.github.com/users/example_org/events{/privacy}", + "received_events_url": "https://api.github.com/users/example_org/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/example_org/example_repo", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/example_org/example_repo", + "forks_url": "https://api.github.com/repos/example_org/example_repo/forks", + "keys_url": "https://api.github.com/repos/example_org/example_repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/example_org/example_repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/example_org/example_repo/teams", + "hooks_url": "https://api.github.com/repos/example_org/example_repo/hooks", + "issue_events_url": "https://api.github.com/repos/example_org/example_repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/example_org/example_repo/events", + "assignees_url": "https://api.github.com/repos/example_org/example_repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/example_org/example_repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/example_org/example_repo/tags", + "blobs_url": "https://api.github.com/repos/example_org/example_repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/example_org/example_repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/example_org/example_repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/example_org/example_repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/example_org/example_repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/example_org/example_repo/languages", + "stargazers_url": "https://api.github.com/repos/example_org/example_repo/stargazers", + "contributors_url": "https://api.github.com/repos/example_org/example_repo/contributors", + "subscribers_url": "https://api.github.com/repos/example_org/example_repo/subscribers", + "subscription_url": "https://api.github.com/repos/example_org/example_repo/subscription", + "commits_url": "https://api.github.com/repos/example_org/example_repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/example_org/example_repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/example_org/example_repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/example_org/example_repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/example_org/example_repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/example_org/example_repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/example_org/example_repo/merges", + "archive_url": "https://api.github.com/repos/example_org/example_repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/example_org/example_repo/downloads", + "issues_url": "https://api.github.com/repos/example_org/example_repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/example_org/example_repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/example_org/example_repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/example_org/example_repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/example_org/example_repo/labels{/name}", + "releases_url": "https://api.github.com/repos/example_org/example_repo/releases{/id}", + "deployments_url": "https://api.github.com/repos/example_org/example_repo/deployments", + "created_at": "2022-10-19T03:41:52Z", + "updated_at": "2022-10-23T23:12:34Z", + "pushed_at": "2023-01-20T09:03:04Z", + "git_url": "git://github.com/example_org/example_repo.git", + "ssh_url": "git@github.com:example_org/example_repo.git", + "clone_url": "https://github.com/example_org/example_repo.git", + "svn_url": "https://github.com/example_org/example_repo", + "homepage": "https://www.example.com", + "size": 642, + "stargazers_count": 1, + "watchers_count": 1, + "language": "TypeScript", + "has_issues": true, + "has_projects": false, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 4, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": false, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "internal", + "forks": 0, + "open_issues": 4, + "watchers": 1, + "default_branch": "main" + }, + "organization": { + "login": "example_org", + "id": 2345678, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjIzNDU2Nzg=", + "url": "https://api.github.com/orgs/example_org", + "repos_url": "https://api.github.com/orgs/example_org/repos", + "events_url": "https://api.github.com/orgs/example_org/events", + "hooks_url": "https://api.github.com/orgs/example_org/hooks", + "issues_url": "https://api.github.com/orgs/example_org/issues", + "members_url": "https://api.github.com/orgs/example_org/members{/member}", + "public_members_url": "https://api.github.com/orgs/example_org/public_members{/member}", + "avatar_url": "https://avatars.githubusercontent.com/u/2345678?v=4", + "description": "Example organization description" + }, + "enterprise": { + "id": 12345, + "slug": "example-enterprise", + "name": "Example Enterprise", + "node_id": "E_kgDRKO7", + "avatar_url": "https://avatars.githubusercontent.com/b/12345?v=4", + "description": "Example enterprise description", + "website_url": "https://www.example.com", + "html_url": "https://github.com/enterprises/example-enterprise", + "created_at": "2022-09-19T23:04:52Z", + "updated_at": "2022-09-19T23:16:12Z" + }, + "sender": { + "login": "jdoe", + "id": 1234567, + "node_id": "MDQ6VXNlcjY3NTE3ODc=", + "avatar_url": "https://avatars.githubusercontent.com/u/1234567?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jdoe", + "html_url": "https://github.com/jdoe", + "followers_url": "https://api.github.com/users/jdoe/followers", + "following_url": "https://api.github.com/users/jdoe/following{/other_user}", + "gists_url": "https://api.github.com/users/jdoe/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jdoe/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jdoe/subscriptions", + "organizations_url": "https://api.github.com/users/jdoe/orgs", + "repos_url": "https://api.github.com/users/jdoe/repos", + "events_url": "https://api.github.com/users/jdoe/events{/privacy}", + "received_events_url": "https://api.github.com/users/jdoe/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/pkg/model/testdata/filter-events/push-foo.json b/pkg/model/testdata/filter-events/push-foo.json new file mode 100644 index 00000000000..763bf0bdb41 --- /dev/null +++ b/pkg/model/testdata/filter-events/push-foo.json @@ -0,0 +1,219 @@ +{ + "ref": "refs/heads/foo", + "before": "1214900eca16aa54d97d062e7b72261616fd53aa", + "after": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "repository": { + "id": 17892893, + "node_id": "MDEwOlJlcG9zaXRvcnkxNzg5Mjg5Mw==", + "name": "codecombat", + "full_name": "walkingtospace/codecombat", + "private": false, + "owner": { + "name": "walkingtospace", + "email": "walkingtospace@gmail.com", + "login": "walkingtospace", + "id": 2024264, + "node_id": "MDQ6VXNlcjIwMjQyNjQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2024264?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/walkingtospace", + "html_url": "https://github.com/walkingtospace", + "followers_url": "https://api.github.com/users/walkingtospace/followers", + "following_url": "https://api.github.com/users/walkingtospace/following{/other_user}", + "gists_url": "https://api.github.com/users/walkingtospace/gists{/gist_id}", + "starred_url": "https://api.github.com/users/walkingtospace/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/walkingtospace/subscriptions", + "organizations_url": "https://api.github.com/users/walkingtospace/orgs", + "repos_url": "https://api.github.com/users/walkingtospace/repos", + "events_url": "https://api.github.com/users/walkingtospace/events{/privacy}", + "received_events_url": "https://api.github.com/users/walkingtospace/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/walkingtospace/codecombat", + "description": "Multiplayer programming game for learning how to code.", + "fork": true, + "url": "https://github.com/walkingtospace/codecombat", + "forks_url": "https://api.github.com/repos/walkingtospace/codecombat/forks", + "keys_url": "https://api.github.com/repos/walkingtospace/codecombat/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/walkingtospace/codecombat/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/walkingtospace/codecombat/teams", + "hooks_url": "https://api.github.com/repos/walkingtospace/codecombat/hooks", + "issue_events_url": "https://api.github.com/repos/walkingtospace/codecombat/issues/events{/number}", + "events_url": "https://api.github.com/repos/walkingtospace/codecombat/events", + "assignees_url": "https://api.github.com/repos/walkingtospace/codecombat/assignees{/user}", + "branches_url": "https://api.github.com/repos/walkingtospace/codecombat/branches{/branch}", + "tags_url": "https://api.github.com/repos/walkingtospace/codecombat/tags", + "blobs_url": "https://api.github.com/repos/walkingtospace/codecombat/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/walkingtospace/codecombat/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/walkingtospace/codecombat/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/walkingtospace/codecombat/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/walkingtospace/codecombat/statuses/{sha}", + "languages_url": "https://api.github.com/repos/walkingtospace/codecombat/languages", + "stargazers_url": "https://api.github.com/repos/walkingtospace/codecombat/stargazers", + "contributors_url": "https://api.github.com/repos/walkingtospace/codecombat/contributors", + "subscribers_url": "https://api.github.com/repos/walkingtospace/codecombat/subscribers", + "subscription_url": "https://api.github.com/repos/walkingtospace/codecombat/subscription", + "commits_url": "https://api.github.com/repos/walkingtospace/codecombat/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/walkingtospace/codecombat/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/walkingtospace/codecombat/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/walkingtospace/codecombat/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/walkingtospace/codecombat/contents/{+path}", + "compare_url": "https://api.github.com/repos/walkingtospace/codecombat/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/walkingtospace/codecombat/merges", + "archive_url": "https://api.github.com/repos/walkingtospace/codecombat/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/walkingtospace/codecombat/downloads", + "issues_url": "https://api.github.com/repos/walkingtospace/codecombat/issues{/number}", + "pulls_url": "https://api.github.com/repos/walkingtospace/codecombat/pulls{/number}", + "milestones_url": "https://api.github.com/repos/walkingtospace/codecombat/milestones{/number}", + "notifications_url": "https://api.github.com/repos/walkingtospace/codecombat/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/walkingtospace/codecombat/labels{/name}", + "releases_url": "https://api.github.com/repos/walkingtospace/codecombat/releases{/id}", + "deployments_url": "https://api.github.com/repos/walkingtospace/codecombat/deployments", + "created_at": 1395205813, + "updated_at": "2023-01-04T18:52:34Z", + "pushed_at": 1672895634, + "git_url": "git://github.com/walkingtospace/codecombat.git", + "ssh_url": "git@github.com:walkingtospace/codecombat.git", + "clone_url": "https://github.com/walkingtospace/codecombat.git", + "svn_url": "https://github.com/walkingtospace/codecombat", + "homepage": "http://codecombat.com", + "size": 9586, + "stargazers_count": 0, + "watchers_count": 0, + "language": "CoffeeScript", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 7, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 7, + "watchers": 0, + "default_branch": "master", + "stargazers": 0, + "master_branch": "master" + }, + "pusher": { + "name": "walkingtospace", + "email": "walkingtospace@gmail.com" + }, + "sender": { + "login": "walkingtospace", + "id": 2024264, + "node_id": "MDQ6VXNlcjIwMjQyNjQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2024264?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/walkingtospace", + "html_url": "https://github.com/walkingtospace", + "followers_url": "https://api.github.com/users/walkingtospace/followers", + "following_url": "https://api.github.com/users/walkingtospace/following{/other_user}", + "gists_url": "https://api.github.com/users/walkingtospace/gists{/gist_id}", + "starred_url": "https://api.github.com/users/walkingtospace/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/walkingtospace/subscriptions", + "organizations_url": "https://api.github.com/users/walkingtospace/orgs", + "repos_url": "https://api.github.com/users/walkingtospace/repos", + "events_url": "https://api.github.com/users/walkingtospace/events{/privacy}", + "received_events_url": "https://api.github.com/users/walkingtospace/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 32787291, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzI3ODcyOTE=" + }, + "created": false, + "deleted": false, + "forced": false, + "base_ref": null, + "compare": "https://github.com/walkingtospace/codecombat/compare/1214900eca16...40a717b3644e", + "commits": [ + { + "id": "a0e0971b7c229a51a41bf46e076e1020bf22b04c", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": false, + "message": "Test", + "timestamp": "2023-01-04T21:13:28-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/a0e0971b7c229a51a41bf46e076e1020bf22b04c", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + }, + { + "id": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": true, + "message": "Merge pull request #10 from walkingtospace/test5\n\nTest", + "timestamp": "2023-01-04T21:13:54-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "username": "web-flow" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + } + ], + "head_commit": { + "id": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": true, + "message": "Merge pull request #10 from walkingtospace/test5\n\nTest", + "timestamp": "2023-01-04T21:13:54-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "username": "web-flow" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + } +} diff --git a/pkg/model/testdata/filter-events/push-master.json b/pkg/model/testdata/filter-events/push-master.json new file mode 100644 index 00000000000..59917c52dc0 --- /dev/null +++ b/pkg/model/testdata/filter-events/push-master.json @@ -0,0 +1,219 @@ +{ + "ref": "refs/heads/master", + "before": "1214900eca16aa54d97d062e7b72261616fd53aa", + "after": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "repository": { + "id": 17892893, + "node_id": "MDEwOlJlcG9zaXRvcnkxNzg5Mjg5Mw==", + "name": "codecombat", + "full_name": "walkingtospace/codecombat", + "private": false, + "owner": { + "name": "walkingtospace", + "email": "walkingtospace@gmail.com", + "login": "walkingtospace", + "id": 2024264, + "node_id": "MDQ6VXNlcjIwMjQyNjQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2024264?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/walkingtospace", + "html_url": "https://github.com/walkingtospace", + "followers_url": "https://api.github.com/users/walkingtospace/followers", + "following_url": "https://api.github.com/users/walkingtospace/following{/other_user}", + "gists_url": "https://api.github.com/users/walkingtospace/gists{/gist_id}", + "starred_url": "https://api.github.com/users/walkingtospace/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/walkingtospace/subscriptions", + "organizations_url": "https://api.github.com/users/walkingtospace/orgs", + "repos_url": "https://api.github.com/users/walkingtospace/repos", + "events_url": "https://api.github.com/users/walkingtospace/events{/privacy}", + "received_events_url": "https://api.github.com/users/walkingtospace/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/walkingtospace/codecombat", + "description": "Multiplayer programming game for learning how to code.", + "fork": true, + "url": "https://github.com/walkingtospace/codecombat", + "forks_url": "https://api.github.com/repos/walkingtospace/codecombat/forks", + "keys_url": "https://api.github.com/repos/walkingtospace/codecombat/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/walkingtospace/codecombat/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/walkingtospace/codecombat/teams", + "hooks_url": "https://api.github.com/repos/walkingtospace/codecombat/hooks", + "issue_events_url": "https://api.github.com/repos/walkingtospace/codecombat/issues/events{/number}", + "events_url": "https://api.github.com/repos/walkingtospace/codecombat/events", + "assignees_url": "https://api.github.com/repos/walkingtospace/codecombat/assignees{/user}", + "branches_url": "https://api.github.com/repos/walkingtospace/codecombat/branches{/branch}", + "tags_url": "https://api.github.com/repos/walkingtospace/codecombat/tags", + "blobs_url": "https://api.github.com/repos/walkingtospace/codecombat/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/walkingtospace/codecombat/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/walkingtospace/codecombat/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/walkingtospace/codecombat/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/walkingtospace/codecombat/statuses/{sha}", + "languages_url": "https://api.github.com/repos/walkingtospace/codecombat/languages", + "stargazers_url": "https://api.github.com/repos/walkingtospace/codecombat/stargazers", + "contributors_url": "https://api.github.com/repos/walkingtospace/codecombat/contributors", + "subscribers_url": "https://api.github.com/repos/walkingtospace/codecombat/subscribers", + "subscription_url": "https://api.github.com/repos/walkingtospace/codecombat/subscription", + "commits_url": "https://api.github.com/repos/walkingtospace/codecombat/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/walkingtospace/codecombat/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/walkingtospace/codecombat/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/walkingtospace/codecombat/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/walkingtospace/codecombat/contents/{+path}", + "compare_url": "https://api.github.com/repos/walkingtospace/codecombat/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/walkingtospace/codecombat/merges", + "archive_url": "https://api.github.com/repos/walkingtospace/codecombat/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/walkingtospace/codecombat/downloads", + "issues_url": "https://api.github.com/repos/walkingtospace/codecombat/issues{/number}", + "pulls_url": "https://api.github.com/repos/walkingtospace/codecombat/pulls{/number}", + "milestones_url": "https://api.github.com/repos/walkingtospace/codecombat/milestones{/number}", + "notifications_url": "https://api.github.com/repos/walkingtospace/codecombat/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/walkingtospace/codecombat/labels{/name}", + "releases_url": "https://api.github.com/repos/walkingtospace/codecombat/releases{/id}", + "deployments_url": "https://api.github.com/repos/walkingtospace/codecombat/deployments", + "created_at": 1395205813, + "updated_at": "2023-01-04T18:52:34Z", + "pushed_at": 1672895634, + "git_url": "git://github.com/walkingtospace/codecombat.git", + "ssh_url": "git@github.com:walkingtospace/codecombat.git", + "clone_url": "https://github.com/walkingtospace/codecombat.git", + "svn_url": "https://github.com/walkingtospace/codecombat", + "homepage": "http://codecombat.com", + "size": 9586, + "stargazers_count": 0, + "watchers_count": 0, + "language": "CoffeeScript", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 7, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 7, + "watchers": 0, + "default_branch": "master", + "stargazers": 0, + "master_branch": "master" + }, + "pusher": { + "name": "walkingtospace", + "email": "walkingtospace@gmail.com" + }, + "sender": { + "login": "walkingtospace", + "id": 2024264, + "node_id": "MDQ6VXNlcjIwMjQyNjQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2024264?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/walkingtospace", + "html_url": "https://github.com/walkingtospace", + "followers_url": "https://api.github.com/users/walkingtospace/followers", + "following_url": "https://api.github.com/users/walkingtospace/following{/other_user}", + "gists_url": "https://api.github.com/users/walkingtospace/gists{/gist_id}", + "starred_url": "https://api.github.com/users/walkingtospace/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/walkingtospace/subscriptions", + "organizations_url": "https://api.github.com/users/walkingtospace/orgs", + "repos_url": "https://api.github.com/users/walkingtospace/repos", + "events_url": "https://api.github.com/users/walkingtospace/events{/privacy}", + "received_events_url": "https://api.github.com/users/walkingtospace/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 32787291, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzI3ODcyOTE=" + }, + "created": false, + "deleted": false, + "forced": false, + "base_ref": null, + "compare": "https://github.com/walkingtospace/codecombat/compare/1214900eca16...40a717b3644e", + "commits": [ + { + "id": "a0e0971b7c229a51a41bf46e076e1020bf22b04c", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": false, + "message": "Test", + "timestamp": "2023-01-04T21:13:28-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/a0e0971b7c229a51a41bf46e076e1020bf22b04c", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + }, + { + "id": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": true, + "message": "Merge pull request #10 from walkingtospace/test5\n\nTest", + "timestamp": "2023-01-04T21:13:54-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "username": "web-flow" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + } + ], + "head_commit": { + "id": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": true, + "message": "Merge pull request #10 from walkingtospace/test5\n\nTest", + "timestamp": "2023-01-04T21:13:54-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "username": "web-flow" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + } +} diff --git a/pkg/model/testdata/filter-events/push-tag-v1.json b/pkg/model/testdata/filter-events/push-tag-v1.json new file mode 100644 index 00000000000..30c67a3e147 --- /dev/null +++ b/pkg/model/testdata/filter-events/push-tag-v1.json @@ -0,0 +1,219 @@ +{ + "ref": "refs/tags/v1", + "before": "1214900eca16aa54d97d062e7b72261616fd53aa", + "after": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "repository": { + "id": 17892893, + "node_id": "MDEwOlJlcG9zaXRvcnkxNzg5Mjg5Mw==", + "name": "codecombat", + "full_name": "walkingtospace/codecombat", + "private": false, + "owner": { + "name": "walkingtospace", + "email": "walkingtospace@gmail.com", + "login": "walkingtospace", + "id": 2024264, + "node_id": "MDQ6VXNlcjIwMjQyNjQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2024264?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/walkingtospace", + "html_url": "https://github.com/walkingtospace", + "followers_url": "https://api.github.com/users/walkingtospace/followers", + "following_url": "https://api.github.com/users/walkingtospace/following{/other_user}", + "gists_url": "https://api.github.com/users/walkingtospace/gists{/gist_id}", + "starred_url": "https://api.github.com/users/walkingtospace/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/walkingtospace/subscriptions", + "organizations_url": "https://api.github.com/users/walkingtospace/orgs", + "repos_url": "https://api.github.com/users/walkingtospace/repos", + "events_url": "https://api.github.com/users/walkingtospace/events{/privacy}", + "received_events_url": "https://api.github.com/users/walkingtospace/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/walkingtospace/codecombat", + "description": "Multiplayer programming game for learning how to code.", + "fork": true, + "url": "https://github.com/walkingtospace/codecombat", + "forks_url": "https://api.github.com/repos/walkingtospace/codecombat/forks", + "keys_url": "https://api.github.com/repos/walkingtospace/codecombat/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/walkingtospace/codecombat/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/walkingtospace/codecombat/teams", + "hooks_url": "https://api.github.com/repos/walkingtospace/codecombat/hooks", + "issue_events_url": "https://api.github.com/repos/walkingtospace/codecombat/issues/events{/number}", + "events_url": "https://api.github.com/repos/walkingtospace/codecombat/events", + "assignees_url": "https://api.github.com/repos/walkingtospace/codecombat/assignees{/user}", + "branches_url": "https://api.github.com/repos/walkingtospace/codecombat/branches{/branch}", + "tags_url": "https://api.github.com/repos/walkingtospace/codecombat/tags", + "blobs_url": "https://api.github.com/repos/walkingtospace/codecombat/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/walkingtospace/codecombat/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/walkingtospace/codecombat/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/walkingtospace/codecombat/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/walkingtospace/codecombat/statuses/{sha}", + "languages_url": "https://api.github.com/repos/walkingtospace/codecombat/languages", + "stargazers_url": "https://api.github.com/repos/walkingtospace/codecombat/stargazers", + "contributors_url": "https://api.github.com/repos/walkingtospace/codecombat/contributors", + "subscribers_url": "https://api.github.com/repos/walkingtospace/codecombat/subscribers", + "subscription_url": "https://api.github.com/repos/walkingtospace/codecombat/subscription", + "commits_url": "https://api.github.com/repos/walkingtospace/codecombat/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/walkingtospace/codecombat/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/walkingtospace/codecombat/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/walkingtospace/codecombat/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/walkingtospace/codecombat/contents/{+path}", + "compare_url": "https://api.github.com/repos/walkingtospace/codecombat/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/walkingtospace/codecombat/merges", + "archive_url": "https://api.github.com/repos/walkingtospace/codecombat/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/walkingtospace/codecombat/downloads", + "issues_url": "https://api.github.com/repos/walkingtospace/codecombat/issues{/number}", + "pulls_url": "https://api.github.com/repos/walkingtospace/codecombat/pulls{/number}", + "milestones_url": "https://api.github.com/repos/walkingtospace/codecombat/milestones{/number}", + "notifications_url": "https://api.github.com/repos/walkingtospace/codecombat/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/walkingtospace/codecombat/labels{/name}", + "releases_url": "https://api.github.com/repos/walkingtospace/codecombat/releases{/id}", + "deployments_url": "https://api.github.com/repos/walkingtospace/codecombat/deployments", + "created_at": 1395205813, + "updated_at": "2023-01-04T18:52:34Z", + "pushed_at": 1672895634, + "git_url": "git://github.com/walkingtospace/codecombat.git", + "ssh_url": "git@github.com:walkingtospace/codecombat.git", + "clone_url": "https://github.com/walkingtospace/codecombat.git", + "svn_url": "https://github.com/walkingtospace/codecombat", + "homepage": "http://codecombat.com", + "size": 9586, + "stargazers_count": 0, + "watchers_count": 0, + "language": "CoffeeScript", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 7, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 7, + "watchers": 0, + "default_branch": "master", + "stargazers": 0, + "master_branch": "master" + }, + "pusher": { + "name": "walkingtospace", + "email": "walkingtospace@gmail.com" + }, + "sender": { + "login": "walkingtospace", + "id": 2024264, + "node_id": "MDQ6VXNlcjIwMjQyNjQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2024264?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/walkingtospace", + "html_url": "https://github.com/walkingtospace", + "followers_url": "https://api.github.com/users/walkingtospace/followers", + "following_url": "https://api.github.com/users/walkingtospace/following{/other_user}", + "gists_url": "https://api.github.com/users/walkingtospace/gists{/gist_id}", + "starred_url": "https://api.github.com/users/walkingtospace/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/walkingtospace/subscriptions", + "organizations_url": "https://api.github.com/users/walkingtospace/orgs", + "repos_url": "https://api.github.com/users/walkingtospace/repos", + "events_url": "https://api.github.com/users/walkingtospace/events{/privacy}", + "received_events_url": "https://api.github.com/users/walkingtospace/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 32787291, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzI3ODcyOTE=" + }, + "created": false, + "deleted": false, + "forced": false, + "base_ref": null, + "compare": "https://github.com/walkingtospace/codecombat/compare/1214900eca16...40a717b3644e", + "commits": [ + { + "id": "a0e0971b7c229a51a41bf46e076e1020bf22b04c", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": false, + "message": "Test", + "timestamp": "2023-01-04T21:13:28-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/a0e0971b7c229a51a41bf46e076e1020bf22b04c", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + }, + { + "id": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": true, + "message": "Merge pull request #10 from walkingtospace/test5\n\nTest", + "timestamp": "2023-01-04T21:13:54-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "username": "web-flow" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + } + ], + "head_commit": { + "id": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": true, + "message": "Merge pull request #10 from walkingtospace/test5\n\nTest", + "timestamp": "2023-01-04T21:13:54-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "username": "web-flow" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + } +} diff --git a/pkg/model/testdata/filter-events/push-tag-v2.json b/pkg/model/testdata/filter-events/push-tag-v2.json new file mode 100644 index 00000000000..5ac0781c6d1 --- /dev/null +++ b/pkg/model/testdata/filter-events/push-tag-v2.json @@ -0,0 +1,219 @@ +{ + "ref": "refs/tags/v2", + "before": "1214900eca16aa54d97d062e7b72261616fd53aa", + "after": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "repository": { + "id": 17892893, + "node_id": "MDEwOlJlcG9zaXRvcnkxNzg5Mjg5Mw==", + "name": "codecombat", + "full_name": "walkingtospace/codecombat", + "private": false, + "owner": { + "name": "walkingtospace", + "email": "walkingtospace@gmail.com", + "login": "walkingtospace", + "id": 2024264, + "node_id": "MDQ6VXNlcjIwMjQyNjQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2024264?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/walkingtospace", + "html_url": "https://github.com/walkingtospace", + "followers_url": "https://api.github.com/users/walkingtospace/followers", + "following_url": "https://api.github.com/users/walkingtospace/following{/other_user}", + "gists_url": "https://api.github.com/users/walkingtospace/gists{/gist_id}", + "starred_url": "https://api.github.com/users/walkingtospace/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/walkingtospace/subscriptions", + "organizations_url": "https://api.github.com/users/walkingtospace/orgs", + "repos_url": "https://api.github.com/users/walkingtospace/repos", + "events_url": "https://api.github.com/users/walkingtospace/events{/privacy}", + "received_events_url": "https://api.github.com/users/walkingtospace/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/walkingtospace/codecombat", + "description": "Multiplayer programming game for learning how to code.", + "fork": true, + "url": "https://github.com/walkingtospace/codecombat", + "forks_url": "https://api.github.com/repos/walkingtospace/codecombat/forks", + "keys_url": "https://api.github.com/repos/walkingtospace/codecombat/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/walkingtospace/codecombat/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/walkingtospace/codecombat/teams", + "hooks_url": "https://api.github.com/repos/walkingtospace/codecombat/hooks", + "issue_events_url": "https://api.github.com/repos/walkingtospace/codecombat/issues/events{/number}", + "events_url": "https://api.github.com/repos/walkingtospace/codecombat/events", + "assignees_url": "https://api.github.com/repos/walkingtospace/codecombat/assignees{/user}", + "branches_url": "https://api.github.com/repos/walkingtospace/codecombat/branches{/branch}", + "tags_url": "https://api.github.com/repos/walkingtospace/codecombat/tags", + "blobs_url": "https://api.github.com/repos/walkingtospace/codecombat/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/walkingtospace/codecombat/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/walkingtospace/codecombat/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/walkingtospace/codecombat/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/walkingtospace/codecombat/statuses/{sha}", + "languages_url": "https://api.github.com/repos/walkingtospace/codecombat/languages", + "stargazers_url": "https://api.github.com/repos/walkingtospace/codecombat/stargazers", + "contributors_url": "https://api.github.com/repos/walkingtospace/codecombat/contributors", + "subscribers_url": "https://api.github.com/repos/walkingtospace/codecombat/subscribers", + "subscription_url": "https://api.github.com/repos/walkingtospace/codecombat/subscription", + "commits_url": "https://api.github.com/repos/walkingtospace/codecombat/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/walkingtospace/codecombat/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/walkingtospace/codecombat/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/walkingtospace/codecombat/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/walkingtospace/codecombat/contents/{+path}", + "compare_url": "https://api.github.com/repos/walkingtospace/codecombat/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/walkingtospace/codecombat/merges", + "archive_url": "https://api.github.com/repos/walkingtospace/codecombat/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/walkingtospace/codecombat/downloads", + "issues_url": "https://api.github.com/repos/walkingtospace/codecombat/issues{/number}", + "pulls_url": "https://api.github.com/repos/walkingtospace/codecombat/pulls{/number}", + "milestones_url": "https://api.github.com/repos/walkingtospace/codecombat/milestones{/number}", + "notifications_url": "https://api.github.com/repos/walkingtospace/codecombat/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/walkingtospace/codecombat/labels{/name}", + "releases_url": "https://api.github.com/repos/walkingtospace/codecombat/releases{/id}", + "deployments_url": "https://api.github.com/repos/walkingtospace/codecombat/deployments", + "created_at": 1395205813, + "updated_at": "2023-01-04T18:52:34Z", + "pushed_at": 1672895634, + "git_url": "git://github.com/walkingtospace/codecombat.git", + "ssh_url": "git@github.com:walkingtospace/codecombat.git", + "clone_url": "https://github.com/walkingtospace/codecombat.git", + "svn_url": "https://github.com/walkingtospace/codecombat", + "homepage": "http://codecombat.com", + "size": 9586, + "stargazers_count": 0, + "watchers_count": 0, + "language": "CoffeeScript", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 7, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 7, + "watchers": 0, + "default_branch": "master", + "stargazers": 0, + "master_branch": "master" + }, + "pusher": { + "name": "walkingtospace", + "email": "walkingtospace@gmail.com" + }, + "sender": { + "login": "walkingtospace", + "id": 2024264, + "node_id": "MDQ6VXNlcjIwMjQyNjQ=", + "avatar_url": "https://avatars.githubusercontent.com/u/2024264?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/walkingtospace", + "html_url": "https://github.com/walkingtospace", + "followers_url": "https://api.github.com/users/walkingtospace/followers", + "following_url": "https://api.github.com/users/walkingtospace/following{/other_user}", + "gists_url": "https://api.github.com/users/walkingtospace/gists{/gist_id}", + "starred_url": "https://api.github.com/users/walkingtospace/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/walkingtospace/subscriptions", + "organizations_url": "https://api.github.com/users/walkingtospace/orgs", + "repos_url": "https://api.github.com/users/walkingtospace/repos", + "events_url": "https://api.github.com/users/walkingtospace/events{/privacy}", + "received_events_url": "https://api.github.com/users/walkingtospace/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 32787291, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMzI3ODcyOTE=" + }, + "created": false, + "deleted": false, + "forced": false, + "base_ref": null, + "compare": "https://github.com/walkingtospace/codecombat/compare/1214900eca16...40a717b3644e", + "commits": [ + { + "id": "a0e0971b7c229a51a41bf46e076e1020bf22b04c", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": false, + "message": "Test", + "timestamp": "2023-01-04T21:13:28-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/a0e0971b7c229a51a41bf46e076e1020bf22b04c", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + }, + { + "id": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": true, + "message": "Merge pull request #10 from walkingtospace/test5\n\nTest", + "timestamp": "2023-01-04T21:13:54-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "username": "web-flow" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + } + ], + "head_commit": { + "id": "40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "tree_id": "d50f3e5752588e7ead772e7e7b3e86393b8f5a4c", + "distinct": true, + "message": "Merge pull request #10 from walkingtospace/test5\n\nTest", + "timestamp": "2023-01-04T21:13:54-08:00", + "url": "https://github.com/walkingtospace/codecombat/commit/40a717b3644e2ddec52cf6c8bfa436767bf0704e", + "author": { + "name": "Honam", + "email": "walkingtospace@gmail.com", + "username": "walkingtospace" + }, + "committer": { + "name": "GitHub", + "email": "noreply@github.com", + "username": "web-flow" + }, + "added": [], + "removed": [], + "modified": [ + "test/app/lib/forms.spec.coffee" + ] + } +} diff --git a/pkg/model/workflow.go b/pkg/model/workflow.go index f8eee0a226f..f859b651cde 100644 --- a/pkg/model/workflow.go +++ b/pkg/model/workflow.go @@ -4,11 +4,15 @@ import ( "errors" "fmt" "io" + "os" "reflect" "regexp" "strconv" "strings" + "github.com/google/go-github/v71/github" + "github.com/nektos/act/pkg/workflowpattern" + "github.com/nektos/act/pkg/common" "github.com/nektos/act/pkg/schema" log "github.com/sirupsen/logrus" @@ -25,6 +29,27 @@ type Workflow struct { Defaults Defaults `yaml:"defaults"` } +type Push struct { + Branches []string `yaml:"branches"` + BranchesIgnore []string `yaml:"branches_ignore"` + Paths []string `yaml:"paths"` + PathsIgnore []string `yaml:"paths_ignore"` + Tags []string `yaml:"tags"` + TagsIgnore []string `yaml:"tags_ignore"` +} + +type PullRequest struct { + Branches []string `yaml:"branches"` + BranchesIgnore []string `yaml:"branches_ignore"` + Paths []string `yaml:"paths"` + PathsIgnore []string `yaml:"paths_ignore"` +} + +type ScheduleCron struct { + Cron string `yaml:"cron"` +} +type Schedule []ScheduleCron + // On events for the workflow func (w *Workflow) On() []string { switch w.RawOn.Kind { @@ -68,6 +93,351 @@ func (w *Workflow) OnEvent(event string) interface{} { return nil } +func (w *Workflow) PushConfig() *Push { + switch w.RawOn.Kind { + case yaml.ScalarNode: + var val string + if !decodeNode(w.RawOn, &val) { + return nil + } + + if val == "push" { + return &Push{} + } + case yaml.SequenceNode: + var val []string + if !decodeNode(w.RawOn, &val) { + return nil + } + for _, v := range val { + if v == "push" { + return &Push{} + } + } + case yaml.MappingNode: + var val map[string]yaml.Node + if !decodeNode(w.RawOn, &val) { + return nil + } + + n, found := val["push"] + var push Push + if found && decodeNode(n, &push) { + return &push + } + default: + return nil + } + return nil +} + +func (w *Workflow) PullRequestConfig() *PullRequest { + switch w.RawOn.Kind { + case yaml.ScalarNode: + var val string + if !decodeNode(w.RawOn, &val) { + return nil + } + if val == "pull_request" || val == "pull_request_target" { + return &PullRequest{} + } + case yaml.SequenceNode: + var val []string + if !decodeNode(w.RawOn, &val) { + return nil + } + for _, v := range val { + if v == "pull_request" || v == "pull_request_target" { + return &PullRequest{} + } + } + case yaml.MappingNode: + var val map[string]yaml.Node + if !decodeNode(w.RawOn, &val) { + return nil + } + + var pullRequest PullRequest + n, found := val["pull_request"] + if found && decodeNode(n, &pullRequest) { + return &pullRequest + } + n, found = val["pull_request_target"] + if found && decodeNode(n, &pullRequest) { + return &pullRequest + } + default: + return nil + } + return nil +} + +func (w *Workflow) ScheduleConfig() *Schedule { + switch w.RawOn.Kind { + case yaml.ScalarNode: + var val string + if !decodeNode(w.RawOn, &val) { + return nil + } + if val == "schedule" { + return &Schedule{} + } + case yaml.SequenceNode: + var val []string + if !decodeNode(w.RawOn, &val) { + return nil + } + for _, v := range val { + if v == "schedule" { + return &Schedule{} + } + } + case yaml.MappingNode: + var val map[string]yaml.Node + if !decodeNode(w.RawOn, &val) { + return nil + } + + n, found := val["schedule"] + var schedule Schedule + if found && decodeNode(n, &schedule) { + return &schedule + } + default: + return nil + } + return nil +} + +type ByteArray []byte + +func readFileByteArray(filePath string) (*ByteArray, error) { + if filePath == "" { + return nil, nil + } + jsonFile, err := os.Open(filePath) + if err != nil { + return nil, err + } + defer jsonFile.Close() + array, err := io.ReadAll(jsonFile) + if err != nil { + return nil, err + } + + return (*ByteArray)(&array), nil +} + +// we extract a number of methods to reduce the cyclomatic complexity of shouldFilterForPush() + +// define alias so we can use as a receiver +type githubPushEvent github.PushEvent +type githubPullRequestEvent github.PullRequestEvent + +func (byteArray ByteArray) asGithubPushEvent() (*githubPushEvent, error) { + event, err := github.ParseWebHook("push", byteArray) + if err != nil { + return nil, err + } + return (*githubPushEvent)(event.(*github.PushEvent)), nil +} + +func (byteArray ByteArray) asGithubPullRequestEvent() (*githubPullRequestEvent, error) { + event, err := github.ParseWebHook("pull_request", byteArray) + if err != nil { + return nil, err + } + return (*githubPullRequestEvent)(event.(*github.PullRequestEvent)), nil +} + +// return true if a workflow should be skipped because of branch +func evaluateBranchSkip(ref string, branchFilters []string) bool { + branchPatterns, err := workflowpattern.CompilePatterns(branchFilters...) + if err != nil { + log.Errorf("Error parsing workflow branch patterns (%s), so we will not filter the workflow", err) + return false + } + return workflowpattern.Skip(branchPatterns, []string{ref}, &workflowpattern.StdOutTraceWriter{}) +} + +// return true if a workflow should be skipped because of branch_ignore +func evaluateBranchFilter(ref string, branchFilters []string) bool { + branchPatterns, err := workflowpattern.CompilePatterns(branchFilters...) + if err != nil { + log.Errorf("Error parsing workflow branch ignore patterns (%s), so we will not filter the workflow", err) + return false + } + return workflowpattern.Filter(branchPatterns, []string{ref}, &workflowpattern.StdOutTraceWriter{}) +} + +// return true if a workflow should be skipped because of tag +func evaluateTagSkip(ref string, tagFilters []string) bool { + tagPatterns, err := workflowpattern.CompilePatterns(tagFilters...) + if err != nil { + log.Errorf("Error parsing workflow tag patterns (%s), so we will not filter the workflow", err) + return false + } + return workflowpattern.Skip(tagPatterns, []string{ref}, &workflowpattern.StdOutTraceWriter{}) +} + +// return true if a workflow should be skipped because of tag_ignore +func evaluateTagFilter(ref string, tagFilters []string) bool { + tagPatterns, err := workflowpattern.CompilePatterns(tagFilters...) + if err != nil { + log.Errorf("Error parsing workflow tag ignore patterns (%s), so we will not filter the workflow", err) + return false + } + return workflowpattern.Filter(tagPatterns, []string{ref}, &workflowpattern.StdOutTraceWriter{}) +} + +// return true if a workflow should be skipped because of path +func evaluatePathSkip(pathChanges []string, pathFilters []string) bool { + pathPatterns, err := workflowpattern.CompilePatterns(pathFilters...) + if err != nil { + log.Errorf("Error parsing workflow path patterns (%s), so we will not filter the workflow", err) + return false + } + return workflowpattern.Skip(pathPatterns, pathChanges, &workflowpattern.StdOutTraceWriter{}) +} + +// return true if a workflow should be skipped because of path_ignore +func evaluatePathFilter(pathChanges []string, pathFilters []string) bool { + pathPatterns, err := workflowpattern.CompilePatterns(pathFilters...) + if err != nil { + log.Errorf("Error parsing workflow path ignore patterns (%s), so we will not filter the workflow", err) + return false + } + return workflowpattern.Filter(pathPatterns, pathChanges, &workflowpattern.StdOutTraceWriter{}) +} + +// return a list of paths of changes as a result of commits in a push event +func pathChangesForPush(pushEvent *githubPushEvent) []string { + pathChanges := make([]string, 0) + for _, commit := range pushEvent.Commits { + pathChanges = append(pathChanges, commit.Added...) + pathChanges = append(pathChanges, commit.Removed...) + pathChanges = append(pathChanges, commit.Modified...) + } + return pathChanges +} + +// return true if a push event should be ignored because the push event does not match the workflow conditions +func (pushEvent *githubPushEvent) shouldFilterForPush(push *Push) bool { + // compare the event with our push object + branchSkip := evaluateBranchSkip(*pushEvent.Ref, push.Branches) + branchIgnoreFilter := evaluateBranchFilter(*pushEvent.Ref, push.BranchesIgnore) + branchFiltersDefined := len(push.Branches) > 0 || len(push.BranchesIgnore) > 0 + + tagSkip := evaluateTagSkip(*pushEvent.Ref, push.Tags) + tagIgnoreFilter := evaluateTagFilter(*pushEvent.Ref, push.TagsIgnore) + tagFiltersDefined := len(push.Tags) > 0 || len(push.TagsIgnore) > 0 + + pathChanges := pathChangesForPush(pushEvent) + + pathSkip := evaluatePathSkip(pathChanges, push.Paths) + pathIgnoreFilter := evaluatePathFilter(pathChanges, push.PathsIgnore) + pathFiltersDefined := len(push.Paths) > 0 || len(push.PathsIgnore) > 0 + + // defining both is an error, so we just accept the workflow + if len(push.Branches) > 0 && len(push.BranchesIgnore) > 0 { + log.Error("Both branch and branch_ignore filters exist which is not allowed, so we will ignore the conditions and just execute this workflow") + return false + } + + if len(push.Tags) > 0 && len(push.TagsIgnore) > 0 { + log.Error("Both tags and tags_ignore filters exist which is not allowed, so we will ignore the conditions and just execute this workflow") + return false + } + + if len(push.Paths) > 0 && len(push.PathsIgnore) > 0 { + log.Error("Both paths and paths_ignore filters exist which is not allowed, so we will ignore the conditions and just execute this workflow") + return false + } + + // we should handle a workflow purely from the perspective of one condition if neither filter types says to skip + processBranch := !(branchSkip || branchIgnoreFilter) + processTag := !(tagSkip || tagIgnoreFilter) + processPaths := !(pathSkip || pathIgnoreFilter) + + // if we have filters for both paths and branches defined then both need to match + processBranchPath := false + if branchFiltersDefined && pathFiltersDefined { + processBranchPath = processBranch && processPaths + } else if branchFiltersDefined { + processBranchPath = processBranch + } else if pathFiltersDefined { + processBranchPath = processPaths + } + + return !(processBranchPath || (tagFiltersDefined && processTag)) +} + +func (pullRequestEvent *githubPullRequestEvent) shouldFilterForPullRequest(pr *PullRequest) bool { + // compare the event with our pr object + branchSkip := evaluateBranchSkip(*pullRequestEvent.PullRequest.Base.Ref, pr.Branches) + branchIgnoreFilter := evaluateBranchFilter(*pullRequestEvent.PullRequest.Base.Ref, pr.BranchesIgnore) + + // defining both is an error, so we just accept the workflow + if len(pr.Branches) > 0 && len(pr.BranchesIgnore) > 0 { + log.Error("Both branch and branch_ignore filters exist which is not allowed, so we will ignore the conditions and just execute this workflow") + return false + } + + // we should handle a workflow purely from the perspective of one condition if neither filter types says to skip + processBranch := !(branchSkip || branchIgnoreFilter) + + return !processBranch +} + +func (w *Workflow) ShouldFilterForEvent(eventName string, eventPath string) bool { + // we know the name of the event so we can try to deserialize the event file to that type + byteArray, err := readFileByteArray(eventPath) + if err != nil { + log.Errorf("Error parsing event file %s (%s), so we will not filter the workflow", eventPath, err) + return false + } + + switch eventName { + case "push": + push := w.PushConfig() + if push == nil { + // no push config found for the workflow, so skip + log.Infof("Filtering workflow %s because its triggers don't match the event type (%s)", w.Name, eventName) + return true + } + if byteArray != nil { + pushEvent, err := byteArray.asGithubPushEvent() + if err != nil { + log.Errorf("Error parsing event (%s), so we will not filter the workflow", err) + return false + } + return pushEvent.shouldFilterForPush(push) + } + + case "pull_request_target": + fallthrough + case "pull_request": + pr := w.PullRequestConfig() + if pr == nil { + // no PR config found for the workflow, so skip + log.Infof("Filtering workflow %s because its triggers don't match the event type (%s)", w.Name, eventName) + return true + } + if byteArray != nil { + prEvent, err := byteArray.asGithubPullRequestEvent() + if err != nil { + log.Errorf("Error parsing event (%s), so we will not filter the workflow", err) + return false + } + return prEvent.shouldFilterForPullRequest(pr) + } + + default: + } + + return false +} + func (w *Workflow) UnmarshalYAML(node *yaml.Node) error { // Validate the schema before deserializing it into our model if err := (&schema.Node{ diff --git a/pkg/model/workflow_test.go b/pkg/model/workflow_test.go index 4ee37109904..d004872f73a 100644 --- a/pkg/model/workflow_test.go +++ b/pkg/model/workflow_test.go @@ -327,10 +327,10 @@ jobs: } func TestReadWorkflow_Strategy(t *testing.T) { - w, err := NewWorkflowPlanner("testdata/strategy/push.yml", true) + w, err := NewWorkflowPlanner("testdata/strategy/push.yml", true, false, "") assert.NoError(t, err) - p, err := w.PlanJob("strategy-only-max-parallel") + p, err := w.PlanJob("strategy-only-max-parallel", "") assert.NoError(t, err) assert.Equal(t, len(p.Stages), 1) @@ -517,3 +517,384 @@ func TestReadWorkflow_WorkflowDispatchConfig(t *testing.T) { Type: "choice", }, workflowDispatch.Inputs["logLevel"]) } + +func TestReadWorkflow_PushConfig(t *testing.T) { + yaml := ` + name: local-action-docker-url + ` + workflow, err := ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push := workflow.PushConfig() + assert.Nil(t, push) + + yaml = ` + name: local-action-docker-url + on: pull_request + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push = workflow.PushConfig() + assert.Nil(t, push) + + yaml = ` + name: local-action-docker-url + on: push + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push = workflow.PushConfig() + assert.NotNil(t, push) + assert.Nil(t, push.Branches) + assert.Nil(t, push.BranchesIgnore) + assert.Nil(t, push.Paths) + assert.Nil(t, push.PathsIgnore) + assert.Nil(t, push.Tags) + assert.Nil(t, push.TagsIgnore) + + yaml = ` + name: local-action-docker-url + on: [pull_request, workflow_dispatch] + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push = workflow.PushConfig() + assert.Nil(t, push) + + yaml = ` + name: local-action-docker-url + on: [push, workflow_dispatch] + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push = workflow.PushConfig() + assert.NotNil(t, push) + assert.Nil(t, push.Branches) + assert.Nil(t, push.BranchesIgnore) + assert.Nil(t, push.Paths) + assert.Nil(t, push.PathsIgnore) + assert.Nil(t, push.Tags) + assert.Nil(t, push.TagsIgnore) + + yaml = ` + name: local-action-docker-url + on: + - push + - workflow_dispatch + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push = workflow.PushConfig() + assert.NotNil(t, push) + assert.Nil(t, push.Branches) + assert.Nil(t, push.BranchesIgnore) + assert.Nil(t, push.Paths) + assert.Nil(t, push.PathsIgnore) + assert.Nil(t, push.Tags) + assert.Nil(t, push.TagsIgnore) + + yaml = ` + name: local-action-docker-url + on: + workflow_dispatch: + pull_request: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push = workflow.PushConfig() + assert.Nil(t, push) + + yaml = ` + name: local-action-docker-url + on: + push: + branches: + - foo + - bar + paths: + - p1 + - p2 + tags: + - t1 + - t2 + pull_request: + workflow_dispatch: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push = workflow.PushConfig() + assert.NotNil(t, push) + assert.Nil(t, push.BranchesIgnore) + assert.Nil(t, push.PathsIgnore) + assert.Nil(t, push.TagsIgnore) + assert.Equal(t, Push{ + Branches: []string{"foo", "bar"}, + Paths: []string{"p1", "p2"}, + Tags: []string{"t1", "t2"}, + }, *push) + + yaml = ` + name: local-action-docker-url + on: + push: + branches_ignore: + - foo + - bar + paths_ignore: + - p1 + - p2 + tags_ignore: + - t1 + - t2 + pull_request: + workflow_dispatch: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + push = workflow.PushConfig() + assert.NotNil(t, push) + assert.Nil(t, push.Branches) + assert.Nil(t, push.Paths) + assert.Nil(t, push.Tags) + assert.Equal(t, Push{ + BranchesIgnore: []string{"foo", "bar"}, + PathsIgnore: []string{"p1", "p2"}, + TagsIgnore: []string{"t1", "t2"}, + }, *push) +} + +func TestReadWorkflow_PullRequestConfig(t *testing.T) { + yaml := ` + name: local-action-docker-url + ` + workflow, err := ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr := workflow.PullRequestConfig() + assert.Nil(t, pr) + + yaml = ` + name: local-action-docker-url + on: push + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr = workflow.PullRequestConfig() + assert.Nil(t, pr) + + yaml = ` + name: local-action-docker-url + on: pull_request + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr = workflow.PullRequestConfig() + assert.NotNil(t, pr) + assert.Nil(t, pr.Branches) + assert.Nil(t, pr.BranchesIgnore) + assert.Nil(t, pr.Paths) + assert.Nil(t, pr.PathsIgnore) + + yaml = ` + name: local-action-docker-url + on: [push, workflow_dispatch] + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr = workflow.PullRequestConfig() + assert.Nil(t, pr) + + yaml = ` + name: local-action-docker-url + on: [pull_request, workflow_dispatch] + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr = workflow.PullRequestConfig() + assert.NotNil(t, pr) + assert.Nil(t, pr.Branches) + assert.Nil(t, pr.BranchesIgnore) + assert.Nil(t, pr.Paths) + assert.Nil(t, pr.PathsIgnore) + + yaml = ` + name: local-action-docker-url + on: + - pull_request + - workflow_dispatch + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr = workflow.PullRequestConfig() + assert.NotNil(t, pr) + assert.Nil(t, pr.Branches) + assert.Nil(t, pr.BranchesIgnore) + assert.Nil(t, pr.Paths) + assert.Nil(t, pr.PathsIgnore) + + yaml = ` + name: local-action-docker-url + on: + workflow_dispatch: + push: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr = workflow.PullRequestConfig() + assert.Nil(t, pr) + + yaml = ` + name: local-action-docker-url + on: + pull_request: + branches: + - foo + - bar + paths: + - p1 + - p2 + push: + workflow_dispatch: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr = workflow.PullRequestConfig() + assert.NotNil(t, pr) + assert.Nil(t, pr.BranchesIgnore) + assert.Nil(t, pr.PathsIgnore) + assert.Equal(t, PullRequest{ + Branches: []string{"foo", "bar"}, + Paths: []string{"p1", "p2"}, + }, *pr) + + yaml = ` + name: local-action-docker-url + on: + pull_request: + branches_ignore: + - foo + - bar + paths_ignore: + - p1 + - p2 + push: + workflow_dispatch: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + pr = workflow.PullRequestConfig() + assert.NotNil(t, pr) + assert.Nil(t, pr.Branches) + assert.Nil(t, pr.Paths) + assert.Equal(t, PullRequest{ + BranchesIgnore: []string{"foo", "bar"}, + PathsIgnore: []string{"p1", "p2"}, + }, *pr) +} + +func TestReadWorkflow_ScheduleConfig(t *testing.T) { + yaml := ` + name: local-action-docker-url + ` + workflow, err := ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule := workflow.ScheduleConfig() + assert.Nil(t, schedule) + + yaml = ` + name: local-action-docker-url + on: push + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule = workflow.ScheduleConfig() + assert.Nil(t, schedule) + + yaml = ` + name: local-action-docker-url + on: schedule + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule = workflow.ScheduleConfig() + assert.NotNil(t, schedule) + assert.Equal(t, 0, len(*schedule)) + + yaml = ` + name: local-action-docker-url + on: [push, workflow_dispatch] + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule = workflow.ScheduleConfig() + assert.Nil(t, schedule) + + yaml = ` + name: local-action-docker-url + on: [schedule, workflow_dispatch] + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule = workflow.ScheduleConfig() + assert.NotNil(t, schedule) + assert.Equal(t, 0, len(*schedule)) + + yaml = ` + name: local-action-docker-url + on: + - schedule + - workflow_dispatch + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule = workflow.ScheduleConfig() + assert.NotNil(t, schedule) + assert.Equal(t, 0, len(*schedule)) + + yaml = ` + name: local-action-docker-url + on: + workflow_dispatch: + push: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule = workflow.ScheduleConfig() + assert.Nil(t, schedule) + + yaml = ` + name: local-action-docker-url + on: + schedule: + - cron: '30 5,17 * * *' + - cron: '45 5,17 * * *' + push: + workflow_dispatch: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule = workflow.ScheduleConfig() + assert.NotNil(t, schedule) + assert.Equal(t, 2, len(*schedule)) + assert.Equal(t, Schedule{ + ScheduleCron{Cron: "30 5,17 * * *"}, + ScheduleCron{Cron: "45 5,17 * * *"}, + }, *schedule) + + yaml = ` + name: local-action-docker-url + on: + schedule: + - cron: '30 5,17 * * *' + - cron: '45 5,17 * * *' + push: + workflow_dispatch: + ` + workflow, err = ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + schedule = workflow.ScheduleConfig() + assert.NotNil(t, schedule) + assert.Equal(t, 2, len(*schedule)) + assert.Equal(t, Schedule{ + ScheduleCron{Cron: "30 5,17 * * *"}, + ScheduleCron{Cron: "45 5,17 * * *"}, + }, *schedule) +} diff --git a/pkg/runner/reusable_workflow.go b/pkg/runner/reusable_workflow.go index 09dfe5a3050..c03a743ce5e 100644 --- a/pkg/runner/reusable_workflow.go +++ b/pkg/runner/reusable_workflow.go @@ -61,7 +61,7 @@ func newActionCacheReusableWorkflowExecutor(rc *RunContext, filename string, rem if _, err = treader.Next(); err != nil { return err } - planner, err := model.NewSingleWorkflowPlanner(remoteReusableWorkflow.Filename, treader) + planner, err := model.NewSingleWorkflowPlanner(remoteReusableWorkflow.Filename, treader, rc.Config.ApplyEventFilters, rc.Config.EventPath) if err != nil { return err } @@ -115,7 +115,7 @@ func cloneIfRequired(rc *RunContext, remoteReusableWorkflow remoteReusableWorkfl func newReusableWorkflowExecutor(rc *RunContext, directory string, workflow string) common.Executor { return func(ctx context.Context) error { - planner, err := model.NewWorkflowPlanner(path.Join(directory, workflow), true) + planner, err := model.NewWorkflowPlanner(path.Join(directory, workflow), true, rc.Config.ApplyEventFilters, rc.Config.EventPath) if err != nil { return err } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 59b92a516c3..6fbdeb282cc 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -61,6 +61,7 @@ type Config struct { Matrix map[string]map[string]bool // Matrix config to run ContainerNetworkMode docker_container.NetworkMode // the network mode of job containers (the value of --network) ActionCache ActionCache // Use a custom ActionCache Implementation + ApplyEventFilters bool // Whether to filter workflows by event type } type caller struct { diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index a6eb46b0c1d..c7f96a97567 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -55,7 +55,7 @@ func init() { } func TestNoWorkflowsFoundByPlanner(t *testing.T) { - planner, err := model.NewWorkflowPlanner("res", true) + planner, err := model.NewWorkflowPlanner("res", true, false, "") assert.NoError(t, err) out := log.StandardLogger().Out @@ -75,7 +75,7 @@ func TestNoWorkflowsFoundByPlanner(t *testing.T) { } func TestGraphMissingEvent(t *testing.T) { - planner, err := model.NewWorkflowPlanner("testdata/issue-1595/no-event.yml", true) + planner, err := model.NewWorkflowPlanner("testdata/issue-1595/no-event.yml", true, false, "") assert.NoError(t, err) out := log.StandardLogger().Out @@ -93,7 +93,7 @@ func TestGraphMissingEvent(t *testing.T) { } func TestGraphMissingFirst(t *testing.T) { - planner, err := model.NewWorkflowPlanner("testdata/issue-1595/no-first.yml", true) + planner, err := model.NewWorkflowPlanner("testdata/issue-1595/no-first.yml", true, false, "") assert.NoError(t, err) plan, err := planner.PlanEvent("push") @@ -103,7 +103,7 @@ func TestGraphMissingFirst(t *testing.T) { } func TestGraphWithMissing(t *testing.T) { - planner, err := model.NewWorkflowPlanner("testdata/issue-1595/missing.yml", true) + planner, err := model.NewWorkflowPlanner("testdata/issue-1595/missing.yml", true, false, "") assert.NoError(t, err) out := log.StandardLogger().Out @@ -122,7 +122,7 @@ func TestGraphWithMissing(t *testing.T) { func TestGraphWithSomeMissing(t *testing.T) { log.SetLevel(log.DebugLevel) - planner, err := model.NewWorkflowPlanner("testdata/issue-1595/", true) + planner, err := model.NewWorkflowPlanner("testdata/issue-1595/", true, false, "") assert.NoError(t, err) out := log.StandardLogger().Out @@ -140,7 +140,7 @@ func TestGraphWithSomeMissing(t *testing.T) { } func TestGraphEvent(t *testing.T) { - planner, err := model.NewWorkflowPlanner("testdata/basic", true) + planner, err := model.NewWorkflowPlanner("testdata/basic", true, false, "") assert.NoError(t, err) plan, err := planner.PlanEvent("push") @@ -198,7 +198,7 @@ func (j *TestJobFileInfo) runTest(ctx context.Context, t *testing.T, cfg *Config runner, err := New(runnerConfig) assert.Nil(t, err, j.workflowPath) - planner, err := model.NewWorkflowPlanner(fullWorkflowPath, true) + planner, err := model.NewWorkflowPlanner(fullWorkflowPath, true, false, "") if j.errorMessage != "" && err != nil { assert.Error(t, err, j.errorMessage) } else if assert.Nil(t, err, fullWorkflowPath) {