pack-release.mjs 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. #!/usr/bin/env node
  2. /**
  3. * Pack every published package into release tarballs, in publish order
  4. * (platform packages first, then the entries that optionally depend on
  5. * them), and write `publish-order.txt` next to them. `pnpm pack` produces
  6. * the EXACT bytes `pnpm publish` would upload and runs each package's
  7. * `prepack` gate, so a missing binary or unbuilt `lib/` refuses here.
  8. *
  9. * Usage: `node scripts/pack-release.mjs [dest] [--current-platform-only]`.
  10. * The flag packs only THIS host's platform package plus the entries — for
  11. * per-architecture CI legs, where the other architecture's binary does not
  12. * exist (the exact refusal its prepack gate exists for).
  13. */
  14. import fs from 'node:fs';
  15. import path from 'node:path';
  16. import { spawnSync } from 'node:child_process';
  17. import { entryDirs, platformDirs, readJson, root } from './repo.mjs';
  18. const args = process.argv.slice(2);
  19. const currentPlatformOnly = args.includes('--current-platform-only');
  20. const destination = path.resolve(args.find((arg) => !arg.startsWith('--')) || path.join(root, 'dist', 'npm'));
  21. function hostPlatformDirs() {
  22. const hostPlatform = `${process.platform}-${process.arch}`;
  23. return platformDirs().filter((dir) => readJson(path.join(root, dir, 'prebuilds.json')).platform === hostPlatform);
  24. }
  25. function run(command, args) {
  26. const result = spawnSync(command, args, {
  27. cwd: root,
  28. stdio: 'inherit',
  29. });
  30. if (result.error) throw result.error;
  31. if (result.status !== 0) {
  32. process.exit(result.status ?? 1);
  33. }
  34. }
  35. function tarballName(manifest) {
  36. if (manifest.name.startsWith('@')) {
  37. return `${manifest.name.slice(1).replace('/', '-')}-${manifest.version}.tgz`;
  38. }
  39. return `${manifest.name}-${manifest.version}.tgz`;
  40. }
  41. fs.rmSync(destination, { recursive: true, force: true });
  42. fs.mkdirSync(destination, { recursive: true });
  43. const dirs = [...(currentPlatformOnly ? hostPlatformDirs() : platformDirs()), ...entryDirs()];
  44. const platformSet = new Set(platformDirs());
  45. const publishOrder = [];
  46. for (const dir of dirs) {
  47. const manifest = readJson(path.join(root, dir, 'package.json'));
  48. // Platform packages are packed with npm: pnpm pack (observed on 11.7.0)
  49. // normalizes file modes and STRIPS the executable bit, which ships a
  50. // launcher no consumer can spawn; npm pack preserves it. Platform packages
  51. // have no dependencies by construction, so they need none of pnpm's
  52. // workspace-protocol conversion — the entry packages do, and carry no
  53. // executables, so they keep pnpm pack.
  54. if (platformSet.has(dir)) {
  55. run('npm', ['pack', `./${dir}`, '--pack-destination', destination]);
  56. } else {
  57. run('pnpm', ['--dir', dir, 'pack', '--pack-destination', destination]);
  58. }
  59. const tarball = tarballName(manifest);
  60. const tarballPath = path.join(destination, tarball);
  61. if (!fs.existsSync(tarballPath)) {
  62. throw new Error(`expected pack output not found: ${tarballPath}`);
  63. }
  64. publishOrder.push(tarball);
  65. }
  66. fs.writeFileSync(path.join(destination, 'publish-order.txt'), `${publishOrder.join('\n')}\n`);
  67. console.log(`Packed ${publishOrder.length} packages into ${path.relative(root, destination)}`);