spindle: rework clone step #277

merged
opened by oppi.li targeting master from push-vquoltwpkuny

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 <url>
git fetch --depth=<d> --recurse-submodules=<yes|no> <sha>
git checkout FETCH_HEAD

Signed-off-by: oppiliappan me@oppi.li

Changed files
+58 -61
spindle
workflow
-1
spindle/models/pipeline.go
··· 69 69 70 70 setup.addStep(nixConfStep()) 71 71 setup.addStep(cloneStep(*twf, *pl.TriggerMetadata, cfg.Server.Dev)) 72 - setup.addStep(checkoutStep(*twf, *pl.TriggerMetadata)) 73 72 // this step could be empty 74 73 if s := dependencyStep(*twf); s != nil { 75 74 setup.addStep(*s)
+46 -57
spindle/models/setup_steps.go
··· 5 5 "path" 6 6 "strings" 7 7 8 - "github.com/go-git/go-git/v5/plumbing" 9 8 "tangled.sh/tangled.sh/core/api/tangled" 10 9 "tangled.sh/tangled.sh/core/workflow" 11 10 ) ··· 19 18 } 20 19 } 21 20 22 - // checkoutStep checks out the specified ref in the cloned repository. 23 - func checkoutStep(twf tangled.Pipeline_Workflow, tr tangled.Pipeline_TriggerMetadata) Step { 24 - if twf.Clone.Skip { 25 - return Step{} 26 - } 27 - 28 - var ref string 29 - switch tr.Kind { 30 - case "push": 31 - ref = tr.Push.NewSha 32 - case "pull_request": 33 - ref = tr.PullRequest.TargetBranch 34 - 35 - // TODO: this needs to be specified in lexicon 36 - case "manual": 37 - ref = tr.Repo.DefaultBranch 38 - } 39 - 40 - checkoutCmd := fmt.Sprintf("git config advice.detachedHead false; git checkout --progress --force %s", ref) 41 - 42 - return Step{ 43 - Command: checkoutCmd, 44 - Name: "Checkout ref " + ref, 45 - } 46 - } 47 - 48 21 // cloneOptsAsSteps processes clone options and adds corresponding steps 49 22 // to the beginning of the workflow's step list if cloning is not skipped. 23 + // 24 + // the steps to do here are: 25 + // - git init 26 + // - git remote add origin <url> 27 + // - git fetch --depth=<d> --recurse-submodules=<yes|no> <sha> 28 + // - git checkout FETCH_HEAD 50 29 func cloneStep(twf tangled.Pipeline_Workflow, tr tangled.Pipeline_TriggerMetadata, dev bool) Step { 51 30 if twf.Clone.Skip { 52 31 return Step{} 53 32 } 54 33 55 - uri := "https://" 34 + var commands []string 35 + 36 + // initialize git repo in workspace 37 + commands = append(commands, "git init") 38 + 39 + // add repo as git remote 40 + scheme := "https://" 56 41 if dev { 57 - uri = "http://" 42 + scheme = "http://" 58 43 tr.Repo.Knot = strings.ReplaceAll(tr.Repo.Knot, "localhost", "host.docker.internal") 59 44 } 45 + url := scheme + path.Join(tr.Repo.Knot, tr.Repo.Did, tr.Repo.Repo) 46 + commands = append(commands, fmt.Sprintf("git remote add origin %s", url)) 60 47 61 - cloneUrl := uri + path.Join(tr.Repo.Knot, tr.Repo.Did, tr.Repo.Repo) 62 - cloneCmd := []string{"git", "clone", cloneUrl, "."} 48 + // run git fetch 49 + { 50 + var fetchArgs []string 63 51 64 - // default clone depth is 1 65 - cloneDepth := 1 66 - if twf.Clone.Depth > 1 { 67 - cloneDepth = int(twf.Clone.Depth) 68 - } 69 - cloneCmd = append(cloneCmd, fmt.Sprintf("--depth=%d", cloneDepth)) 70 - 71 - // select the clone branch 72 - cloneBranch := "" 73 - switch tr.Kind { 74 - case workflow.TriggerKindManual: 75 - // TODO: unimplemented 76 - case workflow.TriggerKindPush: 77 - ref := tr.Push.Ref 78 - refName := plumbing.ReferenceName(ref) 79 - cloneBranch = refName.Short() 80 - case workflow.TriggerKindPullRequest: 81 - cloneBranch = tr.PullRequest.SourceBranch 82 - } 52 + // default clone depth is 1 53 + depth := 1 54 + if twf.Clone.Depth > 1 { 55 + depth = int(twf.Clone.Depth) 56 + } 57 + fetchArgs = append(fetchArgs, fmt.Sprintf("--depth=%d", depth)) 83 58 84 - if cloneBranch != "" { 85 - cloneCmd = append(cloneCmd, fmt.Sprintf("--branch=%s", cloneBranch)) 86 - } 59 + // optionally recurse submodules 60 + if twf.Clone.Submodules { 61 + fetchArgs = append(fetchArgs, "--recurse-submodules=yes") 62 + } 63 + 64 + // set remote to fetch from 65 + fetchArgs = append(fetchArgs, "origin") 66 + 67 + // set revision to checkout 68 + switch workflow.TriggerKind(tr.Kind) { 69 + case workflow.TriggerKindManual: 70 + // TODO: unimplemented 71 + case workflow.TriggerKindPush: 72 + fetchArgs = append(fetchArgs, tr.Push.NewSha) 73 + case workflow.TriggerKindPullRequest: 74 + fetchArgs = append(fetchArgs, tr.PullRequest.SourceSha) 75 + } 87 76 88 - if twf.Clone.Submodules { 89 - cloneCmd = append(cloneCmd, "--recursive") 77 + commands = append(commands, fmt.Sprintf("git fetch %s", strings.Join(fetchArgs, " "))) 90 78 } 91 79 92 - fmt.Println(strings.Join(cloneCmd, " ")) 80 + // run git checkout 81 + commands = append(commands, "git checkout FETCH_HEAD") 93 82 94 83 cloneStep := Step{ 95 - Command: strings.Join(cloneCmd, " "), 84 + Command: strings.Join(commands, "\n"), 96 85 Name: "Clone repository into workspace", 97 86 } 98 87 return cloneStep
+12 -3
workflow/def.go
··· 4 4 "errors" 5 5 "fmt" 6 6 "slices" 7 + "strings" 7 8 8 9 "tangled.sh/tangled.sh/core/api/tangled" 9 10 ··· 51 52 } 52 53 53 54 StringList []string 55 + 56 + TriggerKind string 54 57 ) 55 58 56 59 const ( 57 - TriggerKindPush string = "push" 58 - TriggerKindPullRequest string = "pull_request" 59 - TriggerKindManual string = "manual" 60 + WorkflowDir = ".tangled/workflows" 61 + 62 + TriggerKindPush TriggerKind = "push" 63 + TriggerKindPullRequest TriggerKind = "pull_request" 64 + TriggerKindManual TriggerKind = "manual" 60 65 ) 61 66 67 + func (t TriggerKind) String() string { 68 + return strings.ReplaceAll(string(t), "_", " ") 69 + } 70 + 62 71 func FromFile(name string, contents []byte) (Workflow, error) { 63 72 var wf Workflow 64 73