Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement opt-in/out for pull requests #8

Merged
merged 5 commits into from
Mar 18, 2018
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
13 changes: 13 additions & 0 deletions frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand Down
3 changes: 3 additions & 0 deletions repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
23 changes: 23 additions & 0 deletions templates/auth.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,29 @@
<input type="text" class="form-control" id="repoInput" name="repo" aria-describedby="repoHelp" placeholder="Enter your project slug">
<small id="repoHelp" class="form-text text-muted">Your project slug is the Github user- and repository name separated by a slash e.g. ganggo/federation</small>
</div>
<div class="form-check mb-3">
<input type="checkbox" class="form-check-input" id="optinInput" name="optin" describedby="optinHelp">
<label class="form-check-label" for="optinInput">Check if you want to opt-in on a new test</label>
<small id="optinHelp" class="form-text text-muted">
That would mean that tests are triggered if you specify <code>[ci]</code> in the PR title, body, commit-message
or if the PR was tagged with <span class="badge badge-primary">ci</span>. If you leave the box unchecked
tests will be triggered on every pull-request. However you can skip them by using <code>[ci skip]</code>
in the mentioned fields or tag it with <span class="badge badge-primary">ci skip</span>.
</small>
<div class="form-group">
<label for="optinFlagInput">(optional) Custom Flags</label>
<input type="text" class="form-control" id="optinFlagInput" name="optinFlag" aria-describedby="optinFlagHelp" placeholder="default is 'ci'">
<small id="optinFlagHelp" class="form-text text-muted">
If you want to use custom build triggers for opt-in you can specify it here.
</small>
</div>
<div class="form-group">
<input type="text" class="form-control" name="optoutFlag" aria-describedby="optoutFlagHelp" placeholder="default is 'ci skip'">
<small id="optoutFlagHelp" class="form-text text-muted">
If you want to use custom build triggers for opt-out you can specify it here.
</small>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
Expand Down
84 changes: 75 additions & 9 deletions webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
}
Expand All @@ -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, `{}`)
}