@mui/internal-code-infra 0.0.4-canary.5 → 0.0.4-canary.51

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.
Files changed (109) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +19 -8
  3. package/build/babel-config.d.mts +11 -3
  4. package/build/brokenLinksChecker/crawlWorker.d.mts +1 -0
  5. package/build/brokenLinksChecker/index.d.mts +45 -2
  6. package/build/changelog/types.d.ts +1 -1
  7. package/build/cli/cmdArgosPush.d.mts +2 -2
  8. package/build/cli/cmdBuild.d.mts +2 -2
  9. package/build/cli/cmdCopyFiles.d.mts +2 -2
  10. package/build/cli/cmdExtractErrorCodes.d.mts +2 -2
  11. package/build/cli/cmdGenerateChangelog.d.mts +2 -2
  12. package/build/cli/cmdGithubAuth.d.mts +2 -2
  13. package/build/cli/cmdListWorkspaces.d.mts +4 -2
  14. package/build/cli/cmdNetlifyIgnore.d.mts +3 -2
  15. package/build/cli/cmdPublish.d.mts +4 -2
  16. package/build/cli/cmdPublishCanary.d.mts +3 -3
  17. package/build/cli/cmdPublishNewPackage.d.mts +4 -2
  18. package/build/cli/cmdSetVersionOverrides.d.mts +2 -2
  19. package/build/cli/cmdVale.d.mts +46 -0
  20. package/build/cli/cmdValidateBuiltTypes.d.mts +2 -2
  21. package/build/eslint/baseConfig.d.mts +3 -1
  22. package/build/eslint/mui/rules/disallow-react-api-in-server-components.d.mts +2 -2
  23. package/build/eslint/mui/rules/docgen-ignore-before-comment.d.mts +2 -2
  24. package/build/eslint/mui/rules/no-guarded-throw.d.mts +31 -0
  25. package/build/eslint/mui/rules/no-presentation-role.d.mts +5 -0
  26. package/build/eslint/mui/rules/no-restricted-resolved-imports.d.mts +2 -2
  27. package/build/eslint/mui/rules/nodeEnvUtils.d.mts +18 -0
  28. package/build/markdownlint/duplicate-h1.d.mts +1 -1
  29. package/build/markdownlint/git-diff.d.mts +1 -1
  30. package/build/markdownlint/index.d.mts +1 -1
  31. package/build/markdownlint/straight-quotes.d.mts +1 -1
  32. package/build/markdownlint/table-alignment.d.mts +1 -1
  33. package/build/markdownlint/terminal-language.d.mts +1 -1
  34. package/build/remark/config.d.mts +43 -0
  35. package/build/remark/createLintTester.d.mts +10 -0
  36. package/build/remark/firstBlockHeading.d.mts +4 -0
  37. package/build/remark/gitDiff.d.mts +2 -0
  38. package/build/remark/noSpaceInLinks.d.mts +2 -0
  39. package/build/remark/straightQuotes.d.mts +2 -0
  40. package/build/remark/tableAlignment.d.mts +2 -0
  41. package/build/remark/terminalLanguage.d.mts +2 -0
  42. package/build/utils/babel.d.mts +1 -1
  43. package/build/utils/build.d.mts +4 -4
  44. package/build/utils/github.d.mts +1 -1
  45. package/build/utils/pnpm.d.mts +68 -2
  46. package/build/utils/testUtils.d.mts +7 -0
  47. package/build/utils/typescript.d.mts +2 -2
  48. package/package.json +62 -35
  49. package/src/babel-config.mjs +9 -3
  50. package/src/brokenLinksChecker/__fixtures__/static-site/index.html +1 -0
  51. package/src/brokenLinksChecker/__fixtures__/static-site/invalid-html.html +15 -0
  52. package/src/brokenLinksChecker/crawlWorker.mjs +217 -0
  53. package/src/brokenLinksChecker/index.mjs +217 -164
  54. package/src/brokenLinksChecker/index.test.ts +50 -13
  55. package/src/changelog/categorizeCommits.test.ts +5 -5
  56. package/src/changelog/fetchChangelogs.mjs +6 -2
  57. package/src/changelog/parseCommitLabels.test.ts +5 -5
  58. package/src/changelog/renderChangelog.mjs +1 -1
  59. package/src/changelog/types.ts +1 -1
  60. package/src/cli/cmdListWorkspaces.mjs +9 -2
  61. package/src/cli/cmdNetlifyIgnore.mjs +35 -93
  62. package/src/cli/cmdPublish.mjs +51 -14
  63. package/src/cli/cmdPublishCanary.mjs +128 -132
  64. package/src/cli/cmdPublishNewPackage.mjs +27 -6
  65. package/src/cli/cmdVale.mjs +513 -0
  66. package/src/cli/cmdVale.test.mjs +644 -0
  67. package/src/cli/index.mjs +2 -0
  68. package/src/cli/packageJson.d.ts +1 -1
  69. package/src/eslint/baseConfig.mjs +45 -20
  70. package/src/eslint/docsConfig.mjs +2 -1
  71. package/src/eslint/jsonConfig.mjs +2 -1
  72. package/src/eslint/mui/config.mjs +21 -1
  73. package/src/eslint/mui/index.mjs +4 -0
  74. package/src/eslint/mui/rules/no-guarded-throw.mjs +115 -0
  75. package/src/eslint/mui/rules/no-guarded-throw.test.mjs +206 -0
  76. package/src/eslint/mui/rules/no-presentation-role.mjs +60 -0
  77. package/src/eslint/mui/rules/no-presentation-role.test.mjs +33 -0
  78. package/src/eslint/mui/rules/nodeEnvUtils.mjs +52 -0
  79. package/src/eslint/mui/rules/require-dev-wrapper.mjs +25 -40
  80. package/src/eslint/testConfig.mjs +2 -1
  81. package/src/estree-typescript.d.ts +1 -1
  82. package/src/remark/config.mjs +157 -0
  83. package/src/remark/createLintTester.mjs +19 -0
  84. package/src/remark/firstBlockHeading.mjs +87 -0
  85. package/src/remark/firstBlockHeading.test.mjs +107 -0
  86. package/src/remark/gitDiff.mjs +43 -0
  87. package/src/remark/gitDiff.test.mjs +45 -0
  88. package/src/remark/noSpaceInLinks.mjs +42 -0
  89. package/src/remark/noSpaceInLinks.test.mjs +22 -0
  90. package/src/remark/straightQuotes.mjs +31 -0
  91. package/src/remark/straightQuotes.test.mjs +25 -0
  92. package/src/remark/tableAlignment.mjs +23 -0
  93. package/src/remark/tableAlignment.test.mjs +28 -0
  94. package/src/remark/terminalLanguage.mjs +19 -0
  95. package/src/remark/terminalLanguage.test.mjs +17 -0
  96. package/src/untyped-plugins.d.ts +11 -11
  97. package/src/utils/build.mjs +18 -1
  98. package/src/utils/build.test.mjs +585 -575
  99. package/src/utils/pnpm.mjs +192 -3
  100. package/src/utils/pnpm.test.mjs +580 -0
  101. package/src/utils/testUtils.mjs +18 -0
  102. package/src/utils/typescript.test.mjs +249 -272
  103. package/vale/.vale.ini +1 -0
  104. package/vale/styles/MUI/CorrectReferenceAllCases.yml +43 -0
  105. package/vale/styles/MUI/CorrectRererenceCased.yml +14 -0
  106. package/vale/styles/MUI/GoogleLatin.yml +11 -0
  107. package/vale/styles/MUI/MuiBrandName.yml +22 -0
  108. package/vale/styles/MUI/NoBritish.yml +112 -0
  109. package/vale/styles/MUI/NoCompanyName.yml +17 -0
