diff --git a/frontend.go b/frontend.go index 5c694af..2d77045 100644 --- a/frontend.go +++ b/frontend.go @@ -112,6 +112,19 @@ func resultPage(w http.ResponseWriter, r *http.Request) { Secret: secret, } + // set the repo to opt-in + if strings.ToUpper(r.URL.Query().Get("optin")) == "ON" { + repo.OptIn = true + } + // define custom opt-in flag + if r.URL.Query().Get("optinFlag") != "" { + repo.OptInFlag = r.URL.Query().Get("optinFlag") + } + // define custom opt-out flag + if r.URL.Query().Get("optoutFlag") != "" { + repo.OptOutFlag = r.URL.Query().Get("optoutFlag") + } + name := "web" hook := github.Hook{ Name: &name, Events: []string{"pull_request"}, diff --git a/repo.go b/repo.go index c7c2f85..911e73f 100644 --- a/repo.go +++ b/repo.go @@ -27,6 +27,9 @@ type Repo struct { Slug string Token string Secret string + OptIn bool + OptInFlag string `gorm:"default:'ci'"` + OptOutFlag string `gorm:"default:'ci skip'"` } type Repos []Repo diff --git a/templates/auth.html b/templates/auth.html index ba62653..27daf07 100644 --- a/templates/auth.html +++ b/templates/auth.html @@ -15,6 +15,29 @@ Your project slug is the Github user- and repository name separated by a slash e.g. ganggo/federation +
+ + + + That would mean that tests are triggered if you specify [ci] in the PR title, body, commit-message + or if the PR was tagged with ci. If you leave the box unchecked + tests will be triggered on every pull-request. However you can skip them by using [ci skip] + in the mentioned fields or tag it with ci skip. + +
+ + + + If you want to use custom build triggers for opt-in you can specify it here. + +
+
+ + + If you want to use custom build triggers for opt-out you can specify it here. + +
+
diff --git a/webhook.go b/webhook.go index a9bec60..31373f1 100644 --- a/webhook.go +++ b/webhook.go @@ -25,6 +25,8 @@ import ( "encoding/json" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/sqlite" + "strings" + "context" ) func webhook(w http.ResponseWriter, r *http.Request) { @@ -54,16 +56,18 @@ func webhook(w http.ResponseWriter, r *http.Request) { } // skip all events except for open PRs - if *pr.State != "open" { + if pr.GetState() != "open" { logger.Println("Ignore closed pull request") fmt.Fprintf(w, `{}`) return } var repo Repo - err = db.Where("slug = ?", *pr.Base.Repo.FullName).Find(&repo).Error + err = db.Where("slug = ?", + pr.GetBase().GetRepo().GetFullName(), + ).Find(&repo).Error if err != nil { - logger.Println(err, *pr.Base.Repo.FullName) + logger.Println(err, pr.GetBase().GetRepo().GetFullName()) fmt.Fprintf(w, `{"error":"repo not registered"}`) return } @@ -76,24 +80,86 @@ func webhook(w http.ResponseWriter, r *http.Request) { // return //} + var flagExists = false + var buildFlag = repo.OptOutFlag + if repo.OptIn { + buildFlag = repo.OptInFlag + } + + // check PR title and body for [ci] or [ci skip] flag + if pr.Title != nil && strings.Contains(pr.GetTitle(), + fmt.Sprintf("[%s]", buildFlag)) { + flagExists = true + } else if pr.Body != nil && strings.Contains(pr.GetBody(), + fmt.Sprintf("[%s]", buildFlag)) { + flagExists = true + } else { + // check labels for build flag if we haven't already found it + for _, label := range pr.Labels { + if label.Name != nil && strings.Contains(label.GetName(), buildFlag) { + flagExists = true + break + } + } + + if !flagExists { + // last but not least check the commit message for flags + client := github.NewClient(nil) + commits, _, err := client.PullRequests.ListCommits( + context.Background(), + pr.GetHead().GetUser().GetLogin(), + pr.GetHead().GetRepo().GetName(), + pr.GetNumber(), &github.ListOptions{}) + + if err == nil && len(commits) > 0 { + // check only last commit since older ones are irrelevant + commitMsg := commits[len(commits)-1].GetCommit().GetMessage() + flagExists = strings.Contains( + commitMsg, fmt.Sprintf("[%s]", buildFlag)) + } else { + logger.Printf("Commits is empty or an error occurred: %+v\n", err) + } + } + } + + // ignoring pull-request! Repository is set + // to opt-in and no build flag was found + if repo.OptIn && !flagExists { + logger.Printf( + "Ignore optin=%t buildFlag=%s flagExists=%t\n", + repo.OptIn, buildFlag, flagExists) + fmt.Fprintf(w, `{}`) + return + } + + // ignoring pull-request! Repository is set + // to opt-out and a skip flag was found + if !repo.OptIn && flagExists { + logger.Printf( + "Ignore optin=%t buildFlag=%s flagExists=%t\n", + repo.OptIn, buildFlag, flagExists) + fmt.Fprintf(w, `{}`) + return + } + build := Build{ RepoID: repo.ID, Matrix: fmt.Sprintf( `"PROJECT=%s PRREPO=%s PRSHA=%s"`, repo.Project, - *pr.Head.Repo.CloneURL, - *pr.Head.SHA, + pr.GetHead().GetRepo().GetCloneURL(), + pr.GetHead().GetSHA(), ), - PRUser: *pr.Head.User.Login, - PRRepo: *pr.Head.Repo.Name, - PRSha: *pr.Head.SHA, + PRUser: pr.GetHead().GetUser().GetLogin(), + PRRepo: pr.GetHead().GetRepo().GetName(), + PRSha: pr.GetHead().GetSHA(), } + err = db.Create(&build).Error if err != nil { logger.Println(err) fmt.Fprintf(w, `{"error":"database error"}`) return } - fmt.Fprintf(w, `{}`) }