| package gitiles_common |
| |
| import ( |
| "bytes" |
| "context" |
| "errors" |
| "fmt" |
| "net/http" |
| |
| "go.skia.org/infra/autoroll/go/config_vars" |
| "go.skia.org/infra/autoroll/go/repo_manager/common/version_file_common" |
| "go.skia.org/infra/autoroll/go/revision" |
| "go.skia.org/infra/go/gitiles" |
| "go.skia.org/infra/go/skerr" |
| ) |
| |
| // GitilesConfig provides configuration for GitilesRepo. |
| type GitilesConfig struct { |
| // Branch is the name of the git branch to be tracked by the GitilesRepo. |
| Branch *config_vars.Template `json:"branch"` |
| // RepoURL is the git repository URL. |
| RepoURL string `json:"repoURL"` |
| // Dependencies is an optional specification of dependencies to track. |
| // Revisions generated by the GitilesRepo will contain the pinned versions |
| // of these dependencies. |
| Dependencies []*version_file_common.VersionFileConfig `json:"dependencies,omitempty"` |
| } |
| |
| // See documentation for util.Validator interface. |
| func (c *GitilesConfig) Validate() error { |
| if c.Branch == nil { |
| return errors.New("Branch is required.") |
| } |
| if err := c.Branch.Validate(); err != nil { |
| return skerr.Wrap(err) |
| } |
| if c.RepoURL == "" { |
| return errors.New("RepoURL is required.") |
| } |
| return nil |
| } |
| |
| // GitilesRepo provides helpers for dealing with repos which use Gitiles. |
| type GitilesRepo struct { |
| *gitiles.Repo |
| branch *config_vars.Template |
| deps []*version_file_common.VersionFileConfig |
| } |
| |
| // NewGitilesRepo returns a GitilesRepo instance. |
| func NewGitilesRepo(ctx context.Context, c GitilesConfig, reg *config_vars.Registry, client *http.Client) (*GitilesRepo, error) { |
| if err := c.Validate(); err != nil { |
| return nil, skerr.Wrap(err) |
| } |
| if err := reg.Register(c.Branch); err != nil { |
| return nil, skerr.Wrap(err) |
| } |
| repo := gitiles.NewRepo(c.RepoURL, client) |
| return &GitilesRepo{ |
| Repo: repo, |
| branch: c.Branch, |
| deps: c.Dependencies, |
| }, nil |
| } |
| |
| // Branch returns the resolved name of the branch tracked by this GitilesRepo. |
| func (r *GitilesRepo) Branch() string { |
| return r.branch.String() |
| } |
| |
| // GetRevision returns a revision.Revision instance associated with the given |
| // revision ID, which may be a commit hash or fully-qualified ref name. |
| func (r *GitilesRepo) GetRevision(ctx context.Context, id string) (*revision.Revision, error) { |
| // Load the details for this revision. |
| details, err := r.Details(ctx, id) |
| if err != nil { |
| return nil, skerr.Wrapf(err, "Failed to retrieve revision %q", id) |
| } |
| rev := revision.FromLongCommit(fmt.Sprintf(gitiles.CommitURL, r.URL, "%s"), details) |
| |
| // Optionally load any dependencies. |
| if len(r.deps) > 0 { |
| deps, err := version_file_common.GetPinnedRevs(ctx, r.deps, func(ctx context.Context, path string) (string, error) { |
| return r.GetFile(ctx, path, rev.Id) |
| }) |
| if err != nil { |
| return nil, skerr.Wrap(err) |
| } |
| rev.Dependencies = deps |
| } |
| return rev, nil |
| } |
| |
| // GetTipRevision returns a revision.Revision instance associated with the |
| // current tip of the branch tracked by this GitilesRepo. |
| func (r *GitilesRepo) GetTipRevision(ctx context.Context) (*revision.Revision, error) { |
| return r.GetRevision(ctx, r.branch.String()) |
| } |
| |
| // LogFirstParent returns a slice of revision.Revision instances in the given range. |
| func (r *GitilesRepo) LogFirstParent(ctx context.Context, from, to *revision.Revision) ([]*revision.Revision, error) { |
| commits, err := r.Repo.LogFirstParent(ctx, from.Id, to.Id) |
| if err != nil { |
| return nil, err |
| } |
| revs := make([]*revision.Revision, 0, len(commits)) |
| for _, commit := range commits { |
| rev, err := r.GetRevision(ctx, commit.Hash) |
| if err != nil { |
| return nil, skerr.Wrapf(err, "Failed to retrieve revision") |
| } |
| revs = append(revs, rev) |
| } |
| return revs, nil |
| } |
| |
| // GetFile retrieves the contents of the given file at the given ref. |
| func (r *GitilesRepo) GetFile(ctx context.Context, file, ref string) (string, error) { |
| var buf bytes.Buffer |
| if err := r.ReadFileAtRef(ctx, file, ref, &buf); err != nil { |
| return "", skerr.Wrap(err) |
| } |
| return buf.String(), nil |
| } |