@@ -16,10 +16,12 @@ import * as semver from 'semver';
16
16
 
17
17
  import {
18
18
  getPackageVersionInfo,
19
+ getTransitiveDependencies,
19
20
  getWorkspacePackages,
20
21
  publishPackages,
21
22
  readPackageJson,
22
23
  semverMax,
24
+ validatePublishDependencies,
23
25
  writePackageJson,
24
26
  } from '../utils/pnpm.mjs';
25
27
  import { getCurrentGitSha, getRepositoryInfo } from '../utils/git.mjs';
@@ -28,7 +30,7 @@ import { getCurrentGitSha, getRepositoryInfo } from '../utils/git.mjs';
28
30
  * @typedef {Object} Args
29
31
  * @property {boolean} [dryRun] - Whether to run in dry-run mode
30
32
  * @property {boolean} [githubRelease] - Whether to create GitHub releases for canary packages
31
- * @property {string[]} [package] - Only publish canary versions for specified packages (by name)
33
+ * @property {string[]} [filter] - Same as filtering packages with --filter in pnpm. Only publish packages matching the filter. See https://pnpm.io/filtering.
32
34
  */
33
35
 
34
36
  const CANARY_TAG = 'canary';
@@ -119,80 +121,6 @@ function cleanupCommitMessage(message) {
119
121
  return `${prefix}${msg}`.trim();
120
122
  }
