release.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #!/usr/bin/env node
  2. const exec = require("node:child_process").execSync;
  3. const fs = require("node:fs");
  4. const path = require("node:path");
  5. const crypto = require("node:crypto");
  6. const { parseArgs } = require("node:util");
  7. const args = parseArgs({
  8. options: {
  9. version: { type: "string" },
  10. "dry-run": { type: "boolean", default: false },
  11. },
  12. });
  13. const dryRun = args.values["dry-run"];
  14. if (dryRun) {
  15. console.log('Running in "dry-run" mode');
  16. }
  17. const exitWithError = (message) => {
  18. console.error(`Exit with error: ${message}`);
  19. process.exit(1);
  20. };
  21. if (!process.env.CI) {
  22. exitWithError("The script should only be run in CI");
  23. }
  24. exec('echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc');
  25. async function main() {
  26. const configGit = (await import("./utils/configGit.mjs")).default;
  27. await configGit();
  28. /*
  29. * Check that the git working directory is clean
  30. */
  31. if (exec("git status --porcelain").length) {
  32. exitWithError(
  33. "Make sure the git working directory is clean before releasing"
  34. );
  35. }
  36. /*
  37. * Check that the version is valid. Also extract the dist-tag from the version.
  38. */
  39. const [version, distTag] = (() => {
  40. const inputVersion = args.values.version;
  41. if (!inputVersion) {
  42. exitWithError('Missing required argument: "--version <version>"');
  43. }
  44. if (inputVersion === "experimental") {
  45. const randomId = crypto
  46. .randomBytes(Math.ceil(9 / 2))
  47. .toString("hex")
  48. .slice(0, 9);
  49. return [
  50. `0.0.0-experimental-${randomId}-${new Date()
  51. .toISOString()
  52. .slice(0, 10)
  53. .replace(/-/g, "")}`,
  54. "experimental",
  55. ];
  56. }
  57. const match = inputVersion.match(
  58. /^(?:[0-9]+\.){2}(?:[0-9]+)(?:-(dev|alpha|beta|rc)\.[0-9]+)?$/
  59. );
  60. if (!match) {
  61. exitWithError(`Invalid version: ${inputVersion}`);
  62. }
  63. return [inputVersion, match[1] || "latest"];
  64. })();
  65. /*
  66. * Get the current version
  67. */
  68. const currentVersion = JSON.parse(
  69. fs.readFileSync("package.json", "utf-8")
  70. ).version;
  71. console.log(
  72. `Releasing with version: ${currentVersion} -> ${version} and dist-tag: ${distTag}`
  73. );
  74. /*
  75. * Bump npm versions
  76. */
  77. exec(`npm version ${version} --workspaces --force`);
  78. exec("git add **/package.json");
  79. exec(`npm version ${version} --include-workspace-root --force`);
  80. const pushCommand = `git push origin ${process.env.GITHUB_REF_NAME} --follow-tags`;
  81. if (distTag === "experimental") {
  82. console.log(`Skipping: "${pushCommand}" for experimental version`);
  83. } else {
  84. if (dryRun) {
  85. console.log(`Skipping: "${pushCommand}" in dry-run mode`);
  86. } else {
  87. exec(pushCommand);
  88. }
  89. }
  90. /*
  91. * Build Quill package
  92. */
  93. console.log("Building Quill");
  94. exec("npm run build:quill");
  95. /*
  96. * Publish Quill package
  97. */
  98. console.log("Publishing Quill");
  99. const distFolder = "packages/quill/dist";
  100. if (
  101. JSON.parse(fs.readFileSync(path.join(distFolder, "package.json"), "utf-8"))
  102. .version !== version
  103. ) {
  104. exitWithError(
  105. "Version mismatch between package.json and dist/package.json"
  106. );
  107. }
  108. const readme = fs.readFileSync("README.md", "utf-8");
  109. fs.writeFileSync(path.join(distFolder, "README.md"), readme);
  110. exec(`npm publish --tag ${distTag}${dryRun ? " --dry-run" : ""}`, {
  111. cwd: distFolder,
  112. });
  113. /*
  114. * Create GitHub release
  115. */
  116. if (distTag === "experimental") {
  117. console.log("Skipping GitHub release for experimental version");
  118. } else {
  119. const prereleaseFlag = distTag === "latest" ? "--latest" : " --prerelease";
  120. const releaseCommand = `gh release create v${version} ${prereleaseFlag} -t "Version ${version}" --generate-notes`;
  121. if (dryRun) {
  122. console.log(`Skipping: "${releaseCommand}" in dry-run mode`);
  123. } else {
  124. exec(releaseCommand);
  125. }
  126. }
  127. /*
  128. * Create npm package tarball
  129. */
  130. exec("npm pack", { cwd: distFolder });
  131. }
  132. main();