@i-novus/k8s-version-release
Version:
Release version with git-tag and switch to next snapshot version
134 lines (131 loc) • 5.5 kB
JavaScript
// src/k8s-version-release.ts
import process from "process";
import { stat, readFile, writeFile, access } from "fs/promises";
import { dirname, join } from "path";
import { execSync } from "child_process";
import { input, confirm } from "@inquirer/prompts";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
var { releaseBranch } = yargs(hideBin(process.argv)).option("releaseBranch", {
demandOption: true,
default: "master",
describe: "Branch name from which version release is allowed",
type: "string"
}).help().parseSync();
try {
let isVersionValid = function(version) {
return !!version.match(/^\d+\.\d+\.\d+$/);
}, getNextVersion = function(version) {
if (!isVersionValid(version)) {
throw new Error(`Version "${version}" is not valid`);
}
const [major, minor, patch] = version.split(".");
return [major, minor, Number(patch) + 1].join(".");
};
isVersionValid2 = isVersionValid, getNextVersion2 = getNextVersion;
const { npm_package_json, npm_package_version } = process.env;
const K8S_DIRNAME = ".k8s";
const CHART_CONFIG_FILENAME = "Chart.yaml";
if (!npm_package_json) {
throw new Error('ENV variable "npm_package_json" is not set');
}
await stat(npm_package_json);
if (!npm_package_version) {
throw new Error('ENV variable "npm_package_version" is not set');
}
const projectPath = dirname(npm_package_json);
const chartConfigPath = join(projectPath, K8S_DIRNAME, CHART_CONFIG_FILENAME);
await stat(chartConfigPath);
let packageManager;
if (await checkFileExists(join(projectPath, "package-lock.json"))) {
packageManager = "npm";
} else if (await checkFileExists(join(projectPath, "yarn.lock"))) {
packageManager = "yarn";
} else {
throw new Error('Lock file "package-lock.json" or "yarn.lock" not found');
}
const regexResult = npm_package_version.match(/^\d+\.\d+\.\d+/);
const coreVersion = regexResult ? regexResult[0] : null;
if (!coreVersion) {
throw new Error(`Can not parse package.json version "${npm_package_version}" by regular expression /^\\d+\\.\\d+\\.\\d+/`);
}
const gitStatus = execSync("git status").toString().toLowerCase();
if (!gitStatus.includes("nothing to commit")) {
throw new Error('There are uncommitted changes. Use "git status" to display them');
}
if (!gitStatus.includes(`on branch ${releaseBranch}`)) {
throw new Error(`Releasing from this branch is prohibited. You can only release from "${releaseBranch}" branch. To change the release branch, use the "--releaseBranch" flag when starting.`);
}
console.log(`Current version "${npm_package_version}"`);
const gitTags = execSync("git for-each-ref --format='%(refname:short)' refs/tags").toString().split("\n").map((s) => s.trim()).filter(Boolean);
const isCurrentVersionReleased = gitTags.includes(coreVersion);
let versionToRelease = coreVersion;
if (isCurrentVersionReleased) {
console.log(`Version "${coreVersion}" has already been released`);
versionToRelease = getNextVersion(versionToRelease);
}
versionToRelease = await typeVersion("Which version do you want to release?", versionToRelease);
let nextVersion = await typeVersion("What will be the next version?", getNextVersion(versionToRelease));
nextVersion += "-SNAPSHOT";
console.log("Creating a release commit");
await setChartConfigVersion(versionToRelease);
await setPackageJsonVersion(versionToRelease);
execSync(`${packageManager} install`);
execSync("git add .");
execSync(`git commit -m "${versionToRelease}"`);
execSync(`git tag -fa ${versionToRelease} -m "${versionToRelease}"`);
console.log("Creating a next version commit");
await setChartConfigVersion(nextVersion);
await setPackageJsonVersion(nextVersion);
execSync(`${packageManager} install`);
execSync("git add .");
execSync(`git commit -m "${nextVersion}"`);
if (await confirm({ message: "Push the release commit and commit with the next version?", default: true })) {
execSync("git push origin --follow-tags");
}
async function setChartConfigVersion(version) {
const chartConfig = await readFile(chartConfigPath, { encoding: "utf-8" });
await writeFile(chartConfigPath, chartConfig.replace(/version: .+/, `version: ${version}`));
}
async function setPackageJsonVersion(version) {
if (!npm_package_json) {
throw new Error('ENV variable "npm_package_json" is not set');
}
const packageJson = await readFile(npm_package_json, { encoding: "utf-8" });
await writeFile(npm_package_json, packageJson.replace(/"version": ".+",/, `"version": "${version}",`));
}
async function typeVersion(message, defaultValue) {
return input({
message,
required: true,
default: defaultValue,
validate: (version) => {
if (!isVersionValid(version)) {
return "Version is invalid. The expected format is X.X.X, where X is a positive integer";
}
if (gitTags.includes(version)) {
return `Version "${version}" has already been released`;
}
return true;
}
});
}
async function checkFileExists(file) {
try {
await access(file);
return true;
} catch {
return false;
}
}
} catch (error) {
if (error instanceof Error && "stdout" in error && error.stdout instanceof Buffer) {
throw new Error(`${error.stack}
${error.stdout.toString()}`);
} else {
throw error;
}
}
var isVersionValid2;
var getNextVersion2;