@wyxos/zephyr 0.2.17 → 0.2.18
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 -5
- package/bin/zephyr.mjs +1 -1
- package/package.json +1 -1
- package/src/dependency-scanner.mjs +6 -6
- package/src/index.mjs +32 -24
- package/src/release-node.mjs +40 -22
- package/src/release-packagist.mjs +25 -7
- package/src/ssh-utils.mjs +15 -4
- package/src/version-checker.mjs +0 -1
package/README.md
CHANGED
|
@@ -30,6 +30,12 @@ Follow the interactive prompts to configure your deployment target:
|
|
|
30
30
|
|
|
31
31
|
Configuration is saved automatically for future deployments.
|
|
32
32
|
|
|
33
|
+
## Update Checks
|
|
34
|
+
|
|
35
|
+
When run via `npx`, Zephyr can prompt to re-run itself using the latest published version.
|
|
36
|
+
|
|
37
|
+
- **Skip update check**: set `ZEPHYR_SKIP_VERSION_CHECK=1`
|
|
38
|
+
|
|
33
39
|
## Features
|
|
34
40
|
|
|
35
41
|
- Automated Git operations (branch switching, commits, pushes)
|
|
@@ -49,11 +55,12 @@ Configuration is saved automatically for future deployments.
|
|
|
49
55
|
Zephyr analyzes changed files and runs appropriate tasks:
|
|
50
56
|
|
|
51
57
|
- **Always**: `git pull origin <branch>`
|
|
52
|
-
- **Composer files changed
|
|
53
|
-
- **
|
|
54
|
-
- **package.json
|
|
55
|
-
- **Frontend files changed
|
|
56
|
-
-
|
|
58
|
+
- **Composer files changed** (`composer.json` / `composer.lock`): `composer update --no-dev --no-interaction --prefer-dist`
|
|
59
|
+
- **Migrations changed** (`database/migrations/*.php`): `php artisan migrate --force`
|
|
60
|
+
- **Node dependency files changed** (`package.json` / `package-lock.json`, including nested): `npm install`
|
|
61
|
+
- **Frontend files changed** (`.vue/.js/.ts/.tsx/.css/.scss/.less`): `npm run build`
|
|
62
|
+
- Note: `npm run build` is also scheduled when `npm install` is scheduled.
|
|
63
|
+
- **PHP files changed**: clear caches + restart queue workers (Horizon if configured)
|
|
57
64
|
|
|
58
65
|
## Configuration
|
|
59
66
|
|
|
@@ -64,6 +71,7 @@ Servers are stored globally at `~/.config/zephyr/servers.json`:
|
|
|
64
71
|
```json
|
|
65
72
|
[
|
|
66
73
|
{
|
|
74
|
+
"id": "server_abc123",
|
|
67
75
|
"serverName": "production",
|
|
68
76
|
"serverIp": "192.168.1.100"
|
|
69
77
|
}
|
|
@@ -76,8 +84,17 @@ Deployment targets are stored per-project at `.zephyr/config.json`:
|
|
|
76
84
|
|
|
77
85
|
```json
|
|
78
86
|
{
|
|
87
|
+
"presets": [
|
|
88
|
+
{
|
|
89
|
+
"name": "prod-main",
|
|
90
|
+
"appId": "app_def456",
|
|
91
|
+
"branch": "main"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
79
94
|
"apps": [
|
|
80
95
|
{
|
|
96
|
+
"id": "app_def456",
|
|
97
|
+
"serverId": "server_abc123",
|
|
81
98
|
"serverName": "production",
|
|
82
99
|
"projectPath": "~/webapps/myapp",
|
|
83
100
|
"branch": "main",
|
|
@@ -98,6 +115,11 @@ Zephyr creates a `.zephyr/` directory in your project with:
|
|
|
98
115
|
|
|
99
116
|
The `.zephyr/` directory is automatically added to `.gitignore`.
|
|
100
117
|
|
|
118
|
+
## Notes
|
|
119
|
+
|
|
120
|
+
- If Zephyr reports **"No upstream file changes detected"**, it means the remote repository already matches `origin/<branch>` after `git fetch`. In that case, Zephyr will only run `git pull` and skip all conditional maintenance tasks.
|
|
121
|
+
- If Zephyr prompts to update local file dependencies (path-based deps outside the repo), it may also prompt to commit those updates before continuing.
|
|
122
|
+
|
|
101
123
|
## Requirements
|
|
102
124
|
|
|
103
125
|
- Node.js 16+
|
package/bin/zephyr.mjs
CHANGED
package/package.json
CHANGED
|
@@ -219,16 +219,16 @@ async function updateComposerJsonDependency(rootDir, packageName, newVersion, fi
|
|
|
219
219
|
|
|
220
220
|
async function runCommand(command, args, { cwd = process.cwd(), capture = false } = {}) {
|
|
221
221
|
return new Promise((resolve, reject) => {
|
|
222
|
+
const resolvedCommand = IS_WINDOWS && (command === 'npm' || command === 'npx' || command === 'pnpm' || command === 'yarn')
|
|
223
|
+
? `${command}.cmd`
|
|
224
|
+
: command
|
|
225
|
+
|
|
222
226
|
const spawnOptions = {
|
|
223
227
|
stdio: capture ? ['ignore', 'pipe', 'pipe'] : 'inherit',
|
|
224
228
|
cwd
|
|
225
229
|
}
|
|
226
230
|
|
|
227
|
-
|
|
228
|
-
spawnOptions.shell = true
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const child = spawn(command, args, spawnOptions)
|
|
231
|
+
const child = spawn(resolvedCommand, args, spawnOptions)
|
|
232
232
|
let stdout = ''
|
|
233
233
|
let stderr = ''
|
|
234
234
|
|
|
@@ -247,7 +247,7 @@ async function runCommand(command, args, { cwd = process.cwd(), capture = false
|
|
|
247
247
|
if (code === 0) {
|
|
248
248
|
resolve(capture ? { stdout: stdout.trim(), stderr: stderr.trim() } : undefined)
|
|
249
249
|
} else {
|
|
250
|
-
const error = new Error(`Command failed (${code}): ${
|
|
250
|
+
const error = new Error(`Command failed (${code}): ${resolvedCommand} ${args.join(' ')}`)
|
|
251
251
|
if (capture) {
|
|
252
252
|
error.stdout = stdout
|
|
253
253
|
error.stderr = stderr
|
package/src/index.mjs
CHANGED
|
@@ -23,10 +23,20 @@ const PENDING_TASKS_FILE = 'pending-tasks.json'
|
|
|
23
23
|
const RELEASE_SCRIPT_NAME = 'release'
|
|
24
24
|
const RELEASE_SCRIPT_COMMAND = 'npx @wyxos/zephyr@latest'
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
function writeStdoutLine(message = '') {
|
|
27
|
+
const text = message == null ? '' : String(message)
|
|
28
|
+
process.stdout.write(`${text}\n`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function writeStderrLine(message = '') {
|
|
32
|
+
const text = message == null ? '' : String(message)
|
|
33
|
+
process.stderr.write(`${text}\n`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const logProcessing = (message = '') => writeStdoutLine(chalk.yellow(message))
|
|
37
|
+
const logSuccess = (message = '') => writeStdoutLine(chalk.green(message))
|
|
38
|
+
const logWarning = (message = '') => writeStderrLine(chalk.yellow(message))
|
|
39
|
+
const logError = (message = '') => writeStderrLine(chalk.red(message))
|
|
30
40
|
|
|
31
41
|
let logFilePath = null
|
|
32
42
|
|
|
@@ -120,25 +130,23 @@ const runPrompt = async (questions) => {
|
|
|
120
130
|
|
|
121
131
|
async function runCommand(command, args, { silent = false, cwd } = {}) {
|
|
122
132
|
return new Promise((resolve, reject) => {
|
|
133
|
+
const resolvedCommand = IS_WINDOWS && (command === 'npm' || command === 'npx' || command === 'pnpm' || command === 'yarn')
|
|
134
|
+
? `${command}.cmd`
|
|
135
|
+
: command
|
|
136
|
+
|
|
123
137
|
const spawnOptions = {
|
|
124
138
|
stdio: silent ? 'ignore' : 'inherit',
|
|
125
139
|
cwd
|
|
126
140
|
}
|
|
127
141
|
|
|
128
|
-
|
|
129
|
-
// Git commands work fine without shell
|
|
130
|
-
if (IS_WINDOWS && command !== 'git') {
|
|
131
|
-
spawnOptions.shell = true
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const child = spawn(command, args, spawnOptions)
|
|
142
|
+
const child = spawn(resolvedCommand, args, spawnOptions)
|
|
135
143
|
|
|
136
144
|
child.on('error', reject)
|
|
137
145
|
child.on('close', (code) => {
|
|
138
146
|
if (code === 0) {
|
|
139
147
|
resolve()
|
|
140
148
|
} else {
|
|
141
|
-
const error = new Error(`${
|
|
149
|
+
const error = new Error(`${resolvedCommand} exited with code ${code}`)
|
|
142
150
|
error.exitCode = code
|
|
143
151
|
reject(error)
|
|
144
152
|
}
|
|
@@ -148,6 +156,10 @@ async function runCommand(command, args, { silent = false, cwd } = {}) {
|
|
|
148
156
|
|
|
149
157
|
async function runCommandCapture(command, args, { cwd } = {}) {
|
|
150
158
|
return new Promise((resolve, reject) => {
|
|
159
|
+
const resolvedCommand = IS_WINDOWS && (command === 'npm' || command === 'npx' || command === 'pnpm' || command === 'yarn')
|
|
160
|
+
? `${command}.cmd`
|
|
161
|
+
: command
|
|
162
|
+
|
|
151
163
|
let stdout = ''
|
|
152
164
|
let stderr = ''
|
|
153
165
|
|
|
@@ -156,13 +168,7 @@ async function runCommandCapture(command, args, { cwd } = {}) {
|
|
|
156
168
|
cwd
|
|
157
169
|
}
|
|
158
170
|
|
|
159
|
-
|
|
160
|
-
// Git commands work fine without shell
|
|
161
|
-
if (IS_WINDOWS && command !== 'git') {
|
|
162
|
-
spawnOptions.shell = true
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const child = spawn(command, args, spawnOptions)
|
|
171
|
+
const child = spawn(resolvedCommand, args, spawnOptions)
|
|
166
172
|
|
|
167
173
|
child.stdout.on('data', (chunk) => {
|
|
168
174
|
stdout += chunk
|
|
@@ -177,7 +183,7 @@ async function runCommandCapture(command, args, { cwd } = {}) {
|
|
|
177
183
|
if (code === 0) {
|
|
178
184
|
resolve(stdout)
|
|
179
185
|
} else {
|
|
180
|
-
const error = new Error(`${
|
|
186
|
+
const error = new Error(`${resolvedCommand} exited with code ${code}: ${stderr.trim()}`)
|
|
181
187
|
error.exitCode = code
|
|
182
188
|
reject(error)
|
|
183
189
|
}
|
|
@@ -297,7 +303,9 @@ async function ensureCommittedChangesPushed(targetBranch, rootDir) {
|
|
|
297
303
|
const commitLabel = aheadCount === 1 ? 'commit' : 'commits'
|
|
298
304
|
logProcessing(`Found ${aheadCount} ${commitLabel} not yet pushed to ${upstreamRef}. Pushing before deployment...`)
|
|
299
305
|
|
|
300
|
-
|
|
306
|
+
// Keep terminal output clean: suppress git push progress output (it is very noisy),
|
|
307
|
+
// but still surface errors via the thrown exception message.
|
|
308
|
+
await runCommandCapture('git', ['push', remoteName, `${targetBranch}:${upstreamBranch}`], { cwd: rootDir })
|
|
301
309
|
logSuccess(`Pushed committed changes to ${upstreamRef}.`)
|
|
302
310
|
|
|
303
311
|
return { pushed: true, upstreamRef }
|
|
@@ -1882,7 +1890,7 @@ async function main(releaseType = null) {
|
|
|
1882
1890
|
logError('\nRelease failed:')
|
|
1883
1891
|
logError(error.message)
|
|
1884
1892
|
if (error.stack) {
|
|
1885
|
-
|
|
1893
|
+
writeStderrLine(error.stack)
|
|
1886
1894
|
}
|
|
1887
1895
|
process.exit(1)
|
|
1888
1896
|
}
|
|
@@ -1897,7 +1905,7 @@ async function main(releaseType = null) {
|
|
|
1897
1905
|
logError('\nRelease failed:')
|
|
1898
1906
|
logError(error.message)
|
|
1899
1907
|
if (error.stack) {
|
|
1900
|
-
|
|
1908
|
+
writeStderrLine(error.stack)
|
|
1901
1909
|
}
|
|
1902
1910
|
process.exit(1)
|
|
1903
1911
|
}
|
|
@@ -2018,7 +2026,7 @@ async function main(releaseType = null) {
|
|
|
2018
2026
|
}
|
|
2019
2027
|
|
|
2020
2028
|
logProcessing('\nSelected deployment target:')
|
|
2021
|
-
|
|
2029
|
+
writeStdoutLine(JSON.stringify(deploymentConfig, null, 2))
|
|
2022
2030
|
|
|
2023
2031
|
if (isCreatingNewPreset || !preset) {
|
|
2024
2032
|
const { presetName } = await runPrompt([
|
package/src/release-node.mjs
CHANGED
|
@@ -10,16 +10,34 @@ import { validateLocalDependencies } from './dependency-scanner.mjs'
|
|
|
10
10
|
|
|
11
11
|
const IS_WINDOWS = process.platform === 'win32'
|
|
12
12
|
|
|
13
|
+
function writeStdoutLine(message = '') {
|
|
14
|
+
const text = message == null ? '' : String(message)
|
|
15
|
+
process.stdout.write(`${text}\n`)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function writeStderrLine(message = '') {
|
|
19
|
+
const text = message == null ? '' : String(message)
|
|
20
|
+
process.stderr.write(`${text}\n`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function writeStderr(message = '') {
|
|
24
|
+
const text = message == null ? '' : String(message)
|
|
25
|
+
process.stderr.write(text)
|
|
26
|
+
if (text && !text.endsWith('\n')) {
|
|
27
|
+
process.stderr.write('\n')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
13
31
|
function logStep(message) {
|
|
14
|
-
|
|
32
|
+
writeStdoutLine(chalk.yellow(`→ ${message}`))
|
|
15
33
|
}
|
|
16
34
|
|
|
17
35
|
function logSuccess(message) {
|
|
18
|
-
|
|
36
|
+
writeStdoutLine(chalk.green(`✔ ${message}`))
|
|
19
37
|
}
|
|
20
38
|
|
|
21
39
|
function logWarning(message) {
|
|
22
|
-
|
|
40
|
+
writeStderrLine(chalk.yellow(`⚠ ${message}`))
|
|
23
41
|
}
|
|
24
42
|
|
|
25
43
|
function runCommand(command, args, { cwd = process.cwd(), capture = false, useShell = false } = {}) {
|
|
@@ -155,7 +173,7 @@ async function ensureUpToDateWithUpstream(branch, upstreamRef, rootDir = process
|
|
|
155
173
|
await runCommand('git', ['fetch', remoteName, remoteBranch], { capture: true, cwd: rootDir })
|
|
156
174
|
} catch (error) {
|
|
157
175
|
if (error.stderr) {
|
|
158
|
-
|
|
176
|
+
writeStderr(error.stderr)
|
|
159
177
|
}
|
|
160
178
|
throw new Error(`Failed to fetch ${upstreamRef}: ${error.message}`)
|
|
161
179
|
}
|
|
@@ -181,7 +199,7 @@ async function ensureUpToDateWithUpstream(branch, upstreamRef, rootDir = process
|
|
|
181
199
|
await runCommand('git', ['pull', '--ff-only', remoteName, remoteBranch], { capture: true, cwd: rootDir })
|
|
182
200
|
} catch (error) {
|
|
183
201
|
if (error.stderr) {
|
|
184
|
-
|
|
202
|
+
writeStderr(error.stderr)
|
|
185
203
|
}
|
|
186
204
|
throw new Error(
|
|
187
205
|
`Unable to fast-forward ${branch} with ${upstreamRef}. Resolve conflicts manually, then rerun the release.\n${error.message}`
|
|
@@ -251,10 +269,10 @@ async function runLint(skipLint, pkg, rootDir = process.cwd()) {
|
|
|
251
269
|
logSuccess('Lint passed.')
|
|
252
270
|
} catch (error) {
|
|
253
271
|
if (error.stdout) {
|
|
254
|
-
|
|
272
|
+
writeStderr(error.stdout)
|
|
255
273
|
}
|
|
256
274
|
if (error.stderr) {
|
|
257
|
-
|
|
275
|
+
writeStderr(error.stderr)
|
|
258
276
|
}
|
|
259
277
|
throw error
|
|
260
278
|
}
|
|
@@ -287,10 +305,10 @@ async function runTests(skipTests, pkg, rootDir = process.cwd()) {
|
|
|
287
305
|
logSuccess('Tests passed.')
|
|
288
306
|
} catch (error) {
|
|
289
307
|
if (error.stdout) {
|
|
290
|
-
|
|
308
|
+
writeStderr(error.stdout)
|
|
291
309
|
}
|
|
292
310
|
if (error.stderr) {
|
|
293
|
-
|
|
311
|
+
writeStderr(error.stderr)
|
|
294
312
|
}
|
|
295
313
|
throw error
|
|
296
314
|
}
|
|
@@ -314,10 +332,10 @@ async function runBuild(skipBuild, pkg, rootDir = process.cwd()) {
|
|
|
314
332
|
logSuccess('Build completed.')
|
|
315
333
|
} catch (error) {
|
|
316
334
|
if (error.stdout) {
|
|
317
|
-
|
|
335
|
+
writeStderr(error.stdout)
|
|
318
336
|
}
|
|
319
337
|
if (error.stderr) {
|
|
320
|
-
|
|
338
|
+
writeStderr(error.stderr)
|
|
321
339
|
}
|
|
322
340
|
throw error
|
|
323
341
|
}
|
|
@@ -341,10 +359,10 @@ async function runLibBuild(skipBuild, pkg, rootDir = process.cwd()) {
|
|
|
341
359
|
logSuccess('Library built.')
|
|
342
360
|
} catch (error) {
|
|
343
361
|
if (error.stdout) {
|
|
344
|
-
|
|
362
|
+
writeStderr(error.stdout)
|
|
345
363
|
}
|
|
346
364
|
if (error.stderr) {
|
|
347
|
-
|
|
365
|
+
writeStderr(error.stderr)
|
|
348
366
|
}
|
|
349
367
|
throw error
|
|
350
368
|
}
|
|
@@ -377,7 +395,7 @@ async function ensureNpmAuth(rootDir = process.cwd()) {
|
|
|
377
395
|
logSuccess('npm authenticated.')
|
|
378
396
|
} catch (error) {
|
|
379
397
|
if (error.stderr) {
|
|
380
|
-
|
|
398
|
+
writeStderr(error.stderr)
|
|
381
399
|
}
|
|
382
400
|
throw error
|
|
383
401
|
}
|
|
@@ -438,10 +456,10 @@ async function pushChanges(rootDir = process.cwd()) {
|
|
|
438
456
|
logSuccess('Git push completed.')
|
|
439
457
|
} catch (error) {
|
|
440
458
|
if (error.stdout) {
|
|
441
|
-
|
|
459
|
+
writeStderr(error.stdout)
|
|
442
460
|
}
|
|
443
461
|
if (error.stderr) {
|
|
444
|
-
|
|
462
|
+
writeStderr(error.stderr)
|
|
445
463
|
}
|
|
446
464
|
throw error
|
|
447
465
|
}
|
|
@@ -472,10 +490,10 @@ async function publishPackage(pkg, rootDir = process.cwd()) {
|
|
|
472
490
|
logSuccess('npm publish completed.')
|
|
473
491
|
} catch (error) {
|
|
474
492
|
if (error.stdout) {
|
|
475
|
-
|
|
493
|
+
writeStderr(error.stdout)
|
|
476
494
|
}
|
|
477
495
|
if (error.stderr) {
|
|
478
|
-
|
|
496
|
+
writeStderr(error.stderr)
|
|
479
497
|
}
|
|
480
498
|
throw error
|
|
481
499
|
}
|
|
@@ -566,10 +584,10 @@ async function deployGHPages(skipDeploy, pkg, rootDir = process.cwd()) {
|
|
|
566
584
|
logSuccess('GitHub Pages deployment completed.')
|
|
567
585
|
} catch (error) {
|
|
568
586
|
if (error.stdout) {
|
|
569
|
-
|
|
587
|
+
writeStderr(error.stdout)
|
|
570
588
|
}
|
|
571
589
|
if (error.stderr) {
|
|
572
|
-
|
|
590
|
+
writeStderr(error.stderr)
|
|
573
591
|
}
|
|
574
592
|
throw error
|
|
575
593
|
}
|
|
@@ -611,8 +629,8 @@ export async function releaseNode() {
|
|
|
611
629
|
|
|
612
630
|
logSuccess(`Release workflow completed for ${updatedPkg.name}@${updatedPkg.version}.`)
|
|
613
631
|
} catch (error) {
|
|
614
|
-
|
|
615
|
-
|
|
632
|
+
writeStderrLine('\nRelease failed:')
|
|
633
|
+
writeStderrLine(error.message)
|
|
616
634
|
throw error
|
|
617
635
|
}
|
|
618
636
|
}
|
|
@@ -13,16 +13,34 @@ const WARN_PREFIX = '⚠'
|
|
|
13
13
|
|
|
14
14
|
const IS_WINDOWS = process.platform === 'win32'
|
|
15
15
|
|
|
16
|
+
function writeStdoutLine(message = '') {
|
|
17
|
+
const text = message == null ? '' : String(message)
|
|
18
|
+
process.stdout.write(`${text}\n`)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function writeStderrLine(message = '') {
|
|
22
|
+
const text = message == null ? '' : String(message)
|
|
23
|
+
process.stderr.write(`${text}\n`)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function writeStderr(message = '') {
|
|
27
|
+
const text = message == null ? '' : String(message)
|
|
28
|
+
process.stderr.write(text)
|
|
29
|
+
if (text && !text.endsWith('\n')) {
|
|
30
|
+
process.stderr.write('\n')
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
16
34
|
function logStep(message) {
|
|
17
|
-
|
|
35
|
+
writeStdoutLine(`${STEP_PREFIX} ${message}`)
|
|
18
36
|
}
|
|
19
37
|
|
|
20
38
|
function logSuccess(message) {
|
|
21
|
-
|
|
39
|
+
writeStdoutLine(`${OK_PREFIX} ${message}`)
|
|
22
40
|
}
|
|
23
41
|
|
|
24
42
|
function logWarning(message) {
|
|
25
|
-
|
|
43
|
+
writeStderrLine(`${WARN_PREFIX} ${message}`)
|
|
26
44
|
}
|
|
27
45
|
|
|
28
46
|
function runCommand(command, args, { cwd = process.cwd(), capture = false, useShell = false } = {}) {
|
|
@@ -269,10 +287,10 @@ async function runLint(skipLint, rootDir = process.cwd()) {
|
|
|
269
287
|
}
|
|
270
288
|
process.stdout.write('\n')
|
|
271
289
|
if (error.stdout) {
|
|
272
|
-
|
|
290
|
+
writeStderr(error.stdout)
|
|
273
291
|
}
|
|
274
292
|
if (error.stderr) {
|
|
275
|
-
|
|
293
|
+
writeStderr(error.stderr)
|
|
276
294
|
}
|
|
277
295
|
throw error
|
|
278
296
|
}
|
|
@@ -322,10 +340,10 @@ async function runTests(skipTests, composer, rootDir = process.cwd()) {
|
|
|
322
340
|
}
|
|
323
341
|
process.stdout.write('\n')
|
|
324
342
|
if (error.stdout) {
|
|
325
|
-
|
|
343
|
+
writeStderr(error.stdout)
|
|
326
344
|
}
|
|
327
345
|
if (error.stderr) {
|
|
328
|
-
|
|
346
|
+
writeStderr(error.stderr)
|
|
329
347
|
}
|
|
330
348
|
throw error
|
|
331
349
|
}
|
package/src/ssh-utils.mjs
CHANGED
|
@@ -3,13 +3,24 @@ import os from 'node:os'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { NodeSSH } from 'node-ssh'
|
|
5
5
|
import chalk from 'chalk'
|
|
6
|
+
import process from 'node:process'
|
|
6
7
|
|
|
7
8
|
// Import utility functions - these need to be passed in or redefined to avoid circular dependency
|
|
8
9
|
// For now, we'll redefine the simple ones and accept others as parameters
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
function writeStdoutLine(message = '') {
|
|
11
|
+
const text = message == null ? '' : String(message)
|
|
12
|
+
process.stdout.write(`${text}\n`)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function writeStderrLine(message = '') {
|
|
16
|
+
const text = message == null ? '' : String(message)
|
|
17
|
+
process.stderr.write(`${text}\n`)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const logProcessing = (message = '') => writeStdoutLine(chalk.yellow(message))
|
|
21
|
+
const logSuccess = (message = '') => writeStdoutLine(chalk.green(message))
|
|
22
|
+
const logError = (message = '') => writeStderrLine(chalk.red(message))
|
|
23
|
+
const logWarning = (message = '') => writeStderrLine(chalk.yellow(message))
|
|
13
24
|
|
|
14
25
|
function expandHomePath(targetPath) {
|
|
15
26
|
if (!targetPath) {
|
package/src/version-checker.mjs
CHANGED