@wyxos/zephyr 0.2.15 → 0.2.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wyxos/zephyr",
3
- "version": "0.2.15",
3
+ "version": "0.2.16",
4
4
  "description": "A streamlined deployment tool for web applications with intelligent Laravel project detection",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -1,5 +1,9 @@
1
1
  import { readFile, writeFile } from 'node:fs/promises'
2
2
  import path from 'node:path'
3
+ import { spawn } from 'node:child_process'
4
+ import process from 'node:process'
5
+
6
+ const IS_WINDOWS = process.platform === 'win32'
3
7
 
4
8
  function isLocalPathOutsideRepo(depPath, rootDir) {
5
9
  if (!depPath || typeof depPath !== 'string') {
@@ -212,7 +216,113 @@ async function updateComposerJsonDependency(rootDir, packageName, newVersion, fi
212
216
  await writeFile(composerJsonPath, updatedContent, 'utf8')
213
217
  }
214
218
 
215
- async function validateLocalDependencies(rootDir, promptFn) {
219
+ async function runCommand(command, args, { cwd = process.cwd(), capture = false } = {}) {
220
+ return new Promise((resolve, reject) => {
221
+ const spawnOptions = {
222
+ stdio: capture ? ['ignore', 'pipe', 'pipe'] : 'inherit',
223
+ cwd
224
+ }
225
+
226
+ if (IS_WINDOWS && command !== 'git') {
227
+ spawnOptions.shell = true
228
+ }
229
+
230
+ const child = spawn(command, args, spawnOptions)
231
+ let stdout = ''
232
+ let stderr = ''
233
+
234
+ if (capture) {
235
+ child.stdout.on('data', (chunk) => {
236
+ stdout += chunk
237
+ })
238
+
239
+ child.stderr.on('data', (chunk) => {
240
+ stderr += chunk
241
+ })
242
+ }
243
+
244
+ child.on('error', reject)
245
+ child.on('close', (code) => {
246
+ if (code === 0) {
247
+ resolve(capture ? { stdout: stdout.trim(), stderr: stderr.trim() } : undefined)
248
+ } else {
249
+ const error = new Error(`Command failed (${code}): ${command} ${args.join(' ')}`)
250
+ if (capture) {
251
+ error.stdout = stdout
252
+ error.stderr = stderr
253
+ }
254
+ error.exitCode = code
255
+ reject(error)
256
+ }
257
+ })
258
+ })
259
+ }
260
+
261
+ async function getGitStatus(rootDir) {
262
+ try {
263
+ const result = await runCommand('git', ['status', '--porcelain'], { capture: true, cwd: rootDir })
264
+ return result.stdout || ''
265
+ } catch (error) {
266
+ return ''
267
+ }
268
+ }
269
+
270
+ function hasStagedChanges(statusOutput) {
271
+ if (!statusOutput || statusOutput.length === 0) {
272
+ return false
273
+ }
274
+
275
+ const lines = statusOutput.split('\n').filter((line) => line.trim().length > 0)
276
+
277
+ return lines.some((line) => {
278
+ const firstChar = line[0]
279
+ return firstChar && firstChar !== ' ' && firstChar !== '?'
280
+ })
281
+ }
282
+
283
+ async function commitDependencyUpdates(rootDir, updatedFiles, logFn) {
284
+ try {
285
+ // Check if we're in a git repository
286
+ await runCommand('git', ['rev-parse', '--is-inside-work-tree'], { capture: true, cwd: rootDir })
287
+ } catch {
288
+ // Not a git repository, skip commit
289
+ return false
290
+ }
291
+
292
+ const status = await getGitStatus(rootDir)
293
+
294
+ // Stage the updated files
295
+ for (const file of updatedFiles) {
296
+ try {
297
+ await runCommand('git', ['add', file], { cwd: rootDir })
298
+ } catch {
299
+ // File might not exist or not be tracked, continue
300
+ }
301
+ }
302
+
303
+ const newStatus = await getGitStatus(rootDir)
304
+ if (!hasStagedChanges(newStatus)) {
305
+ return false
306
+ }
307
+
308
+ // Build commit message
309
+ const fileList = updatedFiles.map(f => path.basename(f)).join(', ')
310
+ const commitMessage = `chore: update local file dependencies to online versions (${fileList})`
311
+
312
+ if (logFn) {
313
+ logFn('Committing dependency updates...')
314
+ }
315
+
316
+ await runCommand('git', ['commit', '-m', commitMessage], { cwd: rootDir })
317
+
318
+ if (logFn) {
319
+ logFn('Dependency updates committed.')
320
+ }
321
+
322
+ return true
323
+ }
324
+
325
+ async function validateLocalDependencies(rootDir, promptFn, logFn = null) {
216
326
  const packageDeps = await scanPackageJsonDependencies(rootDir)
217
327
  const composerDeps = await scanComposerJsonDependencies(rootDir)
218
328
 
@@ -265,6 +375,9 @@ async function validateLocalDependencies(rootDir, promptFn) {
265
375
  throw new Error('Release cancelled: local file dependencies must be updated before release.')
266
376
  }
267
377
 
378
+ // Track which files were updated
379
+ const updatedFiles = new Set()
380
+
268
381
  // Update dependencies
269
382
  for (const dep of depsWithVersions) {
270
383
  if (!dep.latestVersion) {
@@ -273,8 +386,10 @@ async function validateLocalDependencies(rootDir, promptFn) {
273
386
 
274
387
  if (dep.field === 'dependencies' || dep.field === 'devDependencies') {
275
388
  await updatePackageJsonDependency(rootDir, dep.packageName, dep.latestVersion, dep.field)
389
+ updatedFiles.add('package.json')
276
390
  } else if (dep.field === 'require' || dep.field === 'require-dev') {
277
391
  await updateComposerJsonDependency(rootDir, dep.packageName, dep.latestVersion, dep.field)
392
+ updatedFiles.add('composer.json')
278
393
  } else if (dep.field === 'repositories') {
279
394
  // For repositories, we need to remove the repository entry
280
395
  // But we still need to update the dependency version
@@ -319,9 +434,15 @@ async function validateLocalDependencies(rootDir, promptFn) {
319
434
  const updatedContent = JSON.stringify(updatedComposer, null, 2) + '\n'
320
435
  await writeFile(composerJsonPath, updatedContent, 'utf8')
321
436
  }
437
+ updatedFiles.add('composer.json')
322
438
  }
323
439
  }
324
440
  }
441
+
442
+ // Commit the changes if any files were updated
443
+ if (updatedFiles.size > 0) {
444
+ await commitDependencyUpdates(rootDir, Array.from(updatedFiles), logFn)
445
+ }
325
446
  }
326
447
 
327
448
  export {
package/src/index.mjs CHANGED
@@ -1915,7 +1915,7 @@ async function main(releaseType = null) {
1915
1915
 
1916
1916
  if (hasPackageJson || hasComposerJson) {
1917
1917
  logProcessing('Validating dependencies...')
1918
- await validateLocalDependencies(rootDir, runPrompt)
1918
+ await validateLocalDependencies(rootDir, runPrompt, logSuccess)
1919
1919
  }
1920
1920
 
1921
1921
  // Load servers first (they may be migrated)
@@ -583,7 +583,7 @@ export async function releaseNode() {
583
583
  const pkg = await readPackage(rootDir)
584
584
 
585
585
  logStep('Validating dependencies...')
586
- await validateLocalDependencies(rootDir, (questions) => inquirer.prompt(questions))
586
+ await validateLocalDependencies(rootDir, (questions) => inquirer.prompt(questions), logSuccess)
587
587
 
588
588
  logStep('Checking working tree status...')
589
589
  await ensureCleanWorkingTree(rootDir)
@@ -387,7 +387,7 @@ export async function releasePackagist() {
387
387
  }
388
388
 
389
389
  logStep('Validating dependencies...')
390
- await validateLocalDependencies(rootDir, (questions) => inquirer.prompt(questions))
390
+ await validateLocalDependencies(rootDir, (questions) => inquirer.prompt(questions), logSuccess)
391
391
 
392
392
  logStep('Checking working tree status...')
393
393
  await ensureCleanWorkingTree(rootDir)