From d30c7fec0068d1eefac4e4277dd183a6f60b42fe Mon Sep 17 00:00:00 2001 From: Alexandre Perrin Date: Mon, 28 Aug 2023 09:27:32 +0200 Subject: [PATCH 1/5] regular expression support for require-msgs-in-commit Signed-off-by: Alexandre Perrin --- README.md | 2 ++ pkg/github/commits.go | 48 +++++++++++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d1bc6bd..42de6e8 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ move-to-projects-for-labels-xored: column: "Backport done to v1.5" # Require msg to be presented in all commits from the given PR require-msgs-in-commit: + # the expected string to be found in the commit. Alternatively you can + # match the commit against a regular expression with regexpMsg instead. - msg: "Signed-off-by" # Helper message that will be set as a comment if the PR does not contain # a the required msg in the commit message. diff --git a/pkg/github/commits.go b/pkg/github/commits.go index a83aeb3..84ed04c 100644 --- a/pkg/github/commits.go +++ b/pkg/github/commits.go @@ -16,7 +16,9 @@ package github import ( "context" + "errors" "fmt" + "regexp" "strings" "time" @@ -24,20 +26,36 @@ import ( ) type MsgInCommit struct { - // Msg is the message that should be found in the commit message. + // Msg is the message that should be found in the commit message. Mutually + // exclusive with RegexpMsg. Msg string `yaml:"msg,omitempty"` - // Helper is the message that should be printed if 'Msg' is not found in - // the commit message. + // RegexpMsg is a regular expression to match the commit message. Mutually + // exclusive with Msg. + RegexpMsg string `yaml:"regexpMsg,omitempty"` + // Helper is the message that should be printed if the commit message + // doesn't contains 'Msg' or doesn't match 'RegexpMsg'. Helper string `yaml:"helper,omitempty"` - // SetLabels are the labels to be set in the PR for which Msg was not found. + // SetLabels are the labels to be set in the PR if the commit message + // doesn't contains 'Msg' or doesn't match 'RegexpMsg'. SetLabels []string `yaml:"set-labels,omitempty"` } -// commitsContains checks if the all commits of the given prNumber contains the -// given msg. -// Returns a slice of commit IDs that don't contain the given msg or an error -// in case of an error. -func (c *Client) commitContains(owner, repoName string, prNumber int, msg string) ([]string, error) { +// Regexp returns a regular expression to be matched either based on Msg or +// RegexpMsg. +func (m MsgInCommit) Regexp() (*regexp.Regexp, error) { + switch { + case len(m.Msg) > 0: + return regexp.Compile(regexp.QuoteMeta(m.Msg)) + case len(m.RegexpMsg) > 0: + return regexp.Compile(m.RegexpMsg) + } + return nil, errors.New("no msg or regexpMsg configured") +} + +// commitMatches checks if the all commits of the given prNumber matches the +// given regexp. +// Returns a slice of commit IDs that don't match the given regexp or an error. +func (c *Client) commitMatches(owner, repoName string, prNumber int, re *regexp.Regexp) ([]string, error) { var ( missSignOff []string cancels []context.CancelFunc @@ -60,7 +78,7 @@ func (c *Client) commitContains(owner, repoName string, prNumber int, msg string return nil, err } for _, commit := range commits { - if !strings.Contains(commit.GetCommit().GetMessage(), msg) { + if !re.MatchString(commit.GetCommit().GetMessage()) { missSignOff = append(missSignOff, commit.GetSHA()) } } @@ -82,7 +100,11 @@ func (c *Client) CommitContains(msgsInCommit []MsgInCommit, owner, repoName stri } }() for _, msgRequired := range msgsInCommit { - commits, err := c.commitContains(owner, repoName, prNumber, msgRequired.Msg) + re, err := msgRequired.Regexp() + if err != nil { + return err + } + commits, err := c.commitMatches(owner, repoName, prNumber, re) if err != nil { return err } @@ -99,9 +121,9 @@ func (c *Client) CommitContains(msgsInCommit []MsgInCommit, owner, repoName stri } var comment string if len(commits) == 1 { - comment = fmt.Sprintf("Commit %%s does not contain %q.", msgRequired.Msg) + comment = fmt.Sprintf("Commit %%s does not match %q.", re) } else { - comment = fmt.Sprintf("Commits %%s do not contain %q.", msgRequired.Msg) + comment = fmt.Sprintf("Commits %%s do not match %q.", re) } if msgRequired.Helper != "" { comment += fmt.Sprintf("\n\nPlease follow instructions provided in %s", msgRequired.Helper) From e2e7cc893a1b36ac6e40b3a5cb3cb631fba6d90c Mon Sep 17 00:00:00 2001 From: Alexandre Perrin Date: Mon, 28 Aug 2023 09:35:44 +0200 Subject: [PATCH 2/5] cmd: use main as default branch See https://github.com/cilium/cilium/issues/23110 Signed-off-by: Alexandre Perrin --- cmd/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/client.go b/cmd/client.go index e720be8..5d65d85 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -43,7 +43,7 @@ func init() { flag.StringVar(&orgName, "org", "cilium", "GitHub organization name (for client-mode)") flag.StringVar(&repoName, "repo", "cilium", "GitHub organization name (for client-mode)") flag.IntVar(&prNumber, "pr", 0, "PR to check for flakes (for client-mode)") - flag.StringVar(&baseBranch, "branch", "master", "Base branch name (for client-mode)") + flag.StringVar(&baseBranch, "branch", "main", "Base branch name (for client-mode)") flag.StringVar(&config, "config", "", "Flake config file (for client-mode)") flag.BoolVar(&clientMode, "client-mode", false, "Runs MLH in client mode (useful for development)") flag.Parse() From 5d5304445be59fcce13480cf7368a697961ef788 Mon Sep 17 00:00:00 2001 From: Alexandre Perrin Date: Mon, 28 Aug 2023 10:05:23 +0200 Subject: [PATCH 3/5] cmd/client: load the full config Signed-off-by: Alexandre Perrin --- cmd/client.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/cmd/client.go b/cmd/client.go index 5d65d85..b2db209 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -63,16 +63,16 @@ var ( ) func runClient() { - flakeCfg, err := loadConfig(config) + cfg, err := loadConfig(config) if err != nil { panic(err) } - triggerRegexp := regexp.MustCompile(flakeCfg.JenkinsConfig.RegexTrigger) + triggerRegexp := regexp.MustCompile(cfg.FlakeTracker.JenkinsConfig.RegexTrigger) useCache := false - if len(flakeCfg.JenkinsConfig.StableJobNames) != len(flakeCfg.JenkinsConfig.PRJobNames) { + if len(cfg.FlakeTracker.JenkinsConfig.StableJobNames) != len(cfg.FlakeTracker.JenkinsConfig.PRJobNames) { panic(fmt.Sprintf("%s jobs and PR jobs should have the same length", baseBranch)) } var ( @@ -129,7 +129,7 @@ func runClient() { // GH Issues fmt.Printf("Getting Issues from GH\n") - issueKnownFlakes, err = ghClient.GetFlakeIssues(globalCtx, orgName, repoName, github.IssueCreator, flakeCfg.IssueTracker.IssueLabels) + issueKnownFlakes, err = ghClient.GetFlakeIssues(globalCtx, orgName, repoName, github.IssueCreator, cfg.FlakeTracker.IssueTracker.IssueLabels) if err != nil { panic(err) } @@ -144,7 +144,7 @@ func runClient() { jobNameToJenkinsFails = map[string]jenkins.JenkinsFailures{} } - jc, err := jenkins.NewJenkinsClient(globalCtx, flakeCfg.JenkinsConfig.JenkinsURL, false) + jc, err := jenkins.NewJenkinsClient(globalCtx, cfg.FlakeTracker.JenkinsConfig.JenkinsURL, false) if err != nil { panic(err) } @@ -156,24 +156,27 @@ func runClient() { default: } - err := ghClient.TriagePRFailures(globalCtx, jc, flakeCfg, prNumber, urlFails, issueKnownFlakes, jobNameToJenkinsFails, triggerRegexp) + err := ghClient.TriagePRFailures(globalCtx, jc, cfg.FlakeTracker, prNumber, urlFails, issueKnownFlakes, jobNameToJenkinsFails, triggerRegexp) if err != nil { panic(err) } } } -func loadConfig(cfgFile string) (*github.FlakeConfig, error) { +func loadConfig(cfgFile string) (*github.PRBlockerConfig, error) { b, err := ioutil.ReadFile(cfgFile) if err != nil { return nil, err } - var cfg github.FlakeConfig + var cfg github.PRBlockerConfig err = yaml.Unmarshal(b, &cfg) if err != nil { return nil, err } + if cfg.FlakeTracker == nil { + cfg.FlakeTracker = &github.FlakeConfig{} + } return &cfg, nil } From 45d31d370c3a48e13e0448851342857fe57f4440 Mon Sep 17 00:00:00 2001 From: Alexandre Perrin Date: Mon, 28 Aug 2023 10:15:29 +0200 Subject: [PATCH 4/5] cmd/client: check for require-msgs-in-commit Signed-off-by: Alexandre Perrin --- cmd/client.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/client.go b/cmd/client.go index b2db209..39282ce 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -101,6 +101,11 @@ func runClient() { ghClient = github.NewClient(os.Getenv("GITHUB_TOKEN"), orgName, repoName, zerolog.Ctx(globalCtx)) if prNumber != 0 { + err := ghClient.CommitContains(cfg.RequireMsgsInCommit, orgName, repoName, prNumber) + if err != nil { + panic(err) + } + ctx := context.WithValue(globalCtx, "include-draft", true) prJenkinsURLFail, err := ghClient.GetPRFailures(ctx, prNumber) if err != nil { From 5b5ec66a93b1bc9e2b0e63a1cea4b4dd1553a7e8 Mon Sep 17 00:00:00 2001 From: Alexandre Perrin Date: Mon, 28 Aug 2023 10:23:06 +0200 Subject: [PATCH 5/5] make: fix clean target Before this patch when running `make clean` we get: make: *** No rule to make target 'rm', needed by 'clean'. Stop. Signed-off-by: Alexandre Perrin --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1709669..a615875 100644 --- a/Makefile +++ b/Makefile @@ -14,4 +14,5 @@ github-actions: local: github-actions strip github-actions -clean: rm -fr github-actions +clean: + rm -fr github-actions