@wyxos/zephyr 0.4.1 → 0.4.3
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 +2 -0
- package/package.json +1 -1
- package/src/application/deploy/build-remote-deployment-plan.mjs +8 -8
- package/src/application/deploy/bump-local-package-version.mjs +5 -1
- package/src/application/deploy/prepare-local-deployment.mjs +5 -1
- package/src/application/deploy/run-deployment.mjs +1 -0
- package/src/application/deploy/run-local-deployment-checks.mjs +12 -4
- package/src/application/release/release-node-package.mjs +27 -16
- package/src/application/release/release-packagist-package.mjs +13 -8
- package/src/cli/options.mjs +3 -1
- package/src/dependency-scanner.mjs +10 -4
- package/src/deploy/local-repo.mjs +24 -8
- package/src/deploy/preflight.mjs +10 -2
- package/src/main.mjs +16 -2
- package/src/project/bootstrap.mjs +6 -3
- package/src/release/shared.mjs +6 -2
- package/src/release-node.mjs +22 -3
- package/src/release-packagist.mjs +18 -3
- package/src/runtime/app-context.mjs +1 -0
- package/src/utils/git-hooks.mjs +26 -0
package/README.md
CHANGED
|
@@ -87,6 +87,8 @@ If Zephyr would normally prompt to:
|
|
|
87
87
|
|
|
88
88
|
then non-interactive mode stops immediately with a clear error instead.
|
|
89
89
|
|
|
90
|
+
For Laravel app deployments, `--maintenance on|off` overrides the maintenance prompt when you want an explicit choice instead of an interactive confirm.
|
|
91
|
+
|
|
90
92
|
## AI Agents and Automation
|
|
91
93
|
|
|
92
94
|
Zephyr can be used safely by Codex, CI jobs, or other automation once configuration is already in place.
|
package/package.json
CHANGED
|
@@ -253,17 +253,17 @@ async function resolveMaintenanceMode({
|
|
|
253
253
|
return snapshot.maintenanceModeEnabled
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
if (executionMode
|
|
257
|
-
if (typeof executionMode.maintenanceMode !== 'boolean') {
|
|
258
|
-
throw new ZephyrError(
|
|
259
|
-
'Zephyr cannot run this Laravel deployment non-interactively without an explicit maintenance-mode decision. Pass --maintenance on or --maintenance off.',
|
|
260
|
-
{code: 'ZEPHYR_MAINTENANCE_FLAG_REQUIRED'}
|
|
261
|
-
)
|
|
262
|
-
}
|
|
263
|
-
|
|
256
|
+
if (typeof executionMode.maintenanceMode === 'boolean') {
|
|
264
257
|
return executionMode.maintenanceMode
|
|
265
258
|
}
|
|
266
259
|
|
|
260
|
+
if (executionMode?.interactive === false) {
|
|
261
|
+
throw new ZephyrError(
|
|
262
|
+
'Zephyr cannot run this Laravel deployment non-interactively without an explicit maintenance-mode decision. Pass --maintenance on or --maintenance off.',
|
|
263
|
+
{code: 'ZEPHYR_MAINTENANCE_FLAG_REQUIRED'}
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
267
|
if (typeof runPrompt !== 'function') {
|
|
268
268
|
return false
|
|
269
269
|
}
|
|
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
|
|
4
4
|
import {commandExists} from '../../utils/command.mjs'
|
|
5
|
+
import {gitCommitArgs} from '../../utils/git-hooks.mjs'
|
|
5
6
|
|
|
6
7
|
async function readPackageJson(rootDir) {
|
|
7
8
|
const packageJsonPath = path.join(rootDir, 'package.json')
|
|
@@ -20,6 +21,7 @@ async function isGitIgnored(rootDir, filePath, {runCommand} = {}) {
|
|
|
20
21
|
|
|
21
22
|
export async function bumpLocalPackageVersion(rootDir, {
|
|
22
23
|
versionArg = null,
|
|
24
|
+
skipGitHooks = false,
|
|
23
25
|
runCommand,
|
|
24
26
|
logProcessing,
|
|
25
27
|
logSuccess,
|
|
@@ -72,7 +74,9 @@ export async function bumpLocalPackageVersion(rootDir, {
|
|
|
72
74
|
return updatedPkg
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
await runCommand('git', ['
|
|
77
|
+
await runCommand('git', gitCommitArgs(['-m', `chore: bump version to ${nextVersion}`, '--', ...filesToStage], {
|
|
78
|
+
skipGitHooks
|
|
79
|
+
}), {
|
|
76
80
|
cwd: rootDir
|
|
77
81
|
})
|
|
78
82
|
logSuccess?.(`Version updated to ${nextVersion}.`)
|
|
@@ -9,6 +9,7 @@ export async function prepareLocalDeployment(config, {
|
|
|
9
9
|
snapshot = null,
|
|
10
10
|
rootDir = process.cwd(),
|
|
11
11
|
versionArg = null,
|
|
12
|
+
skipGitHooks = false,
|
|
12
13
|
runPrompt,
|
|
13
14
|
runCommand,
|
|
14
15
|
runCommandCapture,
|
|
@@ -26,6 +27,7 @@ export async function prepareLocalDeployment(config, {
|
|
|
26
27
|
if (!snapshot && context.isLaravel) {
|
|
27
28
|
await bumpLocalPackageVersion(rootDir, {
|
|
28
29
|
versionArg,
|
|
30
|
+
skipGitHooks,
|
|
29
31
|
runCommand,
|
|
30
32
|
logProcessing,
|
|
31
33
|
logSuccess,
|
|
@@ -39,13 +41,15 @@ export async function prepareLocalDeployment(config, {
|
|
|
39
41
|
runCommandCapture,
|
|
40
42
|
logProcessing,
|
|
41
43
|
logSuccess,
|
|
42
|
-
logWarning
|
|
44
|
+
logWarning,
|
|
45
|
+
skipGitHooks
|
|
43
46
|
})
|
|
44
47
|
|
|
45
48
|
await runLocalDeploymentChecks({
|
|
46
49
|
rootDir,
|
|
47
50
|
isLaravel: context.isLaravel,
|
|
48
51
|
hasHook: context.hasHook,
|
|
52
|
+
skipGitHooks,
|
|
49
53
|
runCommand,
|
|
50
54
|
runCommandCapture,
|
|
51
55
|
logProcessing,
|
|
@@ -85,6 +85,7 @@ export async function runLocalDeploymentChecks({
|
|
|
85
85
|
rootDir,
|
|
86
86
|
isLaravel,
|
|
87
87
|
hasHook,
|
|
88
|
+
skipGitHooks = false,
|
|
88
89
|
runCommand,
|
|
89
90
|
runCommandCapture,
|
|
90
91
|
logProcessing,
|
|
@@ -102,9 +103,15 @@ export async function runLocalDeploymentChecks({
|
|
|
102
103
|
})
|
|
103
104
|
|
|
104
105
|
if (hasHook) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
if (skipGitHooks) {
|
|
107
|
+
logWarning?.(
|
|
108
|
+
'Pre-push git hook detected. Built-in release checks are supported, and Zephyr will skip executing them here. WARNING: --skip-git-hooks is enabled, so Zephyr will also bypass that hook if it needs to push local commits during this release.'
|
|
109
|
+
)
|
|
110
|
+
} else {
|
|
111
|
+
logProcessing?.(
|
|
112
|
+
'Pre-push git hook detected. Built-in release checks are supported, but Zephyr will skip executing them here. If Zephyr pushes local commits during this release, the hook will run during git push.'
|
|
113
|
+
)
|
|
114
|
+
}
|
|
108
115
|
return
|
|
109
116
|
}
|
|
110
117
|
|
|
@@ -124,7 +131,8 @@ export async function runLocalDeploymentChecks({
|
|
|
124
131
|
getGitStatus: (dir) => getGitStatus(dir, {runCommandCapture}),
|
|
125
132
|
runCommand,
|
|
126
133
|
logProcessing,
|
|
127
|
-
logSuccess
|
|
134
|
+
logSuccess,
|
|
135
|
+
skipGitHooks
|
|
128
136
|
})
|
|
129
137
|
}
|
|
130
138
|
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
runReleaseCommand,
|
|
12
12
|
validateReleaseDependencies
|
|
13
13
|
} from '../../release/shared.mjs'
|
|
14
|
+
import {gitCommitArgs, gitPushArgs, npmVersionArgs} from '../../utils/git-hooks.mjs'
|
|
14
15
|
|
|
15
16
|
async function readPackage(rootDir = process.cwd()) {
|
|
16
17
|
const packagePath = join(rootDir, 'package.json')
|
|
@@ -137,7 +138,8 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd(), {
|
|
|
137
138
|
logStep,
|
|
138
139
|
logSuccess,
|
|
139
140
|
logWarning,
|
|
140
|
-
runCommand = runReleaseCommand
|
|
141
|
+
runCommand = runReleaseCommand,
|
|
142
|
+
skipGitHooks = false
|
|
141
143
|
} = {}) {
|
|
142
144
|
if (skipBuild) {
|
|
143
145
|
logWarning?.('Skipping library build because --skip-build flag was provided.')
|
|
@@ -173,7 +175,7 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd(), {
|
|
|
173
175
|
if (hasLibChanges) {
|
|
174
176
|
logStep?.('Committing lib build artifacts...')
|
|
175
177
|
await runCommand('git', ['add', 'lib/'], {capture: true, cwd: rootDir})
|
|
176
|
-
await runCommand('git', ['
|
|
178
|
+
await runCommand('git', gitCommitArgs(['-m', 'chore: build lib artifacts'], {skipGitHooks}), {capture: true, cwd: rootDir})
|
|
177
179
|
logSuccess?.('Lib build artifacts committed.')
|
|
178
180
|
}
|
|
179
181
|
|
|
@@ -183,7 +185,8 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd(), {
|
|
|
183
185
|
async function bumpVersion(releaseType, rootDir = process.cwd(), {
|
|
184
186
|
logStep,
|
|
185
187
|
logSuccess,
|
|
186
|
-
runCommand = runReleaseCommand
|
|
188
|
+
runCommand = runReleaseCommand,
|
|
189
|
+
skipGitHooks = false
|
|
187
190
|
} = {}) {
|
|
188
191
|
logStep?.('Bumping package version...')
|
|
189
192
|
|
|
@@ -199,7 +202,7 @@ async function bumpVersion(releaseType, rootDir = process.cwd(), {
|
|
|
199
202
|
}
|
|
200
203
|
|
|
201
204
|
try {
|
|
202
|
-
await runCommand('npm',
|
|
205
|
+
await runCommand('npm', npmVersionArgs(releaseType, {skipGitHooks}), {capture: true, cwd: rootDir})
|
|
203
206
|
} finally {
|
|
204
207
|
if (hasLibChanges) {
|
|
205
208
|
logStep?.('Restoring lib build artifacts...')
|
|
@@ -207,14 +210,14 @@ async function bumpVersion(releaseType, rootDir = process.cwd(), {
|
|
|
207
210
|
await runCommand('git', ['add', 'lib/'], {capture: true, cwd: rootDir})
|
|
208
211
|
const {stdout: statusAfter} = await runCommand('git', ['status', '--porcelain'], {capture: true, cwd: rootDir})
|
|
209
212
|
if (statusAfter.includes('lib/')) {
|
|
210
|
-
await runCommand('git', ['
|
|
213
|
+
await runCommand('git', gitCommitArgs(['--amend', '--no-edit'], {skipGitHooks}), {capture: true, cwd: rootDir})
|
|
211
214
|
}
|
|
212
215
|
}
|
|
213
216
|
}
|
|
214
217
|
|
|
215
218
|
const pkg = await readPackage(rootDir)
|
|
216
219
|
const commitMessage = `chore: release ${pkg.version}`
|
|
217
|
-
await runCommand('git', ['
|
|
220
|
+
await runCommand('git', gitCommitArgs(['--amend', '-m', commitMessage], {skipGitHooks}), {capture: true, cwd: rootDir})
|
|
218
221
|
await runCommand('git', ['tag', '-fa', `v${pkg.version}`, '-m', `v${pkg.version}`], {capture: true, cwd: rootDir})
|
|
219
222
|
|
|
220
223
|
logSuccess?.(`Version updated to ${pkg.version}.`)
|
|
@@ -224,11 +227,12 @@ async function bumpVersion(releaseType, rootDir = process.cwd(), {
|
|
|
224
227
|
async function pushChanges(rootDir = process.cwd(), {
|
|
225
228
|
logStep,
|
|
226
229
|
logSuccess,
|
|
227
|
-
runCommand = runReleaseCommand
|
|
230
|
+
runCommand = runReleaseCommand,
|
|
231
|
+
skipGitHooks = false
|
|
228
232
|
} = {}) {
|
|
229
233
|
logStep?.('Pushing commits and tags to origin...')
|
|
230
234
|
try {
|
|
231
|
-
await runCommand('git', ['
|
|
235
|
+
await runCommand('git', gitPushArgs(['--follow-tags'], {skipGitHooks}), {capture: true, cwd: rootDir})
|
|
232
236
|
logSuccess?.('Git push completed.')
|
|
233
237
|
} catch (error) {
|
|
234
238
|
if (error.stdout) {
|
|
@@ -256,7 +260,8 @@ async function deployGHPages(skipDeploy, pkg, rootDir = process.cwd(), {
|
|
|
256
260
|
logStep,
|
|
257
261
|
logSuccess,
|
|
258
262
|
logWarning,
|
|
259
|
-
runCommand = runReleaseCommand
|
|
263
|
+
runCommand = runReleaseCommand,
|
|
264
|
+
skipGitHooks = false
|
|
260
265
|
} = {}) {
|
|
261
266
|
if (skipDeploy) {
|
|
262
267
|
logWarning?.('Skipping GitHub Pages deployment because --skip-deploy flag was provided.')
|
|
@@ -324,8 +329,12 @@ async function deployGHPages(skipDeploy, pkg, rootDir = process.cwd(), {
|
|
|
324
329
|
fs.cpSync(distPath, worktreeDir, {recursive: true})
|
|
325
330
|
|
|
326
331
|
await runCommand('git', ['-C', worktreeDir, 'add', '-A'], {capture: true})
|
|
327
|
-
await runCommand('git', [
|
|
328
|
-
|
|
332
|
+
await runCommand('git', [
|
|
333
|
+
'-C',
|
|
334
|
+
worktreeDir,
|
|
335
|
+
...gitCommitArgs(['-m', `deploy: demo ${new Date().toISOString()}`, '--allow-empty'], {skipGitHooks})
|
|
336
|
+
], {capture: true})
|
|
337
|
+
await runCommand('git', ['-C', worktreeDir, ...gitPushArgs(['-f', 'origin', 'gh-pages'], {skipGitHooks})], {capture: true})
|
|
329
338
|
|
|
330
339
|
logSuccess?.('GitHub Pages deployment completed.')
|
|
331
340
|
} catch (error) {
|
|
@@ -341,6 +350,7 @@ async function deployGHPages(skipDeploy, pkg, rootDir = process.cwd(), {
|
|
|
341
350
|
|
|
342
351
|
export async function releaseNodePackage({
|
|
343
352
|
releaseType,
|
|
353
|
+
skipGitHooks = false,
|
|
344
354
|
skipTests = false,
|
|
345
355
|
skipLint = false,
|
|
346
356
|
skipBuild = false,
|
|
@@ -367,7 +377,8 @@ export async function releaseNodePackage({
|
|
|
367
377
|
await validateReleaseDependencies(rootDir, {
|
|
368
378
|
prompt: runPrompt,
|
|
369
379
|
logSuccess,
|
|
370
|
-
interactive
|
|
380
|
+
interactive,
|
|
381
|
+
skipGitHooks
|
|
371
382
|
})
|
|
372
383
|
|
|
373
384
|
logStep?.('Checking working tree status...')
|
|
@@ -376,12 +387,12 @@ export async function releaseNodePackage({
|
|
|
376
387
|
|
|
377
388
|
await runLint(skipLint, pkg, rootDir, {logStep, logSuccess, logWarning, runCommand})
|
|
378
389
|
await runTests(skipTests, pkg, rootDir, {logStep, logSuccess, logWarning, runCommand})
|
|
379
|
-
await runLibBuild(skipBuild, pkg, rootDir, {logStep, logSuccess, logWarning, runCommand})
|
|
390
|
+
await runLibBuild(skipBuild, pkg, rootDir, {logStep, logSuccess, logWarning, runCommand, skipGitHooks})
|
|
380
391
|
|
|
381
|
-
const updatedPkg = await bumpVersion(releaseType, rootDir, {logStep, logSuccess, runCommand})
|
|
392
|
+
const updatedPkg = await bumpVersion(releaseType, rootDir, {logStep, logSuccess, runCommand, skipGitHooks})
|
|
382
393
|
await runBuild(skipBuild, updatedPkg, rootDir, {logStep, logSuccess, logWarning, runCommand})
|
|
383
|
-
await pushChanges(rootDir, {logStep, logSuccess, runCommand})
|
|
384
|
-
await deployGHPages(skipDeploy, updatedPkg, rootDir, {logStep, logSuccess, logWarning, runCommand})
|
|
394
|
+
await pushChanges(rootDir, {logStep, logSuccess, runCommand, skipGitHooks})
|
|
395
|
+
await deployGHPages(skipDeploy, updatedPkg, rootDir, {logStep, logSuccess, logWarning, runCommand, skipGitHooks})
|
|
385
396
|
|
|
386
397
|
logStep?.('Publishing will be handled by GitHub Actions via trusted publishing.')
|
|
387
398
|
logSuccess?.(`Release workflow completed for ${updatedPkg.name}@${updatedPkg.version}.`)
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
runReleaseCommand,
|
|
12
12
|
validateReleaseDependencies
|
|
13
13
|
} from '../../release/shared.mjs'
|
|
14
|
+
import {gitCommitArgs, gitPushArgs} from '../../utils/git-hooks.mjs'
|
|
14
15
|
|
|
15
16
|
async function readComposer(rootDir = process.cwd()) {
|
|
16
17
|
const composerPath = join(rootDir, 'composer.json')
|
|
@@ -162,7 +163,8 @@ async function runTests(skipTests, composer, rootDir = process.cwd(), {
|
|
|
162
163
|
async function bumpVersion(releaseType, rootDir = process.cwd(), {
|
|
163
164
|
logStep,
|
|
164
165
|
logSuccess,
|
|
165
|
-
runCommand = runReleaseCommand
|
|
166
|
+
runCommand = runReleaseCommand,
|
|
167
|
+
skipGitHooks = false
|
|
166
168
|
} = {}) {
|
|
167
169
|
logStep?.('Bumping composer version...')
|
|
168
170
|
|
|
@@ -186,7 +188,7 @@ async function bumpVersion(releaseType, rootDir = process.cwd(), {
|
|
|
186
188
|
|
|
187
189
|
const commitMessage = `chore: release ${newVersion}`
|
|
188
190
|
logStep?.('Committing version bump...')
|
|
189
|
-
await runCommand('git', ['
|
|
191
|
+
await runCommand('git', gitCommitArgs(['-m', commitMessage], {skipGitHooks}), {cwd: rootDir})
|
|
190
192
|
|
|
191
193
|
logStep?.('Creating git tag...')
|
|
192
194
|
await runCommand('git', ['tag', `v${newVersion}`], {cwd: rootDir})
|
|
@@ -198,19 +200,21 @@ async function bumpVersion(releaseType, rootDir = process.cwd(), {
|
|
|
198
200
|
async function pushChanges(rootDir = process.cwd(), {
|
|
199
201
|
logStep,
|
|
200
202
|
logSuccess,
|
|
201
|
-
runCommand = runReleaseCommand
|
|
203
|
+
runCommand = runReleaseCommand,
|
|
204
|
+
skipGitHooks = false
|
|
202
205
|
} = {}) {
|
|
203
206
|
logStep?.('Pushing commits to origin...')
|
|
204
|
-
await runCommand('git', [
|
|
207
|
+
await runCommand('git', gitPushArgs([], {skipGitHooks}), {cwd: rootDir})
|
|
205
208
|
|
|
206
209
|
logStep?.('Pushing tags to origin...')
|
|
207
|
-
await runCommand('git', ['
|
|
210
|
+
await runCommand('git', gitPushArgs(['origin', '--tags'], {skipGitHooks}), {cwd: rootDir})
|
|
208
211
|
|
|
209
212
|
logSuccess?.('Git push completed.')
|
|
210
213
|
}
|
|
211
214
|
|
|
212
215
|
export async function releasePackagistPackage({
|
|
213
216
|
releaseType,
|
|
217
|
+
skipGitHooks = false,
|
|
214
218
|
skipTests = false,
|
|
215
219
|
skipLint = false,
|
|
216
220
|
rootDir = process.cwd(),
|
|
@@ -240,7 +244,8 @@ export async function releasePackagistPackage({
|
|
|
240
244
|
await validateReleaseDependencies(rootDir, {
|
|
241
245
|
prompt: runPrompt,
|
|
242
246
|
logSuccess,
|
|
243
|
-
interactive
|
|
247
|
+
interactive,
|
|
248
|
+
skipGitHooks
|
|
244
249
|
})
|
|
245
250
|
|
|
246
251
|
logStep?.('Checking working tree status...')
|
|
@@ -250,8 +255,8 @@ export async function releasePackagistPackage({
|
|
|
250
255
|
await runLint(skipLint, rootDir, {logStep, logSuccess, logWarning, runCommand, progressWriter})
|
|
251
256
|
await runTests(skipTests, composer, rootDir, {logStep, logSuccess, logWarning, runCommand, progressWriter})
|
|
252
257
|
|
|
253
|
-
const updatedComposer = await bumpVersion(releaseType, rootDir, {logStep, logSuccess, runCommand})
|
|
254
|
-
await pushChanges(rootDir, {logStep, logSuccess, runCommand})
|
|
258
|
+
const updatedComposer = await bumpVersion(releaseType, rootDir, {logStep, logSuccess, runCommand, skipGitHooks})
|
|
259
|
+
await pushChanges(rootDir, {logStep, logSuccess, runCommand, skipGitHooks})
|
|
255
260
|
|
|
256
261
|
logSuccess?.(`Release workflow completed for ${composer.name}@${updatedComposer.version}.`)
|
|
257
262
|
logStep?.('Note: Packagist will automatically detect the new git tag and update the package.')
|
package/src/cli/options.mjs
CHANGED
|
@@ -34,7 +34,8 @@ export function parseCliOptions(args = process.argv.slice(2)) {
|
|
|
34
34
|
.option('--preset <name>', 'Preset name to use for non-interactive app deployments.')
|
|
35
35
|
.option('--resume-pending', 'Resume a saved pending deployment snapshot without prompting.')
|
|
36
36
|
.option('--discard-pending', 'Discard a saved pending deployment snapshot without prompting.')
|
|
37
|
-
.option('--maintenance <mode>', 'Laravel maintenance mode policy for
|
|
37
|
+
.option('--maintenance <mode>', 'Laravel maintenance mode policy for app deployments (on|off).')
|
|
38
|
+
.option('--skip-git-hooks', 'Bypass local git hooks for any commits and pushes Zephyr performs.')
|
|
38
39
|
.option('--skip-tests', 'Skip test execution in package release workflows.')
|
|
39
40
|
.option('--skip-lint', 'Skip lint execution in package release workflows.')
|
|
40
41
|
.option('--skip-build', 'Skip build execution in node/vue release workflows.')
|
|
@@ -66,6 +67,7 @@ export function parseCliOptions(args = process.argv.slice(2)) {
|
|
|
66
67
|
resumePending: Boolean(options.resumePending),
|
|
67
68
|
discardPending: Boolean(options.discardPending),
|
|
68
69
|
maintenanceMode: normalizeMaintenanceMode(options.maintenance),
|
|
70
|
+
skipGitHooks: Boolean(options.skipGitHooks),
|
|
69
71
|
skipTests: Boolean(options.skipTests),
|
|
70
72
|
skipLint: Boolean(options.skipLint),
|
|
71
73
|
skipBuild: Boolean(options.skipBuild),
|
|
@@ -4,6 +4,7 @@ import process from 'node:process'
|
|
|
4
4
|
import chalk from 'chalk'
|
|
5
5
|
import {ZephyrError} from './runtime/errors.mjs'
|
|
6
6
|
import { runCommand as runCommandBase, runCommandCapture as runCommandCaptureBase } from './utils/command.mjs'
|
|
7
|
+
import {gitCommitArgs} from './utils/git-hooks.mjs'
|
|
7
8
|
|
|
8
9
|
function isLocalPathOutsideRepo(depPath, rootDir) {
|
|
9
10
|
if (!depPath || typeof depPath !== 'string') {
|
|
@@ -227,7 +228,9 @@ async function runCommand(command, args, { cwd = process.cwd(), capture = false
|
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
|
|
230
|
-
async function commitDependencyUpdates(rootDir, updatedFiles, promptFn, logFn
|
|
231
|
+
async function commitDependencyUpdates(rootDir, updatedFiles, promptFn, logFn, {
|
|
232
|
+
skipGitHooks = false
|
|
233
|
+
} = {}) {
|
|
231
234
|
try {
|
|
232
235
|
// Check if we're in a git repository
|
|
233
236
|
await runCommand('git', ['rev-parse', '--is-inside-work-tree'], { capture: true, cwd: rootDir })
|
|
@@ -254,7 +257,7 @@ async function commitDependencyUpdates(rootDir, updatedFiles, promptFn, logFn) {
|
|
|
254
257
|
logFn('Committing dependency updates...')
|
|
255
258
|
}
|
|
256
259
|
|
|
257
|
-
await runCommand('git', ['
|
|
260
|
+
await runCommand('git', gitCommitArgs(['-m', commitMessage, '--', ...updatedFiles], {skipGitHooks}), { cwd: rootDir })
|
|
258
261
|
|
|
259
262
|
if (logFn) {
|
|
260
263
|
logFn('Dependency updates committed.')
|
|
@@ -264,7 +267,8 @@ async function commitDependencyUpdates(rootDir, updatedFiles, promptFn, logFn) {
|
|
|
264
267
|
}
|
|
265
268
|
|
|
266
269
|
async function validateLocalDependencies(rootDir, promptFn, logFn = null, {
|
|
267
|
-
interactive = true
|
|
270
|
+
interactive = true,
|
|
271
|
+
skipGitHooks = false
|
|
268
272
|
} = {}) {
|
|
269
273
|
const packageDeps = await scanPackageJsonDependencies(rootDir)
|
|
270
274
|
const composerDeps = await scanComposerJsonDependencies(rootDir)
|
|
@@ -401,7 +405,9 @@ async function validateLocalDependencies(rootDir, promptFn, logFn = null, {
|
|
|
401
405
|
|
|
402
406
|
// Commit the changes if any files were updated
|
|
403
407
|
if (updatedFiles.size > 0) {
|
|
404
|
-
const committed = await commitDependencyUpdates(rootDir, Array.from(updatedFiles), promptFn, logFn
|
|
408
|
+
const committed = await commitDependencyUpdates(rootDir, Array.from(updatedFiles), promptFn, logFn, {
|
|
409
|
+
skipGitHooks
|
|
410
|
+
})
|
|
405
411
|
if (!committed) {
|
|
406
412
|
throw new Error(
|
|
407
413
|
'Release cancelled: dependency updates were applied but were not committed. Commit/stash your changes and rerun.'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getCurrentBranch as getCurrentBranchImpl, getUpstreamRef as getUpstreamRefImpl } from '../utils/git.mjs'
|
|
2
2
|
import {hasPrePushHook} from './preflight.mjs'
|
|
3
|
+
import {gitCommitArgs, gitPushArgs} from '../utils/git-hooks.mjs'
|
|
3
4
|
|
|
4
5
|
export async function getCurrentBranch(rootDir) {
|
|
5
6
|
const branch = await getCurrentBranchImpl(rootDir)
|
|
@@ -165,7 +166,9 @@ async function commitAndPushStagedChanges(targetBranch, rootDir, {
|
|
|
165
166
|
runCommand,
|
|
166
167
|
getGitStatus,
|
|
167
168
|
logProcessing,
|
|
168
|
-
logSuccess
|
|
169
|
+
logSuccess,
|
|
170
|
+
logWarning,
|
|
171
|
+
skipGitHooks = false
|
|
169
172
|
} = {}) {
|
|
170
173
|
const { commitMessage } = await runPrompt([
|
|
171
174
|
{
|
|
@@ -179,15 +182,19 @@ async function commitAndPushStagedChanges(targetBranch, rootDir, {
|
|
|
179
182
|
const message = commitMessage.trim()
|
|
180
183
|
|
|
181
184
|
logProcessing?.('Committing staged changes before deployment...')
|
|
182
|
-
await runCommand('git', ['
|
|
185
|
+
await runCommand('git', gitCommitArgs(['-m', message], {skipGitHooks}), { cwd: rootDir })
|
|
183
186
|
|
|
184
187
|
const prePushHookPresent = await hasPrePushHook(rootDir)
|
|
185
188
|
if (prePushHookPresent) {
|
|
186
|
-
|
|
189
|
+
if (skipGitHooks) {
|
|
190
|
+
logWarning?.('Pre-push git hook detected, but Zephyr will bypass it because --skip-git-hooks was provided.')
|
|
191
|
+
} else {
|
|
192
|
+
logProcessing?.('Pre-push git hook detected. Running hook during git push...')
|
|
193
|
+
}
|
|
187
194
|
}
|
|
188
195
|
|
|
189
196
|
try {
|
|
190
|
-
await runCommand('git', ['
|
|
197
|
+
await runCommand('git', gitPushArgs(['origin', targetBranch], {skipGitHooks}), { cwd: rootDir })
|
|
191
198
|
} catch (error) {
|
|
192
199
|
if (prePushHookPresent) {
|
|
193
200
|
throw new Error(`Git push failed while the pre-push hook was running. See hook output above.\n${error.message}`)
|
|
@@ -211,6 +218,7 @@ export async function ensureCommittedChangesPushed(targetBranch, rootDir, {
|
|
|
211
218
|
logProcessing,
|
|
212
219
|
logSuccess,
|
|
213
220
|
logWarning,
|
|
221
|
+
skipGitHooks = false,
|
|
214
222
|
getUpstreamRef: getUpstreamRefFn = getUpstreamRef,
|
|
215
223
|
readUpstreamSyncState: readUpstreamSyncStateFn = (branch, dir) =>
|
|
216
224
|
readUpstreamSyncState(branch, dir, {
|
|
@@ -256,11 +264,15 @@ export async function ensureCommittedChangesPushed(targetBranch, rootDir, {
|
|
|
256
264
|
const prePushHookPresent = await hasPrePushHookFn(rootDir)
|
|
257
265
|
|
|
258
266
|
if (prePushHookPresent) {
|
|
259
|
-
|
|
267
|
+
if (skipGitHooks) {
|
|
268
|
+
logWarning?.('Pre-push git hook detected, but Zephyr will bypass it because --skip-git-hooks was provided.')
|
|
269
|
+
} else {
|
|
270
|
+
logProcessing?.('Pre-push git hook detected. Running hook during git push...')
|
|
271
|
+
}
|
|
260
272
|
}
|
|
261
273
|
|
|
262
274
|
try {
|
|
263
|
-
await runCommandCapture('git', [
|
|
275
|
+
await runCommandCapture('git', gitPushArgs([remoteName, `${targetBranch}:${upstreamBranch}`], {skipGitHooks}), { cwd: rootDir })
|
|
264
276
|
} catch (error) {
|
|
265
277
|
if (prePushHookPresent) {
|
|
266
278
|
const hookOutput = [error.stdout, error.stderr]
|
|
@@ -290,6 +302,7 @@ export async function ensureLocalRepositoryState(targetBranch, rootDir = process
|
|
|
290
302
|
logProcessing,
|
|
291
303
|
logSuccess,
|
|
292
304
|
logWarning,
|
|
305
|
+
skipGitHooks = false,
|
|
293
306
|
getCurrentBranch: getCurrentBranchFn = getCurrentBranch,
|
|
294
307
|
getGitStatus: getGitStatusFn = (dir) => getGitStatus(dir, { runCommandCapture }),
|
|
295
308
|
readUpstreamSyncState: readUpstreamSyncStateFn = (branch, dir) =>
|
|
@@ -304,7 +317,8 @@ export async function ensureLocalRepositoryState(targetBranch, rootDir = process
|
|
|
304
317
|
runCommandCapture,
|
|
305
318
|
logProcessing,
|
|
306
319
|
logSuccess,
|
|
307
|
-
logWarning
|
|
320
|
+
logWarning,
|
|
321
|
+
skipGitHooks
|
|
308
322
|
})
|
|
309
323
|
} = {}) {
|
|
310
324
|
if (!targetBranch) {
|
|
@@ -369,7 +383,9 @@ export async function ensureLocalRepositoryState(targetBranch, rootDir = process
|
|
|
369
383
|
runCommand,
|
|
370
384
|
getGitStatus: getGitStatusFn,
|
|
371
385
|
logProcessing,
|
|
372
|
-
logSuccess
|
|
386
|
+
logSuccess,
|
|
387
|
+
logWarning,
|
|
388
|
+
skipGitHooks
|
|
373
389
|
})
|
|
374
390
|
|
|
375
391
|
await ensureCommittedChangesPushedFn(targetBranch, rootDir)
|
package/src/deploy/preflight.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs/promises'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
|
|
4
|
+
import {gitCommitArgs} from '../utils/git-hooks.mjs'
|
|
5
|
+
|
|
4
6
|
export async function hasPrePushHook(rootDir) {
|
|
5
7
|
const hookPaths = [
|
|
6
8
|
path.join(rootDir, '.git', 'hooks', 'pre-push'),
|
|
@@ -126,7 +128,13 @@ export function hasStagedChanges(statusOutput) {
|
|
|
126
128
|
})
|
|
127
129
|
}
|
|
128
130
|
|
|
129
|
-
export async function commitLintingChanges(rootDir, {
|
|
131
|
+
export async function commitLintingChanges(rootDir, {
|
|
132
|
+
getGitStatus,
|
|
133
|
+
runCommand,
|
|
134
|
+
logProcessing,
|
|
135
|
+
logSuccess,
|
|
136
|
+
skipGitHooks = false
|
|
137
|
+
} = {}) {
|
|
130
138
|
const status = await getGitStatus(rootDir)
|
|
131
139
|
|
|
132
140
|
if (!hasStagedChanges(status)) {
|
|
@@ -138,7 +146,7 @@ export async function commitLintingChanges(rootDir, { getGitStatus, runCommand,
|
|
|
138
146
|
}
|
|
139
147
|
|
|
140
148
|
logProcessing?.('Committing linting changes...')
|
|
141
|
-
await runCommand('git', ['
|
|
149
|
+
await runCommand('git', gitCommitArgs(['-m', 'style: apply linting fixes'], {skipGitHooks}), { cwd: rootDir })
|
|
142
150
|
logSuccess?.('Linting changes committed.')
|
|
143
151
|
return true
|
|
144
152
|
}
|
package/src/main.mjs
CHANGED
|
@@ -16,6 +16,7 @@ import {createConfigurationService} from './application/configuration/service.mj
|
|
|
16
16
|
import {selectDeploymentTarget} from './application/configuration/select-deployment-target.mjs'
|
|
17
17
|
import {resolvePendingSnapshot} from './application/deploy/resolve-pending-snapshot.mjs'
|
|
18
18
|
import {runDeployment} from './application/deploy/run-deployment.mjs'
|
|
19
|
+
import {SKIP_GIT_HOOKS_WARNING} from './utils/git-hooks.mjs'
|
|
19
20
|
|
|
20
21
|
const RELEASE_SCRIPT_NAME = 'release'
|
|
21
22
|
const RELEASE_SCRIPT_COMMAND = 'npx @wyxos/zephyr@latest'
|
|
@@ -33,6 +34,7 @@ function normalizeMainOptions(firstArg = null, secondArg = null) {
|
|
|
33
34
|
resumePending: firstArg.resumePending === true,
|
|
34
35
|
discardPending: firstArg.discardPending === true,
|
|
35
36
|
maintenanceMode: firstArg.maintenanceMode ?? null,
|
|
37
|
+
skipGitHooks: firstArg.skipGitHooks === true,
|
|
36
38
|
skipTests: firstArg.skipTests === true,
|
|
37
39
|
skipLint: firstArg.skipLint === true,
|
|
38
40
|
skipBuild: firstArg.skipBuild === true,
|
|
@@ -50,6 +52,7 @@ function normalizeMainOptions(firstArg = null, secondArg = null) {
|
|
|
50
52
|
resumePending: false,
|
|
51
53
|
discardPending: false,
|
|
52
54
|
maintenanceMode: null,
|
|
55
|
+
skipGitHooks: false,
|
|
53
56
|
skipTests: false,
|
|
54
57
|
skipLint: false,
|
|
55
58
|
skipBuild: false,
|
|
@@ -86,6 +89,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
86
89
|
workflow: resolveWorkflowName(options.workflowType),
|
|
87
90
|
presetName: options.presetName,
|
|
88
91
|
maintenanceMode: options.maintenanceMode,
|
|
92
|
+
skipGitHooks: options.skipGitHooks === true,
|
|
89
93
|
resumePending: options.resumePending,
|
|
90
94
|
discardPending: options.discardPending
|
|
91
95
|
}
|
|
@@ -114,6 +118,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
114
118
|
nonInteractive: currentExecutionMode.interactive === false,
|
|
115
119
|
presetName: currentExecutionMode.presetName,
|
|
116
120
|
maintenanceMode: currentExecutionMode.maintenanceMode,
|
|
121
|
+
skipGitHooks: currentExecutionMode.skipGitHooks === true,
|
|
117
122
|
resumePending: currentExecutionMode.resumePending,
|
|
118
123
|
discardPending: currentExecutionMode.discardPending
|
|
119
124
|
}
|
|
@@ -122,9 +127,14 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
122
127
|
logProcessing(`Zephyr v${ZEPHYR_VERSION}`)
|
|
123
128
|
}
|
|
124
129
|
|
|
130
|
+
if (currentExecutionMode.skipGitHooks) {
|
|
131
|
+
logWarning(SKIP_GIT_HOOKS_WARNING)
|
|
132
|
+
}
|
|
133
|
+
|
|
125
134
|
if (options.workflowType === 'node' || options.workflowType === 'vue') {
|
|
126
135
|
await releaseNode({
|
|
127
136
|
releaseType: options.versionArg,
|
|
137
|
+
skipGitHooks: options.skipGitHooks,
|
|
128
138
|
skipTests: options.skipTests,
|
|
129
139
|
skipLint: options.skipLint,
|
|
130
140
|
skipBuild: options.skipBuild,
|
|
@@ -144,6 +154,7 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
144
154
|
if (options.workflowType === 'packagist') {
|
|
145
155
|
await releasePackagist({
|
|
146
156
|
releaseType: options.versionArg,
|
|
157
|
+
skipGitHooks: options.skipGitHooks,
|
|
147
158
|
skipTests: options.skipTests,
|
|
148
159
|
skipLint: options.skipLint,
|
|
149
160
|
context: appContext
|
|
@@ -164,13 +175,15 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
164
175
|
projectConfigDir: PROJECT_CONFIG_DIR,
|
|
165
176
|
runCommand,
|
|
166
177
|
logSuccess,
|
|
167
|
-
logWarning
|
|
178
|
+
logWarning,
|
|
179
|
+
skipGitHooks: currentExecutionMode.skipGitHooks
|
|
168
180
|
})
|
|
169
181
|
await bootstrap.ensureProjectReleaseScript(rootDir, {
|
|
170
182
|
runPrompt,
|
|
171
183
|
runCommand,
|
|
172
184
|
logSuccess,
|
|
173
185
|
logWarning,
|
|
186
|
+
skipGitHooks: currentExecutionMode.skipGitHooks,
|
|
174
187
|
interactive: currentExecutionMode.interactive,
|
|
175
188
|
releaseScriptName: RELEASE_SCRIPT_NAME,
|
|
176
189
|
releaseScriptCommand: RELEASE_SCRIPT_COMMAND
|
|
@@ -184,7 +197,8 @@ async function main(optionsOrWorkflowType = null, versionArg = null) {
|
|
|
184
197
|
if (hasPackageJson || hasComposerJson) {
|
|
185
198
|
logProcessing('Validating dependencies...')
|
|
186
199
|
await validateLocalDependencies(rootDir, runPrompt, logSuccess, {
|
|
187
|
-
interactive: currentExecutionMode.interactive
|
|
200
|
+
interactive: currentExecutionMode.interactive,
|
|
201
|
+
skipGitHooks: currentExecutionMode.skipGitHooks
|
|
188
202
|
})
|
|
189
203
|
}
|
|
190
204
|
|
|
@@ -2,12 +2,14 @@ import fs from 'node:fs/promises'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
|
|
4
4
|
import {ZephyrError} from '../runtime/errors.mjs'
|
|
5
|
+
import {gitCommitArgs} from '../utils/git-hooks.mjs'
|
|
5
6
|
|
|
6
7
|
export async function ensureGitignoreEntry(rootDir, {
|
|
7
8
|
projectConfigDir = '.zephyr',
|
|
8
9
|
runCommand,
|
|
9
10
|
logSuccess,
|
|
10
|
-
logWarning
|
|
11
|
+
logWarning,
|
|
12
|
+
skipGitHooks = false
|
|
11
13
|
} = {}) {
|
|
12
14
|
const gitignorePath = path.join(rootDir, '.gitignore')
|
|
13
15
|
const targetEntry = `${projectConfigDir}/`
|
|
@@ -53,7 +55,7 @@ export async function ensureGitignoreEntry(rootDir, {
|
|
|
53
55
|
|
|
54
56
|
try {
|
|
55
57
|
await runCommand('git', ['add', '.gitignore'], { cwd: rootDir })
|
|
56
|
-
await runCommand('git', ['
|
|
58
|
+
await runCommand('git', gitCommitArgs(['-m', 'chore: ignore zephyr config'], {skipGitHooks}), { cwd: rootDir })
|
|
57
59
|
} catch (error) {
|
|
58
60
|
if (error.exitCode === 1) {
|
|
59
61
|
logWarning?.('Git commit skipped: nothing to commit or pre-commit hook prevented commit.')
|
|
@@ -68,6 +70,7 @@ export async function ensureProjectReleaseScript(rootDir, {
|
|
|
68
70
|
runCommand,
|
|
69
71
|
logSuccess,
|
|
70
72
|
logWarning,
|
|
73
|
+
skipGitHooks = false,
|
|
71
74
|
interactive = true,
|
|
72
75
|
releaseScriptName = 'release',
|
|
73
76
|
releaseScriptCommand = 'npx @wyxos/zephyr@latest'
|
|
@@ -141,7 +144,7 @@ export async function ensureProjectReleaseScript(rootDir, {
|
|
|
141
144
|
if (isGitRepo) {
|
|
142
145
|
try {
|
|
143
146
|
await runCommand('git', ['add', 'package.json'], { cwd: rootDir, silent: true })
|
|
144
|
-
await runCommand('git', ['
|
|
147
|
+
await runCommand('git', gitCommitArgs(['-m', 'chore: add zephyr release script'], {skipGitHooks}), { cwd: rootDir, silent: true })
|
|
145
148
|
logSuccess?.('Committed package.json release script addition.')
|
|
146
149
|
} catch (error) {
|
|
147
150
|
if (error.exitCode === 1) {
|
package/src/release/shared.mjs
CHANGED
|
@@ -101,9 +101,13 @@ export async function ensureCleanWorkingTree(rootDir = process.cwd(), {
|
|
|
101
101
|
export async function validateReleaseDependencies(rootDir = process.cwd(), {
|
|
102
102
|
prompt = (questions) => inquirer.prompt(questions),
|
|
103
103
|
logSuccess,
|
|
104
|
-
interactive = true
|
|
104
|
+
interactive = true,
|
|
105
|
+
skipGitHooks = false
|
|
105
106
|
} = {}) {
|
|
106
|
-
await validateLocalDependencies(rootDir, prompt, logSuccess, {
|
|
107
|
+
await validateLocalDependencies(rootDir, prompt, logSuccess, {
|
|
108
|
+
interactive,
|
|
109
|
+
skipGitHooks
|
|
110
|
+
})
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
export async function ensureReleaseBranchReady({
|
package/src/release-node.mjs
CHANGED
|
@@ -3,11 +3,29 @@ import {createAppContext} from './runtime/app-context.mjs'
|
|
|
3
3
|
import {parseReleaseArgs} from './release/shared.mjs'
|
|
4
4
|
import {releaseNodePackage} from './application/release/release-node-package.mjs'
|
|
5
5
|
|
|
6
|
+
function hasExplicitReleaseOptions(options = {}) {
|
|
7
|
+
return [
|
|
8
|
+
'releaseType',
|
|
9
|
+
'skipGitHooks',
|
|
10
|
+
'skipTests',
|
|
11
|
+
'skipLint',
|
|
12
|
+
'skipBuild',
|
|
13
|
+
'skipDeploy'
|
|
14
|
+
].some((key) => key in options)
|
|
15
|
+
}
|
|
16
|
+
|
|
6
17
|
export async function releaseNode(options = {}) {
|
|
7
|
-
const parsed = options
|
|
8
|
-
?
|
|
18
|
+
const parsed = hasExplicitReleaseOptions(options)
|
|
19
|
+
? {
|
|
20
|
+
releaseType: options.releaseType ?? 'patch',
|
|
21
|
+
skipGitHooks: options.skipGitHooks === true,
|
|
22
|
+
skipTests: options.skipTests === true,
|
|
23
|
+
skipLint: options.skipLint === true,
|
|
24
|
+
skipBuild: options.skipBuild === true,
|
|
25
|
+
skipDeploy: options.skipDeploy === true
|
|
26
|
+
}
|
|
9
27
|
: parseReleaseArgs({
|
|
10
|
-
booleanFlags: ['--skip-tests', '--skip-lint', '--skip-build', '--skip-deploy']
|
|
28
|
+
booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint', '--skip-build', '--skip-deploy']
|
|
11
29
|
})
|
|
12
30
|
const rootDir = options.rootDir ?? process.cwd()
|
|
13
31
|
const context = options.context ?? createAppContext({
|
|
@@ -21,6 +39,7 @@ export async function releaseNode(options = {}) {
|
|
|
21
39
|
|
|
22
40
|
await releaseNodePackage({
|
|
23
41
|
releaseType: parsed.releaseType,
|
|
42
|
+
skipGitHooks: parsed.skipGitHooks === true || executionMode?.skipGitHooks === true,
|
|
24
43
|
skipTests: parsed.skipTests === true,
|
|
25
44
|
skipLint: parsed.skipLint === true,
|
|
26
45
|
skipBuild: parsed.skipBuild === true,
|
|
@@ -3,11 +3,25 @@ import {createAppContext} from './runtime/app-context.mjs'
|
|
|
3
3
|
import {parseReleaseArgs} from './release/shared.mjs'
|
|
4
4
|
import {releasePackagistPackage} from './application/release/release-packagist-package.mjs'
|
|
5
5
|
|
|
6
|
+
function hasExplicitReleaseOptions(options = {}) {
|
|
7
|
+
return [
|
|
8
|
+
'releaseType',
|
|
9
|
+
'skipGitHooks',
|
|
10
|
+
'skipTests',
|
|
11
|
+
'skipLint'
|
|
12
|
+
].some((key) => key in options)
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
export async function releasePackagist(options = {}) {
|
|
7
|
-
const parsed = options
|
|
8
|
-
?
|
|
16
|
+
const parsed = hasExplicitReleaseOptions(options)
|
|
17
|
+
? {
|
|
18
|
+
releaseType: options.releaseType ?? 'patch',
|
|
19
|
+
skipGitHooks: options.skipGitHooks === true,
|
|
20
|
+
skipTests: options.skipTests === true,
|
|
21
|
+
skipLint: options.skipLint === true
|
|
22
|
+
}
|
|
9
23
|
: parseReleaseArgs({
|
|
10
|
-
booleanFlags: ['--skip-tests', '--skip-lint']
|
|
24
|
+
booleanFlags: ['--skip-git-hooks', '--skip-tests', '--skip-lint']
|
|
11
25
|
})
|
|
12
26
|
const rootDir = options.rootDir ?? process.cwd()
|
|
13
27
|
const context = options.context ?? createAppContext({
|
|
@@ -21,6 +35,7 @@ export async function releasePackagist(options = {}) {
|
|
|
21
35
|
|
|
22
36
|
await releasePackagistPackage({
|
|
23
37
|
releaseType: parsed.releaseType,
|
|
38
|
+
skipGitHooks: parsed.skipGitHooks === true || executionMode?.skipGitHooks === true,
|
|
24
39
|
skipTests: parsed.skipTests === true,
|
|
25
40
|
skipLint: parsed.skipLint === true,
|
|
26
41
|
rootDir,
|
|
@@ -22,6 +22,7 @@ export function createAppContext({
|
|
|
22
22
|
workflow: executionMode.workflow ?? 'deploy',
|
|
23
23
|
presetName: executionMode.presetName ?? null,
|
|
24
24
|
maintenanceMode: executionMode.maintenanceMode ?? null,
|
|
25
|
+
skipGitHooks: executionMode.skipGitHooks === true,
|
|
25
26
|
resumePending: executionMode.resumePending === true,
|
|
26
27
|
discardPending: executionMode.discardPending === true
|
|
27
28
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const SKIP_GIT_HOOKS_WARNING =
|
|
2
|
+
'WARNING: --skip-git-hooks is enabled. Zephyr will bypass local git hooks for any commits and pushes it performs during this run.'
|
|
3
|
+
|
|
4
|
+
export function gitCommitArgs(args = [], {skipGitHooks = false} = {}) {
|
|
5
|
+
return skipGitHooks
|
|
6
|
+
? ['commit', '--no-verify', ...args]
|
|
7
|
+
: ['commit', ...args]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function gitPushArgs(args = [], {skipGitHooks = false} = {}) {
|
|
11
|
+
return skipGitHooks
|
|
12
|
+
? ['push', '--no-verify', ...args]
|
|
13
|
+
: ['push', ...args]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function npmVersionArgs(releaseType, {
|
|
17
|
+
skipGitHooks = false,
|
|
18
|
+
extraArgs = []
|
|
19
|
+
} = {}) {
|
|
20
|
+
return [
|
|
21
|
+
'version',
|
|
22
|
+
releaseType,
|
|
23
|
+
...(skipGitHooks ? ['--no-commit-hooks'] : []),
|
|
24
|
+
...extraArgs
|
|
25
|
+
]
|
|
26
|
+
}
|