blob: 0417ffa3497e806f942c323004e8bfa66ae6d90d [file] [log] [blame]
package repo_manager
import (
"context"
"net/http"
"path/filepath"
"go.skia.org/infra/autoroll/go/codereview"
"go.skia.org/infra/autoroll/go/config"
"go.skia.org/infra/autoroll/go/config_vars"
"go.skia.org/infra/autoroll/go/repo_manager/child"
"go.skia.org/infra/autoroll/go/repo_manager/child/revision_filter"
"go.skia.org/infra/autoroll/go/repo_manager/parent"
"go.skia.org/infra/autoroll/go/revision"
"go.skia.org/infra/go/git"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
)
// parentChildRepoManager combines a Parent and a Child to implement the
// RepoManager interface.
type parentChildRepoManager struct {
child.Child
parent.Parent
revFilter revision_filter.RevisionFilter
}
// newParentChildRepoManager returns a RepoManager which pairs a Parent with a
// Child.
func newParentChildRepoManager(ctx context.Context, c *config.ParentChildRepoManagerConfig, reg *config_vars.Registry, workdir, rollerName, recipeCfgFile, serverURL string, client *http.Client, cr codereview.CodeReview) (*parentChildRepoManager, error) {
var childRM child.Child
var parentRM parent.Parent
var err error
// Some Child implementations require that they are created by the Parent,
// so we have to create the Parent first.
var childCheckout *git.Checkout
if c.GetDepsLocalGerritParent() != nil {
parentCfg := c.GetDepsLocalGerritParent()
childPath := parentCfg.DepsLocal.ChildPath
if parentCfg.DepsLocal.ChildSubdir != "" {
childPath = filepath.Join(parentCfg.DepsLocal.ChildSubdir, childPath)
}
childFullPath := filepath.Join(workdir, childPath)
childCheckout = &git.Checkout{GitDir: git.GitDir(childFullPath)}
parentRM, err = parent.NewDEPSLocalGerrit(ctx, parentCfg, reg, client, serverURL, workdir, rollerName, recipeCfgFile, cr)
} else if c.GetDepsLocalGithubParent() != nil {
parentCfg := c.GetDepsLocalGithubParent()
childPath := parentCfg.DepsLocal.ChildPath
if parentCfg.DepsLocal.ChildSubdir != "" {
childPath = filepath.Join(parentCfg.DepsLocal.ChildSubdir, childPath)
}
childFullPath := filepath.Join(workdir, childPath)
childCheckout = &git.Checkout{GitDir: git.GitDir(childFullPath)}
parentRM, err = parent.NewDEPSLocalGitHub(ctx, parentCfg, reg, client, serverURL, workdir, rollerName, recipeCfgFile, cr)
} else if c.GetGitCheckoutGithubFileParent() != nil {
parentRM, err = parent.NewGitCheckoutGithubFile(ctx, c.GetGitCheckoutGithubFileParent(), reg, client, serverURL, workdir, rollerName, cr)
} else if c.GetGitilesParent() != nil {
parentRM, err = parent.NewGitilesFile(ctx, c.GetGitilesParent(), reg, client, serverURL)
}
if err != nil {
return nil, skerr.Wrap(err)
}
// Create the Child.
if c.GetCipdChild() != nil {
childRM, err = child.NewCIPD(ctx, c.GetCipdChild(), client, workdir)
} else if c.GetFuchsiaSdkChild() != nil {
childRM, err = child.NewFuchsiaSDK(ctx, c.GetFuchsiaSdkChild(), client)
} else if c.GetGitilesChild() != nil {
childRM, err = child.NewGitiles(ctx, c.GetGitilesChild(), reg, client)
} else if c.GetGitCheckoutChild() != nil {
childRM, err = child.NewGitCheckout(ctx, c.GetGitCheckoutChild(), reg, workdir, cr, childCheckout)
} else if c.GetGitCheckoutGithubChild() != nil {
childRM, err = child.NewGitCheckoutGithub(ctx, c.GetGitCheckoutGithubChild(), reg, workdir, cr, childCheckout)
} else if c.GetSemverGcsChild() != nil {
childRM, err = child.NewSemVerGCS(ctx, c.GetSemverGcsChild(), reg, client)
}
if err != nil {
return nil, skerr.Wrap(err)
}
// Some Parent implementations require a Child to be passed in.
if c.GetCopyParent() != nil {
parentRM, err = parent.NewCopy(ctx, c.GetCopyParent(), reg, client, serverURL, workdir, cr.UserName(), cr.UserEmail(), childRM)
}
if err != nil {
return nil, skerr.Wrap(err)
}
// Revision filter.
var revFilter revision_filter.RevisionFilter
if c.GetBuildbucketRevisionFilter() != nil {
rfConfig := c.GetBuildbucketRevisionFilter()
revFilter, err = revision_filter.NewBuildbucketRevisionFilter(client, rfConfig.Project, rfConfig.Bucket)
}
if err != nil {
return nil, skerr.Wrap(err)
}
// TODO(borenet): Fill this out.
return &parentChildRepoManager{
Child: childRM,
Parent: parentRM,
revFilter: revFilter,
}, nil
}
// See documentation for RepoManager interface.
func (rm *parentChildRepoManager) Update(ctx context.Context) (*revision.Revision, *revision.Revision, []*revision.Revision, error) {
lastRollRevId, err := rm.Parent.Update(ctx)
if err != nil {
return nil, nil, nil, skerr.Wrapf(err, "failed to update Parent")
}
lastRollRev, err := rm.Child.GetRevision(ctx, lastRollRevId)
if err != nil {
sklog.Errorf("Last roll rev %q not found. This is acceptable for some rollers which allow outside versions to be rolled manually (eg. AFDO roller). A human should verify that this is indeed caused by a manual roll. Attempting to continue with no last-rolled revision. The revisions listed in the commit message will be incorrect!", lastRollRevId)
lastRollRev = &revision.Revision{Id: lastRollRevId}
}
tipRev, notRolledRevs, err := rm.Child.Update(ctx, lastRollRev)
if err != nil {
return nil, nil, nil, skerr.Wrapf(err, "failed to get next revision to roll from Child")
}
// Optionally filter not-rolled revisions.
if rm.revFilter != nil {
if err := revision_filter.MaybeSetInvalid(ctx, rm.revFilter, tipRev); err != nil {
return nil, nil, nil, skerr.Wrap(err)
}
for _, notRolledRev := range notRolledRevs {
if err := revision_filter.MaybeSetInvalid(ctx, rm.revFilter, notRolledRev); err != nil {
return nil, nil, nil, skerr.Wrap(err)
}
}
}
return lastRollRev, tipRev, notRolledRevs, nil
}
// parentChildRepoManager implements RepoManager.
var _ RepoManager = &parentChildRepoManager{}