release.js 3.8 KB

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