mirror of
https://github.com/ossf/scorecard.git
synced 2024-11-04 03:52:31 +03:00
Add support for commit-based lookup to GitHub APIs (#1612)
Co-authored-by: Azeem Shaikh <azeems@google.com>
This commit is contained in:
parent
68bf172e59
commit
eac2aecce6
@ -52,6 +52,7 @@ type Client struct {
|
|||||||
|
|
||||||
// InitRepo sets up the GitHub repo in local storage for improving performance and GitHub token usage efficiency.
|
// InitRepo sets up the GitHub repo in local storage for improving performance and GitHub token usage efficiency.
|
||||||
func (client *Client) InitRepo(inputRepo clients.Repo) error {
|
func (client *Client) InitRepo(inputRepo clients.Repo) error {
|
||||||
|
commitSHA := "HEAD"
|
||||||
ghRepo, ok := inputRepo.(*repoURL)
|
ghRepo, ok := inputRepo.(*repoURL)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("%w: %v", errInputRepoType, inputRepo)
|
return fmt.Errorf("%w: %v", errInputRepoType, inputRepo)
|
||||||
@ -67,12 +68,13 @@ func (client *Client) InitRepo(inputRepo clients.Repo) error {
|
|||||||
client.repoName = repo.GetName()
|
client.repoName = repo.GetName()
|
||||||
|
|
||||||
// Init tarballHandler.
|
// Init tarballHandler.
|
||||||
if err := client.tarball.init(client.ctx, client.repo); err != nil {
|
if err := client.tarball.init(client.ctx, client.repo, commitSHA); err != nil {
|
||||||
return fmt.Errorf("error during tarballHandler.init: %w", err)
|
return fmt.Errorf("error during tarballHandler.init: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup GraphQL.
|
// Setup GraphQL.
|
||||||
client.graphClient.init(client.ctx, client.owner, client.repoName)
|
client.graphClient.init(client.ctx, client.owner, client.repoName,
|
||||||
|
client.repo.GetDefaultBranch(), commitSHA)
|
||||||
|
|
||||||
// Setup contributorsHandler.
|
// Setup contributorsHandler.
|
||||||
client.contributors.init(client.ctx, client.owner, client.repoName)
|
client.contributors.init(client.ctx, client.owner, client.repoName)
|
||||||
|
@ -17,6 +17,7 @@ package githubrepo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -38,65 +39,63 @@ const (
|
|||||||
// nolint: govet
|
// nolint: govet
|
||||||
type graphqlData struct {
|
type graphqlData struct {
|
||||||
Repository struct {
|
Repository struct {
|
||||||
IsArchived githubv4.Boolean
|
IsArchived githubv4.Boolean
|
||||||
DefaultBranchRef struct {
|
Object struct {
|
||||||
Target struct {
|
Commit struct {
|
||||||
Commit struct {
|
History struct {
|
||||||
History struct {
|
Nodes []struct {
|
||||||
Nodes []struct {
|
CommittedDate githubv4.DateTime
|
||||||
CommittedDate githubv4.DateTime
|
Message githubv4.String
|
||||||
Message githubv4.String
|
Oid githubv4.GitObjectID
|
||||||
Oid githubv4.GitObjectID
|
Author struct {
|
||||||
Author struct {
|
User struct {
|
||||||
User struct {
|
Login githubv4.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Committer struct {
|
||||||
|
Name *string
|
||||||
|
User struct {
|
||||||
|
Login *string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssociatedPullRequests struct {
|
||||||
|
Nodes []struct {
|
||||||
|
Repository struct {
|
||||||
|
Name githubv4.String
|
||||||
|
Owner struct {
|
||||||
|
Login githubv4.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Author struct {
|
||||||
Login githubv4.String
|
Login githubv4.String
|
||||||
}
|
}
|
||||||
}
|
Number githubv4.Int
|
||||||
Committer struct {
|
HeadRefOid githubv4.String
|
||||||
Name *string
|
MergedAt githubv4.DateTime
|
||||||
User struct {
|
MergeCommit struct {
|
||||||
Login *string
|
// NOTE: only used for sanity check.
|
||||||
|
// Use original commit oid instead.
|
||||||
|
Oid githubv4.GitObjectID
|
||||||
}
|
}
|
||||||
}
|
Labels struct {
|
||||||
AssociatedPullRequests struct {
|
Nodes []struct {
|
||||||
Nodes []struct {
|
Name githubv4.String
|
||||||
Repository struct {
|
}
|
||||||
Name githubv4.String
|
} `graphql:"labels(last: $labelsToAnalyze)"`
|
||||||
Owner struct {
|
Reviews struct {
|
||||||
|
Nodes []struct {
|
||||||
|
State githubv4.String
|
||||||
|
Author struct {
|
||||||
Login githubv4.String
|
Login githubv4.String
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Author struct {
|
} `graphql:"reviews(last: $reviewsToAnalyze)"`
|
||||||
Login githubv4.String
|
}
|
||||||
}
|
} `graphql:"associatedPullRequests(first: $pullRequestsToAnalyze)"`
|
||||||
Number githubv4.Int
|
}
|
||||||
HeadRefOid githubv4.String
|
} `graphql:"history(first: $commitsToAnalyze)"`
|
||||||
MergedAt githubv4.DateTime
|
} `graphql:"... on Commit"`
|
||||||
MergeCommit struct {
|
} `graphql:"object(expression: $commitExpression)"`
|
||||||
// NOTE: only used for sanity check.
|
|
||||||
// Use original commit oid instead.
|
|
||||||
Oid githubv4.GitObjectID
|
|
||||||
}
|
|
||||||
Labels struct {
|
|
||||||
Nodes []struct {
|
|
||||||
Name githubv4.String
|
|
||||||
}
|
|
||||||
} `graphql:"labels(last: $labelsToAnalyze)"`
|
|
||||||
Reviews struct {
|
|
||||||
Nodes []struct {
|
|
||||||
State githubv4.String
|
|
||||||
Author struct {
|
|
||||||
Login githubv4.String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} `graphql:"reviews(last: $reviewsToAnalyze)"`
|
|
||||||
}
|
|
||||||
} `graphql:"associatedPullRequests(first: $pullRequestsToAnalyze)"`
|
|
||||||
}
|
|
||||||
} `graphql:"history(first: $commitsToAnalyze)"`
|
|
||||||
} `graphql:"... on Commit"`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Issues struct {
|
Issues struct {
|
||||||
Nodes []struct {
|
Nodes []struct {
|
||||||
// nolint: revive,stylecheck // naming according to githubv4 convention.
|
// nolint: revive,stylecheck // naming according to githubv4 convention.
|
||||||
@ -115,22 +114,26 @@ type graphqlData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type graphqlHandler struct {
|
type graphqlHandler struct {
|
||||||
client *githubv4.Client
|
client *githubv4.Client
|
||||||
data *graphqlData
|
data *graphqlData
|
||||||
once *sync.Once
|
once *sync.Once
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
errSetup error
|
errSetup error
|
||||||
owner string
|
owner string
|
||||||
repo string
|
repo string
|
||||||
commits []clients.Commit
|
defaultBranch string
|
||||||
issues []clients.Issue
|
commitSHA string
|
||||||
archived bool
|
commits []clients.Commit
|
||||||
|
issues []clients.Issue
|
||||||
|
archived bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *graphqlHandler) init(ctx context.Context, owner, repo string) {
|
func (handler *graphqlHandler) init(ctx context.Context, owner, repo, defaultBranch, commitSHA string) {
|
||||||
handler.ctx = ctx
|
handler.ctx = ctx
|
||||||
handler.owner = owner
|
handler.owner = owner
|
||||||
handler.repo = repo
|
handler.repo = repo
|
||||||
|
handler.defaultBranch = defaultBranch
|
||||||
|
handler.commitSHA = commitSHA
|
||||||
handler.data = new(graphqlData)
|
handler.data = new(graphqlData)
|
||||||
handler.errSetup = nil
|
handler.errSetup = nil
|
||||||
handler.once = new(sync.Once)
|
handler.once = new(sync.Once)
|
||||||
@ -138,6 +141,12 @@ func (handler *graphqlHandler) init(ctx context.Context, owner, repo string) {
|
|||||||
|
|
||||||
func (handler *graphqlHandler) setup() error {
|
func (handler *graphqlHandler) setup() error {
|
||||||
handler.once.Do(func() {
|
handler.once.Do(func() {
|
||||||
|
commitExpression := handler.commitSHA
|
||||||
|
if strings.EqualFold(handler.commitSHA, "HEAD") {
|
||||||
|
// TODO(#575): Confirm that this works as expected.
|
||||||
|
commitExpression = fmt.Sprintf("heads/%s", handler.defaultBranch)
|
||||||
|
}
|
||||||
|
|
||||||
vars := map[string]interface{}{
|
vars := map[string]interface{}{
|
||||||
"owner": githubv4.String(handler.owner),
|
"owner": githubv4.String(handler.owner),
|
||||||
"name": githubv4.String(handler.repo),
|
"name": githubv4.String(handler.repo),
|
||||||
@ -147,6 +156,7 @@ func (handler *graphqlHandler) setup() error {
|
|||||||
"reviewsToAnalyze": githubv4.Int(reviewsToAnalyze),
|
"reviewsToAnalyze": githubv4.Int(reviewsToAnalyze),
|
||||||
"labelsToAnalyze": githubv4.Int(labelsToAnalyze),
|
"labelsToAnalyze": githubv4.Int(labelsToAnalyze),
|
||||||
"commitsToAnalyze": githubv4.Int(commitsToAnalyze),
|
"commitsToAnalyze": githubv4.Int(commitsToAnalyze),
|
||||||
|
"commitExpression": githubv4.String(commitExpression),
|
||||||
}
|
}
|
||||||
if err := handler.client.Query(handler.ctx, handler.data, vars); err != nil {
|
if err := handler.client.Query(handler.ctx, handler.data, vars); err != nil {
|
||||||
handler.errSetup = sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("githubv4.Query: %v", err))
|
handler.errSetup = sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("githubv4.Query: %v", err))
|
||||||
@ -186,7 +196,7 @@ func (handler *graphqlHandler) isArchived() (bool, error) {
|
|||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
func commitsFrom(data *graphqlData, repoOwner, repoName string) ([]clients.Commit, error) {
|
func commitsFrom(data *graphqlData, repoOwner, repoName string) ([]clients.Commit, error) {
|
||||||
ret := make([]clients.Commit, 0)
|
ret := make([]clients.Commit, 0)
|
||||||
for _, commit := range data.Repository.DefaultBranchRef.Target.Commit.History.Nodes {
|
for _, commit := range data.Repository.Object.Commit.History.Nodes {
|
||||||
var committer string
|
var committer string
|
||||||
if commit.Committer.User.Login != nil {
|
if commit.Committer.User.Login != nil {
|
||||||
committer = *commit.Committer.User.Login
|
committer = *commit.Committer.User.Login
|
||||||
|
@ -68,14 +68,14 @@ type tarballHandler struct {
|
|||||||
files []string
|
files []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *tarballHandler) init(ctx context.Context, repo *github.Repository) error {
|
func (handler *tarballHandler) init(ctx context.Context, repo *github.Repository, commitSHA string) error {
|
||||||
// Cleanup any previous state.
|
// Cleanup any previous state.
|
||||||
if err := handler.cleanup(); err != nil {
|
if err := handler.cleanup(); err != nil {
|
||||||
return sce.WithMessage(sce.ErrScorecardInternal, err.Error())
|
return sce.WithMessage(sce.ErrScorecardInternal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup temp dir/files and download repo tarball.
|
// Setup temp dir/files and download repo tarball.
|
||||||
if err := handler.getTarball(ctx, repo); errors.Is(err, errTarballNotFound) {
|
if err := handler.getTarball(ctx, repo, commitSHA); errors.Is(err, errTarballNotFound) {
|
||||||
log.Printf("unable to get tarball %v. Skipping...", err)
|
log.Printf("unable to get tarball %v. Skipping...", err)
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -93,10 +93,14 @@ func (handler *tarballHandler) init(ctx context.Context, repo *github.Repository
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *tarballHandler) getTarball(ctx context.Context, repo *github.Repository) error {
|
func (handler *tarballHandler) getTarball(ctx context.Context, repo *github.Repository, commitSHA string) error {
|
||||||
url := repo.GetArchiveURL()
|
url := repo.GetArchiveURL()
|
||||||
url = strings.Replace(url, "{archive_format}", "tarball/", 1)
|
url = strings.Replace(url, "{archive_format}", "tarball/", 1)
|
||||||
url = strings.Replace(url, "{/ref}", "", 1)
|
if strings.EqualFold(commitSHA, "HEAD") {
|
||||||
|
url = strings.Replace(url, "{/ref}", "", 1)
|
||||||
|
} else {
|
||||||
|
url = strings.Replace(url, "{/ref}", commitSHA, 1)
|
||||||
|
}
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("http.NewRequestWithContext: %w", err)
|
return fmt.Errorf("http.NewRequestWithContext: %w", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user