@wyxos/zephyr 0.8.4 → 0.9.1
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
CHANGED
|
@@ -40,7 +40,10 @@ Common workflows:
|
|
|
40
40
|
# Deploy an app using the saved preset or the interactive prompts
|
|
41
41
|
zephyr
|
|
42
42
|
|
|
43
|
-
# Deploy an app with
|
|
43
|
+
# Deploy an app with Zephyr's recommended local npm package version bump
|
|
44
|
+
zephyr
|
|
45
|
+
|
|
46
|
+
# Deploy an app with an explicit local npm package version bump
|
|
44
47
|
zephyr minor
|
|
45
48
|
|
|
46
49
|
# Deploy an app while bypassing Zephyr's built-in local checks
|
|
@@ -64,7 +67,7 @@ zephyr --non-interactive --preset wyxos-release --resume-pending --maintenance o
|
|
|
64
67
|
# Emit NDJSON events for automation or agent tooling
|
|
65
68
|
zephyr --non-interactive --json --preset wyxos-release --maintenance on
|
|
66
69
|
|
|
67
|
-
# Release a Node/Vue package
|
|
70
|
+
# Release a Node/Vue package with Zephyr's recommended bump
|
|
68
71
|
zephyr --type node
|
|
69
72
|
|
|
70
73
|
# Release a Node/Vue package with an explicit bump
|
|
@@ -81,7 +84,7 @@ zephyr --type node --skip-versioning
|
|
|
81
84
|
zephyr --type packagist --skip-versioning
|
|
82
85
|
```
|
|
83
86
|
|
|
84
|
-
When
|
|
87
|
+
When an app deployment or a `--type node`/`--type vue` package release omits the bump argument, Zephyr recommends a version bump from changes since the last release reference, using Codex when available and deterministic heuristics as a fallback.
|
|
85
88
|
|
|
86
89
|
## Interactive and Non-Interactive Modes
|
|
87
90
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs/promises'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
|
|
4
|
+
import semver from 'semver'
|
|
5
|
+
|
|
4
6
|
import {commandExists} from '../../utils/command.mjs'
|
|
5
7
|
import {gitCommitArgs} from '../../utils/git-hooks.mjs'
|
|
8
|
+
import {resolveReleaseType} from '../../release/release-type.mjs'
|
|
6
9
|
|
|
7
10
|
async function readPackageJson(rootDir) {
|
|
8
11
|
const packageJsonPath = path.join(rootDir, 'package.json')
|
|
@@ -19,8 +22,109 @@ async function isGitIgnored(rootDir, filePath, {runCommand} = {}) {
|
|
|
19
22
|
}
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
function parseVersionBumpCommit(line) {
|
|
26
|
+
const [hash, shortHash, subject] = line.split('\0')
|
|
27
|
+
const match = /^chore: bump version to (\d+\.\d+\.\d+(?:[-+][^\s]+)?)$/i.exec(subject ?? '')
|
|
28
|
+
|
|
29
|
+
if (!match) {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {hash, shortHash, version: match[1]}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function readVersionBumpCommits(rootDir, {runCommand} = {}) {
|
|
37
|
+
if (typeof runCommand !== 'function') {
|
|
38
|
+
return []
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const {stdout = ''} = await runCommand('git', ['log', '--format=%H%x00%h%x00%s', '-1000'], {
|
|
43
|
+
capture: true,
|
|
44
|
+
cwd: rootDir
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
return stdout
|
|
48
|
+
.split('\n')
|
|
49
|
+
.map(parseVersionBumpCommit)
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
} catch {
|
|
52
|
+
return []
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function selectVersionSuggestionReference(currentVersion, versionBumps) {
|
|
57
|
+
const current = semver.parse(currentVersion)
|
|
58
|
+
|
|
59
|
+
if (!current) {
|
|
60
|
+
return versionBumps[0] ?? null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const currentMinorBoundary = versionBumps.find(({version}) => {
|
|
64
|
+
const parsed = semver.parse(version)
|
|
65
|
+
|
|
66
|
+
return parsed
|
|
67
|
+
&& parsed.major === current.major
|
|
68
|
+
&& parsed.minor === current.minor
|
|
69
|
+
&& parsed.patch === 0
|
|
70
|
+
&& parsed.prerelease.length === 0
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
return currentMinorBoundary ?? versionBumps[0] ?? null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function formatVersionReferenceLabel(reference, currentVersion) {
|
|
77
|
+
if (!reference) {
|
|
78
|
+
return null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const current = semver.parse(currentVersion)
|
|
82
|
+
const parsed = semver.parse(reference.version)
|
|
83
|
+
const isCurrentMinorBoundary = current
|
|
84
|
+
&& parsed
|
|
85
|
+
&& parsed.major === current.major
|
|
86
|
+
&& parsed.minor === current.minor
|
|
87
|
+
&& parsed.patch === 0
|
|
88
|
+
&& parsed.prerelease.length === 0
|
|
89
|
+
const prefix = isCurrentMinorBoundary ? 'current app minor baseline' : 'last app version bump'
|
|
90
|
+
|
|
91
|
+
return `${prefix} ${reference.shortHash} (${reference.version})`
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function resolveDeploymentVersionValue(rootDir, {
|
|
95
|
+
versionArg = null,
|
|
96
|
+
pkg,
|
|
97
|
+
interactive = false,
|
|
98
|
+
runPrompt,
|
|
99
|
+
runCommand,
|
|
100
|
+
logProcessing,
|
|
101
|
+
logWarning
|
|
102
|
+
} = {}) {
|
|
103
|
+
if (versionArg && String(versionArg).trim().length > 0) {
|
|
104
|
+
return String(versionArg).trim()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const versionBumps = await readVersionBumpCommits(rootDir, {runCommand})
|
|
108
|
+
const versionReference = selectVersionSuggestionReference(pkg.version, versionBumps)
|
|
109
|
+
|
|
110
|
+
return await resolveReleaseType({
|
|
111
|
+
currentVersion: pkg.version,
|
|
112
|
+
packageName: pkg.name ?? 'this app',
|
|
113
|
+
rootDir,
|
|
114
|
+
interactive,
|
|
115
|
+
runPrompt,
|
|
116
|
+
runCommand,
|
|
117
|
+
logStep: logProcessing,
|
|
118
|
+
logWarning,
|
|
119
|
+
latestTag: versionReference?.hash ?? null,
|
|
120
|
+
referenceLabel: formatVersionReferenceLabel(versionReference, pkg.version)
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
22
124
|
export async function bumpLocalPackageVersion(rootDir, {
|
|
23
125
|
versionArg = null,
|
|
126
|
+
interactive = false,
|
|
127
|
+
runPrompt,
|
|
24
128
|
skipGitHooks = false,
|
|
25
129
|
runCommand,
|
|
26
130
|
logProcessing,
|
|
@@ -43,9 +147,15 @@ export async function bumpLocalPackageVersion(rootDir, {
|
|
|
43
147
|
return null
|
|
44
148
|
}
|
|
45
149
|
|
|
46
|
-
const releaseValue =
|
|
47
|
-
|
|
48
|
-
|
|
150
|
+
const releaseValue = await resolveDeploymentVersionValue(rootDir, {
|
|
151
|
+
versionArg,
|
|
152
|
+
pkg,
|
|
153
|
+
interactive,
|
|
154
|
+
runPrompt,
|
|
155
|
+
runCommand,
|
|
156
|
+
logProcessing,
|
|
157
|
+
logWarning
|
|
158
|
+
})
|
|
49
159
|
|
|
50
160
|
logProcessing?.(`Bumping npm package version (${releaseValue})...`)
|
|
51
161
|
await runCommand('npm', ['version', releaseValue, '--no-git-tag-version', '--force'], {cwd: rootDir})
|
|
@@ -14,6 +14,7 @@ export async function prepareLocalDeployment(config, {
|
|
|
14
14
|
skipLint = false,
|
|
15
15
|
skipVersioning = false,
|
|
16
16
|
autoCommit = false,
|
|
17
|
+
interactive = true,
|
|
17
18
|
runPrompt,
|
|
18
19
|
runCommand,
|
|
19
20
|
runCommandCapture,
|
|
@@ -66,6 +67,8 @@ export async function prepareLocalDeployment(config, {
|
|
|
66
67
|
await bumpLocalPackageVersion(rootDir, {
|
|
67
68
|
versionArg,
|
|
68
69
|
skipGitHooks,
|
|
70
|
+
interactive,
|
|
71
|
+
runPrompt,
|
|
69
72
|
runCommand,
|
|
70
73
|
logProcessing,
|
|
71
74
|
logSuccess,
|
|
@@ -385,6 +385,7 @@ export async function runDeployment(config, options = {}) {
|
|
|
385
385
|
skipLint: executionMode?.skipLint === true,
|
|
386
386
|
skipVersioning: executionMode?.skipVersioning === true,
|
|
387
387
|
autoCommit: executionMode?.autoCommit === true,
|
|
388
|
+
interactive: executionMode?.interactive !== false,
|
|
388
389
|
runPrompt,
|
|
389
390
|
runCommand,
|
|
390
391
|
runCommandCapture: context.runCommandCapture,
|
|
@@ -87,7 +87,11 @@ function buildChoiceOrder(suggestedReleaseType) {
|
|
|
87
87
|
]
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
async function readLatestReleaseTag(rootDir, {runCommand} = {}) {
|
|
90
|
+
async function readLatestReleaseTag(rootDir, {runCommand, latestTag = null} = {}) {
|
|
91
|
+
if (typeof latestTag === 'string' && latestTag.trim() !== '') {
|
|
92
|
+
return latestTag.trim()
|
|
93
|
+
}
|
|
94
|
+
|
|
91
95
|
try {
|
|
92
96
|
const {stdout} = await runCommand('git', ['describe', '--tags', '--abbrev=0'], {
|
|
93
97
|
capture: true,
|
|
@@ -137,16 +141,19 @@ async function readDiffStat(rootDir, {runCommand, latestTag} = {}) {
|
|
|
137
141
|
async function buildReleaseSuggestionContext(rootDir, {
|
|
138
142
|
runCommand,
|
|
139
143
|
currentVersion,
|
|
140
|
-
packageName
|
|
144
|
+
packageName,
|
|
145
|
+
latestTag = null,
|
|
146
|
+
referenceLabel = null
|
|
141
147
|
} = {}) {
|
|
142
|
-
const
|
|
143
|
-
const commitLog = await readCommitLog(rootDir, {runCommand, latestTag})
|
|
144
|
-
const diffStat = await readDiffStat(rootDir, {runCommand, latestTag})
|
|
148
|
+
const resolvedLatestTag = await readLatestReleaseTag(rootDir, {runCommand, latestTag})
|
|
149
|
+
const commitLog = await readCommitLog(rootDir, {runCommand, latestTag: resolvedLatestTag})
|
|
150
|
+
const diffStat = await readDiffStat(rootDir, {runCommand, latestTag: resolvedLatestTag})
|
|
145
151
|
|
|
146
152
|
return {
|
|
147
153
|
currentVersion,
|
|
148
154
|
packageName,
|
|
149
|
-
latestTag,
|
|
155
|
+
latestTag: resolvedLatestTag,
|
|
156
|
+
referenceLabel: referenceLabel ?? resolvedLatestTag,
|
|
150
157
|
commitLog,
|
|
151
158
|
diffStat
|
|
152
159
|
}
|
|
@@ -158,12 +165,16 @@ async function suggestReleaseType(rootDir = process.cwd(), {
|
|
|
158
165
|
packageName,
|
|
159
166
|
commandExistsImpl = commandExists,
|
|
160
167
|
logStep,
|
|
161
|
-
logWarning
|
|
168
|
+
logWarning,
|
|
169
|
+
latestTag = null,
|
|
170
|
+
referenceLabel = null
|
|
162
171
|
} = {}) {
|
|
163
172
|
const context = await buildReleaseSuggestionContext(rootDir, {
|
|
164
173
|
runCommand,
|
|
165
174
|
currentVersion,
|
|
166
|
-
packageName
|
|
175
|
+
packageName,
|
|
176
|
+
latestTag,
|
|
177
|
+
referenceLabel
|
|
167
178
|
})
|
|
168
179
|
const allowedSuggestedReleaseTypes = resolveSuggestedReleaseTypeOptions(currentVersion)
|
|
169
180
|
const heuristicReleaseType = inferReleaseTypeHeuristically(context)
|
|
@@ -201,7 +212,7 @@ async function suggestReleaseType(rootDir = process.cwd(), {
|
|
|
201
212
|
'Prefer stable release types unless the current version already has a prerelease identifier.',
|
|
202
213
|
`Package: ${packageName || 'unknown package'}`,
|
|
203
214
|
`Current version: ${currentVersion || 'unknown'}`,
|
|
204
|
-
`Latest release
|
|
215
|
+
`Latest release reference: ${context.referenceLabel || context.latestTag || 'none found'}`,
|
|
205
216
|
'Commits since the last release:',
|
|
206
217
|
context.commitLog || '- no commits found',
|
|
207
218
|
'Diff summary since the last release:',
|
|
@@ -252,7 +263,9 @@ export async function resolveReleaseType({
|
|
|
252
263
|
runPrompt,
|
|
253
264
|
runCommand,
|
|
254
265
|
logStep,
|
|
255
|
-
logWarning
|
|
266
|
+
logWarning,
|
|
267
|
+
latestTag = null,
|
|
268
|
+
referenceLabel = null
|
|
256
269
|
} = {}) {
|
|
257
270
|
if (releaseType) {
|
|
258
271
|
return releaseType
|
|
@@ -263,10 +276,12 @@ export async function resolveReleaseType({
|
|
|
263
276
|
currentVersion,
|
|
264
277
|
packageName,
|
|
265
278
|
logStep,
|
|
266
|
-
logWarning
|
|
279
|
+
logWarning,
|
|
280
|
+
latestTag,
|
|
281
|
+
referenceLabel
|
|
267
282
|
})
|
|
268
|
-
const rangeLabel = suggested.latestTag
|
|
269
|
-
? `based on changes since ${suggested.latestTag}`
|
|
283
|
+
const rangeLabel = suggested.referenceLabel || suggested.latestTag
|
|
284
|
+
? `based on changes since ${suggested.referenceLabel || suggested.latestTag}`
|
|
270
285
|
: 'based on recent changes'
|
|
271
286
|
|
|
272
287
|
if (!interactive || typeof runPrompt !== 'function') {
|