npm-workspaces-publish-tool 0.0.4 → 0.0.6

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "npm-workspaces-publish-tool",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "An unopinionated tool to assist publishing of npm based mono-repo workspaces",
5
5
  "main": "build/src/cli.js",
6
6
  "type": "module",
package/build/src/cli.js CHANGED
@@ -56,14 +56,14 @@ function getReleaseOrderFromInDegree(inDegree, dependencies) {
56
56
  }
57
57
  return order;
58
58
  }
59
- function getDirtyMap(workspaces, lastTag) {
59
+ function getDirtyMap(workspaces, lastTag, cwd) {
60
60
  const dirtyMap = new Map();
61
61
  const changedFiles = lastTag
62
62
  ? getChangesBetweenRefs(lastTag, 'HEAD', [], '', cwd)
63
63
  : [];
64
64
  for (const ws of workspaces) {
65
65
  const isNew = !lastTag;
66
- const isDirty = changedFiles.some((f) => f.startsWith(ws.path + '/') || f === ws.path);
66
+ const isDirty = changedFiles.some((f) => resolve(cwd, f).includes(ws.path));
67
67
  if (isNew) {
68
68
  dirtyMap.set(ws.name, 'new');
69
69
  }
@@ -123,7 +123,8 @@ function getDirtyPackagesVersionChanges(workspaces, dirtyMap, lastTag, cwd) {
123
123
  });
124
124
  continue;
125
125
  }
126
- const previousPkgRaw = git(['show', `${lastTag}:${ws.path}/package.json`], {
126
+ const relativeWsPath = relative(cwd, ws.path);
127
+ const previousPkgRaw = git(['show', `${lastTag}:${relativeWsPath}/package.json`], {
127
128
  cwd,
128
129
  });
129
130
  if (!previousPkgRaw.success) {
@@ -352,7 +353,7 @@ function validatePublish() {
352
353
  const { dependencies } = createDependencyMap(packageInfos);
353
354
  const inDegree = calculateWorkspaceInDegree(workspaces, dependencies);
354
355
  const releaseOrder = getReleaseOrderFromInDegree(inDegree, dependencies);
355
- const dirtyMap = getDirtyMap(workspaces, lastMonoRepoTag);
356
+ const dirtyMap = getDirtyMap(workspaces, lastMonoRepoTag, cwd);
356
357
  const dirtyVersionChanges = getDirtyPackagesVersionChanges(workspaces, dirtyMap, lastMonoRepoTag, cwd);
357
358
  console.log('šŸ—ļø Building packages...');
358
359
  for (const pkgName of releaseOrder) {
@@ -406,6 +407,7 @@ function validatePublish() {
406
407
  const rootPackageJsonPath = resolve(cwd, 'package.json');
407
408
  let previousRootVersion;
408
409
  let currentRootVersion;
410
+ let rootPackageSuccessMessage;
409
411
  try {
410
412
  const rootPackage = JSON.parse(readFileSync(rootPackageJsonPath, 'utf8'));
411
413
  currentRootVersion = rootPackage.version;
@@ -426,19 +428,19 @@ function validatePublish() {
426
428
  hasError = true;
427
429
  }
428
430
  else {
429
- console.log(`🌳 Root: ${lastRootPackage.version} → ${currentRootVersion}`);
431
+ rootPackageSuccessMessage = `🌳 Root: ${lastRootPackage.version} → ${currentRootVersion}`;
430
432
  }
431
433
  }
432
434
  catch {
433
- console.log(`āš ļø Root: ${currentRootVersion} (previous version unavailable)`);
435
+ rootPackageSuccessMessage = `āš ļø Root: ${currentRootVersion} (previous version unavailable)`;
434
436
  }
435
437
  }
436
438
  else {
437
- console.log(`āš ļø Root: ${currentRootVersion} (previous version unavailable)`);
439
+ rootPackageSuccessMessage = `āš ļø Root: ${currentRootVersion} (previous version unavailable)`;
438
440
  }
439
441
  }
440
442
  else {
441
- console.log(`🌳 Root: ${currentRootVersion} (first release)`);
443
+ rootPackageSuccessMessage = `🌳 Root: ${currentRootVersion} (first release)`;
442
444
  }
443
445
  }
444
446
  catch (e) {
@@ -449,6 +451,7 @@ function validatePublish() {
449
451
  console.error('\nFix the above issues before publishing.\n');
450
452
  process.exit(1);
451
453
  }
454
+ console.log(rootPackageSuccessMessage);
452
455
  console.log('\nšŸ—ƒļø Validating git status...\n');
453
456
  if (!verifyCleanGitStatus(workspaces, dirtyMap, cwd)) {
454
457
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "npm-workspaces-publish-tool",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "An unopinionated tool to assist publishing of npm based mono-repo workspaces",
5
5
  "main": "build/src/cli.js",
6
6
  "type": "module",
@@ -1,482 +0,0 @@
1
- #!/usr/bin/env node
2
- import { program } from 'commander';
3
- import { readFileSync, writeFileSync } from 'fs';
4
- import { createRequire } from 'module';
5
- import { dirname, join, relative, resolve } from 'path';
6
- import { cwd as getCwd } from 'process';
7
- import semver from 'semver';
8
- import { createDependencyMap, getChangesBetweenRefs, getPackageInfos, getWorkspaces, git, } from 'workspace-tools';
9
- import { execSync } from 'child_process';
10
- const require = createRequire(import.meta.url);
11
- const pkg = require('../../package.json');
12
- const cwd = getCwd();
13
- function getLastTag() {
14
- const result = git(['tag', '--list', 'v*', '--sort=-v:refname'], { cwd });
15
- if (!result.success)
16
- return null;
17
- const tags = result.stdout.split('\n').filter(Boolean);
18
- return tags[0] || null;
19
- }
20
- function calculateWorkspaceInDegree(packageInfos, dependencies) {
21
- const inDegree = new Map();
22
- for (const pkgName of Object.keys(packageInfos)) {
23
- inDegree.set(pkgName, 0);
24
- }
25
- for (const [pkgName, deps] of dependencies) {
26
- for (const _ of deps) {
27
- inDegree.set(pkgName, (inDegree.get(pkgName) ?? 0) + 1);
28
- }
29
- }
30
- return inDegree;
31
- }
32
- function getReleaseOrderFromInDegree(inDegree, dependencies) {
33
- const queue = Array.from(inDegree.entries())
34
- .filter(([_, count]) => count === 0)
35
- .map(([pkg]) => pkg);
36
- const order = [];
37
- while (queue.length > 0) {
38
- const current = queue.shift();
39
- order.push(current);
40
- for (const [pkg, deps] of dependencies) {
41
- if (deps.has(current)) {
42
- const newCount = inDegree.get(pkg) - 1;
43
- inDegree.set(pkg, newCount);
44
- if (newCount === 0) {
45
- queue.push(pkg);
46
- }
47
- }
48
- }
49
- }
50
- return order;
51
- }
52
- function getDirtyMap(workspaces, lastTag) {
53
- const dirtyMap = new Map();
54
- const changedFiles = lastTag
55
- ? getChangesBetweenRefs(lastTag, 'HEAD', [], '', cwd)
56
- : [];
57
- for (const ws of workspaces) {
58
- const isNew = !lastTag;
59
- const isDirty = changedFiles.some((f) => f.startsWith(ws.path + '/'));
60
- if (isNew) {
61
- dirtyMap.set(ws.name, 'new');
62
- }
63
- else if (isDirty) {
64
- dirtyMap.set(ws.name, 'dirty');
65
- }
66
- else {
67
- dirtyMap.set(ws.name, 'unchanged');
68
- }
69
- }
70
- return dirtyMap;
71
- }
72
- /**
73
- * Returns version changes only for packages marked as 'dirty' in dirtyMap,
74
- * comparing current package.json version to the version at the last tag.
75
- * Has a `versionIncremented` field indicating if version was increased semver-wise.
76
- */
77
- function getDirtyPackagesVersionChanges(workspaces, dirtyMap, lastTag, cwd) {
78
- const result = new Map();
79
- if (!lastTag)
80
- return result;
81
- for (const ws of workspaces) {
82
- if (dirtyMap.get(ws.name) !== 'dirty')
83
- continue;
84
- const pkgPath = resolve(cwd, ws.path, 'package.json');
85
- let currentPkg;
86
- try {
87
- currentPkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
88
- }
89
- catch (err) {
90
- throw new Error(`Failed to parse current package.json for package "${ws.name}" at path "${pkgPath}": ${err}`);
91
- }
92
- const newVersion = currentPkg.version;
93
- const previousPkgRaw = git(['show', `${lastTag}:${ws.path}/package.json`], { cwd });
94
- if (!previousPkgRaw.success) {
95
- result.set(ws.name, {
96
- oldVersion: null,
97
- newVersion,
98
- versionChanged: true,
99
- versionIncremented: true,
100
- });
101
- continue;
102
- }
103
- let previousPkg;
104
- try {
105
- previousPkg = JSON.parse(previousPkgRaw.stdout);
106
- }
107
- catch (err) {
108
- throw new Error(`Failed to parse package.json from git at tag "${lastTag}" for package "${ws.name}": ${err}`);
109
- }
110
- const oldVersion = previousPkg.version;
111
- const versionChanged = newVersion !== oldVersion;
112
- const versionIncremented = oldVersion === null ||
113
- (semver.valid(newVersion) && semver.valid(oldVersion))
114
- ? semver.gt(newVersion, oldVersion)
115
- : false;
116
- result.set(ws.name, {
117
- oldVersion,
118
- newVersion,
119
- versionChanged,
120
- versionIncremented,
121
- });
122
- }
123
- return result;
124
- }
125
- // Check git status to ensure all changes for release are committed appropriately
126
- function verifyCleanGitStatus(workspaces, dirtyMap, cwd) {
127
- // Files changed since last commit
128
- const changedFilesRaw = git(['diff', '--name-only', 'HEAD'], { cwd })
129
- .stdout.trim()
130
- .split('\n')
131
- .filter(Boolean);
132
- // Files staged for commit
133
- const stagedFilesRaw = git(['diff', '--cached', '--name-only'], { cwd })
134
- .stdout.trim()
135
- .split('\n')
136
- .filter(Boolean);
137
- // Files unstaged but changed (working dir different from index)
138
- const unstagedFilesRaw = git(['diff', '--name-only'], { cwd })
139
- .stdout.trim()
140
- .split('\n')
141
- .filter(Boolean);
142
- // Get untracked files from git status
143
- const status = git(['status', '--porcelain'], { cwd })
144
- .stdout.trim()
145
- .split('\n')
146
- .filter(Boolean);
147
- const untrackedFilesRaw = status
148
- .filter((line) => line.startsWith('??'))
149
- .map((line) => line.slice(3));
150
- // Prepare map of workspace issues
151
- const workspaceIssues = new Map();
152
- for (const ws of workspaces) {
153
- workspaceIssues.set(ws.name, {
154
- stagedPackageJsonDirty: false,
155
- unstagedPackageJsonDirty: false,
156
- stagedFilesNotCommitted: [],
157
- unstagedFilesNotStaged: [],
158
- untrackedFiles: [],
159
- });
160
- }
161
- function findWorkspaceForFile(filePath) {
162
- const absoluteFilePath = resolve(cwd, filePath).replace(/\\/g, '/');
163
- for (const ws of workspaces) {
164
- const wsPathNormalized = ws.path.replace(/\\/g, '/');
165
- if (absoluteFilePath === wsPathNormalized ||
166
- absoluteFilePath.startsWith(wsPathNormalized + '/')) {
167
- return ws;
168
- }
169
- }
170
- return undefined;
171
- }
172
- // Helper sets for quick lookup
173
- const changedFiles = new Set(changedFilesRaw);
174
- const stagedFiles = new Set(stagedFilesRaw);
175
- const unstagedFiles = new Set(unstagedFilesRaw);
176
- const untrackedFiles = new Set(untrackedFilesRaw);
177
- for (const filePath of changedFiles) {
178
- const ws = findWorkspaceForFile(filePath);
179
- if (!ws)
180
- continue;
181
- if (dirtyMap.get(ws.name) !== 'new' &&
182
- dirtyMap.get(ws.name) !== 'dirty')
183
- continue;
184
- const issues = workspaceIssues.get(ws.name);
185
- const isPackageJson = filePath.endsWith('package.json');
186
- const isStaged = stagedFiles.has(filePath);
187
- const isUnstaged = unstagedFiles.has(filePath);
188
- // FIXME here
189
- if (isPackageJson) {
190
- if (!isStaged) {
191
- issues.unstagedPackageJsonDirty = true;
192
- }
193
- else {
194
- issues.stagedPackageJsonDirty = true;
195
- }
196
- }
197
- else {
198
- if (!isStaged) {
199
- issues.unstagedFilesNotStaged.push(filePath);
200
- }
201
- else {
202
- issues.stagedFilesNotCommitted.push(filePath);
203
- }
204
- }
205
- }
206
- for (const filePath of untrackedFilesRaw) {
207
- const ws = findWorkspaceForFile(filePath);
208
- if (!ws)
209
- continue;
210
- if (dirtyMap.get(ws.name) !== 'new' &&
211
- dirtyMap.get(ws.name) !== 'dirty')
212
- continue;
213
- workspaceIssues.get(ws.name).untrackedFiles.push(filePath);
214
- }
215
- let hasIssues = false;
216
- for (const [wsName, issues] of workspaceIssues.entries()) {
217
- const { stagedPackageJsonDirty, unstagedPackageJsonDirty, stagedFilesNotCommitted, unstagedFilesNotStaged, untrackedFiles, } = issues;
218
- if (!stagedPackageJsonDirty &&
219
- !unstagedPackageJsonDirty &&
220
- stagedFilesNotCommitted.length === 0 &&
221
- unstagedFilesNotStaged.length === 0 &&
222
- untrackedFiles.length === 0) {
223
- continue;
224
- }
225
- hasIssues = true;
226
- console.error(`āŒ Workspace '${wsName}' has issues preventing publish:`);
227
- const ws = workspaces.find((w) => w.name === wsName);
228
- const missingFiles = [];
229
- if (unstagedPackageJsonDirty) {
230
- const relativePkgJson = relative(cwd, join(ws.path, 'package.json')).replace(/\\/g, '/');
231
- missingFiles.push(relativePkgJson);
232
- }
233
- for (const file of unstagedFilesNotStaged) {
234
- missingFiles.push(file);
235
- }
236
- if (missingFiles.length > 0) {
237
- console.error(' āš ļø These files have changes since last commit but are NOT staged. Please stage them:');
238
- for (const f of missingFiles) {
239
- console.error(` - ${f}`);
240
- }
241
- }
242
- // fix this this is not relative to the workspace root.. FIXME
243
- if (stagedPackageJsonDirty) {
244
- console.error(' āš ļø package.json is staged but not committed. Please commit it.');
245
- }
246
- if (stagedFilesNotCommitted.length > 0) {
247
- console.error(' āš ļø These files are staged but not committed. Please commit them:');
248
- for (const f of stagedFilesNotCommitted)
249
- console.error(` - ${f}`);
250
- }
251
- if (untrackedFiles.length > 0) {
252
- console.error(' āš ļø Untracked files (consider adding or ignoring):');
253
- for (const f of untrackedFiles)
254
- console.error(` - ${f}`);
255
- }
256
- }
257
- // Check if root package.json has unstaged changes not committed
258
- const rootPackageJsonPath = 'package.json';
259
- const isRootPackageJsonChanged = changedFiles.has(rootPackageJsonPath);
260
- const isRootPackageJsonStaged = stagedFiles.has(rootPackageJsonPath);
261
- const isRootPackageJsonUnstaged = unstagedFiles.has(rootPackageJsonPath);
262
- if (isRootPackageJsonChanged) {
263
- if (!isRootPackageJsonStaged) {
264
- console.error(`āŒ Root package.json has unstaged changes. Please stage or discard them before publishing.`);
265
- hasIssues = true;
266
- }
267
- if (isRootPackageJsonStaged) {
268
- console.error(`āŒ Root package.json is staged but not committed. Please commit it before publishing.`);
269
- hasIssues = true;
270
- }
271
- }
272
- if (hasIssues) {
273
- console.error('Please commit or stash the above changes before publishing.');
274
- return false;
275
- }
276
- return true;
277
- }
278
- function validatePublish() {
279
- const lastMonoRepoTag = getLastTag();
280
- //console.log('lastMonoRepoTag', lastMonoRepoTag);
281
- const workspaces = getWorkspaces(cwd);
282
- //console.log('workspaces', workspaces);
283
- const packageInfos = getPackageInfos(cwd); // this is a map of package.json "name" field and an unpackaked packagejson with packJsonPath extended into it
284
- //const dependencyMap = createDependencyMap(packageInfos);
285
- /*console.log(packageInfos);
286
- console.log('---------------------------------------');*/
287
- const workspacePackageNames = Object.keys(packageInfos); // nodes
288
- //console.log('workspacePackageNames', workspacePackageNames);
289
- //console.log('---------------------------------------');
290
- //console.log(dependencyMap);
291
- //const packageGraph = createPackageGraph(packageInfos);
292
- //console.log('---------------------------------------');
293
- //console.log('packageGraph', packageGraph);
294
- const { dependencies, dependents } = createDependencyMap(packageInfos);
295
- const roots = workspacePackageNames.filter((name) => !dependencies.get(name)?.size);
296
- const visited = new Set();
297
- function buildNode(name) {
298
- if (visited.has(name)) {
299
- return { name, children: [] };
300
- }
301
- visited.add(name);
302
- const kids = Array.from(dependents.get(name) ?? []);
303
- return { name, children: kids.map(buildNode) };
304
- }
305
- const tree = roots.map(buildNode);
306
- console.log('tree', JSON.stringify(tree, null, 4));
307
- const inDegree = calculateWorkspaceInDegree(packageInfos, dependencies);
308
- console.log('inDegree', inDegree);
309
- // Determine release order
310
- const releaseOrder = getReleaseOrderFromInDegree(inDegree, dependencies);
311
- console.log('releaseOrder', releaseOrder);
312
- // Determine status of each workspace
313
- const dirtyMap = getDirtyMap(workspaces, lastMonoRepoTag);
314
- console.log('dirtyMap', dirtyMap);
315
- // Determine which dirty packages have had their version field updated (which permits them to be published) if we have dirty packages which have not all been incremented
316
- // Determine which dirty packages have version changes
317
- const dirtyVersionChanges = getDirtyPackagesVersionChanges(workspaces, dirtyMap, lastMonoRepoTag, cwd);
318
- let hasError = false;
319
- for (const [pkgName, { oldVersion, newVersion, versionChanged, versionIncremented },] of dirtyVersionChanges.entries()) {
320
- if (!semver.valid(newVersion)) {
321
- console.error(`āŒ Package "${pkgName}" has an invalid current version: "${newVersion}".`);
322
- hasError = true;
323
- continue;
324
- }
325
- if (!versionChanged) {
326
- console.error(`āŒ Package "${pkgName}" was modified but the version has not been updated (still "${newVersion}").`);
327
- hasError = true;
328
- // Print changed files directly from git using path as pattern
329
- const ws = workspaces.find((w) => w.name === pkgName);
330
- try {
331
- const changedFiles = getChangesBetweenRefs(lastMonoRepoTag, 'HEAD', [], ws.path, // use path as pattern for precision
332
- cwd);
333
- if (changedFiles.length > 0) {
334
- console.error(` ↪ Changed files in "${pkgName}":`);
335
- for (const file of changedFiles) {
336
- console.error(` - ${file.replace(ws.path + '/', '')}`);
337
- }
338
- }
339
- }
340
- catch (err) {
341
- console.error(` āš ļø Failed to get changed files for "${pkgName}": ${err}`);
342
- }
343
- continue;
344
- }
345
- if (!versionIncremented) {
346
- console.error(`āŒ Package "${pkgName}" version changed from "${oldVersion}" to "${newVersion}", but the new version is not greater (semver).`);
347
- hasError = true;
348
- continue;
349
- }
350
- console.log(`āœ… Package "${pkgName}" is ready to publish. Version increased from "${oldVersion}" to "${newVersion}".`);
351
- }
352
- if (hasError) {
353
- console.error('\nFix the above issues before publishing.\n');
354
- process.exit(1);
355
- }
356
- // Now if we get this far we have a possible combination of 'unchanged', 'dirty' but incremented correctly, or new.
357
- // Before we set of ensure that we have commited all of our changes. And that our git status is clean.
358
- const cleanGitStatus = verifyCleanGitStatus(workspaces, dirtyMap, cwd);
359
- if (!cleanGitStatus)
360
- process.exit(1);
361
- // Print publish summary
362
- console.log('\nPublish summary:\n');
363
- const packagesToRelease = [];
364
- for (const pkgName of releaseOrder) {
365
- const status = dirtyMap.get(pkgName);
366
- const versionInfo = dirtyVersionChanges.get(pkgName);
367
- if (status === 'new') {
368
- packagesToRelease.push(pkgName);
369
- const ws = workspaces.find((w) => w.name === pkgName);
370
- const currentVersion = JSON.parse(readFileSync(resolve(cwd, ws.path, 'package.json'), 'utf8')).version;
371
- console.log(`šŸ†• ${pkgName} @ ${currentVersion} (new)`);
372
- }
373
- if (status === 'dirty' && versionInfo?.versionIncremented) {
374
- packagesToRelease.push(pkgName);
375
- console.log(`ā¬†ļø ${pkgName}: ${versionInfo.oldVersion} → ${versionInfo.newVersion} (version incremented)`);
376
- }
377
- if (status === 'unchanged') {
378
- const ws = workspaces.find((w) => w.name === pkgName);
379
- const currentVersion = JSON.parse(readFileSync(resolve(cwd, ws.path, 'package.json'), 'utf8')).version;
380
- console.log(`āœ”ļø ${pkgName} @ ${currentVersion} (unchanged)`);
381
- }
382
- }
383
- console.log('');
384
- // Now return useful information to the main program
385
- return { releaseOrder, packageInfos };
386
- }
387
- export function replaceWorkspaceDepsWithVersions(packageInfos) {
388
- for (const pkgName in packageInfos) {
389
- const pkgInfo = packageInfos[pkgName];
390
- let changed = false;
391
- [
392
- 'dependencies',
393
- 'devDependencies',
394
- 'peerDependencies',
395
- 'optionalDependencies',
396
- ].forEach((depType) => {
397
- const deps = pkgInfo.packageJson[depType];
398
- if (!deps)
399
- return;
400
- for (const depName in deps) {
401
- if (deps[depName] === '*') {
402
- const wsPkg = packageInfos[depName];
403
- if (wsPkg) {
404
- deps[depName] = wsPkg.packageJson.version;
405
- changed = true;
406
- }
407
- }
408
- }
409
- });
410
- if (changed) {
411
- writeFileSync(pkgInfo.packageJsonPath, JSON.stringify(pkgInfo.packageJson, null, 2));
412
- }
413
- }
414
- }
415
- export function restoreWorkspaceDepsToStar(packageInfos) {
416
- for (const pkgName in packageInfos) {
417
- const pkgInfo = packageInfos[pkgName];
418
- let changed = false;
419
- [
420
- 'dependencies',
421
- 'devDependencies',
422
- 'peerDependencies',
423
- 'optionalDependencies',
424
- ].forEach((depType) => {
425
- const deps = pkgInfo.packageJson[depType];
426
- if (!deps)
427
- return;
428
- for (const depName in deps) {
429
- if (typeof deps[depName] === 'string' &&
430
- deps[depName] !== '*' &&
431
- packageInfos[depName]) {
432
- deps[depName] = '*';
433
- changed = true;
434
- }
435
- }
436
- });
437
- if (changed) {
438
- writeFileSync(pkgInfo.packageJsonPath, JSON.stringify(pkgInfo.packageJson, null, 2));
439
- }
440
- }
441
- }
442
- export function runNpmPublishInReleaseOrder(releaseOrder, packageInfos) {
443
- for (const packageName of releaseOrder) {
444
- const pkgInfo = packageInfos[packageName];
445
- const pkgDir = dirname(pkgInfo.packageJsonPath);
446
- execSync('npm publish', { cwd: pkgDir, stdio: 'inherit' });
447
- }
448
- }
449
- program.name(pkg.name).description(pkg.description).version(pkg.version);
450
- program
451
- .command('publish')
452
- .description('Publish packages')
453
- .option('--dry-run', 'Run the publish command without making changes')
454
- .action((options) => {
455
- const { packageInfos, releaseOrder } = validatePublish();
456
- if (options.dryRun) {
457
- console.log('Dry run: no publishing will be performed.');
458
- }
459
- else {
460
- try {
461
- console.log('Replacing workspace dependencies "*" with actual versions...');
462
- replaceWorkspaceDepsWithVersions(packageInfos);
463
- console.log('Publishing packages in release order...');
464
- runNpmPublishInReleaseOrder(releaseOrder, packageInfos);
465
- console.log('Publish process completed.');
466
- }
467
- catch (error) {
468
- console.error('Publishing failed:', error);
469
- }
470
- finally {
471
- console.log('Restoring workspace dependencies back to "*" ...');
472
- try {
473
- restoreWorkspaceDepsToStar(packageInfos);
474
- console.log('Restoration complete.');
475
- }
476
- catch (restoreError) {
477
- console.error('Failed to restore workspace dependencies:', restoreError);
478
- }
479
- }
480
- }
481
- });
482
- program.parse(process.argv);