blob: bd7892513bd47754035e65c78adf33adc13b5c8c [file] [log] [blame]
// Package gitiles imlements provider.Provider using the Gitiles API.
package gitiles
import (
"context"
"fmt"
"net/http"
"time"
"go.skia.org/infra/go/git"
"go.skia.org/infra/go/gitiles"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
"go.skia.org/infra/go/vcsinfo"
"go.skia.org/infra/perf/go/config"
"go.skia.org/infra/perf/go/git/provider"
)
const (
batchSize = 100
)
// Gitiles implements provider.Provider.
type Gitiles struct {
gr gitiles.GitilesRepo
// startCommit is the commit in the repo where we start tracking commits. If
// not supplied then we start with the first commit in the repo as reachable
// from HEAD.
startCommit string
branch string
}
// New returns a new instance of Gitiles.
func New(c *http.Client, instanceConfig *config.InstanceConfig) *Gitiles {
return &Gitiles{
gr: gitiles.NewRepo(instanceConfig.GitRepoConfig.URL, c),
startCommit: instanceConfig.GitRepoConfig.StartCommit,
branch: instanceConfig.GitRepoConfig.Branch,
}
}
// CommitsFromMostRecentGitHashToHead implements provider.Provider.
func (g *Gitiles) CommitsFromMostRecentGitHashToHead(ctx context.Context, mostRecentGitHash string, cb provider.CommitProcessor) error {
if mostRecentGitHash == "" {
mostRecentGitHash = g.startCommit
}
var expr string
opts := []gitiles.LogOption{
gitiles.LogBatchSize(batchSize),
gitiles.LogReverse(),
}
if g.isMainBranch() {
expr = git.LogFromTo(mostRecentGitHash, "HEAD")
if mostRecentGitHash == "" {
expr = git.MainBranch
}
} else {
sklog.Infof("Ingesting from branch %s", g.branch)
expr = git.FullyQualifiedBranchName(g.branch)
opts = append(opts, gitiles.LogStartCommit(mostRecentGitHash))
}
sklog.Infof("Populating from gitiles from %q", expr)
err := g.gr.LogFnBatch(ctx, expr, func(ctx context.Context, lcs []*vcsinfo.LongCommit) error {
sklog.Infof("Processing %s commits: ", len(lcs))
for _, longCommit := range lcs {
c := provider.Commit{
GitHash: longCommit.Hash,
Timestamp: longCommit.Timestamp.Unix(),
Author: longCommit.Author,
Subject: longCommit.Subject,
Body: longCommit.Body,
}
err := cb(c)
if err != nil {
return skerr.Wrapf(err, "processing callback")
}
}
return nil
}, opts...)
if err != nil {
return skerr.Wrapf(err, "loading commits")
}
return nil
}
// GitHashesInRangeForFile implements provider.Provider.
func (g *Gitiles) GitHashesInRangeForFile(ctx context.Context, begin, end, filename string) ([]string, error) {
lc, err := g.gr.Log(ctx, git.LogFromTo(begin, end), gitiles.LogPath(filename), gitiles.LogReverse())
if err != nil {
return nil, skerr.Wrapf(err, "loading commits")
}
ret := make([]string, len(lc))
for i, c := range lc {
ret[i] = c.Hash
}
return ret, nil
}
// LogEntry implements provider.Provider.
func (g *Gitiles) LogEntry(ctx context.Context, gitHash string) (string, error) {
lc, err := g.gr.Log(ctx, gitHash, gitiles.LogLimit(1))
if err != nil {
return "", skerr.Wrapf(err, "loading log entry")
}
if len(lc) != 1 {
return "", skerr.Fmt("received %d log entries when expecting 1", len(lc))
}
commit := lc[0]
return fmt.Sprintf(`commit %s
Author %s
Date %s
%s
%s`, commit.Hash, commit.Author, commit.Timestamp.Format(time.RFC822Z), commit.Subject, commit.Body), nil
}
// Update implements provider.Provider.
func (g *Gitiles) Update(ctx context.Context) error {
return nil
}
func (g *Gitiles) isMainBranch() bool {
return g.branch == "" || g.branch == "main"
}
// Confirm *Gitiles implements provider.Provider.
var _ provider.Provider = (*Gitiles)(nil)