From 8ce49f07b9d0bf226145a5caff93e6fe73378d07 Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Wed, 9 Jul 2025 18:14:51 +0100 Subject: [PATCH] spindle: rework clone step Change-Id: otpvoqvpqptwryzsntloytvtxstvyxlm use git fetch instead of git clone. git clone is lacking in that it does not permit cloning at a specific rev. when paired with `--branch` flag, there is no guarantee if the required rev is available in the shallow clone. with git fetch however, we are able to fetch a specific rev. the steps are a little more involved however: git init git remote add origin git fetch --depth= --recurse-submodules= git checkout FETCH_HEAD Signed-off-by: oppiliappan --- spindle/models/pipeline.go | 1 - spindle/models/setup_steps.go | 103 +++++++++++++++------------------- workflow/def.go | 15 ++++- 3 files changed, 58 insertions(+), 61 deletions(-) diff --git a/spindle/models/pipeline.go b/spindle/models/pipeline.go index 31c542d..6955979 100644 --- a/spindle/models/pipeline.go +++ b/spindle/models/pipeline.go @@ -69,7 +69,6 @@ func ToPipeline(pl tangled.Pipeline, cfg config.Config) *Pipeline { setup.addStep(nixConfStep()) setup.addStep(cloneStep(*twf, *pl.TriggerMetadata, cfg.Server.Dev)) - setup.addStep(checkoutStep(*twf, *pl.TriggerMetadata)) // this step could be empty if s := dependencyStep(*twf); s != nil { setup.addStep(*s) diff --git a/spindle/models/setup_steps.go b/spindle/models/setup_steps.go index 380a064..4aa620d 100644 --- a/spindle/models/setup_steps.go +++ b/spindle/models/setup_steps.go @@ -5,7 +5,6 @@ import ( "path" "strings" - "github.com/go-git/go-git/v5/plumbing" "tangled.sh/tangled.sh/core/api/tangled" "tangled.sh/tangled.sh/core/workflow" ) @@ -19,80 +18,70 @@ echo 'build-users-group = ' >> /etc/nix/nix.conf` } } -// checkoutStep checks out the specified ref in the cloned repository. -func checkoutStep(twf tangled.Pipeline_Workflow, tr tangled.Pipeline_TriggerMetadata) Step { - if twf.Clone.Skip { - return Step{} - } - - var ref string - switch tr.Kind { - case "push": - ref = tr.Push.NewSha - case "pull_request": - ref = tr.PullRequest.TargetBranch - - // TODO: this needs to be specified in lexicon - case "manual": - ref = tr.Repo.DefaultBranch - } - - checkoutCmd := fmt.Sprintf("git config advice.detachedHead false; git checkout --progress --force %s", ref) - - return Step{ - Command: checkoutCmd, - Name: "Checkout ref " + ref, - } -} - // cloneOptsAsSteps processes clone options and adds corresponding steps // to the beginning of the workflow's step list if cloning is not skipped. +// +// the steps to do here are: +// - git init +// - git remote add origin +// - git fetch --depth= --recurse-submodules= +// - git checkout FETCH_HEAD func cloneStep(twf tangled.Pipeline_Workflow, tr tangled.Pipeline_TriggerMetadata, dev bool) Step { if twf.Clone.Skip { return Step{} } - uri := "https://" + var commands []string + + // initialize git repo in workspace + commands = append(commands, "git init") + + // add repo as git remote + scheme := "https://" if dev { - uri = "http://" + scheme = "http://" tr.Repo.Knot = strings.ReplaceAll(tr.Repo.Knot, "localhost", "host.docker.internal") } + url := scheme + path.Join(tr.Repo.Knot, tr.Repo.Did, tr.Repo.Repo) + commands = append(commands, fmt.Sprintf("git remote add origin %s", url)) - cloneUrl := uri + path.Join(tr.Repo.Knot, tr.Repo.Did, tr.Repo.Repo) - cloneCmd := []string{"git", "clone", cloneUrl, "."} + // run git fetch + { + var fetchArgs []string - // default clone depth is 1 - cloneDepth := 1 - if twf.Clone.Depth > 1 { - cloneDepth = int(twf.Clone.Depth) - } - cloneCmd = append(cloneCmd, fmt.Sprintf("--depth=%d", cloneDepth)) - - // select the clone branch - cloneBranch := "" - switch tr.Kind { - case workflow.TriggerKindManual: - // TODO: unimplemented - case workflow.TriggerKindPush: - ref := tr.Push.Ref - refName := plumbing.ReferenceName(ref) - cloneBranch = refName.Short() - case workflow.TriggerKindPullRequest: - cloneBranch = tr.PullRequest.SourceBranch - } + // default clone depth is 1 + depth := 1 + if twf.Clone.Depth > 1 { + depth = int(twf.Clone.Depth) + } + fetchArgs = append(fetchArgs, fmt.Sprintf("--depth=%d", depth)) - if cloneBranch != "" { - cloneCmd = append(cloneCmd, fmt.Sprintf("--branch=%s", cloneBranch)) - } + // optionally recurse submodules + if twf.Clone.Submodules { + fetchArgs = append(fetchArgs, "--recurse-submodules=yes") + } + + // set remote to fetch from + fetchArgs = append(fetchArgs, "origin") + + // set revision to checkout + switch workflow.TriggerKind(tr.Kind) { + case workflow.TriggerKindManual: + // TODO: unimplemented + case workflow.TriggerKindPush: + fetchArgs = append(fetchArgs, tr.Push.NewSha) + case workflow.TriggerKindPullRequest: + fetchArgs = append(fetchArgs, tr.PullRequest.SourceSha) + } - if twf.Clone.Submodules { - cloneCmd = append(cloneCmd, "--recursive") + commands = append(commands, fmt.Sprintf("git fetch %s", strings.Join(fetchArgs, " "))) } - fmt.Println(strings.Join(cloneCmd, " ")) + // run git checkout + commands = append(commands, "git checkout FETCH_HEAD") cloneStep := Step{ - Command: strings.Join(cloneCmd, " "), + Command: strings.Join(commands, "\n"), Name: "Clone repository into workspace", } return cloneStep diff --git a/workflow/def.go b/workflow/def.go index 436654b..3d0acd3 100644 --- a/workflow/def.go +++ b/workflow/def.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "slices" + "strings" "tangled.sh/tangled.sh/core/api/tangled" @@ -51,14 +52,22 @@ type ( } StringList []string + + TriggerKind string ) const ( - TriggerKindPush string = "push" - TriggerKindPullRequest string = "pull_request" - TriggerKindManual string = "manual" + WorkflowDir = ".tangled/workflows" + + TriggerKindPush TriggerKind = "push" + TriggerKindPullRequest TriggerKind = "pull_request" + TriggerKindManual TriggerKind = "manual" ) +func (t TriggerKind) String() string { + return strings.ReplaceAll(string(t), "_", " ") +} + func FromFile(name string, contents []byte) (Workflow, error) { var wf Workflow -- 2.43.0