forked from
tangled.org/core
Monorepo for Tangled
1package models
2
3import (
4 "strings"
5 "testing"
6
7 "tangled.org/core/api/tangled"
8 "tangled.org/core/workflow"
9)
10
11func sp(s string) *string { return &s }
12
13func TestBuildCloneStep_PushTrigger(t *testing.T) {
14 twf := tangled.Pipeline_Workflow{
15 Clone: &tangled.Pipeline_CloneOpts{
16 Depth: 1,
17 Submodules: false,
18 Skip: false,
19 },
20 }
21 tr := tangled.Pipeline_TriggerMetadata{
22 Kind: string(workflow.TriggerKindPush),
23 Push: &tangled.Pipeline_PushTriggerData{
24 NewSha: "abc123",
25 OldSha: "def456",
26 Ref: "refs/heads/main",
27 },
28 Repo: &tangled.Pipeline_TriggerRepo{
29 Knot: "example.com",
30 Did: "did:plc:user123",
31 Repo: sp("my-repo"),
32 },
33 }
34
35 step := BuildCloneStep(twf, tr, false)
36
37 if step.Kind() != StepKindSystem {
38 t.Errorf("Expected StepKindSystem, got %v", step.Kind())
39 }
40
41 if step.Name() != "Clone repository into workspace" {
42 t.Errorf("Expected 'Clone repository into workspace', got '%s'", step.Name())
43 }
44
45 commands := step.Commands()
46 if len(commands) != 4 {
47 t.Errorf("Expected 4 commands, got %d", len(commands))
48 }
49
50 // Verify commands contain expected git operations
51 allCmds := strings.Join(commands, " ")
52 if !strings.Contains(allCmds, "git init") {
53 t.Error("Commands should contain 'git init'")
54 }
55 if !strings.Contains(allCmds, "git remote add origin") {
56 t.Error("Commands should contain 'git remote add origin'")
57 }
58 if !strings.Contains(allCmds, "git fetch") {
59 t.Error("Commands should contain 'git fetch'")
60 }
61 if !strings.Contains(allCmds, "abc123") {
62 t.Error("Commands should contain commit SHA")
63 }
64 if !strings.Contains(allCmds, "git checkout FETCH_HEAD") {
65 t.Error("Commands should contain 'git checkout FETCH_HEAD'")
66 }
67 if !strings.Contains(allCmds, "https://example.com/did:plc:user123/my-repo") {
68 t.Error("Commands should contain expected repo URL")
69 }
70}
71
72func TestBuildCloneStep_PullRequestTrigger(t *testing.T) {
73 twf := tangled.Pipeline_Workflow{
74 Clone: &tangled.Pipeline_CloneOpts{
75 Depth: 1,
76 Skip: false,
77 },
78 }
79 tr := tangled.Pipeline_TriggerMetadata{
80 Kind: string(workflow.TriggerKindPullRequest),
81 PullRequest: &tangled.Pipeline_PullRequestTriggerData{
82 SourceSha: "pr-sha-789",
83 SourceBranch: "feature-branch",
84 TargetBranch: "main",
85 Action: "opened",
86 },
87 Repo: &tangled.Pipeline_TriggerRepo{
88 Knot: "example.com",
89 Did: "did:plc:user123",
90 Repo: sp("my-repo"),
91 },
92 }
93
94 step := BuildCloneStep(twf, tr, false)
95
96 allCmds := strings.Join(step.Commands(), " ")
97 if !strings.Contains(allCmds, "pr-sha-789") {
98 t.Error("Commands should contain PR commit SHA")
99 }
100}
101
102func TestBuildCloneStep_ManualTrigger(t *testing.T) {
103 twf := tangled.Pipeline_Workflow{
104 Clone: &tangled.Pipeline_CloneOpts{
105 Depth: 1,
106 Skip: false,
107 },
108 }
109 tr := tangled.Pipeline_TriggerMetadata{
110 Kind: string(workflow.TriggerKindManual),
111 Manual: &tangled.Pipeline_ManualTriggerData{
112 Inputs: nil,
113 },
114 Repo: &tangled.Pipeline_TriggerRepo{
115 Knot: "example.com",
116 Did: "did:plc:user123",
117 Repo: sp("my-repo"),
118 },
119 }
120
121 step := BuildCloneStep(twf, tr, false)
122
123 // Manual triggers don't have a SHA yet (TODO), so git fetch won't include a SHA
124 allCmds := strings.Join(step.Commands(), " ")
125 // Should still have basic git commands
126 if !strings.Contains(allCmds, "git init") {
127 t.Error("Commands should contain 'git init'")
128 }
129 if !strings.Contains(allCmds, "git fetch") {
130 t.Error("Commands should contain 'git fetch'")
131 }
132}
133
134func TestBuildCloneStep_SkipFlag(t *testing.T) {
135 twf := tangled.Pipeline_Workflow{
136 Clone: &tangled.Pipeline_CloneOpts{
137 Skip: true,
138 },
139 }
140 tr := tangled.Pipeline_TriggerMetadata{
141 Kind: string(workflow.TriggerKindPush),
142 Push: &tangled.Pipeline_PushTriggerData{
143 NewSha: "abc123",
144 },
145 Repo: &tangled.Pipeline_TriggerRepo{
146 Knot: "example.com",
147 Did: "did:plc:user123",
148 Repo: sp("my-repo"),
149 },
150 }
151
152 step := BuildCloneStep(twf, tr, false)
153
154 // Empty step when skip is true
155 if step.Name() != "" {
156 t.Error("Expected empty step name when Skip is true")
157 }
158 if len(step.Commands()) != 0 {
159 t.Errorf("Expected no commands when Skip is true, got %d commands", len(step.Commands()))
160 }
161}
162
163func TestBuildCloneStep_DevMode(t *testing.T) {
164 twf := tangled.Pipeline_Workflow{
165 Clone: &tangled.Pipeline_CloneOpts{
166 Depth: 1,
167 Skip: false,
168 },
169 }
170 tr := tangled.Pipeline_TriggerMetadata{
171 Kind: string(workflow.TriggerKindPush),
172 Push: &tangled.Pipeline_PushTriggerData{
173 NewSha: "abc123",
174 },
175 Repo: &tangled.Pipeline_TriggerRepo{
176 Knot: "localhost:3000",
177 Did: "did:plc:user123",
178 Repo: sp("my-repo"),
179 },
180 }
181
182 step := BuildCloneStep(twf, tr, true)
183
184 // In dev mode, should use http:// and replace localhost with host.docker.internal
185 allCmds := strings.Join(step.Commands(), " ")
186 expectedURL := "http://host.docker.internal:3000/did:plc:user123/my-repo"
187 if !strings.Contains(allCmds, expectedURL) {
188 t.Errorf("Expected dev mode URL '%s' in commands", expectedURL)
189 }
190}
191
192func TestBuildCloneStep_DepthAndSubmodules(t *testing.T) {
193 twf := tangled.Pipeline_Workflow{
194 Clone: &tangled.Pipeline_CloneOpts{
195 Depth: 10,
196 Submodules: true,
197 Skip: false,
198 },
199 }
200 tr := tangled.Pipeline_TriggerMetadata{
201 Kind: string(workflow.TriggerKindPush),
202 Push: &tangled.Pipeline_PushTriggerData{
203 NewSha: "abc123",
204 },
205 Repo: &tangled.Pipeline_TriggerRepo{
206 Knot: "example.com",
207 Did: "did:plc:user123",
208 Repo: sp("my-repo"),
209 },
210 }
211
212 step := BuildCloneStep(twf, tr, false)
213
214 allCmds := strings.Join(step.Commands(), " ")
215 if !strings.Contains(allCmds, "--depth=10") {
216 t.Error("Commands should contain '--depth=10'")
217 }
218
219 if !strings.Contains(allCmds, "--recurse-submodules=yes") {
220 t.Error("Commands should contain '--recurse-submodules=yes'")
221 }
222}
223
224func TestBuildCloneStep_DefaultDepth(t *testing.T) {
225 twf := tangled.Pipeline_Workflow{
226 Clone: &tangled.Pipeline_CloneOpts{
227 Depth: 0, // Default should be 1
228 Skip: false,
229 },
230 }
231 tr := 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: sp("my-repo"),
240 },
241 }
242
243 step := BuildCloneStep(twf, tr, false)
244
245 allCmds := strings.Join(step.Commands(), " ")
246 if !strings.Contains(allCmds, "--depth=1") {
247 t.Error("Commands should default to '--depth=1'")
248 }
249}
250
251func TestBuildCloneStep_NilPushData(t *testing.T) {
252 twf := tangled.Pipeline_Workflow{
253 Clone: &tangled.Pipeline_CloneOpts{
254 Depth: 1,
255 Skip: false,
256 },
257 }
258 tr := tangled.Pipeline_TriggerMetadata{
259 Kind: string(workflow.TriggerKindPush),
260 Push: nil, // Nil push data should create error step
261 Repo: &tangled.Pipeline_TriggerRepo{
262 Knot: "example.com",
263 Did: "did:plc:user123",
264 Repo: sp("my-repo"),
265 },
266 }
267
268 step := BuildCloneStep(twf, tr, false)
269
270 // Should return an error step
271 if !strings.Contains(step.Name(), "error") {
272 t.Error("Expected error in step name when push data is nil")
273 }
274
275 allCmds := strings.Join(step.Commands(), " ")
276 if !strings.Contains(allCmds, "Failed to get clone info") {
277 t.Error("Commands should contain error message")
278 }
279 if !strings.Contains(allCmds, "exit 1") {
280 t.Error("Commands should exit with error")
281 }
282}
283
284func TestBuildCloneStep_NilPRData(t *testing.T) {
285 twf := tangled.Pipeline_Workflow{
286 Clone: &tangled.Pipeline_CloneOpts{
287 Depth: 1,
288 Skip: false,
289 },
290 }
291 tr := tangled.Pipeline_TriggerMetadata{
292 Kind: string(workflow.TriggerKindPullRequest),
293 PullRequest: nil, // Nil PR data should create error step
294 Repo: &tangled.Pipeline_TriggerRepo{
295 Knot: "example.com",
296 Did: "did:plc:user123",
297 Repo: sp("my-repo"),
298 },
299 }
300
301 step := BuildCloneStep(twf, tr, false)
302
303 // Should return an error step
304 if !strings.Contains(step.Name(), "error") {
305 t.Error("Expected error in step name when pull request data is nil")
306 }
307
308 allCmds := strings.Join(step.Commands(), " ")
309 if !strings.Contains(allCmds, "Failed to get clone info") {
310 t.Error("Commands should contain error message")
311 }
312}
313
314func TestBuildCloneStep_UnknownTriggerKind(t *testing.T) {
315 twf := tangled.Pipeline_Workflow{
316 Clone: &tangled.Pipeline_CloneOpts{
317 Depth: 1,
318 Skip: false,
319 },
320 }
321 tr := tangled.Pipeline_TriggerMetadata{
322 Kind: "unknown_trigger",
323 Repo: &tangled.Pipeline_TriggerRepo{
324 Knot: "example.com",
325 Did: "did:plc:user123",
326 Repo: sp("my-repo"),
327 },
328 }
329
330 step := BuildCloneStep(twf, tr, false)
331
332 // Should return an error step
333 if !strings.Contains(step.Name(), "error") {
334 t.Error("Expected error in step name for unknown trigger kind")
335 }
336
337 allCmds := strings.Join(step.Commands(), " ")
338 if !strings.Contains(allCmds, "unknown trigger kind") {
339 t.Error("Commands should contain error message about unknown trigger kind")
340 }
341}
342
343func TestBuildCloneStep_NilCloneOpts(t *testing.T) {
344 twf := tangled.Pipeline_Workflow{
345 Clone: nil, // Nil clone options should use defaults
346 }
347 tr := tangled.Pipeline_TriggerMetadata{
348 Kind: string(workflow.TriggerKindPush),
349 Push: &tangled.Pipeline_PushTriggerData{
350 NewSha: "abc123",
351 },
352 Repo: &tangled.Pipeline_TriggerRepo{
353 Knot: "example.com",
354 Did: "did:plc:user123",
355 Repo: sp("my-repo"),
356 },
357 }
358
359 step := BuildCloneStep(twf, tr, false)
360
361 // Should still work with default options
362 if step.Kind() != StepKindSystem {
363 t.Errorf("Expected StepKindSystem, got %v", step.Kind())
364 }
365
366 allCmds := strings.Join(step.Commands(), " ")
367 if !strings.Contains(allCmds, "--depth=1") {
368 t.Error("Commands should default to '--depth=1' when Clone is nil")
369 }
370 if !strings.Contains(allCmds, "git init") {
371 t.Error("Commands should contain 'git init'")
372 }
373}