2021-03-16 07:35:57 -03:00

114 lines
3.7 KiB
Go

// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.
package initializer
import (
"context"
"os"
"github.com/opentracing/opentracing-go"
"golang.org/x/xerrors"
"github.com/gitpod-io/gitpod/common-go/log"
"github.com/gitpod-io/gitpod/common-go/tracing"
csapi "github.com/gitpod-io/gitpod/content-service/api"
"github.com/gitpod-io/gitpod/content-service/pkg/archive"
"github.com/gitpod-io/gitpod/content-service/pkg/git"
)
// CloneTargetMode is the target state in which we want to leave a GitInitializer
type CloneTargetMode string
const (
// RemoteHead has the local WS point at the remote branch head
RemoteHead CloneTargetMode = "head"
// RemoteCommit has the local WS point at a specific commit
RemoteCommit CloneTargetMode = "commit"
// RemoteBranch has the local WS point at a remote branch
RemoteBranch CloneTargetMode = "remote-branch"
// LocalBranch creates a local branch in the workspace
LocalBranch CloneTargetMode = "local-branch"
)
// GitInitializer is a local workspace with a Git connection
type GitInitializer struct {
git.Client
// The target mode determines what gets checked out
TargetMode CloneTargetMode
// The value for the clone target mode - use depends on the target mode
CloneTarget string
}
// Run initializes the workspace using Git
func (ws *GitInitializer) Run(ctx context.Context, mappings []archive.IDMapping) (src csapi.WorkspaceInitSource, err error) {
isGitWS := git.IsWorkingCopy(ws.Location)
//nolint:ineffassign
span, ctx := opentracing.StartSpanFromContext(ctx, "GitInitializer.Run")
span.SetTag("isGitWS", isGitWS)
defer tracing.FinishSpan(span, &err)
src = csapi.WorkspaceInitFromOther
if isGitWS {
log.WithField("stage", "init").WithField("location", ws.Location).Info("Not running git clone. Workspace is already a Git workspace")
return
}
if err := os.MkdirAll(ws.Location, 0770); err != nil {
return src, xerrors.Errorf("git initializer: %w", err)
}
log.WithField("stage", "init").WithField("location", ws.Location).Debug("Running git clone on workspace")
if err := ws.Clone(ctx); err != nil {
return src, xerrors.Errorf("git initializer: %w", err)
}
if err := ws.realizeCloneTarget(ctx); err != nil {
return src, xerrors.Errorf("git initializer: %w", err)
}
if err := ws.UpdateRemote(ctx); err != nil {
return src, xerrors.Errorf("git initializer: %w", err)
}
if err := ws.UpdateSubmodules(ctx); err != nil {
log.WithError(err).Warn("error while updating submodules - continuing")
}
log.WithField("stage", "init").WithField("location", ws.Location).Info("Git operations complete")
return
}
// realizeCloneTarget ensures the clone target is checked out
func (ws *GitInitializer) realizeCloneTarget(ctx context.Context) (err error) {
//nolint:ineffassign
span, ctx := opentracing.StartSpanFromContext(ctx, "realizeCloneTarget")
span.SetTag("remoteURI", ws.RemoteURI)
span.SetTag("cloneTarget", ws.CloneTarget)
span.SetTag("targetMode", ws.TargetMode)
defer tracing.FinishSpan(span, &err)
// checkout branch
if ws.TargetMode == RemoteBranch {
// create local branch based on remote
if err := ws.Git(ctx, "checkout", "-B", ws.CloneTarget, "origin/"+ws.CloneTarget); err != nil {
return err
}
} else if ws.TargetMode == LocalBranch {
if err := ws.Git(ctx, "checkout", "-b", ws.CloneTarget); err != nil {
return err
}
} else if ws.TargetMode == RemoteCommit {
// checkout specific commit
if err := ws.Git(ctx, "checkout", ws.CloneTarget); err != nil {
return err
}
} else { //nolint:staticcheck
// nothing to do - we're already on the remote branch
}
return nil
}