contrib/git-changes-action/detector/git/ref.go
package git
import (
"context"
"encoding/json"
"fmt"
"github.com/avast/retry-go"
"github.com/google/go-github/v41/github"
"github.com/synapsecns/sanguine/contrib/git-changes-action/detector/actionscore"
"github.com/synapsecns/sanguine/contrib/git-changes-action/detector/tree"
"golang.org/x/exp/slices"
"golang.org/x/oauth2"
"os"
"strings"
"time"
)
// GetChangeTree returns the ref for the given event name.
// it is based on https://github.com/dorny/paths-filter/blob/4067d885736b84de7c414f582ac45897079b0a78/src/main.ts#L36
func GetChangeTree(ctx context.Context, repoPath, ref, token, base string) (tree.Tree, error) {
ghContext := actionscore.NewContext()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token})
tc := oauth2.NewClient(ctx, ts)
client := github.NewClient(tc)
isPrEvent := slices.ContainsFunc([]EventType{EventPullRequest, EventPullRequestReview, EventPullRequestReviewComment, EventPullRequestTarget}, func(eventType EventType) bool {
return strings.EqualFold(ghContext.EventName, eventType.String())
})
if isPrEvent {
return getChangedFilesFromAPI(ctx, ghContext, client)
}
ct, err := getChangeTreeFromGit(repoPath, ghContext, ref, base)
if err != nil {
return nil, fmt.Errorf("could not get change tree: %w", err)
}
return ct, nil
}
// nolint: cyclop
func getChangedFilesFromAPI(ctx context.Context, ghContext *actionscore.Context, client *github.Client) (ct tree.Tree, err error) {
var gpe github.PullRequestEvent
// TODO: should rap into context
f, err := os.Open(os.Getenv("GITHUB_EVENT_PATH"))
if err != nil {
return nil, fmt.Errorf("could not open event path: %w", err)
}
defer func() {
_ = f.Close()
}()
if err := json.NewDecoder(f).Decode(&gpe); err != nil {
return nil, fmt.Errorf("could not decode event: %w", err)
}
repoOwner, repoName := ghContext.Repo()
prNumber := gpe.GetPullRequest().GetNumber()
ct = tree.NewTree()
page := 1
const retryCount = 10
const perPage = 100
for {
var files []*github.CommitFile
var res *github.Response
err = retry.Do(func() error {
reqCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
files, res, err = client.PullRequests.ListFiles(reqCtx, repoOwner, repoName, prNumber, &github.ListOptions{
Page: page,
PerPage: perPage,
})
if err != nil {
return fmt.Errorf("could not get files for repoOwner %s, repoName %s, prNumber %d, page number %d with page size %d: %w",
repoOwner, repoName, prNumber, page, perPage, err)
}
return nil
}, retry.Context(ctx), retry.Attempts(retryCount))
if err != nil {
return nil, fmt.Errorf("could not get files after %d retries: %w", retryCount, err)
}
for _, file := range files {
if file.Filename != nil {
ct.Add(file.GetFilename())
}
if file.PreviousFilename != nil {
ct.Add(file.GetPreviousFilename())
}
}
if res.NextPage == 0 {
break
}
page = res.NextPage
}
return ct, nil
}
// EventType is the type of github api event.
//
//go:generate go run golang.org/x/tools/cmd/stringer -type=EventType -linecomment
type EventType uint8
const (
// EventPullRequest is a pull request event.
EventPullRequest EventType = iota // pull_request
// EventPush is a push event.
EventPush // push
// EventRelease is a release event.
EventRelease // release
// EventTag is a tag event.
EventTag // tag
// EventPullRequestReview is a pull request review event.
EventPullRequestReview // pull_request_review
// EventPullRequestReviewComment is a pull request review comment event.
EventPullRequestReviewComment // pull_request_review_comment
// EventPullRequestTarget is a pull request target event.
EventPullRequestTarget // pull_request_target
// EventIssueComment is an issue comment event.
EventIssueComment // issue_comment
// EventIssues is an issues event.
EventIssues // issues
// EventCreate is a create event.
EventCreate // create
// EventDelete is a delete event.
EventDelete // delete
// EventDeployment is a deployment event.
EventDeployment // deployment
)