+19
-58
spindle/engines/nixery/setup_steps.go
+19
-58
spindle/engines/nixery/setup_steps.go
···
2
2
3
3
import (
4
4
"fmt"
5
-
"path"
6
5
"strings"
7
6
8
7
"tangled.org/core/api/tangled"
9
-
"tangled.org/core/workflow"
8
+
"tangled.org/core/spindle/workflow"
10
9
)
11
10
12
11
func nixConfStep() Step {
···
19
18
}
20
19
}
21
20
22
-
// cloneOptsAsSteps processes clone options and adds corresponding steps
23
-
// to the beginning of the workflow's step list if cloning is not skipped.
24
-
//
25
-
// the steps to do here are:
21
+
// cloneStep uses the shared clone step builder to generate git clone commands.
22
+
// The shared builder handles:
26
23
// - git init
27
24
// - git remote add origin <url>
28
25
// - git fetch --depth=<d> --recurse-submodules=<yes|no> <sha>
29
26
// - git checkout FETCH_HEAD
27
+
// And supports all trigger types (push, PR, manual) and clone options.
30
28
func cloneStep(twf tangled.Pipeline_Workflow, tr tangled.Pipeline_TriggerMetadata, dev bool) Step {
31
-
if twf.Clone.Skip {
32
-
return Step{}
29
+
info, err := workflow.GetCloneInfo(workflow.CloneOptions{
30
+
Workflow: twf,
31
+
TriggerMetadata: tr,
32
+
DevMode: dev,
33
+
WorkspaceDir: workspaceDir,
34
+
})
35
+
if err != nil {
36
+
return Step{
37
+
command: fmt.Sprintf("echo 'Failed to get clone info: %s' && exit 1", err.Error()),
38
+
name: "Clone repository into workspace (error)",
39
+
}
33
40
}
34
41
35
-
var commands []string
36
-
37
-
// initialize git repo in workspace
38
-
commands = append(commands, "git init")
39
-
40
-
// add repo as git remote
41
-
scheme := "https://"
42
-
if dev {
43
-
scheme = "http://"
44
-
tr.Repo.Knot = strings.ReplaceAll(tr.Repo.Knot, "localhost", "host.docker.internal")
42
+
if info.Skip {
43
+
return Step{}
45
44
}
46
-
url := scheme + path.Join(tr.Repo.Knot, tr.Repo.Did, tr.Repo.Repo)
47
-
commands = append(commands, fmt.Sprintf("git remote add origin %s", url))
48
45
49
-
// run git fetch
50
-
{
51
-
var fetchArgs []string
52
-
53
-
// default clone depth is 1
54
-
depth := 1
55
-
if twf.Clone.Depth > 1 {
56
-
depth = int(twf.Clone.Depth)
57
-
}
58
-
fetchArgs = append(fetchArgs, fmt.Sprintf("--depth=%d", depth))
59
-
60
-
// optionally recurse submodules
61
-
if twf.Clone.Submodules {
62
-
fetchArgs = append(fetchArgs, "--recurse-submodules=yes")
63
-
}
64
-
65
-
// set remote to fetch from
66
-
fetchArgs = append(fetchArgs, "origin")
67
-
68
-
// set revision to checkout
69
-
switch workflow.TriggerKind(tr.Kind) {
70
-
case workflow.TriggerKindManual:
71
-
// TODO: unimplemented
72
-
case workflow.TriggerKindPush:
73
-
fetchArgs = append(fetchArgs, tr.Push.NewSha)
74
-
case workflow.TriggerKindPullRequest:
75
-
fetchArgs = append(fetchArgs, tr.PullRequest.SourceSha)
76
-
}
77
-
78
-
commands = append(commands, fmt.Sprintf("git fetch %s", strings.Join(fetchArgs, " ")))
79
-
}
80
-
81
-
// run git checkout
82
-
commands = append(commands, "git checkout FETCH_HEAD")
83
-
84
-
cloneStep := Step{
85
-
command: strings.Join(commands, "\n"),
46
+
return Step{
47
+
command: strings.Join(info.Commands, "\n"),
86
48
name: "Clone repository into workspace",
87
49
}
88
-
return cloneStep
89
50
}
90
51
91
52
// dependencyStep processes dependencies defined in the workflow.
+144
spindle/workflow/clone.go
+144
spindle/workflow/clone.go
···
1
+
package workflow
2
+
3
+
import (
4
+
"fmt"
5
+
"strings"
6
+
7
+
"tangled.org/core/api/tangled"
8
+
"tangled.org/core/workflow"
9
+
)
10
+
11
+
type CloneOptions struct {
12
+
Workflow tangled.Pipeline_Workflow
13
+
TriggerMetadata tangled.Pipeline_TriggerMetadata
14
+
DevMode bool
15
+
WorkspaceDir string
16
+
}
17
+
18
+
type CloneInfo struct {
19
+
Commands []string
20
+
RepoURL string
21
+
CommitSHA string
22
+
Skip bool
23
+
}
24
+
25
+
// GetCloneInfo generates git clone commands and metadata from pipeline trigger metadata
26
+
func GetCloneInfo(opts CloneOptions) (*CloneInfo, error) {
27
+
if opts.Workflow.Clone != nil && opts.Workflow.Clone.Skip {
28
+
return &CloneInfo{Skip: true}, nil
29
+
}
30
+
31
+
commitSHA, err := extractCommitSHA(opts.TriggerMetadata)
32
+
if err != nil {
33
+
return nil, fmt.Errorf("failed to extract commit SHA: %w", err)
34
+
}
35
+
36
+
repoURL := buildRepoURL(opts.TriggerMetadata, opts.DevMode)
37
+
38
+
workspaceDir := opts.WorkspaceDir
39
+
if workspaceDir == "" {
40
+
workspaceDir = "/tangled/workspace"
41
+
}
42
+
43
+
initCmd := fmt.Sprintf("git init %s", workspaceDir)
44
+
remoteCmd := fmt.Sprintf("git remote add origin %s", repoURL)
45
+
46
+
var cloneOpts tangled.Pipeline_CloneOpts
47
+
if opts.Workflow.Clone != nil {
48
+
cloneOpts = *opts.Workflow.Clone
49
+
}
50
+
fetchArgs := buildFetchArgs(cloneOpts, commitSHA)
51
+
fetchCmd := fmt.Sprintf("git fetch %s", strings.Join(fetchArgs, " "))
52
+
53
+
checkoutCmd := "git checkout FETCH_HEAD"
54
+
55
+
commands := []string{
56
+
initCmd,
57
+
fmt.Sprintf("cd %s", workspaceDir),
58
+
remoteCmd,
59
+
fetchCmd,
60
+
checkoutCmd,
61
+
}
62
+
63
+
return &CloneInfo{
64
+
Commands: commands,
65
+
RepoURL: repoURL,
66
+
CommitSHA: commitSHA,
67
+
Skip: false,
68
+
}, nil
69
+
}
70
+
71
+
// extractCommitSHA extracts the commit SHA from trigger metadata based on trigger type
72
+
func extractCommitSHA(tr tangled.Pipeline_TriggerMetadata) (string, error) {
73
+
switch workflow.TriggerKind(tr.Kind) {
74
+
case workflow.TriggerKindPush:
75
+
if tr.Push == nil {
76
+
return "", fmt.Errorf("push trigger metadata is nil")
77
+
}
78
+
return tr.Push.NewSha, nil
79
+
80
+
case workflow.TriggerKindPullRequest:
81
+
if tr.PullRequest == nil {
82
+
return "", fmt.Errorf("pull request trigger metadata is nil")
83
+
}
84
+
return tr.PullRequest.SourceSha, nil
85
+
86
+
case workflow.TriggerKindManual:
87
+
// Manual triggers don't have an explicit SHA in the metadata
88
+
// For now, return empty string - could be enhanced to fetch from default branch
89
+
// TODO: Implement manual trigger SHA resolution (fetch default branch HEAD)
90
+
return "", nil
91
+
92
+
default:
93
+
return "", fmt.Errorf("unknown trigger kind: %s", tr.Kind)
94
+
}
95
+
}
96
+
97
+
// buildRepoURL constructs the repository URL from trigger metadata
98
+
func buildRepoURL(tr tangled.Pipeline_TriggerMetadata, devMode bool) string {
99
+
if tr.Repo == nil {
100
+
return ""
101
+
}
102
+
103
+
// Determine protocol
104
+
scheme := "https://"
105
+
if devMode {
106
+
scheme = "http://"
107
+
}
108
+
109
+
// Get host from knot
110
+
host := tr.Repo.Knot
111
+
112
+
// In dev mode, replace localhost with host.docker.internal for Docker networking
113
+
if devMode && strings.Contains(host, "localhost") {
114
+
host = strings.ReplaceAll(host, "localhost", "host.docker.internal")
115
+
}
116
+
117
+
// Build URL: {scheme}{knot}/{did}/{repo}
118
+
return fmt.Sprintf("%s%s/%s/%s", scheme, host, tr.Repo.Did, tr.Repo.Repo)
119
+
}
120
+
121
+
// buildFetchArgs constructs the arguments for git fetch based on clone options
122
+
func buildFetchArgs(clone tangled.Pipeline_CloneOpts, sha string) []string {
123
+
args := []string{}
124
+
125
+
// Set fetch depth (default to 1 for shallow clone)
126
+
depth := clone.Depth
127
+
if depth == 0 {
128
+
depth = 1
129
+
}
130
+
args = append(args, fmt.Sprintf("--depth=%d", depth))
131
+
132
+
// Add submodules if requested
133
+
if clone.Submodules {
134
+
args = append(args, "--recurse-submodules=yes")
135
+
}
136
+
137
+
// Add remote and SHA
138
+
args = append(args, "origin")
139
+
if sha != "" {
140
+
args = append(args, sha)
141
+
}
142
+
143
+
return args
144
+
}
+420
spindle/workflow/clone_test.go
+420
spindle/workflow/clone_test.go
···
1
+
package workflow
2
+
3
+
import (
4
+
"strings"
5
+
"testing"
6
+
7
+
"tangled.org/core/api/tangled"
8
+
"tangled.org/core/workflow"
9
+
)
10
+
11
+
func TestGetCloneInfo_PushTrigger(t *testing.T) {
12
+
cfg := CloneOptions{
13
+
Workflow: tangled.Pipeline_Workflow{
14
+
Clone: &tangled.Pipeline_CloneOpts{
15
+
Depth: 1,
16
+
Submodules: false,
17
+
Skip: false,
18
+
},
19
+
},
20
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
21
+
Kind: string(workflow.TriggerKindPush),
22
+
Push: &tangled.Pipeline_PushTriggerData{
23
+
NewSha: "abc123",
24
+
OldSha: "def456",
25
+
Ref: "refs/heads/main",
26
+
},
27
+
Repo: &tangled.Pipeline_TriggerRepo{
28
+
Knot: "example.com",
29
+
Did: "did:plc:user123",
30
+
Repo: "my-repo",
31
+
},
32
+
},
33
+
DevMode: false,
34
+
WorkspaceDir: "/tangled/workspace",
35
+
}
36
+
37
+
info, err := GetCloneInfo(cfg)
38
+
if err != nil {
39
+
t.Fatalf("GetCloneInfo failed: %v", err)
40
+
}
41
+
42
+
if info.Skip {
43
+
t.Error("Expected Skip to be false")
44
+
}
45
+
46
+
if info.CommitSHA != "abc123" {
47
+
t.Errorf("Expected CommitSHA 'abc123', got '%s'", info.CommitSHA)
48
+
}
49
+
50
+
expectedURL := "https://example.com/did:plc:user123/my-repo"
51
+
if info.RepoURL != expectedURL {
52
+
t.Errorf("Expected RepoURL '%s', got '%s'", expectedURL, info.RepoURL)
53
+
}
54
+
55
+
if len(info.Commands) != 5 {
56
+
t.Errorf("Expected 5 commands, got %d", len(info.Commands))
57
+
}
58
+
59
+
// Verify commands contain expected git operations
60
+
allCmds := strings.Join(info.Commands, " ")
61
+
if !strings.Contains(allCmds, "git init") {
62
+
t.Error("Commands should contain 'git init'")
63
+
}
64
+
if !strings.Contains(allCmds, "git remote add origin") {
65
+
t.Error("Commands should contain 'git remote add origin'")
66
+
}
67
+
if !strings.Contains(allCmds, "git fetch") {
68
+
t.Error("Commands should contain 'git fetch'")
69
+
}
70
+
if !strings.Contains(allCmds, "abc123") {
71
+
t.Error("Commands should contain commit SHA")
72
+
}
73
+
if !strings.Contains(allCmds, "git checkout FETCH_HEAD") {
74
+
t.Error("Commands should contain 'git checkout FETCH_HEAD'")
75
+
}
76
+
}
77
+
78
+
func TestGetCloneInfo_PullRequestTrigger(t *testing.T) {
79
+
cfg := CloneOptions{
80
+
Workflow: tangled.Pipeline_Workflow{
81
+
Clone: &tangled.Pipeline_CloneOpts{
82
+
Depth: 1,
83
+
Skip: false,
84
+
},
85
+
},
86
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
87
+
Kind: string(workflow.TriggerKindPullRequest),
88
+
PullRequest: &tangled.Pipeline_PullRequestTriggerData{
89
+
SourceSha: "pr-sha-789",
90
+
SourceBranch: "feature-branch",
91
+
TargetBranch: "main",
92
+
Action: "opened",
93
+
},
94
+
Repo: &tangled.Pipeline_TriggerRepo{
95
+
Knot: "example.com",
96
+
Did: "did:plc:user123",
97
+
Repo: "my-repo",
98
+
},
99
+
},
100
+
DevMode: false,
101
+
WorkspaceDir: "/tangled/workspace",
102
+
}
103
+
104
+
info, err := GetCloneInfo(cfg)
105
+
if err != nil {
106
+
t.Fatalf("GetCloneInfo failed: %v", err)
107
+
}
108
+
109
+
if info.CommitSHA != "pr-sha-789" {
110
+
t.Errorf("Expected CommitSHA 'pr-sha-789', got '%s'", info.CommitSHA)
111
+
}
112
+
113
+
allCmds := strings.Join(info.Commands, " ")
114
+
if !strings.Contains(allCmds, "pr-sha-789") {
115
+
t.Error("Commands should contain PR commit SHA")
116
+
}
117
+
}
118
+
119
+
func TestGetCloneInfo_ManualTrigger(t *testing.T) {
120
+
cfg := CloneOptions{
121
+
Workflow: tangled.Pipeline_Workflow{
122
+
Clone: &tangled.Pipeline_CloneOpts{
123
+
Depth: 1,
124
+
Skip: false,
125
+
},
126
+
},
127
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
128
+
Kind: string(workflow.TriggerKindManual),
129
+
Manual: &tangled.Pipeline_ManualTriggerData{
130
+
Inputs: nil,
131
+
},
132
+
Repo: &tangled.Pipeline_TriggerRepo{
133
+
Knot: "example.com",
134
+
Did: "did:plc:user123",
135
+
Repo: "my-repo",
136
+
},
137
+
},
138
+
DevMode: false,
139
+
WorkspaceDir: "/tangled/workspace",
140
+
}
141
+
142
+
info, err := GetCloneInfo(cfg)
143
+
if err != nil {
144
+
t.Fatalf("GetCloneInfo failed: %v", err)
145
+
}
146
+
147
+
// Manual triggers don't have a SHA yet (TODO)
148
+
if info.CommitSHA != "" {
149
+
t.Errorf("Expected empty CommitSHA for manual trigger, got '%s'", info.CommitSHA)
150
+
}
151
+
}
152
+
153
+
func TestGetCloneInfo_SkipFlag(t *testing.T) {
154
+
cfg := CloneOptions{
155
+
Workflow: tangled.Pipeline_Workflow{
156
+
Clone: &tangled.Pipeline_CloneOpts{
157
+
Skip: true,
158
+
},
159
+
},
160
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
161
+
Kind: string(workflow.TriggerKindPush),
162
+
Push: &tangled.Pipeline_PushTriggerData{
163
+
NewSha: "abc123",
164
+
},
165
+
Repo: &tangled.Pipeline_TriggerRepo{
166
+
Knot: "example.com",
167
+
Did: "did:plc:user123",
168
+
Repo: "my-repo",
169
+
},
170
+
},
171
+
}
172
+
173
+
info, err := GetCloneInfo(cfg)
174
+
if err != nil {
175
+
t.Fatalf("GetCloneInfo failed: %v", err)
176
+
}
177
+
178
+
if !info.Skip {
179
+
t.Error("Expected Skip to be true")
180
+
}
181
+
182
+
if len(info.Commands) != 0 {
183
+
t.Errorf("Expected no commands when Skip is true, got %d commands", len(info.Commands))
184
+
}
185
+
}
186
+
187
+
func TestGetCloneInfo_DevMode(t *testing.T) {
188
+
cfg := CloneOptions{
189
+
Workflow: tangled.Pipeline_Workflow{
190
+
Clone: &tangled.Pipeline_CloneOpts{
191
+
Depth: 1,
192
+
Skip: false,
193
+
},
194
+
},
195
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
196
+
Kind: string(workflow.TriggerKindPush),
197
+
Push: &tangled.Pipeline_PushTriggerData{
198
+
NewSha: "abc123",
199
+
},
200
+
Repo: &tangled.Pipeline_TriggerRepo{
201
+
Knot: "localhost:3000",
202
+
Did: "did:plc:user123",
203
+
Repo: "my-repo",
204
+
},
205
+
},
206
+
DevMode: true,
207
+
WorkspaceDir: "/tangled/workspace",
208
+
}
209
+
210
+
info, err := GetCloneInfo(cfg)
211
+
if err != nil {
212
+
t.Fatalf("GetCloneInfo failed: %v", err)
213
+
}
214
+
215
+
// In dev mode, should use http:// and replace localhost with host.docker.internal
216
+
expectedURL := "http://host.docker.internal:3000/did:plc:user123/my-repo"
217
+
if info.RepoURL != expectedURL {
218
+
t.Errorf("Expected dev mode URL '%s', got '%s'", expectedURL, info.RepoURL)
219
+
}
220
+
}
221
+
222
+
func TestGetCloneInfo_DepthAndSubmodules(t *testing.T) {
223
+
cfg := CloneOptions{
224
+
Workflow: tangled.Pipeline_Workflow{
225
+
Clone: &tangled.Pipeline_CloneOpts{
226
+
Depth: 10,
227
+
Submodules: true,
228
+
Skip: false,
229
+
},
230
+
},
231
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
232
+
Kind: string(workflow.TriggerKindPush),
233
+
Push: &tangled.Pipeline_PushTriggerData{
234
+
NewSha: "abc123",
235
+
},
236
+
Repo: &tangled.Pipeline_TriggerRepo{
237
+
Knot: "example.com",
238
+
Did: "did:plc:user123",
239
+
Repo: "my-repo",
240
+
},
241
+
},
242
+
DevMode: false,
243
+
WorkspaceDir: "/tangled/workspace",
244
+
}
245
+
246
+
info, err := GetCloneInfo(cfg)
247
+
if err != nil {
248
+
t.Fatalf("GetCloneInfo failed: %v", err)
249
+
}
250
+
251
+
allCmds := strings.Join(info.Commands, " ")
252
+
if !strings.Contains(allCmds, "--depth=10") {
253
+
t.Error("Commands should contain '--depth=10'")
254
+
}
255
+
256
+
if !strings.Contains(allCmds, "--recurse-submodules=yes") {
257
+
t.Error("Commands should contain '--recurse-submodules=yes'")
258
+
}
259
+
}
260
+
261
+
func TestGetCloneInfo_DefaultDepth(t *testing.T) {
262
+
cfg := CloneOptions{
263
+
Workflow: tangled.Pipeline_Workflow{
264
+
Clone: &tangled.Pipeline_CloneOpts{
265
+
Depth: 0, // Default should be 1
266
+
Skip: false,
267
+
},
268
+
},
269
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
270
+
Kind: string(workflow.TriggerKindPush),
271
+
Push: &tangled.Pipeline_PushTriggerData{
272
+
NewSha: "abc123",
273
+
},
274
+
Repo: &tangled.Pipeline_TriggerRepo{
275
+
Knot: "example.com",
276
+
Did: "did:plc:user123",
277
+
Repo: "my-repo",
278
+
},
279
+
},
280
+
WorkspaceDir: "/tangled/workspace",
281
+
}
282
+
283
+
info, err := GetCloneInfo(cfg)
284
+
if err != nil {
285
+
t.Fatalf("GetCloneInfo failed: %v", err)
286
+
}
287
+
288
+
allCmds := strings.Join(info.Commands, " ")
289
+
if !strings.Contains(allCmds, "--depth=1") {
290
+
t.Error("Commands should default to '--depth=1'")
291
+
}
292
+
}
293
+
294
+
func TestGetCloneInfo_NilPushData(t *testing.T) {
295
+
cfg := CloneOptions{
296
+
Workflow: tangled.Pipeline_Workflow{
297
+
Clone: &tangled.Pipeline_CloneOpts{
298
+
Depth: 1,
299
+
Skip: false,
300
+
},
301
+
},
302
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
303
+
Kind: string(workflow.TriggerKindPush),
304
+
Push: nil, // Nil push data should return error
305
+
Repo: &tangled.Pipeline_TriggerRepo{
306
+
Knot: "example.com",
307
+
Did: "did:plc:user123",
308
+
Repo: "my-repo",
309
+
},
310
+
},
311
+
WorkspaceDir: "/tangled/workspace",
312
+
}
313
+
314
+
_, err := GetCloneInfo(cfg)
315
+
if err == nil {
316
+
t.Error("Expected error when push data is nil")
317
+
}
318
+
319
+
if !strings.Contains(err.Error(), "push trigger metadata is nil") {
320
+
t.Errorf("Expected error about nil push metadata, got: %v", err)
321
+
}
322
+
}
323
+
324
+
func TestGetCloneInfo_NilPRData(t *testing.T) {
325
+
cfg := CloneOptions{
326
+
Workflow: tangled.Pipeline_Workflow{
327
+
Clone: &tangled.Pipeline_CloneOpts{
328
+
Depth: 1,
329
+
Skip: false,
330
+
},
331
+
},
332
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
333
+
Kind: string(workflow.TriggerKindPullRequest),
334
+
PullRequest: nil, // Nil PR data should return error
335
+
Repo: &tangled.Pipeline_TriggerRepo{
336
+
Knot: "example.com",
337
+
Did: "did:plc:user123",
338
+
Repo: "my-repo",
339
+
},
340
+
},
341
+
WorkspaceDir: "/tangled/workspace",
342
+
}
343
+
344
+
_, err := GetCloneInfo(cfg)
345
+
if err == nil {
346
+
t.Error("Expected error when pull request data is nil")
347
+
}
348
+
349
+
if !strings.Contains(err.Error(), "pull request trigger metadata is nil") {
350
+
t.Errorf("Expected error about nil PR metadata, got: %v", err)
351
+
}
352
+
}
353
+
354
+
func TestGetCloneInfo_CustomWorkspace(t *testing.T) {
355
+
cfg := CloneOptions{
356
+
Workflow: tangled.Pipeline_Workflow{
357
+
Clone: &tangled.Pipeline_CloneOpts{
358
+
Depth: 1,
359
+
Skip: false,
360
+
},
361
+
},
362
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
363
+
Kind: string(workflow.TriggerKindPush),
364
+
Push: &tangled.Pipeline_PushTriggerData{
365
+
NewSha: "abc123",
366
+
},
367
+
Repo: &tangled.Pipeline_TriggerRepo{
368
+
Knot: "example.com",
369
+
Did: "did:plc:user123",
370
+
Repo: "my-repo",
371
+
},
372
+
},
373
+
DevMode: false,
374
+
WorkspaceDir: "/custom/path",
375
+
}
376
+
377
+
info, err := GetCloneInfo(cfg)
378
+
if err != nil {
379
+
t.Fatalf("GetCloneInfo failed: %v", err)
380
+
}
381
+
382
+
allCmds := strings.Join(info.Commands, " ")
383
+
if !strings.Contains(allCmds, "/custom/path") {
384
+
t.Error("Commands should use custom workspace directory")
385
+
}
386
+
}
387
+
388
+
func TestGetCloneInfo_DefaultWorkspace(t *testing.T) {
389
+
cfg := CloneOptions{
390
+
Workflow: tangled.Pipeline_Workflow{
391
+
Clone: &tangled.Pipeline_CloneOpts{
392
+
Depth: 1,
393
+
Skip: false,
394
+
},
395
+
},
396
+
TriggerMetadata: tangled.Pipeline_TriggerMetadata{
397
+
Kind: string(workflow.TriggerKindPush),
398
+
Push: &tangled.Pipeline_PushTriggerData{
399
+
NewSha: "abc123",
400
+
},
401
+
Repo: &tangled.Pipeline_TriggerRepo{
402
+
Knot: "example.com",
403
+
Did: "did:plc:user123",
404
+
Repo: "my-repo",
405
+
},
406
+
},
407
+
DevMode: false,
408
+
WorkspaceDir: "", // Empty should default to /tangled/workspace
409
+
}
410
+
411
+
info, err := GetCloneInfo(cfg)
412
+
if err != nil {
413
+
t.Fatalf("GetCloneInfo failed: %v", err)
414
+
}
415
+
416
+
allCmds := strings.Join(info.Commands, " ")
417
+
if !strings.Contains(allCmds, "/tangled/workspace") {
418
+
t.Error("Commands should default to /tangled/workspace")
419
+
}
420
+
}