Skip to content

Commit

Permalink
implement stronger pull request review decision check
Browse files Browse the repository at this point in the history
  • Loading branch information
corymurphy committed Oct 25, 2024
1 parent 35d9f22 commit 90c80c6
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 57 deletions.
4 changes: 2 additions & 2 deletions charts/argobot/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ apiVersion: v2
name: argobot
description: Helm chart for the corymurphy/argobot app
type: application
version: 0.17.0
appVersion: 0.17.0
version: 0.18.0
appVersion: 0.18.0
17 changes: 17 additions & 0 deletions pkg/github/pull_request_review_decision.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package github

// {"data":{"repository":{"pullRequest":{"reviewDecision":"APPROVED"}}}}

type PullRequestReviewDecision struct {
Data struct {
Repository struct {
PullRequest struct {
ReviewDecision string `json:"reviewDecision"`
} `json:"pullRequest"`
} `json:"repository"`
} `json:"data"`
}

func (p *PullRequestReviewDecision) Approved() bool {
return p.Data.Repository.PullRequest.ReviewDecision == "APPROVED"
}
61 changes: 7 additions & 54 deletions pkg/github/pull_status_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,69 +78,22 @@ func (g *GithubPullRequestStatusFetcher) PullIsApproved(ctx context.Context, eve
return approvalStatus, nil
}

// TODO: complete the bypass functionality from atlantis
// TODO: check if approved by codeowner
func (g *GithubPullRequestStatusFetcher) PullIsMergeable(ctx context.Context, event Event, vcsstatusname string) (bool, error) {
g.logger.Debug("Checking if GitHub pull request %d is mergeable", event.PullRequest.Number)
githubPR, _, err := g.client.PullRequests.Get(ctx, event.Repository.Owner, event.Repository.Name, event.PullRequest.Number)
if err != nil {
return false, errors.Wrap(err, "getting pull request")
}

vscClient := NewClient(g.client, g.logger)

state := githubPR.GetMergeableState()
if state != "clean" && state != "unstable" && state != "has_hooks" {
//mergeable bypass apply code hidden by feature flag
// if g.config.AllowMergeableBypassApply {
// logger.Debug("AllowMergeableBypassApply feature flag is enabled - attempting to bypass apply from mergeable requirements")
// if state == "blocked" {
// //check status excluding atlantis apply
// status, err := g.GetCombinedStatusMinusApply(logger, repo, githubPR, vcsstatusname)
// if err != nil {
// return false, errors.Wrap(err, "getting pull request status")
// }

// //check to see if pr is approved using reviewDecision
// approved, err := g.GetPullReviewDecision(pull)
// if err != nil {
// return false, errors.Wrap(err, "getting pull request reviewDecision")
// }

// //if all other status checks EXCEPT atlantis/apply are successful, and the PR is approved based on reviewDecision, let it proceed
// if status && approved {
// return true, nil
// }
// }
// }

return false, nil
approved, err := vscClient.GetPullReviewDecision(event)
if err != nil {
return false, errors.Wrap(err, "getting pull request reviewDecision")
}
return approved, nil
}
return true, nil
}

// func (g *GithubPullRequestStatusFetcher) GetPullReviewDecision(pull models.PullRequest) (approvalStatus bool, err error) {
// var query struct {
// Repository struct {
// PullRequest struct {
// ReviewDecision string
// } `graphql:"pullRequest(number: $number)"`
// } `graphql:"repository(owner: $owner, name: $name)"`
// }

// variables := map[string]interface{}{
// "owner": githubv4.String(pull.Owner),
// "name": githubv4.String(pull.Name),
// "number": githubv4.Int(pull.Number),
// }

// // g.client.BaseURL.Query()
// err = g.v4Client.Query(g.ctx, &query, variables)
// if err != nil {
// return approvalStatus, errors.Wrap(err, "getting reviewDecision")
// }

// if query.Repository.PullRequest.ReviewDecision == "APPROVED" || len(query.Repository.PullRequest.ReviewDecision) == 0 {
// return true, nil
// }

// return false, nil
// }
60 changes: 60 additions & 0 deletions pkg/github/vsc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ package github

import (
"context"
"encoding/json"
"fmt"

"io"

"github.com/corymurphy/argobot/pkg/logging"
"github.com/google/go-github/v53/github"
"github.com/pkg/errors"
)

type VscClient struct {
Expand All @@ -19,6 +24,61 @@ func NewClient(client *github.Client, logger logging.SimpleLogging) *VscClient {
}
}

type reviewDecisionRequest struct {
Query string `json:"query"`
Variables string `json:"variables"`
}

func (v *VscClient) GetPullReviewDecision(event Event) (approvalStatus bool, err error) {

query := `
query($owner: String!, $name: String!, $number: Int!) {
repository(owner: $owner, name: $name) {
pullRequest(number: $number) {
reviewDecision
}
}
}
`
variables := fmt.Sprintf(`
{
"owner": "%s",
"name": "%s",
"number": %d
}
`, event.Repository.Owner, event.Repository.Name, event.PullRequest.Number)

body := reviewDecisionRequest{
Query: query,
Variables: variables,
}

request, err := v.client.NewRequest("POST", "/graphql", body)

if err != nil {
return false, errors.Wrap(err, "unable to create http request")
}

response, err := v.client.Client().Do(request)
if err != nil {
return false, errors.Wrap(err, "failed while calling the graphql api")
}
defer response.Body.Close()
dataSerialized, err := io.ReadAll(io.Reader(response.Body))
if err != nil {
return false, errors.Wrap(err, "unable to read response")
}
v.logger.Info(string(dataSerialized))

var decision PullRequestReviewDecision
err = json.Unmarshal(dataSerialized, &decision)
if err != nil {
return false, errors.Wrap(err, "unable to deserialize response")
}
return decision.Approved(), nil
}

func (v *VscClient) SetStatusCheck(ctx context.Context, event Event, state CommitState, context string, description string, url string) error {

status := &github.RepoStatus{
Expand Down
2 changes: 1 addition & 1 deletion version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.17.0
0.18.0

0 comments on commit 90c80c6

Please sign in to comment.