Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ github-actions:
local: github-actions
strip github-actions

clean: rm -fr github-actions
clean:
rm -fr github-actions
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
26 changes: 17 additions & 9 deletions cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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 (
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -129,7 +134,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)
}
Expand All @@ -144,7 +149,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)
}
Expand All @@ -156,24 +161,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
Comment on lines -172 to +177
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aanm is this breaking the current client mode workflow? I guess the FlakeConfig has now to be under flake-tracker:, is that a problem?

Copy link
Copy Markdown
Member

@aanm aanm Aug 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine, client mode is meant for development purposes anyway.

err = yaml.Unmarshal(b, &cfg)
if err != nil {
return nil, err
}
if cfg.FlakeTracker == nil {
cfg.FlakeTracker = &github.FlakeConfig{}
}

return &cfg, nil
}
48 changes: 35 additions & 13 deletions pkg/github/commits.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,46 @@ package github

import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"time"

gh "github.com/google/go-github/v50/github"
)

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