pipecraft 0.29.3 → 0.36.14
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.
- package/README.md +128 -54
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +68 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/init.tpl.d.ts +4 -4
- package/dist/generators/init.tpl.d.ts.map +1 -1
- package/dist/generators/init.tpl.js +214 -108
- package/dist/generators/init.tpl.js.map +1 -1
- package/dist/generators/workflows.tpl.d.ts +9 -9
- package/dist/generators/workflows.tpl.d.ts.map +1 -1
- package/dist/generators/workflows.tpl.js +33 -36
- package/dist/generators/workflows.tpl.js.map +1 -1
- package/dist/templates/actions/calculate-version.yml.tpl.d.ts +7 -4
- package/dist/templates/actions/calculate-version.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/calculate-version.yml.tpl.js +49 -23
- package/dist/templates/actions/calculate-version.yml.tpl.js.map +1 -1
- package/dist/templates/actions/create-pr.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/create-pr.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/create-pr.yml.tpl.js +14 -8
- package/dist/templates/actions/create-pr.yml.tpl.js.map +1 -1
- package/dist/templates/actions/create-release.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/create-release.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/create-release.yml.tpl.js +16 -11
- package/dist/templates/actions/create-release.yml.tpl.js.map +1 -1
- package/dist/templates/actions/create-tag.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/create-tag.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/create-tag.yml.tpl.js +13 -9
- package/dist/templates/actions/create-tag.yml.tpl.js.map +1 -1
- package/dist/templates/actions/detect-changes.yml.tpl.d.ts +17 -51
- package/dist/templates/actions/detect-changes.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/detect-changes.yml.tpl.js +130 -110
- package/dist/templates/actions/detect-changes.yml.tpl.js.map +1 -1
- package/dist/templates/actions/manage-branch.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/manage-branch.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/manage-branch.yml.tpl.js +13 -9
- package/dist/templates/actions/manage-branch.yml.tpl.js.map +1 -1
- package/dist/templates/actions/promote-branch.yml.tpl.d.ts +5 -2
- package/dist/templates/actions/promote-branch.yml.tpl.d.ts.map +1 -1
- package/dist/templates/actions/promote-branch.yml.tpl.js +39 -92
- package/dist/templates/actions/promote-branch.yml.tpl.js.map +1 -1
- package/dist/templates/release-it.cjs.tpl.d.ts +1 -1
- package/dist/templates/release-it.cjs.tpl.d.ts.map +1 -1
- package/dist/templates/release-it.cjs.tpl.js +38 -29
- package/dist/templates/release-it.cjs.tpl.js.map +1 -1
- package/dist/templates/workflows/enforce-pr-target.yml.tpl.d.ts +1 -1
- package/dist/templates/workflows/enforce-pr-target.yml.tpl.d.ts.map +1 -1
- package/dist/templates/workflows/enforce-pr-target.yml.tpl.js +2 -3
- package/dist/templates/workflows/enforce-pr-target.yml.tpl.js.map +1 -1
- package/dist/templates/workflows/pipeline.yml.tpl.d.ts +2 -2
- package/dist/templates/workflows/pipeline.yml.tpl.d.ts.map +1 -1
- package/dist/templates/workflows/pipeline.yml.tpl.js +337 -84
- package/dist/templates/workflows/pipeline.yml.tpl.js.map +1 -1
- package/dist/templates/workflows/pr-title-check.yml.tpl.d.ts +1 -1
- package/dist/templates/workflows/pr-title-check.yml.tpl.d.ts.map +1 -1
- package/dist/templates/workflows/pr-title-check.yml.tpl.js +101 -22
- package/dist/templates/workflows/pr-title-check.yml.tpl.js.map +1 -1
- package/dist/templates/workflows/shared/index.d.ts +4 -2
- package/dist/templates/workflows/shared/index.d.ts.map +1 -1
- package/dist/templates/workflows/shared/index.js +4 -2
- package/dist/templates/workflows/shared/index.js.map +1 -1
- package/dist/templates/workflows/shared/managed-workflow.d.ts +32 -0
- package/dist/templates/workflows/shared/managed-workflow.d.ts.map +1 -0
- package/dist/templates/workflows/shared/managed-workflow.js +51 -0
- package/dist/templates/workflows/shared/managed-workflow.js.map +1 -0
- package/dist/templates/workflows/shared/operations-changes.d.ts +13 -3
- package/dist/templates/workflows/shared/operations-changes.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-changes.js +42 -16
- package/dist/templates/workflows/shared/operations-changes.js.map +1 -1
- package/dist/templates/workflows/shared/operations-domain-jobs.d.ts +18 -1
- package/dist/templates/workflows/shared/operations-domain-jobs.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-domain-jobs.js +142 -17
- package/dist/templates/workflows/shared/operations-domain-jobs.js.map +1 -1
- package/dist/templates/workflows/shared/operations-gate.d.ts +6 -0
- package/dist/templates/workflows/shared/operations-gate.d.ts.map +1 -0
- package/dist/templates/workflows/shared/operations-gate.js +116 -0
- package/dist/templates/workflows/shared/operations-gate.js.map +1 -0
- package/dist/templates/workflows/shared/operations-header.d.ts +11 -1
- package/dist/templates/workflows/shared/operations-header.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-header.js +66 -7
- package/dist/templates/workflows/shared/operations-header.js.map +1 -1
- package/dist/templates/workflows/shared/operations-tag-promote.d.ts +4 -3
- package/dist/templates/workflows/shared/operations-tag-promote.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-tag-promote.js +144 -33
- package/dist/templates/workflows/shared/operations-tag-promote.js.map +1 -1
- package/dist/templates/workflows/shared/operations-version.d.ts +3 -2
- package/dist/templates/workflows/shared/operations-version.d.ts.map +1 -1
- package/dist/templates/workflows/shared/operations-version.js +17 -16
- package/dist/templates/workflows/shared/operations-version.js.map +1 -1
- package/dist/templates/yaml-format-utils.d.ts.map +1 -1
- package/dist/templates/yaml-format-utils.js +1 -5
- package/dist/templates/yaml-format-utils.js.map +1 -1
- package/dist/types/index.d.ts +65 -53
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/action-reference.d.ts +73 -0
- package/dist/utils/action-reference.d.ts.map +1 -0
- package/dist/utils/action-reference.js +120 -0
- package/dist/utils/action-reference.js.map +1 -0
- package/dist/utils/ast-path-operations.d.ts +3 -3
- package/dist/utils/ast-path-operations.d.ts.map +1 -1
- package/dist/utils/ast-path-operations.js +58 -17
- package/dist/utils/ast-path-operations.js.map +1 -1
- package/dist/utils/config.d.ts +16 -5
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +69 -12
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/github-setup.d.ts +7 -7
- package/dist/utils/github-setup.d.ts.map +1 -1
- package/dist/utils/github-setup.js +84 -63
- package/dist/utils/github-setup.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/messaging.d.ts +2 -2
- package/dist/utils/messaging.d.ts.map +1 -1
- package/dist/utils/messaging.js +12 -8
- package/dist/utils/messaging.js.map +1 -1
- package/dist/utils/preflight.d.ts +2 -2
- package/dist/utils/preflight.d.ts.map +1 -1
- package/dist/utils/preflight.js +43 -41
- package/dist/utils/preflight.js.map +1 -1
- package/dist/utils/versioning.d.ts +1 -1
- package/dist/utils/versioning.d.ts.map +1 -1
- package/dist/utils/versioning.js +10 -10
- package/dist/utils/versioning.js.map +1 -1
- package/dist/utils/workflow-semantics.d.ts +61 -0
- package/dist/utils/workflow-semantics.d.ts.map +1 -0
- package/dist/utils/workflow-semantics.js +230 -0
- package/dist/utils/workflow-semantics.js.map +1 -0
- package/package.json +12 -4
- package/src/generators/init.tpl.ts +275 -128
- package/src/generators/workflows.tpl.ts +54 -57
- package/dist/templates/actions/detect-changes-nx.yml.tpl.d.ts +0 -32
- package/dist/templates/actions/detect-changes-nx.yml.tpl.d.ts.map +0 -1
- package/dist/templates/actions/detect-changes-nx.yml.tpl.js +0 -227
- package/dist/templates/actions/detect-changes-nx.yml.tpl.js.map +0 -1
- package/dist/templates/workflows/pipeline-nx.yml.tpl.d.ts +0 -22
- package/dist/templates/workflows/pipeline-nx.yml.tpl.d.ts.map +0 -1
- package/dist/templates/workflows/pipeline-nx.yml.tpl.js +0 -196
- package/dist/templates/workflows/pipeline-nx.yml.tpl.js.map +0 -1
- package/dist/utils/idempotency.d.ts +0 -187
- package/dist/utils/idempotency.d.ts.map +0 -1
- package/dist/utils/idempotency.js +0 -304
- package/dist/utils/idempotency.js.map +0 -1
|
@@ -1,43 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Init Template Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates the initial PipeCraft configuration file (.pipecraftrc
|
|
3
|
+
*
|
|
4
|
+
* Generates the initial PipeCraft configuration file (.pipecraftrc) with default settings.
|
|
5
5
|
* This generator is invoked by the `pipecraft init` command and prompts the user for
|
|
6
6
|
* basic project configuration preferences.
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* @module generators/init.tpl
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```typescript
|
|
12
12
|
* import { generate } from './generators/init.tpl.js'
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
* // Called by CLI with Pinion context
|
|
15
15
|
* await generate(pinionContext)
|
|
16
|
-
*
|
|
17
|
-
* // Creates .pipecraftrc
|
|
16
|
+
*
|
|
17
|
+
* // Creates .pipecraftrc with:
|
|
18
18
|
* // - CI provider (GitHub/GitLab)
|
|
19
19
|
* // - Merge strategy (fast-forward/merge)
|
|
20
20
|
* // - Branch flow configuration
|
|
21
21
|
* // - Domain-based change detection
|
|
22
22
|
* // - Semantic versioning rules
|
|
23
23
|
* ```
|
|
24
|
-
*
|
|
24
|
+
*
|
|
25
25
|
* @note Current Implementation: The generator currently uses hardcoded defaults
|
|
26
26
|
* from `defaultConfig` regardless of user prompt responses. This is intentional
|
|
27
27
|
* for the initial release to ensure consistent behavior. Future versions will
|
|
28
28
|
* respect user input and allow customization.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
import { PinionContext
|
|
32
|
-
import { existsSync,
|
|
31
|
+
import type { PinionContext } from '@featherscloud/pinion'
|
|
32
|
+
import { existsSync, writeFileSync } from 'fs'
|
|
33
33
|
import inquirer from 'inquirer'
|
|
34
|
-
import { IdempotencyManager } from '../utils/idempotency.js'
|
|
35
|
-
import { VersionManager } from '../utils/versioning.js'
|
|
36
|
-
import { PipecraftConfig } from '../types/index.js'
|
|
37
34
|
|
|
38
35
|
/**
|
|
39
36
|
* Default PipeCraft configuration for new projects.
|
|
40
|
-
*
|
|
37
|
+
*
|
|
41
38
|
* Provides a complete, working trunk-based development workflow with:
|
|
42
39
|
* - GitHub Actions CI/CD
|
|
43
40
|
* - Fast-forward merge strategy
|
|
@@ -45,7 +42,7 @@ import { PipecraftConfig } from '../types/index.js'
|
|
|
45
42
|
* - Conventional commits enforcement
|
|
46
43
|
* - Semantic versioning with standard bump rules
|
|
47
44
|
* - Domain-based change detection for monorepos
|
|
48
|
-
*
|
|
45
|
+
*
|
|
49
46
|
* @const
|
|
50
47
|
*/
|
|
51
48
|
const defaultConfig = {
|
|
@@ -55,14 +52,28 @@ const defaultConfig = {
|
|
|
55
52
|
initialBranch: 'develop',
|
|
56
53
|
finalBranch: 'main',
|
|
57
54
|
branchFlow: ['develop', 'staging', 'main'],
|
|
58
|
-
|
|
55
|
+
autoPromote: {
|
|
59
56
|
staging: true,
|
|
60
57
|
main: true
|
|
61
58
|
},
|
|
62
59
|
semver: {
|
|
63
60
|
bumpRules: {
|
|
64
|
-
|
|
61
|
+
test: 'ignore',
|
|
62
|
+
build: 'ignore',
|
|
63
|
+
|
|
64
|
+
ci: 'patch',
|
|
65
|
+
docs: 'patch',
|
|
66
|
+
style: 'patch',
|
|
65
67
|
fix: 'patch',
|
|
68
|
+
perf: 'patch',
|
|
69
|
+
refactor: 'patch',
|
|
70
|
+
chore: 'patch',
|
|
71
|
+
patch: 'patch',
|
|
72
|
+
|
|
73
|
+
feat: 'minor',
|
|
74
|
+
minor: 'minor',
|
|
75
|
+
|
|
76
|
+
major: 'major',
|
|
66
77
|
breaking: 'major'
|
|
67
78
|
}
|
|
68
79
|
},
|
|
@@ -87,54 +98,216 @@ const defaultConfig = {
|
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
/**
|
|
90
|
-
* Generates a
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* @
|
|
99
|
-
*
|
|
101
|
+
* Generates a YAML configuration file with comprehensive comments.
|
|
102
|
+
*
|
|
103
|
+
* Creates a .pipecraftrc file with:
|
|
104
|
+
* - Descriptive section headers
|
|
105
|
+
* - Inline comments for each configuration option
|
|
106
|
+
* - Examples and valid values
|
|
107
|
+
* - Proper YAML formatting
|
|
108
|
+
*
|
|
109
|
+
* @param {any} config - The configuration object to serialize
|
|
110
|
+
* @returns {string} YAML string with comments
|
|
100
111
|
*/
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
const generateYamlConfig = (config: any): string => {
|
|
113
|
+
const lines: string[] = []
|
|
114
|
+
|
|
115
|
+
// Header
|
|
116
|
+
lines.push('# PipeCraft Configuration')
|
|
117
|
+
lines.push('# Trunk-based development workflow automation')
|
|
118
|
+
lines.push('# https://pipecraft.thecraftlab.dev')
|
|
119
|
+
lines.push('')
|
|
120
|
+
|
|
121
|
+
// CI Provider
|
|
122
|
+
lines.push('# CI/CD Platform')
|
|
123
|
+
lines.push(`ciProvider: ${config.ciProvider}`)
|
|
124
|
+
lines.push('')
|
|
125
|
+
|
|
126
|
+
// Merge Strategy
|
|
127
|
+
lines.push('# Merge strategy for automatic promotions')
|
|
128
|
+
lines.push(
|
|
129
|
+
"# Options: 'fast-forward' (clean linear history, recommended) | 'merge' (creates merge commits)"
|
|
130
|
+
)
|
|
131
|
+
lines.push(`mergeStrategy: ${config.mergeStrategy}`)
|
|
132
|
+
lines.push('')
|
|
133
|
+
|
|
134
|
+
// Conventional Commits
|
|
135
|
+
lines.push('# Enforce conventional commit messages (feat:, fix:, etc.)')
|
|
136
|
+
lines.push(`requireConventionalCommits: ${config.requireConventionalCommits}`)
|
|
137
|
+
lines.push('')
|
|
138
|
+
|
|
139
|
+
// Branch Configuration
|
|
140
|
+
lines.push('# Branch flow configuration')
|
|
141
|
+
lines.push(`initialBranch: ${config.initialBranch} # Where features land`)
|
|
142
|
+
lines.push(`finalBranch: ${config.finalBranch} # Production branch`)
|
|
143
|
+
lines.push('')
|
|
144
|
+
|
|
145
|
+
// Branch Flow
|
|
146
|
+
lines.push(`# Promotion flow: ${config.branchFlow.join(' → ')}`)
|
|
147
|
+
lines.push('branchFlow:')
|
|
148
|
+
config.branchFlow.forEach((branch: string, index: number) => {
|
|
149
|
+
const comments = [
|
|
150
|
+
'# Feature integration and initial testing',
|
|
151
|
+
'# Pre-production validation',
|
|
152
|
+
'# Production releases'
|
|
153
|
+
]
|
|
154
|
+
lines.push(` - ${branch} ${comments[index] || ''}`)
|
|
155
|
+
})
|
|
156
|
+
lines.push('')
|
|
157
|
+
|
|
158
|
+
// Auto Merge
|
|
159
|
+
lines.push('# Automatic promotion after successful tests')
|
|
160
|
+
lines.push('autoPromote:')
|
|
161
|
+
const autoPromoteEntries = Object.entries(config.autoPromote)
|
|
162
|
+
autoPromoteEntries.forEach(([key, value]) => {
|
|
163
|
+
const flowIndex = config.branchFlow.indexOf(key)
|
|
164
|
+
const fromBranch = flowIndex > 0 ? config.branchFlow[flowIndex - 1] : ''
|
|
165
|
+
const comment = fromBranch ? ` # Auto-promote ${fromBranch} → ${key}` : ''
|
|
166
|
+
lines.push(` ${key}: ${value}${comment}`)
|
|
167
|
+
})
|
|
168
|
+
lines.push('')
|
|
169
|
+
|
|
170
|
+
// Package Manager (if present)
|
|
171
|
+
if (config.packageManager) {
|
|
172
|
+
lines.push('# Package manager')
|
|
173
|
+
lines.push(`packageManager: ${config.packageManager}`)
|
|
174
|
+
lines.push('')
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Semantic Versioning
|
|
178
|
+
lines.push('# Semantic versioning rules')
|
|
179
|
+
lines.push('# Prefixes are used to determine the type of change and the version bump level')
|
|
180
|
+
lines.push('semver:')
|
|
181
|
+
lines.push(' bumpRules:')
|
|
182
|
+
|
|
183
|
+
const bumpRules = config.semver.bumpRules
|
|
184
|
+
const ruleGroups = [
|
|
185
|
+
{ title: '# Ignored types (no version bump)', keys: ['test', 'build'] },
|
|
186
|
+
{
|
|
187
|
+
title: '# Patch-level changes (0.0.x)',
|
|
188
|
+
keys: ['ci', 'docs', 'style', 'fix', 'perf', 'refactor', 'chore', 'patch']
|
|
112
189
|
},
|
|
113
|
-
|
|
190
|
+
{ title: '# Minor-level changes (0.x.0)', keys: ['feat', 'minor'] },
|
|
191
|
+
{ title: '# Major-level changes (x.0.0)', keys: ['major', 'breaking'] }
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
ruleGroups.forEach((group, groupIndex) => {
|
|
195
|
+
if (groupIndex > 0) lines.push('')
|
|
196
|
+
lines.push(` ${group.title}`)
|
|
197
|
+
group.keys.forEach(key => {
|
|
198
|
+
if (bumpRules[key]) {
|
|
199
|
+
lines.push(` ${key}: '${bumpRules[key]}'`)
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
lines.push('')
|
|
204
|
+
|
|
205
|
+
// Domains
|
|
206
|
+
lines.push('# Domain definitions - what parts of your codebase trigger which jobs')
|
|
207
|
+
lines.push(
|
|
208
|
+
'# Will create placeholder jobs for each domain if no jobs are defined in the pipeline.yml'
|
|
209
|
+
)
|
|
210
|
+
lines.push('domains:')
|
|
211
|
+
|
|
212
|
+
Object.entries(config.domains).forEach(([domainName, domainConfig]: [string, any]) => {
|
|
213
|
+
lines.push(` ${domainName}:`)
|
|
214
|
+
|
|
215
|
+
// Description (always write as field)
|
|
216
|
+
if (domainConfig.description) {
|
|
217
|
+
lines.push(` description: '${domainConfig.description}'`)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Paths
|
|
221
|
+
if (domainConfig.paths) {
|
|
222
|
+
lines.push(' paths:')
|
|
223
|
+
domainConfig.paths.forEach((path: string) => {
|
|
224
|
+
lines.push(` - ${path}`)
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Prefixes (if present)
|
|
229
|
+
if (domainConfig.prefixes) {
|
|
230
|
+
lines.push(` prefixes: [${domainConfig.prefixes.map((p: string) => `'${p}'`).join(', ')}]`)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
lines.push('')
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// Versioning (if present)
|
|
237
|
+
if (config.versioning) {
|
|
238
|
+
lines.push('# Version calculation and release automation')
|
|
239
|
+
lines.push('versioning:')
|
|
240
|
+
lines.push(` enabled: ${config.versioning.enabled}`)
|
|
241
|
+
if (config.versioning.releaseItConfig) {
|
|
242
|
+
lines.push(` releaseItConfig: ${config.versioning.releaseItConfig}`)
|
|
243
|
+
}
|
|
244
|
+
if (config.versioning.conventionalCommits !== undefined) {
|
|
245
|
+
lines.push(
|
|
246
|
+
` conventionalCommits: ${config.versioning.conventionalCommits} # Use conventional commits for version bumps`
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
if (config.versioning.autoTag !== undefined) {
|
|
250
|
+
lines.push(
|
|
251
|
+
` autoTag: ${config.versioning.autoTag} # Automatically create git tags`
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
if (config.versioning.autoPush !== undefined) {
|
|
255
|
+
lines.push(
|
|
256
|
+
` autoPush: ${config.versioning.autoPush} # Manual control over git push`
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
if (config.versioning.changelog !== undefined) {
|
|
260
|
+
lines.push(` changelog: ${config.versioning.changelog} # Generate CHANGELOG.md`)
|
|
261
|
+
}
|
|
262
|
+
// Note: bumpRules are defined in the semver section, not here
|
|
263
|
+
lines.push('')
|
|
114
264
|
}
|
|
115
265
|
|
|
116
|
-
//
|
|
117
|
-
if (
|
|
118
|
-
|
|
266
|
+
// Rebuild configuration (if present)
|
|
267
|
+
if (config.rebuild) {
|
|
268
|
+
lines.push('# Workflow rebuild optimization')
|
|
269
|
+
lines.push('rebuild:')
|
|
270
|
+
lines.push(` enabled: ${config.rebuild.enabled} # Enable smart rebuild detection`)
|
|
271
|
+
if (config.rebuild.skipIfUnchanged !== undefined) {
|
|
272
|
+
lines.push(
|
|
273
|
+
` skipIfUnchanged: ${config.rebuild.skipIfUnchanged} # Skip regeneration if config hasn't changed`
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
if (config.rebuild.forceRegenerate !== undefined) {
|
|
277
|
+
lines.push(
|
|
278
|
+
` forceRegenerate: ${config.rebuild.forceRegenerate} # Force regenerate even if unchanged`
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
if (config.rebuild.cacheFile) {
|
|
282
|
+
lines.push(` cacheFile: ${config.rebuild.cacheFile}`)
|
|
283
|
+
}
|
|
284
|
+
lines.push('')
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Remove trailing empty line
|
|
288
|
+
while (lines[lines.length - 1] === '') {
|
|
289
|
+
lines.pop()
|
|
119
290
|
}
|
|
120
291
|
|
|
121
|
-
|
|
292
|
+
lines.push('') // Single trailing newline
|
|
293
|
+
|
|
294
|
+
return lines.join('\n')
|
|
122
295
|
}
|
|
123
296
|
|
|
124
297
|
/**
|
|
125
298
|
* Init generator main entry point.
|
|
126
|
-
*
|
|
299
|
+
*
|
|
127
300
|
* Orchestrates the initialization process by:
|
|
128
301
|
* 1. Prompting user for project preferences (currently unused - see note)
|
|
129
302
|
* 2. Merging user input with default configuration
|
|
130
303
|
* 3. Generating and writing .pipecraftrc.json file
|
|
131
|
-
*
|
|
304
|
+
*
|
|
132
305
|
* @param {PinionContext} ctx - Pinion generator context from CLI
|
|
133
306
|
* @returns {Promise<PinionContext>} Updated context after file generation
|
|
134
|
-
*
|
|
307
|
+
*
|
|
135
308
|
* @throws {Error} If configuration file cannot be written
|
|
136
309
|
* @throws {Error} If user input validation fails
|
|
137
|
-
*
|
|
310
|
+
*
|
|
138
311
|
* @example
|
|
139
312
|
* ```typescript
|
|
140
313
|
* // Called by Pinion framework when user runs `pipecraft init`
|
|
@@ -143,16 +316,16 @@ const configTemplate = (ctx: PipecraftConfig) => {
|
|
|
143
316
|
* argv: ['init'],
|
|
144
317
|
* pinion: { ... }
|
|
145
318
|
* })
|
|
146
|
-
*
|
|
319
|
+
*
|
|
147
320
|
* // Results in: /path/to/project/.pipecraftrc.json
|
|
148
321
|
* ```
|
|
149
|
-
*
|
|
322
|
+
*
|
|
150
323
|
* @note Current Behavior: Despite prompting for user input, the generator
|
|
151
324
|
* currently overwrites all responses with `defaultConfig` values (line 167).
|
|
152
325
|
* This ensures consistency for the initial release. Future versions will
|
|
153
326
|
* respect user choices and allow customization of branch names, merge strategies,
|
|
154
327
|
* and domain configurations.
|
|
155
|
-
*
|
|
328
|
+
*
|
|
156
329
|
* Prompts Presented (currently unused):
|
|
157
330
|
* - Project name
|
|
158
331
|
* - CI provider (GitHub/GitLab)
|
|
@@ -165,24 +338,36 @@ const configTemplate = (ctx: PipecraftConfig) => {
|
|
|
165
338
|
export const generate = async (ctx: PinionContext) => {
|
|
166
339
|
const cwd = ctx.cwd || process.cwd()
|
|
167
340
|
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
341
|
+
// Check if .pipecraftrc already exists (YAML format)
|
|
342
|
+
const configPath = `${cwd}/.pipecraftrc`
|
|
343
|
+
const legacyConfigPath = `${cwd}/.pipecraftrc.json`
|
|
344
|
+
|
|
345
|
+
if (existsSync(configPath) || existsSync(legacyConfigPath)) {
|
|
346
|
+
const existingPath = existsSync(configPath) ? '.pipecraftrc' : '.pipecraftrc.json'
|
|
347
|
+
const overwriteAnswer = await inquirer.prompt([
|
|
348
|
+
{
|
|
349
|
+
type: 'confirm',
|
|
350
|
+
name: 'overwrite',
|
|
351
|
+
message: `⚠️ ${existingPath} already exists. Overwrite it?`,
|
|
352
|
+
default: false
|
|
353
|
+
}
|
|
354
|
+
])
|
|
355
|
+
|
|
356
|
+
if (!overwriteAnswer.overwrite) {
|
|
357
|
+
console.log('\n❌ Init cancelled. Existing configuration preserved.\n')
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
console.log('\n✅ Proceeding with overwrite...\n')
|
|
362
|
+
|
|
363
|
+
// Set force flag to true so Pinion will overwrite the file
|
|
364
|
+
if (ctx.pinion) {
|
|
365
|
+
ctx.pinion.force = true
|
|
366
|
+
}
|
|
176
367
|
}
|
|
177
368
|
|
|
178
369
|
// Run inquirer prompts
|
|
179
370
|
const answers = await inquirer.prompt([
|
|
180
|
-
{
|
|
181
|
-
type: 'input',
|
|
182
|
-
name: 'projectName',
|
|
183
|
-
message: 'What is your project name?',
|
|
184
|
-
default: 'my-project'
|
|
185
|
-
},
|
|
186
371
|
{
|
|
187
372
|
type: 'list',
|
|
188
373
|
name: 'ciProvider',
|
|
@@ -228,13 +413,6 @@ export const generate = async (ctx: PinionContext) => {
|
|
|
228
413
|
default: 'develop,staging,main',
|
|
229
414
|
filter: (input: string) => input.split(',').map(b => b.trim())
|
|
230
415
|
},
|
|
231
|
-
{
|
|
232
|
-
type: 'list',
|
|
233
|
-
name: 'packageManager',
|
|
234
|
-
message: `Which package manager do you use? (detected: ${detectedPackageManager})`,
|
|
235
|
-
choices: ['npm', 'yarn', 'pnpm'],
|
|
236
|
-
default: detectedPackageManager
|
|
237
|
-
},
|
|
238
416
|
{
|
|
239
417
|
type: 'list',
|
|
240
418
|
name: 'domainSelection',
|
|
@@ -261,13 +439,20 @@ export const generate = async (ctx: PinionContext) => {
|
|
|
261
439
|
if (!input.trim()) {
|
|
262
440
|
return 'Please enter at least one domain'
|
|
263
441
|
}
|
|
264
|
-
const domains = input
|
|
442
|
+
const domains = input
|
|
443
|
+
.split(',')
|
|
444
|
+
.map(d => d.trim())
|
|
445
|
+
.filter(d => d)
|
|
265
446
|
if (domains.length === 0) {
|
|
266
447
|
return 'Please enter valid domain names'
|
|
267
448
|
}
|
|
268
449
|
return true
|
|
269
450
|
},
|
|
270
|
-
filter: (input: string) =>
|
|
451
|
+
filter: (input: string) =>
|
|
452
|
+
input
|
|
453
|
+
.split(',')
|
|
454
|
+
.map(d => d.trim())
|
|
455
|
+
.filter(d => d)
|
|
271
456
|
}
|
|
272
457
|
])
|
|
273
458
|
selectedDomains = customDomainsAnswer.customDomains
|
|
@@ -278,7 +463,10 @@ export const generate = async (ctx: PinionContext) => {
|
|
|
278
463
|
'frontend-backend': ['frontend', 'backend'],
|
|
279
464
|
'apps-libs': ['apps', 'libs']
|
|
280
465
|
}
|
|
281
|
-
selectedDomains = domainMappings[answers.domainSelection as keyof typeof domainMappings] || [
|
|
466
|
+
selectedDomains = domainMappings[answers.domainSelection as keyof typeof domainMappings] || [
|
|
467
|
+
'api',
|
|
468
|
+
'web'
|
|
469
|
+
]
|
|
282
470
|
}
|
|
283
471
|
|
|
284
472
|
// Generate domain configuration
|
|
@@ -292,64 +480,20 @@ export const generate = async (ctx: PinionContext) => {
|
|
|
292
480
|
|
|
293
481
|
// Add cicd domain for CI/CD changes
|
|
294
482
|
domainConfig.cicd = {
|
|
295
|
-
paths: ['.github
|
|
483
|
+
paths: ['.github/**'],
|
|
296
484
|
description: 'CI/CD configuration changes'
|
|
297
485
|
}
|
|
298
486
|
|
|
299
487
|
// Show warning for custom domains about path editing
|
|
300
488
|
if (answers.domainSelection === 'custom') {
|
|
301
489
|
console.log('\n⚠️ Custom domains selected!')
|
|
302
|
-
console.log(' You will need to edit the paths in .pipecraftrc
|
|
490
|
+
console.log(' You will need to edit the paths in .pipecraftrc after generation')
|
|
303
491
|
console.log(' to match your actual project structure.\n')
|
|
304
492
|
}
|
|
305
493
|
|
|
306
494
|
// Merge answers with context and defaults
|
|
307
495
|
const mergedCtx = { ...ctx, ...defaultConfig, ...answers } as any
|
|
308
496
|
|
|
309
|
-
// Detect Nx workspace
|
|
310
|
-
const nxJsonPath = `${cwd}/nx.json`
|
|
311
|
-
let nxConfig = undefined
|
|
312
|
-
|
|
313
|
-
if (existsSync(nxJsonPath)) {
|
|
314
|
-
try {
|
|
315
|
-
const nxJsonContent = readFileSync(nxJsonPath, 'utf8')
|
|
316
|
-
const nxJson = JSON.parse(nxJsonContent)
|
|
317
|
-
|
|
318
|
-
// Extract tasks from targetDefaults
|
|
319
|
-
const tasks = nxJson.targetDefaults ? Object.keys(nxJson.targetDefaults) : []
|
|
320
|
-
|
|
321
|
-
// Sort tasks in a logical order (quality → test → build → e2e)
|
|
322
|
-
const taskOrder = ['lint', 'typecheck', 'test', 'unit-test', 'build', 'integration-test', 'e2e', 'e2e-ci']
|
|
323
|
-
const sortedTasks = tasks.sort((a, b) => {
|
|
324
|
-
const aIdx = taskOrder.indexOf(a)
|
|
325
|
-
const bIdx = taskOrder.indexOf(b)
|
|
326
|
-
if (aIdx === -1 && bIdx === -1) return 0
|
|
327
|
-
if (aIdx === -1) return 1
|
|
328
|
-
if (bIdx === -1) return -1
|
|
329
|
-
return aIdx - bIdx
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
console.log('✅ Nx workspace detected - enabling Nx integration')
|
|
333
|
-
console.log(` Detected tasks: ${sortedTasks.join(', ')}`)
|
|
334
|
-
|
|
335
|
-
nxConfig = {
|
|
336
|
-
enabled: true,
|
|
337
|
-
tasks: sortedTasks,
|
|
338
|
-
baseRef: 'origin/main',
|
|
339
|
-
enableCache: true
|
|
340
|
-
}
|
|
341
|
-
} catch (error) {
|
|
342
|
-
console.warn('⚠️ Found nx.json but could not parse it:', error)
|
|
343
|
-
console.log(' Using default Nx configuration')
|
|
344
|
-
nxConfig = {
|
|
345
|
-
enabled: true,
|
|
346
|
-
tasks: ['lint', 'test', 'build', 'integration-test'],
|
|
347
|
-
baseRef: 'origin/main',
|
|
348
|
-
enableCache: true
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
497
|
const configData: any = {
|
|
354
498
|
ciProvider: mergedCtx.ciProvider,
|
|
355
499
|
mergeStrategy: mergedCtx.mergeStrategy,
|
|
@@ -357,18 +501,21 @@ export const generate = async (ctx: PinionContext) => {
|
|
|
357
501
|
initialBranch: mergedCtx.initialBranch,
|
|
358
502
|
finalBranch: mergedCtx.finalBranch,
|
|
359
503
|
branchFlow: mergedCtx.branchFlow,
|
|
360
|
-
|
|
361
|
-
packageManager: mergedCtx.packageManager,
|
|
504
|
+
autoPromote: mergedCtx.autoPromote,
|
|
362
505
|
semver: {
|
|
363
506
|
bumpRules: mergedCtx.semver.bumpRules
|
|
364
507
|
},
|
|
365
508
|
domains: domainConfig // Use user-selected domains instead of defaults
|
|
366
509
|
}
|
|
367
510
|
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
511
|
+
// Generate YAML content with comments
|
|
512
|
+
const yamlContent = generateYamlConfig(configData)
|
|
513
|
+
|
|
514
|
+
// Write the .pipecraftrc file
|
|
515
|
+
const outputPath = `${cwd}/.pipecraftrc`
|
|
516
|
+
writeFileSync(outputPath, yamlContent, 'utf-8')
|
|
372
517
|
|
|
373
|
-
|
|
374
|
-
|
|
518
|
+
console.log(`\n✅ Created ${outputPath}\n`)
|
|
519
|
+
|
|
520
|
+
return mergedCtx
|
|
521
|
+
}
|