From 3658e9def407b18836e5acc8f2571ed0c6e82e4b Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 23 Feb 2023 12:51:35 -0500 Subject: [PATCH] Various improvements to release-tool - Pass more IO from script to user to provide better UX - Interactive versioning using lerna directly - Remove all CMD args in favour of interactive Signed-off-by: Sebastian Malton --- package-lock.json | 42 +-------- packages/release-tool/package.json | 8 +- packages/release-tool/src/index.ts | 137 ++++++++--------------------- 3 files changed, 41 insertions(+), 146 deletions(-) diff --git a/package-lock.json b/package-lock.json index 24cae086b2..c58e01e70a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5955,15 +5955,6 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, - "node_modules/@types/jsonfile": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.1.tgz", - "integrity": "sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -28093,6 +28084,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.1.2.tgz", "integrity": "sha512-BlIbgFryTbw3Dz6hyoWFhKk+unCcHMSkZGrTFVAx2WmttdBSonsdtRlwiuTbDqTKr+UlXIUqJVS4QT5tUzGENQ==", + "dev": true, "bin": { "rimraf": "dist/cjs/src/bin.js" }, @@ -34464,7 +34456,7 @@ "version": "6.4.0-beta.13", "license": "MIT", "dependencies": { - "rimraf": "^4.1.2" + "semver": "^7.3.8" }, "bin": { "create-release-pr": "dist/index.js" @@ -34472,23 +34464,9 @@ "devDependencies": { "@swc/cli": "^0.1.61", "@swc/core": "^1.3.35", - "@types/command-line-args": "^5.2.0", - "@types/fs-extra": "^11.0.1", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "command-line-args": "^5.2.1", - "fs-extra": "^11.1.0", - "semver": "^7.3.8" - } - }, - "packages/release-tool/node_modules/@types/fs-extra": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.1.tgz", - "integrity": "sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==", - "dev": true, - "dependencies": { - "@types/jsonfile": "*", - "@types/node": "*" + "rimraf": "^4.1.2" } }, "packages/release-tool/node_modules/@types/node": { @@ -34497,20 +34475,6 @@ "integrity": "sha512-vzLe5NaNMjIE3mcddFVGlAXN1LEWueUsMsOJWaT6wWMJGyljHAWHznqfnKUQWGzu7TLPrGvWdNAsvQYW+C0xtw==", "dev": true }, - "packages/release-tool/node_modules/fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "packages/semver": { "name": "@k8slens/semver", "version": "6.4.0-beta.13", diff --git a/packages/release-tool/package.json b/packages/release-tool/package.json index 517b354203..8a69fbd404 100644 --- a/packages/release-tool/package.json +++ b/packages/release-tool/package.json @@ -16,15 +16,11 @@ "devDependencies": { "@swc/cli": "^0.1.61", "@swc/core": "^1.3.35", - "@types/command-line-args": "^5.2.0", - "@types/fs-extra": "^11.0.1", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "command-line-args": "^5.2.1", - "fs-extra": "^11.1.0", - "semver": "^7.3.8" + "rimraf": "^4.1.2" }, "dependencies": { - "rimraf": "^4.1.2" + "semver": "^7.3.8" } } diff --git a/packages/release-tool/src/index.ts b/packages/release-tool/src/index.ts index 2f788dd117..b58acabdeb 100755 --- a/packages/release-tool/src/index.ts +++ b/packages/release-tool/src/index.ts @@ -4,9 +4,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import child_process from "child_process"; -import commandLineArgs from "command-line-args"; -import fse from "fs-extra"; -import { basename } from "path"; +import { readFile } from "fs/promises"; import { createInterface } from "readline"; import semver from "semver"; import { promisify } from "util"; @@ -18,89 +16,40 @@ const { lte: semverLte, } = semver; const exec = promisify(child_process.exec); -const execFile = promisify(child_process.execFile); +const spawn = promisify(child_process.spawn); -const options = commandLineArgs([ - { - name: "type", - defaultOption: true, - }, - { - name: "preid", - }, - { - name: "check-commits", - type: Boolean, - }, -]); +const repoRoot = (await exec("git rev-parse --show-toplevel")).stdout; -const validReleaseValues = [ - "major", - "minor", - "patch", -]; -const validPrereleaseValues = [ - "premajor", - "preminor", - "prepatch", - "prerelease", -]; -const validPreidValues = [ - "alpha", - "beta", -]; - -const errorMessages = { - noReleaseType: `No release type provided. Valid options are: ${[...validReleaseValues, ...validPrereleaseValues].join(", ")}`, - invalidRelease: (invalid: string) => `Invalid release type was provided (value was "${invalid}"). Valid options are: ${[...validReleaseValues, ...validPrereleaseValues].join(", ")}`, - noPreid: `No preid was provided. Use '--preid' to specify. Valid options are: ${validPreidValues.join(", ")}`, - invalidPreid: (invalid: string) => `Invalid preid was provided (value was "${invalid}"). Valid options are: ${validPreidValues.join(", ")}`, - wrongCwd: "It looks like you are running this script from the 'scripts' directory. This script assumes it is run from the root of the git repo", -}; - -if (!options.type) { - console.error(errorMessages.noReleaseType); - process.exit(1); +if (process.cwd() !== repoRoot) { + console.error("It looks like you are running this script from the 'scripts' directory. This script assumes it is run from the root of the git repo"); } -if (validReleaseValues.includes(options.type)) { - // do nothing, is valid -} else if (validPrereleaseValues.includes(options.type)) { - if (!options.preid) { - console.error(errorMessages.noPreid); - process.exit(1); - } +const currentVersion = new SemVer(JSON.parse((await readFile("./lerna.json", "utf-8"))).version); - if (!validPreidValues.includes(options.preid)) { - console.error(errorMessages.invalidPreid(options.preid)); - process.exit(1); - } -} else { - console.error(errorMessages.invalidRelease(options.type)); - process.exit(1); -} +await spawn("npm", ["run", "bump-version"], { + stdio: "inherit", +}); -if (basename(process.cwd()) === "scripts") { - console.error(errorMessages.wrongCwd); -} - -const currentVersion = new SemVer((await fse.readJson("./lerna.json")).version); - -console.log(`current version: ${currentVersion.format()}`); - -const newVersion = currentVersion.inc(options.type, options.preid); +const newVersion = new SemVer(JSON.parse((await readFile("./lerna.json", "utf-8"))).version); const newVersionMilestone = `${newVersion.major}.${newVersion.minor}.${newVersion.patch}`; const prBranch = `release/v${newVersion.format()}`; -await exec(`npm run bump-version --yes ${newVersion.format()}`); -await exec(`git checkout -b ${prBranch}`); -await exec("git add lerna.json packages/*/package.json"); -await exec(`git commit -sm "Release ${newVersion.format()}"`); +await spawn("git", ["checkout", "-b", prBranch], { + stdio: "inherit", +}); +await spawn("git", ["add", "lerna.json", "packages/*/package.json"], { + stdio: "inherit", +}); +await spawn("git", ["commit", "-sm", `"Release ${newVersion.format()}"`], { + stdio: "inherit", +}); console.log(`new version: ${newVersion.format()}`); console.log("fetching tags..."); -await exec("git fetch --tags --force"); +await spawn("git", ["fetch", "--tags", "--force"], { + stdio: "inherit", +}); const actualTags = (await exec("git tag --list", { encoding: "utf-8" })).stdout.split(/\r?\n/).map(line => line.trim()); const [previousReleasedVersion] = actualTags @@ -193,9 +142,7 @@ function getPrEntry(pr: ExtendedGithubPrData) { } const rl = createInterface(process.stdin); -const prBase = newVersion.patch === 0 - ? "master" - : `release/v${newVersion.major}.${newVersion.minor}`; +const prBase = (await exec("git branch --show-current")).stdout.trim(); function askQuestion(question: string): Promise { return new Promise(resolve => { @@ -220,20 +167,15 @@ function askQuestion(question: string): Promise { } async function handleRelaventPr(pr: ExtendedGithubPrData) { - if (options["check-commits"] && !(await askQuestion(`Would you like to use #${pr.number}: ${pr.title}? - Y/N`))) { + if (prBase !== "master" && !(await askQuestion(`Would you like to use #${pr.number}: ${pr.title}? - Y/N`))) { return; } if (prBase !== "master") { - try { - const promise = exec(`git cherry-pick ${pr.mergeCommit.oid}`); - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - promise.child.stdout!.pipe(process.stdout); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - promise.child.stderr!.pipe(process.stderr); - - await promise; + try { + await spawn("git", ["cherry-pick", pr.mergeCommit.oid], { + stdio: "inherit", + }); } catch { console.error(`Failed to cherry-pick ${pr.mergeCommit.oid}, please resolve conflicts and then press enter here:`); await new Promise(resolve => rl.once("line", () => resolve())); @@ -290,7 +232,10 @@ const prBodyLines = [ ), ]; const prBody = prBodyLines.join("\n"); -const createPrArgs = [ + +await exec(`git push --set-upstream origin ${prBranch}`); + +await spawn("gh", [ "pr", "create", "--base", prBase, @@ -298,17 +243,7 @@ const createPrArgs = [ "--label", "skip-changelog", "--label", "release", "--milestone", `${newVersion.major}.${newVersion.minor}.${newVersion.patch}`, - "--body-file", "-", -]; - -await exec(`git push --set-upstream origin ${prBranch}`); - -const createPrProcess = execFile("gh", createPrArgs); - -createPrProcess.child.stdout?.pipe(process.stdout); -createPrProcess.child.stderr?.pipe(process.stderr); - -createPrProcess.child.stdin?.write(prBody); -createPrProcess.child.stdin?.end(); - -await createPrProcess; + "--body-file", prBody, +], { + stdio: "inherit" +});