From dc1ea9f68f947f26723192e1e3e9b1e4132f9bf7 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 27 Apr 2023 00:26:22 +0000 Subject: [PATCH] improve release script with new args --- scripts/release.js | 86 ++++++++++++++++----------- scripts/utils/bumpVersion.js | 99 +++++++++++++++++++++++++++++++ scripts/utils/composeChangelog.js | 90 ++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+), 33 deletions(-) create mode 100644 scripts/utils/bumpVersion.js create mode 100644 scripts/utils/composeChangelog.js diff --git a/scripts/release.js b/scripts/release.js index 3f8e58d7..eba82678 100755 --- a/scripts/release.js +++ b/scripts/release.js @@ -12,40 +12,14 @@ const axios = require("axios") const repo = "ragestudio/comty" const appSrcPath = path.resolve(process.cwd(), "packages/app/src") const appDistPath = path.resolve(process.cwd(), "packages/app/dist") +const changelogsPath = path.resolve(process.cwd(), "changelogs") const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }) -async function getChangeLogString() { - // get latest tag - const latestTag = await octokit.repos.getLatestRelease({ - owner: repo.split("/")[0], - repo: repo.split("/")[1] - }) - - // get commits since latest tag - const commits = await octokit.repos.listCommits({ - owner: repo.split("/")[0], - repo: repo.split("/")[1], - since: latestTag.data.published_at - }) - - const changelog = commits.data.map((commit) => { - return { - message: commit.commit.message, - author: commit.commit.author.name, - url: commit.html_url, - } - }) - - // make a string from the changes with Markdown syntax - const changelogString = changelog.map((commit) => { - return `* [${commit.message}](${commit.url}) - ${commit.author}` - }).join("\n") - - return changelogString -} +const composeChangelog = require("./utils/composeChangelog") +const bumpVersion = require("./utils/bumpVersion") async function createGithubRelease(payload) { if (process.argv.includes("--noPublish")) { @@ -93,8 +67,8 @@ async function createAppDistBundle() { } async function compressDistBundle() { - if (process.argv.includes("--noCompress")) { - console.log("🔥 Skipping build due to `noBuild` argument") + if (process.argv.includes("--noCompress") || process.argv.includes("--noBuild")) { + console.log("🔥 Skipping compress due to `noBuild` or `noCompress` argument") return true } @@ -124,6 +98,12 @@ async function compressDistBundle() { } async function uploadAssets({ release, bundlePath }) { + // check if has `noPublish` argument, if true, skip uploading assets + if (process.argv.includes("--noPublish")) { + console.log("🔥 Skipping upload assets due to `noPublish` argument") + return true + } + console.log("⚒ Uploading assets...") console.log(`ReleaseID: ${release.id}`) @@ -146,13 +126,53 @@ async function uploadAssets({ release, bundlePath }) { } async function main() { + let currentVersion = packagejson.version + + // check if currentVersion match with current latest release on github + const latestRelease = await octokit.repos.getLatestRelease({ + owner: repo.split("/")[0], + repo: repo.split("/")[1] + }).catch((err) => { + console.error(`🆘 Failed to get latest release: ${err}`) + return false + }) + + if (latestRelease && latestRelease.data.tag_name === currentVersion && !process.argv.includes("--force")) { + if (process.argv.includes("--bump")) { + const bumpType = process.argv[process.argv.indexOf("--bump") + 1] + + const newVersion = await bumpVersion(bumpType, 1).catch((err) => { + console.error(`🆘 Failed to bump version: ${err}`) + return false + }) + + if (!newVersion) { + throw new Error("Failed to bump version") + } + + currentVersion = newVersion + } else { + console.log("🚫 Current version is already latest version, please bump version first. \n - use --bump to automatically bump version. \n - use --force to force release.") + } + + return true + } + + if (!latestRelease) return + await createAppDistBundle() + const bundlePath = await compressDistBundle() - const changelog = await getChangeLogString() + const changelog = await composeChangelog() + + console.log("📝 Writing changelog to file...") + + // write changelog to file + fs.writeFileSync(path.resolve(changelogsPath, `v${currentVersion.replace(".", "-")}.md`), changelog) const release = await createGithubRelease({ - version: packagejson.version, + version: currentVersion, changelog, }).catch((err) => { console.error(`🆘 Failed to create release: ${err}`) diff --git a/scripts/utils/bumpVersion.js b/scripts/utils/bumpVersion.js new file mode 100644 index 00000000..7c3a7ff7 --- /dev/null +++ b/scripts/utils/bumpVersion.js @@ -0,0 +1,99 @@ +const path = require("path") +const fs = require("fs") + +const validTypes = ["patch", "minor", "major"] + +async function bumpVersion(type, count, noWrite = false) { + if (!validTypes.includes(type)) { + console.error("Invalid version type") + return false + } + + // read all directories from `./packages` and __dirname/.. + // find `package.json` files + // and bump depending on the `type` argument (patch, minor, major) + // write into `package.json` files + // exclude gitignored + + const ignore = fs.readFileSync(path.resolve(process.cwd(), ".gitignore"), "utf8").split("\n").filter(line => line !== "").filter(line => !line.startsWith("#")) + + const ignoreRegex = ignore.map((line) => { + let regex = line.replace(/\./g, "\\.").replace(/\*/g, ".*") + + if (!regex.startsWith("/")) { + regex = `/${regex}` + } + + if (!regex.endsWith("/")) { + regex = `${regex}/` + } + + return regex + }) + + const packagesPath = path.resolve(__dirname, "..", "..", "packages") + + let packages = fs.readdirSync(packagesPath) + + packages = packages.filter((package) => { + let isIgnored = false + + ignoreRegex.forEach(regex => { + if (new RegExp(regex).test(`/${package}/`)) { + isIgnored = true + } + }) + + return !isIgnored + }) + + // filter out ignored packages + packages = packages.filter((package) => !ignore.includes(package)) + + // filter out non-directories + packages = packages.filter((package) => fs.lstatSync(path.resolve(packagesPath, package)).isDirectory()) + + // filter out non-package.json + packages = packages.filter((package) => fs.existsSync(path.resolve(packagesPath, package, "package.json"))) + + for (let package of packages) { + const pkgjson = require(path.resolve(packagesPath, package, "package.json")) + + if (!pkgjson || !pkgjson.version) { + continue + } + + let version = pkgjson.version.split(".") + + switch (type) { + case "patch": + version[2] = parseInt(version[2]) + Number(count ?? 1) + break + case "minor": + version[1] = parseInt(version[1]) + Number(count ?? 1) + break + case "major": + version[0] = parseInt(version[0]) + Number(count ?? 1) + break + default: + console.error("Invalid version type") + return false + } + + version = version.join(".") + + console.log(`⏩ Bumped [${pkgjson.name}] ${pkgjson.version} to ${version}`) + + pkgjson.version = version + + if (noWrite) { + continue + } + + fs.writeFileSync(path.resolve(packagesPath, package, "package.json"), JSON.stringify(pkgjson, null, 4)) + } + + return true +} + +module.exports = bumpVersion \ No newline at end of file diff --git a/scripts/utils/composeChangelog.js b/scripts/utils/composeChangelog.js new file mode 100644 index 00000000..dbee6cc8 --- /dev/null +++ b/scripts/utils/composeChangelog.js @@ -0,0 +1,90 @@ +require("dotenv").config() + +const { Octokit } = require("@octokit/rest") +const repo = "ragestudio/comty" + +const octokit = new Octokit({ + auth: process.env.GITHUB_TOKEN, +}) + +async function getChangeLogString() { + // get latest tag + const latestTag = await octokit.repos.getLatestRelease({ + owner: repo.split("/")[0], + repo: repo.split("/")[1] + }) + + // get commits since latest tag + const commits = await octokit.repos.listCommits({ + owner: repo.split("/")[0], + repo: repo.split("/")[1], + since: latestTag.data.published_at + }) + + let changelog = commits.data.map(async (commit) => { + const commitData = await octokit.repos.getCommit({ + owner: repo.split("/")[0], + repo: repo.split("/")[1], + ref: commit.sha + }) + + const filenamesChanged = commitData.data.files.map((file) => { + return file.filename + }) + + // check packages involved in each commit + let packagesChanged = filenamesChanged.map((file) => { + // search for the pkg name in the path (eg packages/app/src/...) + const pkg = file.split("/")[1] + + // if the pkg is not found, return null + if (!pkg) return null + + return pkg + }) + + // filter out null values + packagesChanged = packagesChanged.filter((pkg) => { + return pkg !== null + }) + + // remove duplicates + packagesChanged = [...new Set(packagesChanged)] + + // if no packages changed, return "internal" + if (packagesChanged.length === 0) { + packagesChanged = ["internal"] + } + + return { + message: commitData.data.commit.message, + author: commitData.data.commit.author.name, + authorUrl: commitData.data.author.html_url, + url: commit.html_url, + filenamesChanged: filenamesChanged, + files: commitData.data.files, + packages: packagesChanged, + } + }) + + changelog = await Promise.all(changelog) + + // make a string from the changes with Markdown syntax + let changelogString = changelog.map((commit) => { + const additions = commit.files.map((file) => { + return file.additions + }).reduce((a, b) => a + b, 0) + + const deletions = commit.files.map((file) => { + return file.deletions + }).reduce((a, b) => a + b, 0) + + return `* [+${additions}/-${deletions}][${commit.packages.join(" | ")}] [${commit.message}](${commit.url}) - by [@${commit.author}](${commit.authorUrl})` + }).join("\n") + + changelogString = changelogString.trim() + + return changelogString +} + +module.exports = getChangeLogString \ No newline at end of file