121
123
 
122
- async function getPackageToDependencyMap() {
123
- /**
124
- * @type {(PublicPackage & { dependencies: Record<string, unknown>; private: boolean; })[]}
125
- */
126
- const packagesWithDeps = JSON.parse(
127
- (await $`pnpm ls -r --json --exclude-peers --only-projects --prod`).stdout,
128
- );
129
- /** @type {Record<string, string[]>} */
130
- const directPkgDependencies = packagesWithDeps
131
- .filter((pkg) => !pkg.private)
132
- .reduce((acc, pkg) => {
133
- if (!pkg.name) {
134
- return acc;
135
- }
136
- const deps = pkg.dependencies ? Object.keys(pkg.dependencies) : [];
137
- if (!deps.length) {
138
- return acc;
139
- }
140
- acc[pkg.name] = deps;
141
- return acc;
142
- }, /** @type {Record<string, string[]>} */ ({}));
143
- return directPkgDependencies;
144
- }
145
-
146
- /**
147
- * @param {Record<string, string[]>} pkgGraph
148
- */
149
- function resolveTransitiveDependencies(pkgGraph = {}) {
150
- // Compute transitive (nested) dependencies limited to workspace packages and avoid cycles.
151
- const workspacePkgNames = new Set(Object.keys(pkgGraph));
152
- const nestedMap = /** @type {Record<string, string[]>} */ ({});
153
-
154
- /**
155
- *
156
- * @param {string} pkgName
157
- * @returns {string[]}
158
- */
159
- const getTransitiveDeps = (pkgName) => {
160
- /**
161
- * @type {Set<string>}
162
- */
163
- const seen = new Set();
164
- const stack = (pkgGraph[pkgName] || []).slice();
165
-
166
- while (stack.length) {
167
- const dep = stack.pop();
168
- if (!dep || seen.has(dep)) {
169
- continue;
170
- }
171
- // Only consider workspace packages for transitive expansion
172
- if (!workspacePkgNames.has(dep)) {
173
- // still record external deps as direct deps but don't traverse into them
174
- seen.add(dep);
175
- continue;
176
- }
177
- seen.add(dep);
178
- const children = pkgGraph[dep] || [];
179
- for (const c of children) {
180
- if (!seen.has(c)) {
181
- stack.push(c);
182
- }
183
- }
184
- }
185
-
186
- return Array.from(seen);
187
- };
188
-
189
- for (const name of Object.keys(pkgGraph)) {
190
- nestedMap[name] = getTransitiveDeps(name);
191
- }
192
-
193
- return nestedMap;
194
- }
195
-
196
124
  /**
197
125
  * Prepare changelog data for packages using GitHub API
198
126
  * @param {PublicPackage[]} packagesToPublish - Packages that will be published
@@ -225,14 +153,23 @@ async function prepareChangelogsFromGitCli(packagesToPublish, allPackages, canar
225
153
  }
226
154
  }),
227
155
  );
228
- // Second pass: check for dependency updates in other packages not part of git history
229
- const pkgDependencies = await getPackageToDependencyMap();
230
- const transitiveDependencies = resolveTransitiveDependencies(pkgDependencies);
156
+ // Second pass: check for dependency updates in other packages not part of git history.
157
+ const workspacePathByName = new Map(allPackages.map((pkg) => [pkg.name, pkg.path]));
158
+ const publishedNames = new Set(packagesToPublish.map((p) => p.name));
159
+
160
+ const transitiveDepSets = await Promise.all(
161
+ allPackages.map((pkg) =>
162
+ getTransitiveDependencies([pkg.name], {
163
+ includeDev: false,
164
+ workspacePathByName,
165
+ }),
166
+ ),
167
+ );
231
168
 
232
169
  for (let i = 0; i < allPackages.length; i += 1) {
233
170
  const pkg = allPackages[i];
234
- const depsToPublish = (transitiveDependencies[pkg.name] ?? []).filter((dep) =>
235
- packagesToPublish.some((p) => p.name === dep),
171
+ const depsToPublish = [...transitiveDepSets[i]].filter(
172
+ (dep) => dep !== pkg.name && publishedNames.has(dep),
236
173
  );
237
174
  if (depsToPublish.length === 0) {
238
175
  continue;
@@ -291,6 +228,41 @@ async function prepareChangelogsForPackages(packagesToPublish, allPackages, cana
291
228
  return changelogs;
292
229
  }
293
230
 
231
+ /**
232
+ * Create or replace a GitHub release. Attempts to create the release first,
233
+ * and if it already exists (422), deletes the existing one and retries.
234
+ *
235
+ * @param {InstanceType<typeof Octokit>} octokit
236
+ * @param {NonNullable<Parameters<Octokit['repos']['createRelease']>[0]>} params
237
+ */
238
+ async function upsertGitHubRelease(octokit, params) {
239
+ try {
240
+ return await octokit.repos.createRelease(params);
241
+ } catch (/** @type {any} */ error) {
242
+ const isAlreadyExists =
243
+ error.status === 422 &&
244
+ error.response?.data?.errors?.some(
245
+ (/** @type {any} */ err) => err.code === 'already_exists' && err.field === 'tag_name',
246
+ );
247
+ if (!isAlreadyExists) {
248
+ throw error;
249
+ }
250
+ }
251
+
252
+ // Release already exists — delete and recreate
253
+ const existing = await octokit.repos.getReleaseByTag({
254
+ owner: params.owner,
255
+ repo: params.repo,
256
+ tag: params.tag_name,
257
+ });
258
+ await octokit.repos.deleteRelease({
259
+ owner: params.owner,
260
+ repo: params.repo,
261
+ release_id: existing.data.id,
262
+ });
263
+ return octokit.repos.createRelease(params);
264
+ }
265
+
294
266
  /**
295
267
  * Create GitHub releases and tags for published packages
296
268
  * @param {PublicPackage[]} publishedPackages - Packages that were published
@@ -343,15 +315,20 @@ async function createGitHubReleasesForPackages(
343
315
  GIT_COMMITTER_NAME: 'Code infra',
344
316
  GIT_COMMITTER_EMAIL: 'code-infra@mui.com',
345
317
  },
346
- })`git tag -a ${tagName} -m ${`Canary release ${pkg.name}@${version}`}`;
318
+ })`git tag -fa ${tagName} -m ${`Canary release ${pkg.name}@${version}`}`;
347
319
 
320
+ // Force-push to handle retries where the tag already exists from a previous
321
+ // failed publish. The npm registry is the source of truth for published
322
+ // versions, so it's safe to rewrite a tag even if it points to a different
323
+ // commit — it just means the prior publish for this version failed partway
324
+ // through and the GitHub release needs to be recreated.
348
325
  // eslint-disable-next-line no-await-in-loop
349
- await $`git push origin ${tagName}`;
326
+ await $`git push --force origin ${tagName}`;
350
327
  console.log(`✅ Created and pushed git tag: ${tagName}`);
351
328
 
352
329
  // Create GitHub release
353
330
  // eslint-disable-next-line no-await-in-loop
354
- const res = await octokit.repos.createRelease({
331
+ const res = await upsertGitHubRelease(octokit, {
355
332
  owner: repoInfo.owner,
356
333
  repo: repoInfo.repo,
357
334
  tag_name: tagName,
@@ -381,7 +358,14 @@ async function getLastCanaryTag() {
381
358
  // Tag might not exist locally, which is fine
382
359
  }
383
360
 
384
- await $`git fetch origin tag ${CANARY_TAG}`;
361
+ try {
362
+ await $`git fetch origin tag ${CANARY_TAG}`;
363
+ } catch (err) {
364
+ // Tag might not exist on the remote yet (first canary run), which is fine
365
+ if (!(/** @type {Error} */ (err).message?.includes("couldn't find remote ref"))) {
366
+ throw err;
367
+ }
368
+ }
385
369
  const { stdout: remoteCanaryTag } = await $`git ls-remote --tags origin ${CANARY_TAG}`;
