forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
1package models 2 3import ( 4 "fmt" 5 "strings" 6 7 "tangled.org/core/api/tangled" 8 "tangled.org/core/workflow" 9) 10 11type CloneStep struct { 12 name string 13 kind StepKind 14 commands []string 15} 16 17func (s CloneStep) Name() string { 18 return s.name 19} 20 21func (s CloneStep) Commands() []string { 22 return s.commands 23} 24 25func (s CloneStep) Command() string { 26 return strings.Join(s.commands, "\n") 27} 28 29func (s CloneStep) Kind() StepKind { 30 return s.kind 31} 32 33// BuildCloneStep generates git clone commands. 34// The caller must ensure the current working directory is set to the desired 35// workspace directory before executing these commands. 36// 37// The generated commands are: 38// - git init 39// - git remote add origin <url> 40// - git fetch --depth=<d> --recurse-submodules=<yes|no> <sha> 41// - git checkout FETCH_HEAD 42// 43// Supports all trigger types (push, PR, manual) and clone options. 44func BuildCloneStep(twf tangled.Pipeline_Workflow, tr tangled.Pipeline_TriggerMetadata, dev bool) CloneStep { 45 if twf.Clone != nil && twf.Clone.Skip { 46 return CloneStep{} 47 } 48 49 commitSHA, err := extractCommitSHA(tr) 50 if err != nil { 51 return CloneStep{ 52 kind: StepKindSystem, 53 name: "Clone repository into workspace (error)", 54 commands: []string{fmt.Sprintf("echo 'Failed to get clone info: %s' && exit 1", err.Error())}, 55 } 56 } 57 58 repoURL := buildRepoURL(tr, dev) 59 60 var cloneOpts tangled.Pipeline_CloneOpts 61 if twf.Clone != nil { 62 cloneOpts = *twf.Clone 63 } 64 fetchArgs := buildFetchArgs(cloneOpts, commitSHA) 65 66 return CloneStep{ 67 kind: StepKindSystem, 68 name: "Clone repository into workspace", 69 commands: []string{ 70 "git init", 71 fmt.Sprintf("git remote add origin %s", repoURL), 72 fmt.Sprintf("git fetch %s", strings.Join(fetchArgs, " ")), 73 "git checkout FETCH_HEAD", 74 }, 75 } 76} 77 78// extractCommitSHA extracts the commit SHA from trigger metadata based on trigger type 79func extractCommitSHA(tr tangled.Pipeline_TriggerMetadata) (string, error) { 80 switch workflow.TriggerKind(tr.Kind) { 81 case workflow.TriggerKindPush: 82 if tr.Push == nil { 83 return "", fmt.Errorf("push trigger metadata is nil") 84 } 85 return tr.Push.NewSha, nil 86 87 case workflow.TriggerKindPullRequest: 88 if tr.PullRequest == nil { 89 return "", fmt.Errorf("pull request trigger metadata is nil") 90 } 91 return tr.PullRequest.SourceSha, nil 92 93 case workflow.TriggerKindManual: 94 // Manual triggers don't have an explicit SHA in the metadata 95 // For now, return empty string - could be enhanced to fetch from default branch 96 // TODO: Implement manual trigger SHA resolution (fetch default branch HEAD) 97 return "", nil 98 99 default: 100 return "", fmt.Errorf("unknown trigger kind: %s", tr.Kind) 101 } 102} 103 104// buildRepoURL constructs the repository URL from trigger metadata 105func buildRepoURL(tr tangled.Pipeline_TriggerMetadata, devMode bool) string { 106 if tr.Repo == nil { 107 return "" 108 } 109 110 // Determine protocol 111 scheme := "https://" 112 if devMode { 113 scheme = "http://" 114 } 115 116 // Get host from knot 117 host := tr.Repo.Knot 118 119 // In dev mode, replace localhost with host.docker.internal for Docker networking 120 if devMode && strings.Contains(host, "localhost") { 121 host = strings.ReplaceAll(host, "localhost", "host.docker.internal") 122 } 123 124 // Build URL: {scheme}{knot}/{did}/{repo} 125 return fmt.Sprintf("%s%s/%s/%s", scheme, host, tr.Repo.Did, tr.Repo.Repo) 126} 127 128// buildFetchArgs constructs the arguments for git fetch based on clone options 129func buildFetchArgs(clone tangled.Pipeline_CloneOpts, sha string) []string { 130 args := []string{} 131 132 // Set fetch depth (default to 1 for shallow clone) 133 depth := clone.Depth 134 if depth == 0 { 135 depth = 1 136 } 137 args = append(args, fmt.Sprintf("--depth=%d", depth)) 138 139 // Add submodules if requested 140 if clone.Submodules { 141 args = append(args, "--recurse-submodules=yes") 142 } 143 144 // Add remote and SHA 145 args = append(args, "origin") 146 if sha != "" { 147 args = append(args, sha) 148 } 149 150 return args 151}