pipecraft 0.0.0-releaseit

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/.claude/settings.local.json +35 -0
  2. package/.github/actions/calculate-version/action.yml +106 -0
  3. package/.github/actions/create-pr/action.yml +122 -0
  4. package/.github/actions/create-release/action.yml +74 -0
  5. package/.github/actions/create-tag/action.yml +94 -0
  6. package/.github/actions/detect-changes/action.yml +62 -0
  7. package/.github/actions/manage-branch/action.yml +113 -0
  8. package/.github/actions/promote-branch/action.yml +352 -0
  9. package/.github/example/workflows/job.analyze.code.yml +26 -0
  10. package/.github/example/workflows/job.analyze.docker.yml +32 -0
  11. package/.github/example/workflows/job.app.api.deploy.yml +127 -0
  12. package/.github/example/workflows/job.app.api.test.yml +102 -0
  13. package/.github/example/workflows/job.app.docs.deploy.yml +40 -0
  14. package/.github/example/workflows/job.app.docs.test.yml +50 -0
  15. package/.github/example/workflows/job.app.web.deploy.yml +96 -0
  16. package/.github/example/workflows/job.app.web.test.yml +49 -0
  17. package/.github/example/workflows/job.changes.yml +82 -0
  18. package/.github/example/workflows/job.create-pr.yml +96 -0
  19. package/.github/example/workflows/job.env-check.yml +43 -0
  20. package/.github/example/workflows/job.fast-forward.yml +103 -0
  21. package/.github/example/workflows/job.lint.yml +64 -0
  22. package/.github/example/workflows/job.pr-name.yml +70 -0
  23. package/.github/example/workflows/job.pr-squash-name.yml +27 -0
  24. package/.github/example/workflows/job.tag.yml +38 -0
  25. package/.github/example/workflows/job.version.yml +99 -0
  26. package/.github/example/workflows/lib.plugin-base.publish.yml +59 -0
  27. package/.github/example/workflows/pipe.yml +178 -0
  28. package/.github/example/workflows/scripts/fastforward.sh +51 -0
  29. package/.github/example/workflows/scripts/pipe-cleaner.sh +70 -0
  30. package/.github/scripts/fastforward.sh +51 -0
  31. package/.github/scripts/pipe-cleaner.sh +70 -0
  32. package/.github/workflows/pipeline.yml +220 -0
  33. package/.github/workflows/pr-title-check.yml +70 -0
  34. package/.github/workflows/publish.yml +39 -0
  35. package/.pipecraftrc.json +78 -0
  36. package/.release-it.cjs +71 -0
  37. package/PIPELINE_TESTING_PLAN.md +499 -0
  38. package/README.md +1101 -0
  39. package/TRUNK_FLOW_PLAN.md +401 -0
  40. package/assets/logo_banner.png +0 -0
  41. package/assets/logo_banner.webp +0 -0
  42. package/dist/cli/index.d.ts +3 -0
  43. package/dist/cli/index.d.ts.map +1 -0
  44. package/dist/cli/index.js +364 -0
  45. package/dist/cli/index.js.map +1 -0
  46. package/dist/generators/init.tpl.d.ts +3 -0
  47. package/dist/generators/init.tpl.d.ts.map +1 -0
  48. package/dist/generators/init.tpl.js +117 -0
  49. package/dist/generators/init.tpl.js.map +1 -0
  50. package/dist/generators/workflows.tpl.d.ts +7 -0
  51. package/dist/generators/workflows.tpl.d.ts.map +1 -0
  52. package/dist/generators/workflows.tpl.js +73 -0
  53. package/dist/generators/workflows.tpl.js.map +1 -0
  54. package/dist/templates/actions/calculate-version.yml.tpl.d.ts +3 -0
  55. package/dist/templates/actions/calculate-version.yml.tpl.d.ts.map +1 -0
  56. package/dist/templates/actions/calculate-version.yml.tpl.js +122 -0
  57. package/dist/templates/actions/calculate-version.yml.tpl.js.map +1 -0
  58. package/dist/templates/actions/create-pr.yml.tpl.d.ts +3 -0
  59. package/dist/templates/actions/create-pr.yml.tpl.d.ts.map +1 -0
  60. package/dist/templates/actions/create-pr.yml.tpl.js +145 -0
  61. package/dist/templates/actions/create-pr.yml.tpl.js.map +1 -0
  62. package/dist/templates/actions/create-tag.yml.tpl.d.ts +3 -0
  63. package/dist/templates/actions/create-tag.yml.tpl.d.ts.map +1 -0
  64. package/dist/templates/actions/create-tag.yml.tpl.js +111 -0
  65. package/dist/templates/actions/create-tag.yml.tpl.js.map +1 -0
  66. package/dist/templates/actions/detect-changes.yml.tpl.d.ts +3 -0
  67. package/dist/templates/actions/detect-changes.yml.tpl.d.ts.map +1 -0
  68. package/dist/templates/actions/detect-changes.yml.tpl.js +79 -0
  69. package/dist/templates/actions/detect-changes.yml.tpl.js.map +1 -0
  70. package/dist/templates/actions/manage-branch.yml.tpl.d.ts +3 -0
  71. package/dist/templates/actions/manage-branch.yml.tpl.d.ts.map +1 -0
  72. package/dist/templates/actions/manage-branch.yml.tpl.js +130 -0
  73. package/dist/templates/actions/manage-branch.yml.tpl.js.map +1 -0
  74. package/dist/templates/actions/promote-branch.yml.tpl.d.ts +3 -0
  75. package/dist/templates/actions/promote-branch.yml.tpl.d.ts.map +1 -0
  76. package/dist/templates/actions/promote-branch.yml.tpl.js +362 -0
  77. package/dist/templates/actions/promote-branch.yml.tpl.js.map +1 -0
  78. package/dist/templates/workflows/pipeline-path-based.yml.tpl.d.ts +16 -0
  79. package/dist/templates/workflows/pipeline-path-based.yml.tpl.d.ts.map +1 -0
  80. package/dist/templates/workflows/pipeline-path-based.yml.tpl.js +652 -0
  81. package/dist/templates/workflows/pipeline-path-based.yml.tpl.js.map +1 -0
  82. package/dist/types/index.d.ts +63 -0
  83. package/dist/types/index.d.ts.map +1 -0
  84. package/dist/types/index.js +2 -0
  85. package/dist/types/index.js.map +1 -0
  86. package/dist/utils/ast-path-operations.d.ts +287 -0
  87. package/dist/utils/ast-path-operations.d.ts.map +1 -0
  88. package/dist/utils/ast-path-operations.js +419 -0
  89. package/dist/utils/ast-path-operations.js.map +1 -0
  90. package/dist/utils/config.d.ts +3 -0
  91. package/dist/utils/config.d.ts.map +1 -0
  92. package/dist/utils/config.js +49 -0
  93. package/dist/utils/config.js.map +1 -0
  94. package/dist/utils/github-setup.d.ts +74 -0
  95. package/dist/utils/github-setup.d.ts.map +1 -0
  96. package/dist/utils/github-setup.js +418 -0
  97. package/dist/utils/github-setup.js.map +1 -0
  98. package/dist/utils/idempotency.d.ts +47 -0
  99. package/dist/utils/idempotency.d.ts.map +1 -0
  100. package/dist/utils/idempotency.js +176 -0
  101. package/dist/utils/idempotency.js.map +1 -0
  102. package/dist/utils/preflight.d.ts +55 -0
  103. package/dist/utils/preflight.d.ts.map +1 -0
  104. package/dist/utils/preflight.js +261 -0
  105. package/dist/utils/preflight.js.map +1 -0
  106. package/dist/utils/versioning.d.ts +41 -0
  107. package/dist/utils/versioning.d.ts.map +1 -0
  108. package/dist/utils/versioning.js +219 -0
  109. package/dist/utils/versioning.js.map +1 -0
  110. package/docs/USER_JOURNEY_ERRORS.md +352 -0
  111. package/eslint.config.js +77 -0
  112. package/examples/basic-config.json +41 -0
  113. package/examples/monorepo-config.json +49 -0
  114. package/examples/usage.md +289 -0
  115. package/package.json +58 -0
  116. package/scripts/debug-workflows.sh +339 -0
  117. package/scripts/parse-pipeline.js +29 -0
  118. package/scripts/test-job-order.cjs +140 -0
  119. package/scripts/validate-pipeline.cjs +379 -0
  120. package/scripts/verify-job-order.sh +30 -0
  121. package/src/cli/index.ts +414 -0
  122. package/src/generators/init.tpl.ts +126 -0
  123. package/src/generators/workflows.tpl.ts +80 -0
  124. package/src/templates/actions/calculate-version.yml.tpl.ts +124 -0
  125. package/src/templates/actions/create-pr.yml.tpl.ts +147 -0
  126. package/src/templates/actions/create-tag.yml.tpl.ts +112 -0
  127. package/src/templates/actions/detect-changes.yml.tpl.ts +87 -0
  128. package/src/templates/actions/manage-branch.yml.tpl.ts +132 -0
  129. package/src/templates/actions/promote-branch.yml.tpl.ts +364 -0
  130. package/src/templates/workflows/pipeline-path-based.yml.tpl.ts +706 -0
  131. package/src/types/index.ts +64 -0
  132. package/src/utils/README-ast-path-operations.md +390 -0
  133. package/src/utils/ast-path-operations.ts +581 -0
  134. package/src/utils/config.ts +64 -0
  135. package/src/utils/github-setup.ts +558 -0
  136. package/src/utils/idempotency.ts +215 -0
  137. package/src/utils/preflight.ts +306 -0
  138. package/src/utils/versioning.ts +244 -0
  139. package/tests/README.md +229 -0
  140. package/tests/TEST_STRUCTURE.md +256 -0
  141. package/tests/act/run-act-tests.sh +345 -0
  142. package/tests/debugging/debug-utils.ts +538 -0
  143. package/tests/debugging/debug-workflow.test.ts +339 -0
  144. package/tests/debugging/debug-workflows.sh +339 -0
  145. package/tests/debugging/iterative-debug.ts +652 -0
  146. package/tests/debugging/run-debug-tests.sh +431 -0
  147. package/tests/fixtures/basic-config.json +51 -0
  148. package/tests/fixtures/invalid-config.json +9 -0
  149. package/tests/fixtures/pipeline-generated.yml +235 -0
  150. package/tests/fixtures/pipeline-preserve-comments.yml +245 -0
  151. package/tests/fixtures/pipeline-user-modified.yml +245 -0
  152. package/tests/fixtures/test-config.json +58 -0
  153. package/tests/github-live/README.md +250 -0
  154. package/tests/github-local/JOB_WORKFLOW_TESTS.md +296 -0
  155. package/tests/github-local/README.md +240 -0
  156. package/tests/github-local/run-all-tests.sh +422 -0
  157. package/tests/github-local/test-job-workflows.sh +631 -0
  158. package/tests/github-local/test-pipeline-workflow.sh +440 -0
  159. package/tests/integration/generators.test.ts +578 -0
  160. package/tests/integration/path-based-template.test.ts +510 -0
  161. package/tests/integration/simple-path-based.test.ts +415 -0
  162. package/tests/setup.ts +56 -0
  163. package/tests/unit/ast-path-operations-extended.test.ts +302 -0
  164. package/tests/unit/cli.test.ts +541 -0
  165. package/tests/unit/config-extended.test.ts +412 -0
  166. package/tests/unit/config.test.ts +152 -0
  167. package/tests/unit/github-setup.test.ts +189 -0
  168. package/tests/unit/idempotency-isolated.test.ts +297 -0
  169. package/tests/unit/job-order.test.ts +157 -0
  170. package/tests/unit/pipeline-path-based.test.ts +511 -0
  171. package/tests/unit/validate-pipeline.test.ts +384 -0
  172. package/tests/unit/versioning-extended.test.ts +279 -0
  173. package/tests/unit/versioning.test.ts +241 -0
  174. package/tsconfig.debug.json +17 -0
  175. package/tsconfig.json +28 -0
  176. package/vitest.config.ts +51 -0
