forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1package steps
2
3import (
4 "fmt"
5 "strings"
6
7 "tangled.org/core/api/tangled"
8 "tangled.org/core/workflow"
9)
10
11// BuildCloneCommands generates git clone commands from pipeline trigger metadata
12// Returns engine-agnostic command strings that engines can execute in their own way
13func BuildCloneCommands(cfg CloneConfig) (*CloneCommands, error) {
14 // Check if cloning should be skipped
15 if cfg.Workflow.Clone != nil && cfg.Workflow.Clone.Skip {
16 return &CloneCommands{Skip: true}, nil
17 }
18
19 // Extract commit SHA based on trigger type
20 commitSHA, err := extractCommitSHA(cfg.TriggerMetadata)
21 if err != nil {
22 return nil, fmt.Errorf("failed to extract commit SHA: %w", err)
23 }
24
25 // Build repository URL
26 repoURL := buildRepoURL(cfg.TriggerMetadata, cfg.DevMode)
27
28 // Set default workspace if not provided
29 workspaceDir := cfg.WorkspaceDir
30 if workspaceDir == "" {
31 workspaceDir = "/tangled/workspace"
32 }
33
34 // Build individual git commands
35 initCmd := fmt.Sprintf("git init %s", workspaceDir)
36 remoteCmd := fmt.Sprintf("git remote add origin %s", repoURL)
37
38 // Build fetch command with options
39 var cloneOpts tangled.Pipeline_CloneOpts
40 if cfg.Workflow.Clone != nil {
41 cloneOpts = *cfg.Workflow.Clone
42 }
43 fetchArgs := buildFetchArgs(cloneOpts, commitSHA)
44 fetchCmd := fmt.Sprintf("git fetch %s", strings.Join(fetchArgs, " "))
45
46 checkoutCmd := "git checkout FETCH_HEAD"
47
48 // Combine all commands
49 allCmds := []string{
50 initCmd,
51 fmt.Sprintf("cd %s", workspaceDir),
52 remoteCmd,
53 fetchCmd,
54 checkoutCmd,
55 }
56
57 return &CloneCommands{
58 Init: initCmd,
59 Remote: remoteCmd,
60 Fetch: fetchCmd,
61 Checkout: checkoutCmd,
62 All: allCmds,
63 RepoURL: repoURL,
64 CommitSHA: commitSHA,
65 Skip: false,
66 }, nil
67}
68
69// extractCommitSHA extracts the commit SHA from trigger metadata based on trigger type
70func extractCommitSHA(tr tangled.Pipeline_TriggerMetadata) (string, error) {
71 switch workflow.TriggerKind(tr.Kind) {
72 case workflow.TriggerKindPush:
73 if tr.Push == nil {
74 return "", fmt.Errorf("push trigger metadata is nil")
75 }
76 return tr.Push.NewSha, nil
77
78 case workflow.TriggerKindPullRequest:
79 if tr.PullRequest == nil {
80 return "", fmt.Errorf("pull request trigger metadata is nil")
81 }
82 return tr.PullRequest.SourceSha, nil
83
84 case workflow.TriggerKindManual:
85 // Manual triggers don't have an explicit SHA in the metadata
86 // For now, return empty string - could be enhanced to fetch from default branch
87 // TODO: Implement manual trigger SHA resolution (fetch default branch HEAD)
88 return "", nil
89
90 default:
91 return "", fmt.Errorf("unknown trigger kind: %s", tr.Kind)
92 }
93}
94
95// buildRepoURL constructs the repository URL from trigger metadata
96func buildRepoURL(tr tangled.Pipeline_TriggerMetadata, devMode bool) string {
97 if tr.Repo == nil {
98 return ""
99 }
100
101 // Determine protocol
102 scheme := "https://"
103 if devMode {
104 scheme = "http://"
105 }
106
107 // Get host from knot
108 host := tr.Repo.Knot
109
110 // In dev mode, replace localhost with host.docker.internal for Docker networking
111 if devMode && strings.Contains(host, "localhost") {
112 host = strings.ReplaceAll(host, "localhost", "host.docker.internal")
113 }
114
115 // Build URL: {scheme}{knot}/{did}/{repo}
116 return fmt.Sprintf("%s%s/%s/%s", scheme, host, tr.Repo.Did, tr.Repo.Repo)
117}
118
119// buildFetchArgs constructs the arguments for git fetch based on clone options
120func buildFetchArgs(clone tangled.Pipeline_CloneOpts, sha string) []string {
121 args := []string{}
122
123 // Set fetch depth (default to 1 for shallow clone)
124 depth := clone.Depth
125 if depth == 0 {
126 depth = 1
127 }
128 args = append(args, fmt.Sprintf("--depth=%d", depth))
129
130 // Add submodules if requested
131 if clone.Submodules {
132 args = append(args, "--recurse-submodules=yes")
133 }
134
135 // Add remote and SHA
136 args = append(args, "origin")
137 if sha != "" {
138 args = append(args, sha)
139 }
140
141 return args
142}