386
370
  return remoteCanaryTag.trim() ? CANARY_TAG : null;
387
371
  }
@@ -493,20 +477,23 @@ async function publishCanaryVersions(
493
477
  }
494
478
 
495
479
  // Third pass: publish only the changed packages using recursive publish
496
- let publishSuccess = false;
480
+ /** @type {Set<string>} */
481
+ const publishedNames = new Set();
497
482
  try {
498
483
  console.log(`📤 Publishing ${packagesToPublish.length} canary versions...`);
499
- await publishPackages(packagesToPublish, {
484
+ const publishedPackages = await publishPackages(packagesToPublish, {
500
485
  dryRun: options.dryRun,
501
486
  noGitChecks: true,
502
487
  tag: CANARY_TAG,
503
488
  });
504
489
 
505
- packagesToPublish.forEach((pkg) => {
506
- const canaryVersion = canaryVersions.get(pkg.name);
507
- console.log(`✅ Published ${pkg.name}@${canaryVersion}`);
508
- });
509
- publishSuccess = true;
490
+ // Only use package names from the report summary, not versions.
491
+ // pnpm-publish-summary.json reports the version from the workspace
492
+ // package.json, which is wrong for packages with publishConfig.directory.
493
+ for (const { name } of publishedPackages) {
494
+ publishedNames.add(name);
495
+ console.log(`✅ Published ${name}@${canaryVersions.get(name)}`);
496
+ }
510
497
  } finally {
511
498
  // Always restore original package.json files in parallel
512
499
  console.log('\n🔄 Restoring original package.json files...');
@@ -520,16 +507,26 @@ async function publishCanaryVersions(
520
507
  await Promise.all(restorePromises);
521
508
  }
522
509
 
523
- if (publishSuccess) {
524
- // Create/update the canary tag after successful publish
525
- await createCanaryTag(options.dryRun);
526
-
527
- // Create GitHub releases if requested
510
+ if (publishedNames.size > 0) {
511
+ // Create GitHub releases only for actually published packages
528
512
  if (options.githubRelease) {
529
- await createGitHubReleasesForPackages(packagesToPublish, canaryVersions, changelogs, options);
513
+ const actuallyPublished = packagesToPublish.filter((pkg) => publishedNames.has(pkg.name));
514
+ await createGitHubReleasesForPackages(actuallyPublished, canaryVersions, changelogs, options);
530
515
  }
531
516
 
532
- console.log('\n🎉 All canary versions published successfully!');
517
+ // Only advance the canary tag if all expected packages were published.
518
+ // Otherwise the tag would skip over unpublished packages and they'd
519
+ // never be retried on the next run.
520
+ const missing = packagesToPublish.filter((pkg) => !publishedNames.has(pkg.name));
521
+ if (missing.length === 0) {
522
+ await createCanaryTag(options.dryRun);
523
+ console.log('\n🎉 All canary versions published successfully!');
524
+ } else {
525
+ const missingNames = missing.map((pkg) => pkg.name).join(', ');
526
+ console.warn(
527
+ `\n⚠️ Canary tag not advanced, some packages failed to publish: ${missingNames}`,
528
+ );
529
+ }
533
530
  }
534
531
  }
535
532
 
@@ -548,14 +545,15 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
548
545
  default: false,
549
546
  description: 'Create GitHub releases for published packages',
550
547
  })
551
- .option('package', {
548
+ .option('filter', {
552
549
  type: 'string',
553
550
  array: true,
554
- description: 'Only publish canary versions for specified packages (by name)',
551
+ description:
552
+ 'Same as filtering packages with --filter in pnpm. Only publish packages matching the filter. See https://pnpm.io/filtering.',
555
553
  });
556
554
  },
557
555
  handler: async (argv) => {
558
- const { dryRun = false, githubRelease = false, package: explicitPackages = [] } = argv;
556
+ const { dryRun = false, githubRelease = false, filter = [] } = argv;
559
557
 
560
558
  const options = { dryRun, githubRelease };
561
559
 
@@ -567,48 +565,46 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
567
565
  console.log('📝 GitHub releases will be created for published packages\n');
568
566
  }
569
567
 
570
- // Always get all packages first
568
+ // All public packages — needed by publishCanaryVersions to bump versions and update
569
+ // package.json across the entire workspace, even for packages not being published.
571
570
  console.log('🔍 Discovering all workspace packages...');
572
- const allPackages = await getWorkspacePackages({ publicOnly: true });
571
+ const filteredPackages = await getWorkspacePackages({ publicOnly: true, filter });
573
572
 
574
- if (allPackages.length === 0) {
575
- console.log('⚠️ No public packages found in workspace');
573
+ if (filteredPackages.length === 0) {
574
+ console.log(
575
+ `⚠️ No publishable packages found in workspace${filter.length > 0 ? ` matching filter "${filter.join(', ')}"` : ''}`,
576
+ );
576
577
  return;
577
578
  }
578
579
 
579
- // Validate that all workspace dependencies are explicitly passed by the user
580
- if (explicitPackages.length > 0) {
581
- const pkgDepMap = await getPackageToDependencyMap();
582
- const missingDeps = new Set();
583
- for (const pkg of explicitPackages) {
584
- const deps = pkgDepMap[pkg] || [];
585
- deps.forEach((dep) => {
586
- if (!explicitPackages.includes(dep)) {
587
- missingDeps.add(dep);
588
- }
589
- });
590
- }
591
- if (missingDeps.size > 0) {
580
+ if (filter.length > 0) {
581
+ console.log('🔍 Validating workspace dependencies for filtered packages...');
582
+
583
+ const { issues } = await validatePublishDependencies(filteredPackages);
584
+
585
+ if (issues.length > 0) {
592
586
  throw new Error(
593
- `Missing required workspace dependencies:
594
- ${Array.from(missingDeps).join('\n ')}
595
- Pass all workspace dependencies explicitly through the --package argument.`,
587
+ `Invalid dependencies structure of packages to be published -
588
+ ${issues.join('\n ')}
589
+ `,
590
+ {
591
+ cause: issues,
592
+ },
596
593
  );
597
594
  }
595
+
596
+ console.log('✅ All workspace dependency requirements satisfied');
598
597
  }
599
598
 
600
- // Check for canary tag to determine selective publishing
599
+ // Check for canary tag to determine selective publishing.
600
+ // --filter is applied on top of sinceRef: publish only packages that have
601
+ // changed since the last canary tag AND match the filter.
601
602
  const canaryTag = await getLastCanaryTag();
602
603
 
603
604
  console.log('🔍 Checking for packages changed since canary tag...');
604
- let packages = canaryTag
605
- ? await getWorkspacePackages({ sinceRef: canaryTag, publicOnly: true })
606
- : allPackages;
607
-
608
- // If user provided package list, filter to only those in packageNames
609
- if (explicitPackages.length > 0) {
610
- packages = packages.filter((pkg) => explicitPackages.includes(pkg.name));
611
- }
605
+ const packages = canaryTag
606
+ ? await getWorkspacePackages({ sinceRef: canaryTag, publicOnly: true, filter })
607
+ : filteredPackages;
612
608
 
613
609
  console.log(`📋 Found ${packages.length} packages(s) for canary publishing:`);
614
610
  packages.forEach((pkg) => {
@@ -617,7 +613,7 @@ Pass all workspace dependencies explicitly through the --package argument.`,
617
613
 
618
614
  // Fetch version info for all packages in parallel
619
615
  console.log('\n🔍 Fetching package version information...');
620
- const versionInfoPromises = allPackages.map(async (pkg) => {
616
+ const versionInfoPromises = filteredPackages.map(async (pkg) => {
621
617
  const versionInfo = await getPackageVersionInfo(pkg.name, pkg.version);
622
618
  return { packageName: pkg.name, versionInfo };
623
619
  });
@@ -629,7 +625,7 @@ Pass all workspace dependencies explicitly through the --package argument.`,
629
625
  packageVersionInfo.set(packageName, versionInfo);
630
626
  }
631
627
 
632
- await publishCanaryVersions(packages, allPackages, packageVersionInfo, options);
628
+ await publishCanaryVersions(packages, filteredPackages, packageVersionInfo, options);
633
629
 
634
630
  console.log('\n🏁 Publishing complete!');
635
631
  },
@@ -16,17 +16,34 @@ import { getWorkspacePackages } from '../utils/pnpm.mjs';
16
16
  /**
17
17
  * @typedef {Object} Args
18
18
  * @property {boolean} [dryRun] If true, will only log the commands without executing them
19
+ * @property {string} [otp] 6 digit auth code to forward to npm for two-factor authentication
19
20
  */
20
21
 
21
22
  export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
22
23
  command: 'publish-new-package [pkg...]',
23
24
  describe: 'Publish new empty package(s) to the npm registry.',
24
25
  builder: (yargs) =>
25
- yargs.option('dryRun', {
26
- type: 'boolean',
27
- default: false,
28
- description: 'If true, will only log the commands without executing them.',
29
- }),
26
+ yargs
27
+ .option('dryRun', {
28
+ type: 'boolean',
29
+ default: false,
30
+ description: 'If true, will only log the commands without executing them.',
31
+ })
32
+ .option('otp', {
33
+ type: 'string',
34
+ description: '6 digit auth code to forward to npm for two-factor authentication.',
35
+ coerce: (value) => {
36
+ if (value === undefined) {
37
+ return value;
38
+ }
39
+
40
+ if (!/^\d{6}$/.test(value)) {
41
+ throw new Error('The --otp option must be a 6 digit number.');
42
+ }
43
+
44
+ return value;
45
+ },
46
+ }),
30
47
  async handler(args) {
31
48
  console.log(`🔍 Detecting new packages to publish in workspace...`);
32
49
  const newPackages = await getWorkspacePackages({ nonPublishedOnly: true });
@@ -62,7 +79,7 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
62
79
  version: '0.0.1',
63
80
  repository: {
64
81
  type: 'git',
65
- url: `git+https://github.com/${repo.owner}/${repo.remoteName}.git`,
82
+ url: `git+https://github.com/${repo.owner}/${repo.repo}.git`,
66
83
  directory: toPosixPath(path.relative(workspaceDir, pkg.path)),
67
84
  },
68
85
  };
@@ -78,8 +95,12 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
78
95
  if (args.dryRun) {
79
96
  publishArgs.push('--dry-run');
80
97
  }
98
+ if (args.otp) {
99
+ publishArgs.push('--otp', args.otp);
100
+ }
81
101
  await $({
82
102
  cwd: newPkgDir,
103
+ stdio: 'inherit',
83
104
  })`npm publish --access public --tag=canary ${publishArgs}`;
84
105
  console.log(
85
106
  `✅ ${args.dryRun ? '[Dry run] ' : ''}Published ${chalk.bold(`${pkg.name}@${packageJson.version}`)} to npm registry.`,