@@ -0,0 +1,415 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest'
2
+ import { writeFileSync, existsSync, rmSync, readFileSync, mkdirSync } from 'fs'
3
+ import { join } from 'path'
4
+ import { TEST_DIR } from '../setup'
5
+ import { parse } from 'yaml'
6
+ import { applyPathOperations, PathOperationConfig, createValueFromString, createValueFromObject } from '../../src/utils/ast-path-operations'
7
+ import { parseDocument, stringify } from 'yaml'
8
+
9
+ describe('Simple Path-Based Template Tests', () => {
10
+ beforeEach(() => {
11
+ // Clean up test files
12
+ const filesToClean = ['.pipecraft-cache.json']
13
+ filesToClean.forEach(file => {
14
+ const fullPath = join(TEST_DIR, file)
15
+ if (existsSync(fullPath)) {
16
+ rmSync(fullPath, { recursive: true, force: true })
17
+ }
18
+ })
19
+ })
20
+
21
+ afterEach(() => {
22
+ // Clean up after each test
23
+ const filesToClean = ['.pipecraft-cache.json']
24
+ filesToClean.forEach(file => {
25
+ const fullPath = join(TEST_DIR, file)
26
+ if (existsSync(fullPath)) {
27
+ rmSync(fullPath, { recursive: true, force: true })
28
+ }
29
+ })
30
+ })
31
+
32
+ describe('Path Operations with Simple YAML', () => {
33
+ it('should apply set operations for workflow inputs', () => {
34
+ // Create a simple YAML document
35
+ const simpleYaml = `name: "Test Pipeline"
36
+ on:
37
+ pull_request:
38
+ branches: [develop]
39
+ jobs:
40
+ test:
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - name: Test
44
+ run: echo "test"`
45
+
46
+ const doc = parseDocument(simpleYaml)
47
+
48
+ // Apply path operations
49
+ const operations: PathOperationConfig[] = [
50
+ {
51
+ path: 'on.workflow_call.inputs.version',
52
+ operation: 'set',
53
+ value: {
54
+ description: 'The version to deploy',
55
+ required: false,
56
+ type: 'string'
57
+ },
58
+ required: true
59
+ },
60
+ {
61
+ path: 'on.workflow_call.inputs.baseRef',
62
+ operation: 'set',
63
+ value: {
64
+ description: 'The base reference for comparison',
65
+ required: false,
66
+ type: 'string'
67
+ },
68
+ required: true
69
+ }
70
+ ]
71
+
72
+ applyPathOperations(doc.contents, operations)
73
+
74
+ // Stringify and parse to verify
75
+ const result = stringify(doc)
76
+ const parsed = parse(result)
77
+
78
+ expect(parsed.on.workflow_call?.inputs?.version).toEqual({
79
+ description: 'The version to deploy',
80
+ required: false,
81
+ type: 'string'
82
+ })
83
+ expect(parsed.on.workflow_call?.inputs?.baseRef).toEqual({
84
+ description: 'The base reference for comparison',
85
+ required: false,
86
+ type: 'string'
87
+ })
88
+ })
89
+
90
+ it('should apply merge operations for branch configuration', () => {
91
+ // Create a simple YAML document with existing branches
92
+ const simpleYaml = `name: "Test Pipeline"
93
+ on:
94
+ pull_request:
95
+ branches: [develop, feature]
96
+ jobs:
97
+ test:
98
+ runs-on: ubuntu-latest
99
+ steps:
100
+ - name: Test
101
+ run: echo "test"`
102
+
103
+ const doc = parseDocument(simpleYaml)
104
+
105
+ // Apply merge operation for branches
106
+ const operations: PathOperationConfig[] = [
107
+ {
108
+ path: 'on.pull_request.branches',
109
+ operation: 'merge',
110
+ value: ['alpha', 'beta', 'gamma', 'delta', 'epsilon'],
111
+ required: true
112
+ }
113
+ ]
114
+
115
+ applyPathOperations(doc.contents, operations)
116
+
117
+ // Stringify and parse to verify
118
+ const result = stringify(doc)
119
+ const parsed = parse(result)
120
+
121
+ // Should contain both existing and new branches
122
+ expect(parsed.on.pull_request.branches).toContain('develop')
123
+ expect(parsed.on.pull_request.branches).toContain('feature')
124
+ expect(parsed.on.pull_request.branches).toContain('alpha')
125
+ expect(parsed.on.pull_request.branches).toContain('beta')
126
+ expect(parsed.on.pull_request.branches).toContain('gamma')
127
+ expect(parsed.on.pull_request.branches).toContain('delta')
128
+ expect(parsed.on.pull_request.branches).toContain('epsilon')
129
+ })
130
+
131
+ it('should apply overwrite operations for core jobs', () => {
132
+ // Create a simple YAML document with existing jobs
133
+ const simpleYaml = `name: "Test Pipeline"
134
+ on:
135
+ pull_request:
136
+ branches: [develop]
137
+ jobs:
138
+ changes:
139
+ runs-on: ubuntu-latest
140
+ steps:
141
+ - name: Old Changes Job
142
+ run: echo "This should be overwritten"
143
+ version:
144
+ runs-on: ubuntu-latest
145
+ steps:
146
+ - name: Old Version Job
147
+ run: echo "This should be overwritten"`
148
+
149
+ const doc = parseDocument(simpleYaml)
150
+
151
+ // Apply overwrite operations for core jobs
152
+ const operations: PathOperationConfig[] = [
153
+ {
154
+ path: 'jobs.changes',
155
+ operation: 'overwrite',
156
+ value: createValueFromString(`
157
+ runs-on: ubuntu-latest
158
+ steps:
159
+ - uses: ./.github/actions/detect-changes
160
+ with:
161
+ baseRef: \${{ inputs.baseRef || 'main' }}
162
+ `),
163
+ required: true
164
+ },
165
+ {
166
+ path: 'jobs.version',
167
+ operation: 'overwrite',
168
+ value: createValueFromString(`
169
+ if: github.ref_name == 'alpha'
170
+ needs: changes
171
+ runs-on: ubuntu-latest
172
+ steps:
173
+ - uses: ./.github/actions/calculate-version
174
+ with:
175
+ baseRef: \${{ inputs.baseRef || 'main' }}
176
+ `),
177
+ required: true
178
+ }
179
+ ]
180
+
181
+ applyPathOperations(doc.contents, operations)
182
+
183
+ // Stringify and parse to verify
184
+ const result = stringify(doc)
185
+ const parsed = parse(result)
186
+
187
+
188
+ // Verify core jobs are overwritten
189
+ expect(parsed.jobs.changes).toBeDefined()
190
+ expect(parsed.jobs.version).toBeDefined()
191
+
192
+ // Check if steps exist and have the expected structure
193
+ if (parsed.jobs.changes.steps && parsed.jobs.changes.steps.length > 0) {
194
+ expect(parsed.jobs.changes.steps[0].uses).toBe('./.github/actions/detect-changes')
195
+ expect(parsed.jobs.changes.steps[0].name).toBeUndefined() // No custom name
196
+ }
197
+
198
+ if (parsed.jobs.version.steps && parsed.jobs.version.steps.length > 0) {
199
+ expect(parsed.jobs.version.steps[0].uses).toBe('./.github/actions/calculate-version')
200
+ expect(parsed.jobs.version.steps[0].name).toBeUndefined() // No custom name
201
+ }
202
+
203
+ // Check if the if condition exists
204
+ if (parsed.jobs.version.if) {
205
+ expect(parsed.jobs.version.if).toBe("github.ref_name == 'alpha'")
206
+ }
207
+ })
208
+
209
+ it('should apply preserve operations for user-managed sections', () => {
210
+ // Create a simple YAML document with user jobs
211
+ const simpleYaml = `name: "Test Pipeline"
212
+ on:
213
+ pull_request:
214
+ branches: [develop]
215
+ jobs:
216
+ testing-section:
217
+ test-api:
218
+ needs: changes
219
+ runs-on: ubuntu-latest
220
+ steps:
221
+ - name: Test API
222
+ run: echo "Running API tests"
223
+ deployment-section:
224
+ deploy-api:
225
+ needs: version
226
+ runs-on: ubuntu-latest
227
+ steps:
228
+ - name: Deploy API
229
+ run: echo "Deploying API"`
230
+
231
+ const doc = parseDocument(simpleYaml)
232
+
233
+ // Apply preserve operations for user-managed sections
234
+ const operations: PathOperationConfig[] = [
235
+ {
236
+ path: 'jobs.testing-section',
237
+ operation: 'preserve',
238
+ value: createValueFromString(`
239
+ # Add your testing jobs here
240
+ # Example:
241
+ # test-api:
242
+ # needs: changes
243
+ # runs-on: ubuntu-latest
244
+ # steps:
245
+ # - name: Test API
246
+ # run: echo "Run API tests"
247
+ `),
248
+ required: false
249
+ },
250
+ {
251
+ path: 'jobs.deployment-section',
252
+ operation: 'preserve',
253
+ value: createValueFromString(`
254
+ # Add your deployment jobs here
255
+ # Example:
256
+ # deploy-api:
257
+ # needs: version
258
+ # runs-on: ubuntu-latest
259
+ # steps:
260
+ # - name: Deploy API
261
+ # run: echo "Deploy API to production"
262
+ `),
263
+ required: false
264
+ }
265
+ ]
266
+
267
+ applyPathOperations(doc.contents, operations)
268
+
269
+ // Stringify and parse to verify
270
+ const result = stringify(doc)
271
+ const parsed = parse(result)
272
+
273
+ // Verify user-managed sections are preserved
274
+ expect(parsed.jobs['testing-section']['test-api']).toBeDefined()
275
+ expect(parsed.jobs['testing-section']['test-api'].steps[0].name).toBe('Test API')
276
+ expect(parsed.jobs['deployment-section']['deploy-api']).toBeDefined()
277
+ expect(parsed.jobs['deployment-section']['deploy-api'].steps[0].name).toBe('Deploy API')
278
+ })
279
+ })
280
+
281
+ describe('CLI Integration with Custom Files', () => {
282
+ it('should handle custom config file with unexpected variables', async () => {
283
+ // Create custom config with unexpected variables
284
+ const customConfig = {
285
+ ciProvider: 'github',
286
+ mergeStrategy: 'fast-forward',
287
+ requireConventionalCommits: true,
288
+ initialBranch: 'alpha',
289
+ finalBranch: 'epsilon',
290
+ branchFlow: ['alpha', 'beta', 'gamma', 'delta', 'epsilon'],
291
+ semver: {
292
+ bumpRules: {
293
+ feat: 'minor',
294
+ fix: 'patch',
295
+ breaking: 'major'
296
+ }
297
+ },
298
+ actions: {
299
+ onDevelopMerge: ['runTests', 'fastForwardToStaging'],
300
+ onStagingMerge: ['runTests', 'calculateVersion', 'createOrFastForwardToMain']
301
+ },
302
+ domains: {
303
+ 'fake-domain1': {
304
+ paths: ['apps/fake-domain1/**'],
305
+ description: 'fake-domain1 application changes'
306
+ },
307
+ 'fake-domain2': {
308
+ paths: ['apps/fake-domain2/**'],
309
+ description: 'fake-domain2 application changes'
310
+ },
311
+ 'fake-domain3': {
312
+ paths: ['libs/fake-domain3/**'],
313
+ description: 'fake-domain3 application changes'
314
+ },
315
+ 'fake-domain4': {
316
+ paths: ['.github/workflows/fake-domain4/**'],
317
+ description: 'fake-domain4 application changes'
318
+ }
319
+ }
320
+ }
321
+
322
+ const configPath = join(TEST_DIR, 'custom-pipecraftrc.json')
323
+ writeFileSync(configPath, JSON.stringify(customConfig, null, 2))
324
+
325
+ // Test that the config can be loaded and parsed
326
+ const loadedConfig = JSON.parse(readFileSync(configPath, 'utf8'))
327
+ expect(loadedConfig.initialBranch).toBe('alpha')
328
+ expect(loadedConfig.finalBranch).toBe('epsilon')
329
+ expect(loadedConfig.branchFlow).toEqual(['alpha', 'beta', 'gamma', 'delta', 'epsilon'])
330
+ expect(loadedConfig.domains['fake-domain1']).toBeDefined()
331
+ expect(loadedConfig.domains['fake-domain2']).toBeDefined()
332
+ expect(loadedConfig.domains['fake-domain3']).toBeDefined()
333
+ expect(loadedConfig.domains['fake-domain4']).toBeDefined()
334
+ })
335
+
336
+ it('should handle custom pipeline file with user customizations', async () => {
337
+ // Create existing pipeline with user customizations
338
+ const existingPipeline = {
339
+ name: "USER NAME",
340
+ on: {
341
+ pull_request: {
342
+ paths: ['**/*.yml', '**/*.yaml', '**/*.json', '**/*.ts', '**/*.js', '**/*.tsx'],
343
+ branches: ['develop', 'feature']
344
+ },
345
+ workflow_call: {
346
+ inputs: {
347
+ fakevar1: {
348
+ description: 'The fake version to deploy',
349
+ required: false,
350
+ type: 'string'
351
+ },
352
+ version: {
353
+ description: 'The version to deploy',
354
+ required: false,
355
+ type: 'string'
356
+ },
357
+ fakevar2: {
358
+ description: 'The fake version to deploy',
359
+ required: false,
360
+ type: 'string'
361
+ }
362
+ },
363
+ outputs: {
364
+ fakevar3: {
365
+ value: 'fakevalue3'
366
+ },
367
+ fakevar4: {
368
+ value: 'fakevalue4'
369
+ }
370
+ }
371
+ }
372
+ },
373
+ jobs: {
374
+ 'fake-job-1': {
375
+ runs_on: 'ubuntu-latest',
376
+ steps: [
377
+ {
378
+ name: 'Fake Job',
379
+ run: 'echo "Running fake job"'
380
+ }
381
+ ]
382
+ },
383
+ changes: {
384
+ runs_on: 'ubuntu-latest',
385
+ steps: [
386
+ {
387
+ uses: './.github/actions/detect-changes',
388
+ with: {
389
+ baseRef: '${{ inputs.baseRef || \'main\' }}'
390
+ }
391
+ }
392
+ ]
393
+ }
394
+ }
395
+ }
396
+
397
+ const pipelinePath = join(TEST_DIR, 'custom-pipeline.yml')
398
+ writeFileSync(pipelinePath, stringify(existingPipeline))
399
+
400
+ // Test that the pipeline can be loaded and parsed
401
+ const loadedPipeline = parse(readFileSync(pipelinePath, 'utf8'))
402
+ expect(loadedPipeline.name).toBe('USER NAME')
403
+ expect(loadedPipeline.on.pull_request.paths).toContain('**/*.yml')
404
+ expect(loadedPipeline.on.pull_request.branches).toContain('develop')
405
+ expect(loadedPipeline.on.pull_request.branches).toContain('feature')
406
+ expect(loadedPipeline.on.workflow_call.inputs.fakevar1).toBeDefined()
407
+ expect(loadedPipeline.on.workflow_call.inputs.version).toBeDefined()
408
+ expect(loadedPipeline.on.workflow_call.inputs.fakevar2).toBeDefined()
409
+ expect(loadedPipeline.on.workflow_call.outputs.fakevar3).toBeDefined()
410
+ expect(loadedPipeline.on.workflow_call.outputs.fakevar4).toBeDefined()
411
+ expect(loadedPipeline.jobs['fake-job-1']).toBeDefined()
412
+ expect(loadedPipeline.jobs.changes).toBeDefined()
413
+ })
414
+ })
415
+ })
package/tests/setup.ts ADDED
@@ -0,0 +1,56 @@
1
+ import { beforeAll, afterAll, beforeEach, afterEach, vi } from 'vitest'
2
+ import { mkdirSync, rmSync, existsSync } from 'fs'
3
+ import { join } from 'path'
4
+
5
+ // Test utilities
6
+ export const TEST_DIR = join(process.cwd(), 'test-temp')
7
+ export const FIXTURES_DIR = join(__dirname, 'fixtures')
8
+
9
+ // Setup test environment
10
+ beforeAll(() => {
11
+ // Create test directory
12
+ if (existsSync(TEST_DIR)) {
13
+ try {
14
+ rmSync(TEST_DIR, { recursive: true, force: true })
15
+ } catch (error) {
16
+ // If directory is not empty, try to remove contents first
17
+ if (error.code === 'ENOTEMPTY') {
18
+ rmSync(TEST_DIR, { recursive: true, force: true, maxRetries: 3 })
19
+ }
20
+ }
21
+ }
22
+ mkdirSync(TEST_DIR, { recursive: true })
23
+ })
24
+
25
+ afterAll(() => {
26
+ // Don't delete TEST_DIR as other test files may still need it
27
+ // The directory will be cleaned up at the start of the next test run by beforeAll
28
+ })
29
+
30
+ beforeEach(() => {
31
+ // Reset test environment before each test
32
+ // Ensure TEST_DIR exists but DON'T chdir to it globally
33
+ // Individual tests should manage their own working directories
34
+ if (!existsSync(TEST_DIR)) {
35
+ mkdirSync(TEST_DIR, { recursive: true })
36
+ }
37
+ })
38
+
39
+ afterEach(() => {
40
+ // Clean up after each test
41
+ if (existsSync(join(TEST_DIR, '.pipecraft-cache.json'))) {
42
+ rmSync(join(TEST_DIR, '.pipecraft-cache.json'))
43
+ }
44
+ })
45
+
46
+ // Mock console methods to avoid noise in tests
47
+ const originalConsole = { ...console }
48
+ beforeEach(() => {
49
+ console.log = vi.fn()
50
+ console.error = vi.fn()
51
+ console.warn = vi.fn()
52
+ })
53
+
54
+ afterEach(() => {
55
+ Object.assign(console, originalConsole)
56
+ })