@wyxos/zephyr 0.8.3 → 0.9.0
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 +6 -3
- package/package.json +1 -1
- package/src/application/deploy/bump-local-package-version.mjs +65 -3
- package/src/application/deploy/prepare-local-deployment.mjs +3 -0
- package/src/application/deploy/run-deployment.mjs +1 -0
- package/src/release/commit-message.mjs +24 -2
- package/src/release/release-type.mjs +28 -13
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
|
@@ -3,6 +3,7 @@ import path from 'node:path'
|
|
|
3
3
|
|
|
4
4
|
import {commandExists} from '../../utils/command.mjs'
|
|
5
5
|
import {gitCommitArgs} from '../../utils/git-hooks.mjs'
|
|
6
|
+
import {resolveReleaseType} from '../../release/release-type.mjs'
|
|
6
7
|
|
|
7
8
|
async function readPackageJson(rootDir) {
|
|
8
9
|
const packageJsonPath = path.join(rootDir, 'package.json')
|
|
@@ -19,8 +20,63 @@ async function isGitIgnored(rootDir, filePath, {runCommand} = {}) {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
async function readLatestVersionBumpCommit(rootDir, {runCommand} = {}) {
|
|
24
|
+
if (typeof runCommand !== 'function') {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const {stdout = ''} = await runCommand('git', ['log', '--format=%H%x00%h%x00%s', '-50'], {
|
|
30
|
+
capture: true,
|
|
31
|
+
cwd: rootDir
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
for (const line of stdout.split('\n')) {
|
|
35
|
+
const [hash, shortHash, subject] = line.split('\0')
|
|
36
|
+
if (/^chore: bump version to \d+\.\d+\.\d+(?:[-+].*)?$/i.test(subject ?? '')) {
|
|
37
|
+
return {hash, shortHash}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function resolveDeploymentVersionValue(rootDir, {
|
|
48
|
+
versionArg = null,
|
|
49
|
+
pkg,
|
|
50
|
+
interactive = false,
|
|
51
|
+
runPrompt,
|
|
52
|
+
runCommand,
|
|
53
|
+
logProcessing,
|
|
54
|
+
logWarning
|
|
55
|
+
} = {}) {
|
|
56
|
+
if (versionArg && String(versionArg).trim().length > 0) {
|
|
57
|
+
return String(versionArg).trim()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const latestVersionBump = await readLatestVersionBumpCommit(rootDir, {runCommand})
|
|
61
|
+
|
|
62
|
+
return await resolveReleaseType({
|
|
63
|
+
currentVersion: pkg.version,
|
|
64
|
+
packageName: pkg.name ?? 'this app',
|
|
65
|
+
rootDir,
|
|
66
|
+
interactive,
|
|
67
|
+
runPrompt,
|
|
68
|
+
runCommand,
|
|
69
|
+
logStep: logProcessing,
|
|
70
|
+
logWarning,
|
|
71
|
+
latestTag: latestVersionBump?.hash ?? null,
|
|
72
|
+
referenceLabel: latestVersionBump ? `last app version bump ${latestVersionBump.shortHash}` : null
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
22
76
|
export async function bumpLocalPackageVersion(rootDir, {
|
|
23
77
|
versionArg = null,
|
|
78
|
+
interactive = false,
|
|
79
|
+
runPrompt,
|
|
24
80
|
skipGitHooks = false,
|
|
25
81
|
runCommand,
|
|
26
82
|
logProcessing,
|
|
@@ -43,9 +99,15 @@ export async function bumpLocalPackageVersion(rootDir, {
|
|
|
43
99
|
return null
|
|
44
100
|
}
|
|
45
101
|
|
|
46
|
-
const releaseValue =
|
|
47
|
-
|
|
48
|
-
|
|
102
|
+
const releaseValue = await resolveDeploymentVersionValue(rootDir, {
|
|
103
|
+
versionArg,
|
|
104
|
+
pkg,
|
|
105
|
+
interactive,
|
|
106
|
+
runPrompt,
|
|
107
|
+
runCommand,
|
|
108
|
+
logProcessing,
|
|
109
|
+
logWarning
|
|
110
|
+
})
|
|
49
111
|
|
|
50
112
|
logProcessing?.(`Bumping npm package version (${releaseValue})...`)
|
|
51
113
|
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,
|
|
@@ -161,6 +161,17 @@ export function suggestFallbackCommitMessage(statusEntries = []) {
|
|
|
161
161
|
return null
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
const hasTests = paths.some((entryPath) => (
|
|
165
|
+
entryPath.startsWith('tests/')
|
|
166
|
+
|| entryPath.includes('.test.')
|
|
167
|
+
|| entryPath.includes('.spec.')
|
|
168
|
+
))
|
|
169
|
+
const hasApplicationCode = paths.some((entryPath) => (
|
|
170
|
+
['app/', 'bootstrap/', 'config/', 'database/', 'extension/', 'resources/', 'routes/'].some((prefix) => entryPath.startsWith(prefix))
|
|
171
|
+
|| entryPath.startsWith('artisan')
|
|
172
|
+
|| entryPath.startsWith('vite.config.')
|
|
173
|
+
))
|
|
174
|
+
|
|
164
175
|
if (paths.some((entryPath) => entryPath.includes('FullscreenPreviewRail'))) {
|
|
165
176
|
return 'feat: refine fullscreen preview rail'
|
|
166
177
|
}
|
|
@@ -174,7 +185,7 @@ export function suggestFallbackCommitMessage(statusEntries = []) {
|
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
if (paths.some((entryPath) => entryPath.startsWith('src/'))) {
|
|
177
|
-
return
|
|
188
|
+
return hasTests
|
|
178
189
|
? 'fix: update source behavior and tests'
|
|
179
190
|
: 'fix: update source behavior'
|
|
180
191
|
}
|
|
@@ -183,9 +194,20 @@ export function suggestFallbackCommitMessage(statusEntries = []) {
|
|
|
183
194
|
return 'chore: update package metadata'
|
|
184
195
|
}
|
|
185
196
|
|
|
186
|
-
|
|
197
|
+
if (hasApplicationCode) {
|
|
198
|
+
return hasTests
|
|
199
|
+
? 'fix: update application behavior and tests'
|
|
200
|
+
: 'fix: update application behavior'
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (hasTests) {
|
|
204
|
+
return 'test: update test coverage'
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return 'chore: update project files'
|
|
187
208
|
}
|
|
188
209
|
|
|
210
|
+
|
|
189
211
|
export async function suggestCommitMessage(rootDir = process.cwd(), {
|
|
190
212
|
runCommand,
|
|
191
213
|
commandExistsImpl = commandExists,
|
|
@@ -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') {
|