This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / workflow / compile_test.go
8.0 kB 332 lines
1package workflow 2 3import ( 4 "encoding/json" 5 "strings" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "tangled.org/core/api/tangled" 10) 11 12var trigger = tangled.Pipeline_TriggerMetadata{ 13 Kind: string(TriggerKindPush), 14 Push: &tangled.Pipeline_PushTriggerData{ 15 Ref: "refs/heads/main", 16 OldSha: strings.Repeat("0", 40), 17 NewSha: strings.Repeat("f", 40), 18 }, 19} 20 21var when = []Constraint{ 22 { 23 Event: []string{"push"}, 24 Branch: []string{"main"}, 25 }, 26} 27 28func TestCompileWorkflow_MatchingWorkflowWithSteps(t *testing.T) { 29 wf := Workflow{ 30 Name: ".tangled/workflows/test.yml", 31 Engine: "nixery", 32 When: when, 33 CloneOpts: CloneOpts{}, // default true 34 } 35 36 c := Compiler{Trigger: trigger} 37 cp := c.Compile([]Workflow{wf}) 38 39 assert.Len(t, cp.Workflows, 1) 40 assert.Equal(t, wf.Name, cp.Workflows[0].Name) 41 assert.False(t, cp.Workflows[0].Clone.Skip) 42 assert.False(t, c.Diagnostics.IsErr()) 43} 44 45func TestCompileWorkflow_RunsOnLabelsPersistWithoutFanout(t *testing.T) { 46 wf := Workflow{ 47 Name: ".tangled/workflows/arm64.yml", 48 Engine: "microvm", 49 When: when, 50 RunsOn: []string{"linux/arm64", "kvm"}, 51 } 52 53 c := Compiler{Trigger: trigger} 54 cp := c.Compile([]Workflow{wf}) 55 56 assert.Len(t, cp.Workflows, 1) 57 assert.Equal(t, []string{"linux/arm64", "kvm"}, cp.Workflows[0].RunsOn) 58 59 raw, err := json.Marshal(cp.Workflows[0]) 60 assert.NoError(t, err) 61 62 var persisted map[string]any 63 assert.NoError(t, json.Unmarshal(raw, &persisted)) 64 assert.Equal(t, []any{"linux/arm64", "kvm"}, persisted["runsOn"]) 65} 66 67func TestCompileWorkflow_LegacyWorkflowOmitsRunsOn(t *testing.T) { 68 wf := Workflow{ 69 Name: ".tangled/workflows/legacy.yml", 70 Engine: "microvm", 71 When: when, 72 } 73 74 c := Compiler{Trigger: trigger} 75 cp := c.Compile([]Workflow{wf}) 76 77 assert.Len(t, cp.Workflows, 1) 78 assert.Empty(t, cp.Workflows[0].RunsOn) 79 80 raw, err := json.Marshal(cp.Workflows[0]) 81 assert.NoError(t, err) 82 83 var persisted map[string]any 84 assert.NoError(t, json.Unmarshal(raw, &persisted)) 85 _, ok := persisted["runsOn"] 86 assert.False(t, ok, "legacy workflow JSON should not gain runsOn") 87} 88 89func TestCompileWorkflow_TriggerMismatch(t *testing.T) { 90 wf := Workflow{ 91 Name: ".tangled/workflows/mismatch.yml", 92 Engine: "nixery", 93 When: []Constraint{ 94 { 95 Event: []string{"push"}, 96 Branch: []string{"master"}, // different branch 97 }, 98 }, 99 } 100 101 c := Compiler{Trigger: trigger} 102 cp := c.Compile([]Workflow{wf}) 103 104 assert.Len(t, cp.Workflows, 0) 105 assert.Len(t, c.Diagnostics.Warnings, 1) 106 assert.Equal(t, WorkflowSkipped, c.Diagnostics.Warnings[0].Type) 107} 108 109func TestCompileWorkflow_CloneFalseWithShallowTrue(t *testing.T) { 110 wf := Workflow{ 111 Name: ".tangled/workflows/clone_skip.yml", 112 Engine: "nixery", 113 When: when, 114 CloneOpts: CloneOpts{ 115 Skip: true, 116 Depth: 1, 117 }, // false 118 } 119 120 c := Compiler{Trigger: trigger} 121 cp := c.Compile([]Workflow{wf}) 122 123 assert.Len(t, cp.Workflows, 1) 124 assert.True(t, cp.Workflows[0].Clone.Skip) 125 assert.Len(t, c.Diagnostics.Warnings, 1) 126 assert.Equal(t, InvalidConfiguration, c.Diagnostics.Warnings[0].Type) 127} 128 129func TestCompileWorkflow_MissingEngine(t *testing.T) { 130 wf := Workflow{ 131 Name: ".tangled/workflows/missing_engine.yml", 132 When: when, 133 Engine: "", 134 } 135 136 c := Compiler{Trigger: trigger} 137 cp := c.Compile([]Workflow{wf}) 138 139 assert.Len(t, cp.Workflows, 0) 140 assert.Len(t, c.Diagnostics.Errors, 1) 141 assert.Equal(t, MissingEngine, c.Diagnostics.Errors[0].Error) 142} 143 144func TestCompileWorkflow_ChangedFilesMatchesPaths(t *testing.T) { 145 wf := Workflow{ 146 Name: ".tangled/workflows/test.yml", 147 Engine: "nixery", 148 When: []Constraint{ 149 { 150 Event: []string{"push"}, 151 Branch: []string{"main"}, 152 Paths: []string{"src/**"}, 153 }, 154 }, 155 } 156 157 c := Compiler{ 158 Trigger: trigger, 159 ChangedFiles: []string{"src/main.go", "src/util.go"}, 160 } 161 cp := c.Compile([]Workflow{wf}) 162 163 assert.Len(t, cp.Workflows, 1) 164 assert.Equal(t, wf.Name, cp.Workflows[0].Name) 165 assert.False(t, c.Diagnostics.IsErr()) 166} 167 168func TestCompileWorkflow_ChangedFilesNoMatch(t *testing.T) { 169 wf := Workflow{ 170 Name: ".tangled/workflows/test.yml", 171 Engine: "nixery", 172 When: []Constraint{ 173 { 174 Event: []string{"push"}, 175 Branch: []string{"main"}, 176 Paths: []string{"src/**"}, 177 }, 178 }, 179 } 180 181 c := Compiler{ 182 Trigger: trigger, 183 ChangedFiles: []string{"docs/guide.md", "README.md"}, 184 } 185 cp := c.Compile([]Workflow{wf}) 186 187 assert.Len(t, cp.Workflows, 0) 188 assert.Len(t, c.Diagnostics.Warnings, 1) 189 assert.Equal(t, WorkflowSkipped, c.Diagnostics.Warnings[0].Type) 190} 191 192func TestCompileWorkflow_NoPaths_ChangedFilesIgnored(t *testing.T) { 193 wf := Workflow{ 194 Name: ".tangled/workflows/test.yml", 195 Engine: "nixery", 196 When: when, // no Paths constraint 197 } 198 199 c := Compiler{ 200 Trigger: trigger, 201 ChangedFiles: []string{"docs/guide.md"}, 202 } 203 cp := c.Compile([]Workflow{wf}) 204 205 assert.Len(t, cp.Workflows, 1) 206 assert.False(t, c.Diagnostics.IsErr()) 207} 208 209func TestCompileWorkflow_MultipleBranchAndTag(t *testing.T) { 210 wf := Workflow{ 211 Name: ".tangled/workflows/branch_and_tag.yml", 212 When: []Constraint{ 213 { 214 Event: []string{"push"}, 215 Branch: []string{"main", "develop"}, 216 Tag: []string{"v*"}, 217 }, 218 }, 219 Engine: "nixery", 220 } 221 222 tests := []struct { 223 name string 224 trigger tangled.Pipeline_TriggerMetadata 225 shouldMatch bool 226 expectedCount int 227 }{ 228 { 229 name: "matches main branch", 230 trigger: tangled.Pipeline_TriggerMetadata{ 231 Kind: string(TriggerKindPush), 232 Push: &tangled.Pipeline_PushTriggerData{ 233 Ref: "refs/heads/main", 234 OldSha: strings.Repeat("0", 40), 235 NewSha: strings.Repeat("f", 40), 236 }, 237 }, 238 shouldMatch: true, 239 expectedCount: 1, 240 }, 241 { 242 name: "matches develop branch", 243 trigger: tangled.Pipeline_TriggerMetadata{ 244 Kind: string(TriggerKindPush), 245 Push: &tangled.Pipeline_PushTriggerData{ 246 Ref: "refs/heads/develop", 247 OldSha: strings.Repeat("0", 40), 248 NewSha: strings.Repeat("f", 40), 249 }, 250 }, 251 shouldMatch: true, 252 expectedCount: 1, 253 }, 254 { 255 name: "matches v* tag pattern", 256 trigger: tangled.Pipeline_TriggerMetadata{ 257 Kind: string(TriggerKindPush), 258 Push: &tangled.Pipeline_PushTriggerData{ 259 Ref: "refs/tags/v1.0.0", 260 OldSha: strings.Repeat("0", 40), 261 NewSha: strings.Repeat("f", 40), 262 }, 263 }, 264 shouldMatch: true, 265 expectedCount: 1, 266 }, 267 { 268 name: "matches v* tag pattern with different version", 269 trigger: tangled.Pipeline_TriggerMetadata{ 270 Kind: string(TriggerKindPush), 271 Push: &tangled.Pipeline_PushTriggerData{ 272 Ref: "refs/tags/v2.5.3", 273 OldSha: strings.Repeat("0", 40), 274 NewSha: strings.Repeat("f", 40), 275 }, 276 }, 277 shouldMatch: true, 278 expectedCount: 1, 279 }, 280 { 281 name: "does not match master branch", 282 trigger: tangled.Pipeline_TriggerMetadata{ 283 Kind: string(TriggerKindPush), 284 Push: &tangled.Pipeline_PushTriggerData{ 285 Ref: "refs/heads/master", 286 OldSha: strings.Repeat("0", 40), 287 NewSha: strings.Repeat("f", 40), 288 }, 289 }, 290 shouldMatch: false, 291 expectedCount: 0, 292 }, 293 { 294 name: "does not match non-v tag", 295 trigger: tangled.Pipeline_TriggerMetadata{ 296 Kind: string(TriggerKindPush), 297 Push: &tangled.Pipeline_PushTriggerData{ 298 Ref: "refs/tags/release-1.0", 299 OldSha: strings.Repeat("0", 40), 300 NewSha: strings.Repeat("f", 40), 301 }, 302 }, 303 shouldMatch: false, 304 expectedCount: 0, 305 }, 306 { 307 name: "does not match feature branch", 308 trigger: tangled.Pipeline_TriggerMetadata{ 309 Kind: string(TriggerKindPush), 310 Push: &tangled.Pipeline_PushTriggerData{ 311 Ref: "refs/heads/feature/new-feature", 312 OldSha: strings.Repeat("0", 40), 313 NewSha: strings.Repeat("f", 40), 314 }, 315 }, 316 shouldMatch: false, 317 expectedCount: 0, 318 }, 319 } 320 321 for _, tt := range tests { 322 t.Run(tt.name, func(t *testing.T) { 323 c := Compiler{Trigger: tt.trigger} 324 cp := c.Compile([]Workflow{wf}) 325 326 assert.Len(t, cp.Workflows, tt.expectedCount) 327 if tt.shouldMatch { 328 assert.Equal(t, wf.Name, cp.Workflows[0].Name) 329 } 330 }) 331 } 332}