1package steps
2
3import (
4 "strings"
5 "testing"
6
7 "tangled.org/core/api/tangled"
8 "tangled.org/core/workflow"
9)
10
11func TestBuildCloneCommands_PushTrigger(t *testing.T) {
12 cfg := CloneConfig{
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 cmds, err := BuildCloneCommands(cfg)
38 if err != nil {
39 t.Fatalf("BuildCloneCommands failed: %v", err)
40 }
41
42 if cmds.Skip {
43 t.Error("Expected Skip to be false")
44 }
45
46 if cmds.CommitSHA != "abc123" {
47 t.Errorf("Expected CommitSHA 'abc123', got '%s'", cmds.CommitSHA)
48 }
49
50 expectedURL := "https://example.com/did:plc:user123/my-repo"
51 if cmds.RepoURL != expectedURL {
52 t.Errorf("Expected RepoURL '%s', got '%s'", expectedURL, cmds.RepoURL)
53 }
54
55 if !strings.Contains(cmds.Init, "git init") {
56 t.Error("Init command should contain 'git init'")
57 }
58
59 if !strings.Contains(cmds.Remote, "git remote add origin") {
60 t.Error("Remote command should contain 'git remote add origin'")
61 }
62
63 if !strings.Contains(cmds.Fetch, "git fetch") {
64 t.Error("Fetch command should contain 'git fetch'")
65 }
66
67 if !strings.Contains(cmds.Fetch, "abc123") {
68 t.Error("Fetch command should contain commit SHA")
69 }
70
71 if cmds.Checkout != "git checkout FETCH_HEAD" {
72 t.Errorf("Expected Checkout 'git checkout FETCH_HEAD', got '%s'", cmds.Checkout)
73 }
74
75 if len(cmds.All) != 5 {
76 t.Errorf("Expected 5 commands, got %d", len(cmds.All))
77 }
78}
79
80func TestBuildCloneCommands_PullRequestTrigger(t *testing.T) {
81 cfg := CloneConfig{
82 Workflow: tangled.Pipeline_Workflow{
83 Clone: &tangled.Pipeline_CloneOpts{
84 Depth: 1,
85 Skip: false,
86 },
87 },
88 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
89 Kind: string(workflow.TriggerKindPullRequest),
90 PullRequest: &tangled.Pipeline_PullRequestTriggerData{
91 SourceSha: "pr-sha-789",
92 SourceBranch: "feature-branch",
93 TargetBranch: "main",
94 Action: "opened",
95 },
96 Repo: &tangled.Pipeline_TriggerRepo{
97 Knot: "example.com",
98 Did: "did:plc:user123",
99 Repo: "my-repo",
100 },
101 },
102 DevMode: false,
103 WorkspaceDir: "/tangled/workspace",
104 }
105
106 cmds, err := BuildCloneCommands(cfg)
107 if err != nil {
108 t.Fatalf("BuildCloneCommands failed: %v", err)
109 }
110
111 if cmds.CommitSHA != "pr-sha-789" {
112 t.Errorf("Expected CommitSHA 'pr-sha-789', got '%s'", cmds.CommitSHA)
113 }
114
115 if !strings.Contains(cmds.Fetch, "pr-sha-789") {
116 t.Error("Fetch command should contain PR commit SHA")
117 }
118}
119
120func TestBuildCloneCommands_ManualTrigger(t *testing.T) {
121 cfg := CloneConfig{
122 Workflow: tangled.Pipeline_Workflow{
123 Clone: &tangled.Pipeline_CloneOpts{
124 Depth: 1,
125 Skip: false,
126 },
127 },
128 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
129 Kind: string(workflow.TriggerKindManual),
130 Manual: &tangled.Pipeline_ManualTriggerData{
131 Inputs: nil,
132 },
133 Repo: &tangled.Pipeline_TriggerRepo{
134 Knot: "example.com",
135 Did: "did:plc:user123",
136 Repo: "my-repo",
137 },
138 },
139 DevMode: false,
140 WorkspaceDir: "/tangled/workspace",
141 }
142
143 cmds, err := BuildCloneCommands(cfg)
144 if err != nil {
145 t.Fatalf("BuildCloneCommands failed: %v", err)
146 }
147
148 // Manual triggers don't have a SHA yet (TODO)
149 if cmds.CommitSHA != "" {
150 t.Errorf("Expected empty CommitSHA for manual trigger, got '%s'", cmds.CommitSHA)
151 }
152}
153
154func TestBuildCloneCommands_SkipFlag(t *testing.T) {
155 cfg := CloneConfig{
156 Workflow: tangled.Pipeline_Workflow{
157 Clone: &tangled.Pipeline_CloneOpts{
158 Skip: true,
159 },
160 },
161 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
162 Kind: string(workflow.TriggerKindPush),
163 Push: &tangled.Pipeline_PushTriggerData{
164 NewSha: "abc123",
165 },
166 Repo: &tangled.Pipeline_TriggerRepo{
167 Knot: "example.com",
168 Did: "did:plc:user123",
169 Repo: "my-repo",
170 },
171 },
172 }
173
174 cmds, err := BuildCloneCommands(cfg)
175 if err != nil {
176 t.Fatalf("BuildCloneCommands failed: %v", err)
177 }
178
179 if !cmds.Skip {
180 t.Error("Expected Skip to be true")
181 }
182
183 if len(cmds.All) != 0 {
184 t.Errorf("Expected no commands when Skip is true, got %d commands", len(cmds.All))
185 }
186}
187
188func TestBuildCloneCommands_DevMode(t *testing.T) {
189 cfg := CloneConfig{
190 Workflow: tangled.Pipeline_Workflow{
191 Clone: &tangled.Pipeline_CloneOpts{
192 Depth: 1,
193 Skip: false,
194 },
195 },
196 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
197 Kind: string(workflow.TriggerKindPush),
198 Push: &tangled.Pipeline_PushTriggerData{
199 NewSha: "abc123",
200 },
201 Repo: &tangled.Pipeline_TriggerRepo{
202 Knot: "localhost:3000",
203 Did: "did:plc:user123",
204 Repo: "my-repo",
205 },
206 },
207 DevMode: true,
208 WorkspaceDir: "/tangled/workspace",
209 }
210
211 cmds, err := BuildCloneCommands(cfg)
212 if err != nil {
213 t.Fatalf("BuildCloneCommands failed: %v", err)
214 }
215
216 // In dev mode, should use http:// and replace localhost with host.docker.internal
217 expectedURL := "http://host.docker.internal:3000/did:plc:user123/my-repo"
218 if cmds.RepoURL != expectedURL {
219 t.Errorf("Expected dev mode URL '%s', got '%s'", expectedURL, cmds.RepoURL)
220 }
221}
222
223func TestBuildCloneCommands_DepthAndSubmodules(t *testing.T) {
224 cfg := CloneConfig{
225 Workflow: tangled.Pipeline_Workflow{
226 Clone: &tangled.Pipeline_CloneOpts{
227 Depth: 10,
228 Submodules: true,
229 Skip: false,
230 },
231 },
232 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
233 Kind: string(workflow.TriggerKindPush),
234 Push: &tangled.Pipeline_PushTriggerData{
235 NewSha: "abc123",
236 },
237 Repo: &tangled.Pipeline_TriggerRepo{
238 Knot: "example.com",
239 Did: "did:plc:user123",
240 Repo: "my-repo",
241 },
242 },
243 DevMode: false,
244 WorkspaceDir: "/tangled/workspace",
245 }
246
247 cmds, err := BuildCloneCommands(cfg)
248 if err != nil {
249 t.Fatalf("BuildCloneCommands failed: %v", err)
250 }
251
252 if !strings.Contains(cmds.Fetch, "--depth=10") {
253 t.Error("Fetch command should contain '--depth=10'")
254 }
255
256 if !strings.Contains(cmds.Fetch, "--recurse-submodules=yes") {
257 t.Error("Fetch command should contain '--recurse-submodules=yes'")
258 }
259}
260
261func TestBuildCloneCommands_DefaultDepth(t *testing.T) {
262 cfg := CloneConfig{
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 cmds, err := BuildCloneCommands(cfg)
284 if err != nil {
285 t.Fatalf("BuildCloneCommands failed: %v", err)
286 }
287
288 if !strings.Contains(cmds.Fetch, "--depth=1") {
289 t.Error("Fetch command should default to '--depth=1'")
290 }
291}
292
293func TestBuildCloneCommands_NilPushData(t *testing.T) {
294 cfg := CloneConfig{
295 Workflow: tangled.Pipeline_Workflow{
296 Clone: &tangled.Pipeline_CloneOpts{
297 Depth: 1,
298 Skip: false,
299 },
300 },
301 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
302 Kind: string(workflow.TriggerKindPush),
303 Push: nil, // Nil push data should return error
304 Repo: &tangled.Pipeline_TriggerRepo{
305 Knot: "example.com",
306 Did: "did:plc:user123",
307 Repo: "my-repo",
308 },
309 },
310 WorkspaceDir: "/tangled/workspace",
311 }
312
313 _, err := BuildCloneCommands(cfg)
314 if err == nil {
315 t.Error("Expected error when push data is nil")
316 }
317
318 if !strings.Contains(err.Error(), "push trigger metadata is nil") {
319 t.Errorf("Expected error about nil push metadata, got: %v", err)
320 }
321}
322
323func TestBuildCloneCommands_NilPRData(t *testing.T) {
324 cfg := CloneConfig{
325 Workflow: tangled.Pipeline_Workflow{
326 Clone: &tangled.Pipeline_CloneOpts{
327 Depth: 1,
328 Skip: false,
329 },
330 },
331 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
332 Kind: string(workflow.TriggerKindPullRequest),
333 PullRequest: nil, // Nil PR data should return error
334 Repo: &tangled.Pipeline_TriggerRepo{
335 Knot: "example.com",
336 Did: "did:plc:user123",
337 Repo: "my-repo",
338 },
339 },
340 WorkspaceDir: "/tangled/workspace",
341 }
342
343 _, err := BuildCloneCommands(cfg)
344 if err == nil {
345 t.Error("Expected error when pull request data is nil")
346 }
347
348 if !strings.Contains(err.Error(), "pull request trigger metadata is nil") {
349 t.Errorf("Expected error about nil PR metadata, got: %v", err)
350 }
351}
352
353func TestBuildCloneCommands_CustomWorkspace(t *testing.T) {
354 cfg := CloneConfig{
355 Workflow: tangled.Pipeline_Workflow{
356 Clone: &tangled.Pipeline_CloneOpts{
357 Depth: 1,
358 Skip: false,
359 },
360 },
361 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
362 Kind: string(workflow.TriggerKindPush),
363 Push: &tangled.Pipeline_PushTriggerData{
364 NewSha: "abc123",
365 },
366 Repo: &tangled.Pipeline_TriggerRepo{
367 Knot: "example.com",
368 Did: "did:plc:user123",
369 Repo: "my-repo",
370 },
371 },
372 DevMode: false,
373 WorkspaceDir: "/custom/path",
374 }
375
376 cmds, err := BuildCloneCommands(cfg)
377 if err != nil {
378 t.Fatalf("BuildCloneCommands failed: %v", err)
379 }
380
381 if !strings.Contains(cmds.Init, "/custom/path") {
382 t.Error("Init command should use custom workspace directory")
383 }
384
385 if !strings.Contains(cmds.All[1], "/custom/path") {
386 t.Error("cd command should use custom workspace directory")
387 }
388}
389
390func TestBuildCloneCommands_DefaultWorkspace(t *testing.T) {
391 cfg := CloneConfig{
392 Workflow: tangled.Pipeline_Workflow{
393 Clone: &tangled.Pipeline_CloneOpts{
394 Depth: 1,
395 Skip: false,
396 },
397 },
398 TriggerMetadata: tangled.Pipeline_TriggerMetadata{
399 Kind: string(workflow.TriggerKindPush),
400 Push: &tangled.Pipeline_PushTriggerData{
401 NewSha: "abc123",
402 },
403 Repo: &tangled.Pipeline_TriggerRepo{
404 Knot: "example.com",
405 Did: "did:plc:user123",
406 Repo: "my-repo",
407 },
408 },
409 DevMode: false,
410 WorkspaceDir: "", // Empty should default to /tangled/workspace
411 }
412
413 cmds, err := BuildCloneCommands(cfg)
414 if err != nil {
415 t.Fatalf("BuildCloneCommands failed: %v", err)
416 }
417
418 if !strings.Contains(cmds.Init, "/tangled/workspace") {
419 t.Error("Init command should default to /tangled/workspace")
420 }
421}