@wyxos/zephyr 0.6.0 → 0.7.4
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 +27 -3
- package/package.json +1 -1
- package/src/application/configuration/preset-selection.mjs +0 -6
- package/src/application/configuration/select-deployment-target.mjs +108 -71
- package/src/application/deploy/build-remote-deployment-plan.mjs +13 -1
- package/src/application/deploy/plan-laravel-deployment-tasks.mjs +23 -2
- package/src/application/deploy/prepare-local-deployment.mjs +18 -9
- package/src/application/deploy/run-deployment.mjs +5 -1
- package/src/application/deploy/run-local-deployment-checks.mjs +38 -2
- package/src/application/release/release-node-package.mjs +68 -12
- package/src/application/release/release-packagist-package.mjs +56 -12
- package/src/cli/options.mjs +28 -1
- package/src/config/preset-options.mjs +89 -0
- package/src/config/project.mjs +45 -10
- package/src/deploy/local-repo.mjs +29 -16
- package/src/deploy/preflight.mjs +57 -3
- package/src/main.mjs +54 -4
- package/src/release/commit-message.mjs +8 -239
- package/src/release-node.mjs +8 -1
- package/src/release-packagist.mjs +10 -3
- package/src/runtime/app-context.mjs +10 -1
package/src/main.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import * as bootstrap from './project/bootstrap.mjs'
|
|
|
11
11
|
import {getErrorCode, ZephyrError} from './runtime/errors.mjs'
|
|
12
12
|
import {PROJECT_CONFIG_DIR} from './utils/paths.mjs'
|
|
13
13
|
import {writeStderrLine} from './utils/output.mjs'
|
|
14
|
+
import {mergeDeployOptions} from './config/preset-options.mjs'
|
|
14
15
|
import {createAppContext} from './runtime/app-context.mjs'
|
|
15
16
|
import {createConfigurationService} from './application/configuration/service.mjs'
|
|
16
17
|
import {selectDeploymentTarget} from './application/configuration/select-deployment-target.mjs'
|
|
@@ -35,12 +36,21 @@ function normalizeMainOptions(firstArg = null, secondArg = null) {
|
|
|
35
36
|
resumePending: firstArg.resumePending === true,
|
|
36
37
|
discardPending: firstArg.discardPending === true,
|
|
37
38
|
maintenanceMode: firstArg.maintenanceMode ?? null,
|
|
39
|
+
autoCommit: firstArg.autoCommit === true,
|
|
40
|
+
skipVersioning: firstArg.skipVersioning === true,
|
|
38
41
|
skipGitHooks: firstArg.skipGitHooks === true,
|
|
39
42
|
skipChecks: firstArg.skipChecks === true,
|
|
40
43
|
skipTests: firstArg.skipTests === true || firstArg.skipChecks === true,
|
|
41
44
|
skipLint: firstArg.skipLint === true || firstArg.skipChecks === true,
|
|
42
45
|
skipBuild: firstArg.skipBuild === true,
|
|
43
46
|
skipDeploy: firstArg.skipDeploy === true,
|
|
47
|
+
explicitMaintenanceMode: firstArg.explicitMaintenanceMode === true || 'maintenanceMode' in firstArg,
|
|
48
|
+
explicitAutoCommit: firstArg.explicitAutoCommit === true || 'autoCommit' in firstArg,
|
|
49
|
+
explicitSkipVersioning: firstArg.explicitSkipVersioning === true || 'skipVersioning' in firstArg,
|
|
50
|
+
explicitSkipGitHooks: firstArg.explicitSkipGitHooks === true || 'skipGitHooks' in firstArg,
|
|
51
|
+
explicitSkipChecks: firstArg.explicitSkipChecks === true || 'skipChecks' in firstArg,
|
|
52
|
+
explicitSkipTests: firstArg.explicitSkipTests === true || 'skipTests' in firstArg || 'skipChecks' in firstArg,
|
|
53
|
+
explicitSkipLint: firstArg.explicitSkipLint === true || 'skipLint' in firstArg || 'skipChecks' in firstArg,
|
|
44
54
|
context: firstArg.context ?? null
|
|
45
55
|
}
|
|
46
56
|
}
|
|
@@ -54,12 +64,21 @@ function normalizeMainOptions(firstArg = null, secondArg = null) {
|
|
|
54
64
|
resumePending: false,
|
|
55
65
|
discardPending: false,
|
|
56
66
|
maintenanceMode: null,
|
|
67
|
+
autoCommit: false,
|
|
68
|
+
skipVersioning: false,
|
|
57
69
|
skipGitHooks: false,
|
|
58
70
|
skipChecks: false,
|
|
59
71
|
skipTests: false,
|
|
60
72
|
skipLint: false,
|
|
61
73
|
skipBuild: false,
|
|
62
74
|
skipDeploy: false,
|
|
75
|
+
explicitMaintenanceMode: false,
|
|
76
|
+
explicitAutoCommit: false,
|
|
77
|
+
explicitSkipVersioning: false,
|
|
78
|
+
explicitSkipGitHooks: false,
|
|
79
|
+
explicitSkipChecks: false,
|
|
80
|
+
explicitSkipTests: false,
|
|
81
|
+
explicitSkipLint: false,
|
|
63
82
|
context: null
|
|
64
83
|
}
|
|
65
84
|
}
|
|
@@ -110,12 +129,21 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
110
129
|
workflow: resolveWorkflowName(options.workflowType),
|
|
111
130
|
presetName: options.presetName,
|
|
112
131
|
maintenanceMode: options.maintenanceMode,
|
|
132
|
+
autoCommit: options.autoCommit === true,
|
|
133
|
+
skipVersioning: options.skipVersioning === true,
|
|
113
134
|
skipGitHooks: options.skipGitHooks === true,
|
|
114
135
|
skipChecks: options.skipChecks === true,
|
|
115
136
|
skipTests: options.skipTests === true,
|
|
116
137
|
skipLint: options.skipLint === true,
|
|
117
138
|
resumePending: options.resumePending,
|
|
118
|
-
discardPending: options.discardPending
|
|
139
|
+
discardPending: options.discardPending,
|
|
140
|
+
explicitMaintenanceMode: options.explicitMaintenanceMode === true,
|
|
141
|
+
explicitAutoCommit: options.explicitAutoCommit === true,
|
|
142
|
+
explicitSkipVersioning: options.explicitSkipVersioning === true,
|
|
143
|
+
explicitSkipGitHooks: options.explicitSkipGitHooks === true,
|
|
144
|
+
explicitSkipChecks: options.explicitSkipChecks === true,
|
|
145
|
+
explicitSkipTests: options.explicitSkipTests === true,
|
|
146
|
+
explicitSkipLint: options.explicitSkipLint === true
|
|
119
147
|
}
|
|
120
148
|
const appContext = options.context ?? createAppContext({executionMode})
|
|
121
149
|
const {
|
|
@@ -127,7 +155,11 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
127
155
|
runCommand,
|
|
128
156
|
emitEvent
|
|
129
157
|
} = appContext
|
|
130
|
-
|
|
158
|
+
let currentExecutionMode = {
|
|
159
|
+
...executionMode,
|
|
160
|
+
...(appContext.executionMode ?? {})
|
|
161
|
+
}
|
|
162
|
+
appContext.executionMode = currentExecutionMode
|
|
131
163
|
const configurationService = createConfigurationService(appContext)
|
|
132
164
|
|
|
133
165
|
try {
|
|
@@ -142,6 +174,8 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
142
174
|
nonInteractive: currentExecutionMode.interactive === false,
|
|
143
175
|
presetName: currentExecutionMode.presetName,
|
|
144
176
|
maintenanceMode: currentExecutionMode.maintenanceMode,
|
|
177
|
+
autoCommit: currentExecutionMode.autoCommit === true,
|
|
178
|
+
skipVersioning: currentExecutionMode.skipVersioning === true,
|
|
145
179
|
skipGitHooks: currentExecutionMode.skipGitHooks === true,
|
|
146
180
|
skipChecks: currentExecutionMode.skipChecks === true,
|
|
147
181
|
skipTests: currentExecutionMode.skipTests === true,
|
|
@@ -170,6 +204,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
170
204
|
skipGitHooks: options.skipGitHooks,
|
|
171
205
|
skipTests: options.skipTests,
|
|
172
206
|
skipLint: options.skipLint,
|
|
207
|
+
skipVersioning: options.skipVersioning,
|
|
173
208
|
skipBuild: options.skipBuild,
|
|
174
209
|
skipDeploy: options.skipDeploy,
|
|
175
210
|
context: appContext
|
|
@@ -198,6 +233,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
198
233
|
skipGitHooks: options.skipGitHooks,
|
|
199
234
|
skipTests: options.skipTests,
|
|
200
235
|
skipLint: options.skipLint,
|
|
236
|
+
skipVersioning: options.skipVersioning,
|
|
201
237
|
context: appContext
|
|
202
238
|
})
|
|
203
239
|
emitEvent?.('run_completed', {
|
|
@@ -249,7 +285,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
249
285
|
})
|
|
250
286
|
}
|
|
251
287
|
|
|
252
|
-
const {deploymentConfig} = await selectDeploymentTarget(rootDir, {
|
|
288
|
+
const {deploymentConfig, presetState} = await selectDeploymentTarget(rootDir, {
|
|
253
289
|
configurationService,
|
|
254
290
|
runPrompt,
|
|
255
291
|
logProcessing,
|
|
@@ -259,6 +295,19 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
259
295
|
executionMode: currentExecutionMode
|
|
260
296
|
})
|
|
261
297
|
|
|
298
|
+
if (presetState) {
|
|
299
|
+
const effectiveDeployOptions = mergeDeployOptions(currentExecutionMode, presetState.options)
|
|
300
|
+
currentExecutionMode = {
|
|
301
|
+
...currentExecutionMode,
|
|
302
|
+
presetName: presetState.name,
|
|
303
|
+
...effectiveDeployOptions,
|
|
304
|
+
skipChecks: currentExecutionMode.skipChecks === true ||
|
|
305
|
+
(effectiveDeployOptions.skipTests === true && effectiveDeployOptions.skipLint === true)
|
|
306
|
+
}
|
|
307
|
+
appContext.executionMode = currentExecutionMode
|
|
308
|
+
await presetState.applyExecutionMode(currentExecutionMode)
|
|
309
|
+
}
|
|
310
|
+
|
|
262
311
|
const snapshotToUse = await resolvePendingSnapshot(rootDir, deploymentConfig, {
|
|
263
312
|
runPrompt,
|
|
264
313
|
logProcessing,
|
|
@@ -270,7 +319,8 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
270
319
|
rootDir,
|
|
271
320
|
snapshot: snapshotToUse,
|
|
272
321
|
versionArg: options.versionArg,
|
|
273
|
-
context: appContext
|
|
322
|
+
context: appContext,
|
|
323
|
+
presetState
|
|
274
324
|
})
|
|
275
325
|
|
|
276
326
|
emitEvent?.('run_completed', {
|
|
@@ -24,8 +24,6 @@ const GENERIC_SUBJECT_PATTERNS = [
|
|
|
24
24
|
/^(improve|update|adjust|refine|align|support|enable)\s+.+\s+(workflow|process|flow)$/i
|
|
25
25
|
]
|
|
26
26
|
const MAX_WORKING_TREE_PREVIEW = 20
|
|
27
|
-
const MAX_DIFF_EXCERPT_LINES = 60
|
|
28
|
-
const MAX_DIFF_EXCERPT_CHARS = 4000
|
|
29
27
|
const STATUS_LABELS = {
|
|
30
28
|
A: 'added',
|
|
31
29
|
C: 'copied',
|
|
@@ -35,59 +33,6 @@ const STATUS_LABELS = {
|
|
|
35
33
|
T: 'type-changed',
|
|
36
34
|
U: 'conflicted'
|
|
37
35
|
}
|
|
38
|
-
const TOPIC_STOP_WORDS = new Set([
|
|
39
|
-
'src',
|
|
40
|
-
'test',
|
|
41
|
-
'tests',
|
|
42
|
-
'__tests__',
|
|
43
|
-
'spec',
|
|
44
|
-
'specs',
|
|
45
|
-
'app',
|
|
46
|
-
'lib',
|
|
47
|
-
'dist',
|
|
48
|
-
'packages',
|
|
49
|
-
'package',
|
|
50
|
-
'application',
|
|
51
|
-
'shared',
|
|
52
|
-
'index',
|
|
53
|
-
'main',
|
|
54
|
-
'local',
|
|
55
|
-
'repo',
|
|
56
|
-
'prepare',
|
|
57
|
-
'commit',
|
|
58
|
-
'message',
|
|
59
|
-
'js',
|
|
60
|
-
'jsx',
|
|
61
|
-
'ts',
|
|
62
|
-
'tsx',
|
|
63
|
-
'mjs',
|
|
64
|
-
'cjs',
|
|
65
|
-
'php',
|
|
66
|
-
'json',
|
|
67
|
-
'yaml',
|
|
68
|
-
'yml',
|
|
69
|
-
'md',
|
|
70
|
-
'toml',
|
|
71
|
-
'lock'
|
|
72
|
-
])
|
|
73
|
-
|
|
74
|
-
function buildTargetedFallbackCommitMessage(statusEntries = []) {
|
|
75
|
-
const paths = statusEntries.map((entry) => entry.path.toLowerCase())
|
|
76
|
-
const touchesDeployPrep = paths.some((pathValue) => pathValue.includes('prepare-local-deployment'))
|
|
77
|
-
const touchesLocalRepo = paths.some((pathValue) => pathValue.includes('local-repo'))
|
|
78
|
-
const touchesCommitMessage = paths.some((pathValue) => pathValue.includes('commit-message'))
|
|
79
|
-
const touchesReleaseFlow = paths.some((pathValue) => pathValue.includes('/release/') || pathValue.includes('release-'))
|
|
80
|
-
|
|
81
|
-
if (touchesDeployPrep && touchesLocalRepo) {
|
|
82
|
-
return 'fix: prompt for dirty deploy changes before version bump'
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (touchesCommitMessage && touchesReleaseFlow) {
|
|
86
|
-
return 'fix: tighten release commit suggestions'
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return null
|
|
90
|
-
}
|
|
91
36
|
|
|
92
37
|
function resolveWorkingTreeEntryLabel(entry) {
|
|
93
38
|
if (entry.indexStatus === '?' && entry.worktreeStatus === '?') {
|
|
@@ -108,32 +53,6 @@ function resolveWorkingTreeEntryLabel(entry) {
|
|
|
108
53
|
return 'changed'
|
|
109
54
|
}
|
|
110
55
|
|
|
111
|
-
function tokenizePath(pathValue = '') {
|
|
112
|
-
return pathValue
|
|
113
|
-
.split(/[\\/]/)
|
|
114
|
-
.flatMap((segment) => segment.split(/[^a-zA-Z0-9]+/))
|
|
115
|
-
.map((token) => token.toLowerCase())
|
|
116
|
-
.filter((token) => token.length >= 3 && !TOPIC_STOP_WORDS.has(token))
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function inferCommitTypeFromEntries(statusEntries = []) {
|
|
120
|
-
const paths = statusEntries.map((entry) => entry.path.toLowerCase())
|
|
121
|
-
|
|
122
|
-
if (paths.every((pathValue) => pathValue.endsWith('.md') || pathValue.includes('/docs/') || pathValue.startsWith('docs/'))) {
|
|
123
|
-
return 'docs'
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (paths.every((pathValue) => /\.test\.[^.]+$/.test(pathValue) || pathValue.includes('/tests/'))) {
|
|
127
|
-
return 'test'
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (paths.some((pathValue) => pathValue.includes('.github/workflows/') || pathValue.includes('/ci/'))) {
|
|
131
|
-
return 'ci'
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return 'chore'
|
|
135
|
-
}
|
|
136
|
-
|
|
137
56
|
export function parseWorkingTreeStatus(stdout = '') {
|
|
138
57
|
return stdout
|
|
139
58
|
.split(/\r?\n/)
|
|
@@ -228,148 +147,11 @@ export function sanitizeSuggestedCommitMessage(message) {
|
|
|
228
147
|
return normalized
|
|
229
148
|
}
|
|
230
149
|
|
|
231
|
-
export function buildFallbackCommitMessage(statusEntries = []) {
|
|
232
|
-
const targetedFallback = buildTargetedFallbackCommitMessage(statusEntries)
|
|
233
|
-
if (targetedFallback) {
|
|
234
|
-
return targetedFallback
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const tokenCounts = new Map()
|
|
238
|
-
|
|
239
|
-
for (const entry of statusEntries) {
|
|
240
|
-
for (const token of tokenizePath(entry.path)) {
|
|
241
|
-
tokenCounts.set(token, (tokenCounts.get(token) ?? 0) + 1)
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const orderedTokens = Array.from(tokenCounts.entries())
|
|
246
|
-
.sort((left, right) => {
|
|
247
|
-
if (right[1] !== left[1]) {
|
|
248
|
-
return right[1] - left[1]
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return left[0].localeCompare(right[0])
|
|
252
|
-
})
|
|
253
|
-
.map(([token]) => token)
|
|
254
|
-
|
|
255
|
-
const primaryTopic = orderedTokens[0] ?? 'release'
|
|
256
|
-
const commitType = inferCommitTypeFromEntries(statusEntries)
|
|
257
|
-
|
|
258
|
-
if (commitType === 'docs') {
|
|
259
|
-
return `docs: update ${primaryTopic} documentation`
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (commitType === 'test') {
|
|
263
|
-
return `test: expand ${primaryTopic} coverage`
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (commitType === 'ci') {
|
|
267
|
-
return `ci: update ${primaryTopic} pipeline`
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return `chore: update ${primaryTopic} handling`
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
async function collectDiffNumstat(rootDir, {runCommand} = {}) {
|
|
274
|
-
try {
|
|
275
|
-
const {stdout} = await runCommand('git', ['diff', '--numstat', 'HEAD', '--'], {
|
|
276
|
-
capture: true,
|
|
277
|
-
cwd: rootDir
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
return stdout
|
|
281
|
-
.split(/\r?\n/)
|
|
282
|
-
.map((line) => line.trim())
|
|
283
|
-
.filter(Boolean)
|
|
284
|
-
.reduce((map, line) => {
|
|
285
|
-
const [addedRaw, deletedRaw, filePath] = line.split('\t')
|
|
286
|
-
if (!filePath) {
|
|
287
|
-
return map
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const added = Number.parseInt(addedRaw, 10)
|
|
291
|
-
const deleted = Number.parseInt(deletedRaw, 10)
|
|
292
|
-
map.set(filePath, {
|
|
293
|
-
added: Number.isFinite(added) ? added : 0,
|
|
294
|
-
deleted: Number.isFinite(deleted) ? deleted : 0
|
|
295
|
-
})
|
|
296
|
-
return map
|
|
297
|
-
}, new Map())
|
|
298
|
-
} catch {
|
|
299
|
-
return new Map()
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function shouldIncludeDiffExcerptLine(line = '') {
|
|
304
|
-
if (line.startsWith('diff --git ')) {
|
|
305
|
-
return true
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (line.startsWith('@@')) {
|
|
309
|
-
return true
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return (line.startsWith('+') || line.startsWith('-')) && !line.startsWith('+++') && !line.startsWith('---')
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function trimDiffExcerpt(diffText = '') {
|
|
316
|
-
const selectedLines = []
|
|
317
|
-
let totalChars = 0
|
|
318
|
-
|
|
319
|
-
for (const rawLine of diffText.split(/\r?\n/)) {
|
|
320
|
-
const line = rawLine.trimEnd()
|
|
321
|
-
|
|
322
|
-
if (!shouldIncludeDiffExcerptLine(line)) {
|
|
323
|
-
continue
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
const truncatedLine = line.length > 180 ? `${line.slice(0, 177)}...` : line
|
|
327
|
-
const nextTotal = totalChars + truncatedLine.length + 1
|
|
328
|
-
|
|
329
|
-
if (selectedLines.length >= MAX_DIFF_EXCERPT_LINES || nextTotal > MAX_DIFF_EXCERPT_CHARS) {
|
|
330
|
-
break
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
selectedLines.push(truncatedLine)
|
|
334
|
-
totalChars = nextTotal
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return selectedLines.join('\n')
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
async function collectDiffExcerpt(rootDir, {runCommand} = {}) {
|
|
341
|
-
try {
|
|
342
|
-
const {stdout} = await runCommand('git', ['diff', '--unified=0', '--no-color', 'HEAD', '--'], {
|
|
343
|
-
capture: true,
|
|
344
|
-
cwd: rootDir
|
|
345
|
-
})
|
|
346
|
-
|
|
347
|
-
return trimDiffExcerpt(stdout)
|
|
348
|
-
} catch {
|
|
349
|
-
return ''
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
async function buildCommitMessageContext(rootDir, {
|
|
354
|
-
runCommand,
|
|
355
|
-
statusEntries = []
|
|
356
|
-
} = {}) {
|
|
357
|
-
const changeCountsByPath = await collectDiffNumstat(rootDir, {runCommand})
|
|
358
|
-
const summary = statusEntries.map((entry) => `- ${summarizeWorkingTreeEntry(entry, {changeCountsByPath})}`).join('\n')
|
|
359
|
-
const diffExcerpt = await collectDiffExcerpt(rootDir, {runCommand})
|
|
360
|
-
|
|
361
|
-
return {
|
|
362
|
-
summary,
|
|
363
|
-
diffExcerpt
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
150
|
export async function suggestCommitMessage(rootDir = process.cwd(), {
|
|
368
151
|
runCommand,
|
|
369
152
|
commandExistsImpl = commandExists,
|
|
370
153
|
logStep,
|
|
371
|
-
logWarning
|
|
372
|
-
statusEntries = []
|
|
154
|
+
logWarning
|
|
373
155
|
} = {}) {
|
|
374
156
|
if (!commandExistsImpl('codex')) {
|
|
375
157
|
return null
|
|
@@ -380,28 +162,9 @@ export async function suggestCommitMessage(rootDir = process.cwd(), {
|
|
|
380
162
|
try {
|
|
381
163
|
tempDir = await mkdtemp(path.join(tmpdir(), 'zephyr-release-commit-'))
|
|
382
164
|
const outputPath = path.join(tempDir, 'codex-last-message.txt')
|
|
383
|
-
const commitContext = await buildCommitMessageContext(rootDir, {
|
|
384
|
-
runCommand,
|
|
385
|
-
statusEntries
|
|
386
|
-
})
|
|
387
165
|
|
|
388
166
|
logStep?.('Generating a suggested commit message with Codex...')
|
|
389
167
|
|
|
390
|
-
const promptSections = [
|
|
391
|
-
'Write exactly one short conventional commit message for these pending changes.',
|
|
392
|
-
'Use the exact format "<type>: <subject>" with no scope, no exclamation mark, and no extra text.',
|
|
393
|
-
'Choose the most appropriate type from: fix, feat, chore, docs, refactor, test, style, perf, build, ci, revert.',
|
|
394
|
-
'Base the subject on the actual behavior, safeguard, bug fix, feature, or API change shown below.',
|
|
395
|
-
'Avoid generic nouns like "workflow", "process", "flow", "changes", or "updates" unless the diff truly changes CI or docs.',
|
|
396
|
-
'Do not describe the commit itself, staging, or "pending changes"; describe the underlying code or product change.',
|
|
397
|
-
'Pending change summary:',
|
|
398
|
-
commitContext.summary || '- changed files present'
|
|
399
|
-
]
|
|
400
|
-
|
|
401
|
-
if (commitContext.diffExcerpt) {
|
|
402
|
-
promptSections.push('Diff excerpt:', commitContext.diffExcerpt)
|
|
403
|
-
}
|
|
404
|
-
|
|
405
168
|
await runCommand('codex', [
|
|
406
169
|
'exec',
|
|
407
170
|
'--ephemeral',
|
|
@@ -412,7 +175,13 @@ export async function suggestCommitMessage(rootDir = process.cwd(), {
|
|
|
412
175
|
'--skip-git-repo-check',
|
|
413
176
|
'--output-last-message',
|
|
414
177
|
outputPath,
|
|
415
|
-
|
|
178
|
+
[
|
|
179
|
+
'Inspect the current repository and decide the best conventional commit message for the pending changes.',
|
|
180
|
+
'Use whatever read-only inspection you need.',
|
|
181
|
+
'Reply with exactly one line in the format "<type>: <subject>".',
|
|
182
|
+
'Do not use scopes like "fix(scope): ...".',
|
|
183
|
+
'Do not include extra text.'
|
|
184
|
+
].join('\n\n')
|
|
416
185
|
], {
|
|
417
186
|
capture: true,
|
|
418
187
|
cwd: rootDir
|
package/src/release-node.mjs
CHANGED
|
@@ -9,6 +9,7 @@ function hasExplicitReleaseOptions(options = {}) {
|
|
|
9
9
|
'skipGitHooks',
|
|
10
10
|
'skipTests',
|
|
11
11
|
'skipLint',
|
|
12
|
+
'skipVersioning',
|
|
12
13
|
'skipBuild',
|
|
13
14
|
'skipDeploy'
|
|
14
15
|
].some((key) => key in options)
|
|
@@ -21,12 +22,17 @@ export async function releaseNode(options = {}) {
|
|
|
21
22
|
skipGitHooks: options.skipGitHooks === true,
|
|
22
23
|
skipTests: options.skipTests === true,
|
|
23
24
|
skipLint: options.skipLint === true,
|
|
25
|
+
skipVersioning: options.skipVersioning === true,
|
|
24
26
|
skipBuild: options.skipBuild === true,
|
|
25
27
|
skipDeploy: options.skipDeploy === true
|
|
26
28
|
}
|
|
27
29
|
: parseReleaseArgs({
|
|
28
|
-
booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint', '--skip-build', '--skip-deploy']
|
|
30
|
+
booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint', '--skip-versioning', '--skip-build', '--skip-deploy']
|
|
29
31
|
})
|
|
32
|
+
|
|
33
|
+
if (parsed.skipVersioning && parsed.releaseType) {
|
|
34
|
+
throw new Error('--skip-versioning cannot be used together with an explicit version or bump argument.')
|
|
35
|
+
}
|
|
30
36
|
const rootDir = options.rootDir ?? process.cwd()
|
|
31
37
|
const context = options.context ?? createAppContext({
|
|
32
38
|
executionMode: {
|
|
@@ -42,6 +48,7 @@ export async function releaseNode(options = {}) {
|
|
|
42
48
|
skipGitHooks: parsed.skipGitHooks === true || executionMode?.skipGitHooks === true,
|
|
43
49
|
skipTests: parsed.skipTests === true,
|
|
44
50
|
skipLint: parsed.skipLint === true,
|
|
51
|
+
skipVersioning: parsed.skipVersioning === true,
|
|
45
52
|
skipBuild: parsed.skipBuild === true,
|
|
46
53
|
skipDeploy: parsed.skipDeploy === true,
|
|
47
54
|
rootDir,
|
|
@@ -8,7 +8,8 @@ function hasExplicitReleaseOptions(options = {}) {
|
|
|
8
8
|
'releaseType',
|
|
9
9
|
'skipGitHooks',
|
|
10
10
|
'skipTests',
|
|
11
|
-
'skipLint'
|
|
11
|
+
'skipLint',
|
|
12
|
+
'skipVersioning'
|
|
12
13
|
].some((key) => key in options)
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -18,11 +19,16 @@ export async function releasePackagist(options = {}) {
|
|
|
18
19
|
releaseType: 'releaseType' in options ? (options.releaseType ?? null) : null,
|
|
19
20
|
skipGitHooks: options.skipGitHooks === true,
|
|
20
21
|
skipTests: options.skipTests === true,
|
|
21
|
-
skipLint: options.skipLint === true
|
|
22
|
+
skipLint: options.skipLint === true,
|
|
23
|
+
skipVersioning: options.skipVersioning === true
|
|
22
24
|
}
|
|
23
25
|
: parseReleaseArgs({
|
|
24
|
-
booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint']
|
|
26
|
+
booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint', '--skip-versioning']
|
|
25
27
|
})
|
|
28
|
+
|
|
29
|
+
if (parsed.skipVersioning && parsed.releaseType) {
|
|
30
|
+
throw new Error('--skip-versioning cannot be used together with an explicit version or bump argument.')
|
|
31
|
+
}
|
|
26
32
|
const rootDir = options.rootDir ?? process.cwd()
|
|
27
33
|
const context = options.context ?? createAppContext({
|
|
28
34
|
executionMode: {
|
|
@@ -38,6 +44,7 @@ export async function releasePackagist(options = {}) {
|
|
|
38
44
|
skipGitHooks: parsed.skipGitHooks === true || executionMode?.skipGitHooks === true,
|
|
39
45
|
skipTests: parsed.skipTests === true,
|
|
40
46
|
skipLint: parsed.skipLint === true,
|
|
47
|
+
skipVersioning: parsed.skipVersioning === true,
|
|
41
48
|
rootDir,
|
|
42
49
|
logStep,
|
|
43
50
|
logSuccess,
|
|
@@ -24,12 +24,21 @@ export function createAppContext({
|
|
|
24
24
|
workflow: executionMode.workflow ?? 'deploy',
|
|
25
25
|
presetName: executionMode.presetName ?? null,
|
|
26
26
|
maintenanceMode: executionMode.maintenanceMode ?? null,
|
|
27
|
+
autoCommit: executionMode.autoCommit === true,
|
|
28
|
+
skipVersioning: executionMode.skipVersioning === true,
|
|
27
29
|
skipGitHooks: executionMode.skipGitHooks === true,
|
|
28
30
|
skipChecks: executionMode.skipChecks === true,
|
|
29
31
|
skipTests: executionMode.skipTests === true || executionMode.skipChecks === true,
|
|
30
32
|
skipLint: executionMode.skipLint === true || executionMode.skipChecks === true,
|
|
31
33
|
resumePending: executionMode.resumePending === true,
|
|
32
|
-
discardPending: executionMode.discardPending === true
|
|
34
|
+
discardPending: executionMode.discardPending === true,
|
|
35
|
+
explicitMaintenanceMode: executionMode.explicitMaintenanceMode === true,
|
|
36
|
+
explicitAutoCommit: executionMode.explicitAutoCommit === true,
|
|
37
|
+
explicitSkipVersioning: executionMode.explicitSkipVersioning === true,
|
|
38
|
+
explicitSkipGitHooks: executionMode.explicitSkipGitHooks === true,
|
|
39
|
+
explicitSkipChecks: executionMode.explicitSkipChecks === true,
|
|
40
|
+
explicitSkipTests: executionMode.explicitSkipTests === true || executionMode.explicitSkipChecks === true,
|
|
41
|
+
explicitSkipLint: executionMode.explicitSkipLint === true || executionMode.explicitSkipChecks === true
|
|
33
42
|
}
|
|
34
43
|
const emitEvent = normalizedExecutionMode.json
|
|
35
44
|
? createJsonEventEmitter({workflow: normalizedExecutionMode.workflow})
|