blob: 29800c649affa05c447266772f395720a6335f9f [file] [log] [blame]
package parent
/*
Package parent contains implementations of the Parent interface.
*/
import (
"bytes"
"context"
"fmt"
"sort"
"text/template"
"go.skia.org/infra/autoroll/go/repo_manager/common/version_file_common"
"go.skia.org/infra/autoroll/go/revision"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/util"
)
// Parent represents a git repo (or other destination) which depends on a Child
// and is capable of producing rolls.
type Parent interface {
// Update returns the pinned version of the dependency at the most
// recent revision of the Parent. For implementations which use local
// checkouts, this implies a sync.
Update(context.Context) (string, error)
// CreateNewRoll uploads a CL which updates the pinned version of the
// dependency to the given Revision.
CreateNewRoll(ctx context.Context, from, to *revision.Revision, rolling []*revision.Revision, emails []string, cqExtraTrybots string, dryRun bool) (int64, error)
}
// BaseConfig provides common configuration for all implementations of Parent.
// It is intended to be embedded in the various Parent Config types.
type BaseConfig struct {
// Required fields.
// If false, roll CLs do not link to bugs referenced by the Revisions
// in the roll.
IncludeBugs bool `json:"includeBugs"`
// If true, include the "git log" (or other revision details) in the
// commit message. This should be false for internal -> external rollers
// to avoid leaking internal commit messages.
IncludeLog bool `json:"includeLog"`
// TODO(borenet): These fields are not applicable to some rollers, but
// they're needed for CommitMsgVars. We should probably revisit how we
// build commit messages.
ChildPath string `json:"childPath"`
ChildRepo string `json:"childRepo"`
// Optional fields.
// CommitMsgTmpl is a template used to build commit messages. See the
// parent.CommitMsgVars type for more information.
CommitMsgTmpl string `json:"commitMsgTmpl"`
// Monorail project name associated with the Parent.
// TODO(borenet): Add a BugFramework interface to support other
// frameworks (eg. Buganizer, GitHub).
MonorailProject string `json:"monorailProject,omitempty"`
}
// See documentation for util.Validator interface.
func (c BaseConfig) Validate() error {
if c.ChildPath == "" {
return skerr.Fmt("ChildPath is required")
}
if c.ChildRepo == "" {
return skerr.Fmt("ChildRepo is required")
}
// All other fields are booleans or optional.
return nil
}
// baseParent provides common functionality for all implementations of Parent.
type baseParent struct {
childPath string
childRepoUrl string
commitMsgTmpl *template.Template
includeBugs bool
includeLog bool
monorailProject string
serverUrl string
}
func newBaseParent(ctx context.Context, c BaseConfig, serverUrl string) (*baseParent, error) {
commitMsgTmplStr := TMPL_COMMIT_MSG_DEFAULT
if c.CommitMsgTmpl != "" {
commitMsgTmplStr = c.CommitMsgTmpl
}
commitMsgTmpl, err := ParseCommitMsgTemplate(commitMsgTmplStr)
if err != nil {
return nil, err
}
return &baseParent{
childPath: c.ChildPath,
childRepoUrl: c.ChildRepo,
commitMsgTmpl: commitMsgTmpl,
includeBugs: c.IncludeBugs,
includeLog: c.IncludeLog,
monorailProject: c.MonorailProject,
serverUrl: serverUrl,
}, nil
}
// buildCommitMsg is a helper function used to create commit messages.
func (p *baseParent) buildCommitMsg(from, to *revision.Revision, rolling []*revision.Revision, reviewers []string, cqExtraTrybots string, transitiveDeps []*version_file_common.TransitiveDepUpdate) (string, error) {
// Basic variables.
vars := &CommitMsgVars{
ChildPath: p.childPath,
ChildRepo: p.childRepoUrl,
CqExtraTrybots: cqExtraTrybots,
Reviewers: reviewers,
Revisions: rolling,
RollingFrom: from,
RollingTo: to,
ServerURL: p.serverUrl,
TransitiveDeps: transitiveDeps,
}
// Bugs.
vars.Bugs = nil
if p.includeBugs {
// TODO(borenet): Move this to a util.MakeBugLines utility?
bugMap := map[string]bool{}
for _, rev := range vars.Revisions {
for _, bug := range rev.Bugs[p.monorailProject] {
bugMap[bug] = true
}
}
if len(bugMap) > 0 {
vars.Bugs = make([]string, 0, len(bugMap))
for bug := range bugMap {
bugStr := fmt.Sprintf("%s:%s", p.monorailProject, bug)
if p.monorailProject == util.BUG_PROJECT_BUGANIZER {
bugStr = fmt.Sprintf("b/%s", bug)
}
vars.Bugs = append(vars.Bugs, bugStr)
}
sort.Strings(vars.Bugs)
}
}
// IncludeLog.
vars.IncludeLog = p.includeLog
// Tests.
vars.Tests = nil
testsMap := map[string]bool{}
for _, rev := range vars.Revisions {
for _, test := range rev.Tests {
testsMap[test] = true
}
}
if len(testsMap) > 0 {
vars.Tests = make([]string, 0, len(testsMap))
for test := range testsMap {
vars.Tests = append(vars.Tests, test)
}
sort.Strings(vars.Tests)
}
// Create the commit message.
var buf bytes.Buffer
if err := p.commitMsgTmpl.Execute(&buf, vars); err != nil {
return "", err
}
return buf.String(), nil
}