github.com/traefik/lobicornis@v1.3.0/gh/state.go (about)

     1  package gh
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"log"
     8  
     9  	"github.com/google/go-github/github"
    10  )
    11  
    12  const (
    13  	// Pending Check state
    14  	Pending = "pending"
    15  	// Success Check state
    16  	Success = "success"
    17  
    18  	// Approved Review state
    19  	Approved = "APPROVED"
    20  	// Commented Review state
    21  	Commented = "COMMENTED"
    22  	// Dismissed Review state
    23  	Dismissed = "DISMISSED"
    24  )
    25  
    26  // HasReviewsApprove check if a PR have the required number of review
    27  func (g *GHub) HasReviewsApprove(ctx context.Context, pr *github.PullRequest, minReview int) error {
    28  	if minReview != 0 {
    29  
    30  		owner := pr.Base.Repo.Owner.GetLogin()
    31  		repositoryName := pr.Base.Repo.GetName()
    32  		prNumber := pr.GetNumber()
    33  
    34  		opt := &github.ListOptions{
    35  			PerPage: 100,
    36  		}
    37  
    38  		reviewsState := make(map[string]string)
    39  		for {
    40  			reviews, resp, err := g.client.PullRequests.ListReviews(ctx, owner, repositoryName, prNumber, opt)
    41  			if err != nil {
    42  				return err
    43  			}
    44  
    45  			for _, review := range reviews {
    46  				if review.GetState() == Dismissed {
    47  					delete(reviewsState, review.User.GetLogin())
    48  				} else if review.GetState() != Commented {
    49  					reviewsState[review.User.GetLogin()] = review.GetState()
    50  				}
    51  			}
    52  			if resp.NextPage == 0 {
    53  				break
    54  			}
    55  			opt.Page = resp.NextPage
    56  		}
    57  
    58  		if len(reviewsState) < minReview {
    59  			return fmt.Errorf("need more review [%v/2]", len(reviewsState))
    60  		}
    61  
    62  		for login, state := range reviewsState {
    63  			if state != Approved {
    64  				return fmt.Errorf("%s by %s", state, login)
    65  			}
    66  		}
    67  	}
    68  	return nil
    69  }
    70  
    71  // IsUpToDateBranch check if a PR is up to date
    72  func (g *GHub) IsUpToDateBranch(ctx context.Context, pr *github.PullRequest) (bool, error) {
    73  	cc, _, err := g.client.Repositories.CompareCommits(ctx,
    74  		pr.Base.Repo.Owner.GetLogin(), pr.Base.Repo.GetName(),
    75  		pr.Base.GetRef(), fmt.Sprintf("%s:%s", pr.Head.User.GetLogin(), pr.Head.GetRef()))
    76  	if err != nil {
    77  		return false, err
    78  	}
    79  
    80  	if g.debug {
    81  		log.Println("Merge Base Commit:", cc.MergeBaseCommit.GetSHA())
    82  		log.Println("Behind By:", cc.GetBehindBy())
    83  	}
    84  
    85  	return cc.GetBehindBy() == 0, nil
    86  }
    87  
    88  // GetStatus provide checks status (CI)
    89  func (g *GHub) GetStatus(ctx context.Context, pr *github.PullRequest) (string, error) {
    90  
    91  	owner := pr.Base.Repo.Owner.GetLogin()
    92  	repositoryName := pr.Base.Repo.GetName()
    93  	prRef := pr.Head.GetSHA()
    94  
    95  	sts, _, err := g.client.Repositories.GetCombinedStatus(ctx, owner, repositoryName, prRef, nil)
    96  	if err != nil {
    97  		return "", err
    98  	}
    99  
   100  	if sts.GetState() == Success {
   101  		return sts.GetState(), nil
   102  	}
   103  
   104  	// pending: if there are no statuses or a context is pending
   105  	// https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
   106  	if sts.GetState() == Pending {
   107  		if sts.GetTotalCount() == 0 {
   108  			return Success, nil
   109  		}
   110  		return sts.GetState(), nil
   111  	}
   112  
   113  	statuses, _, err := g.client.Repositories.ListStatuses(ctx, owner, repositoryName, prRef, nil)
   114  	if err != nil {
   115  		return "", err
   116  	}
   117  	var summary string
   118  	for _, stat := range statuses {
   119  		if stat.GetState() != Success {
   120  			summary += stat.GetDescription() + "\n"
   121  		}
   122  	}
   123  	return "", errors.New(summary)
   124  }