@process-engine/ci_tools
Version:
CI tools for process-engine.io
218 lines (174 loc) • 7.21 kB
text/typescript
import * as chalk from 'chalk';
import * as fs from 'fs';
import { existsSync } from 'fs';
import * as yargsParser from 'yargs-parser';
import { getGitBranch, getGitTagList, getGitTagsFromCommit, gitAdd, gitCommit, gitPush } from '../git/git';
import { getVersionTag } from '../versions/git_helpers';
import { getPackageVersion, setPackageVersion } from '../versions/package_version';
import { printMultiLineString } from '../cli/printMultiLineString';
import { sh } from '../cli/shell';
import { PACKAGE_MODE_DOTNET, PACKAGE_MODE_NODE, PACKAGE_MODE_PYTHON } from '../contracts/modes';
import { getCsprojAsObject, getCsprojPath } from '../versions/package_version/dotnet';
const COMMAND_NAME = 'copy-and-commit-version-for-subpackage';
const BADGE = `[${COMMAND_NAME}]\t`;
const DEFAULT_MODE = 'node';
const DOC = `
Copies the version from the main package to a subpackage and commits the change.
OPTIONS
--mode sets the package mode [dotnet, node, python] (default: node)
`;
// DOC: see above
export async function run(...args): Promise<boolean> {
const argv = yargsParser(args, { alias: { help: ['h'] }, default: { mode: DEFAULT_MODE } });
const isDryRun = args.indexOf('--dry') !== -1;
const isForced = process.env.CI_TOOLS_FORCE_PUBLISH === 'true' || args.indexOf('--force') !== -1;
const mode = argv.mode;
const subpackageLocation = getSubpackageLocationFromArgs(args);
const mainPackageVersion = await getPackageVersion(mode);
await printInfo(mode, mainPackageVersion, isDryRun, isForced);
const subpackageLocationWithSlash = subpackageLocation.endsWith('/') ? subpackageLocation : `${subpackageLocation}/`;
await abortIfRetryRun(mode, mainPackageVersion, subpackageLocationWithSlash);
abortIfSubpackageLocationIsMissing(subpackageLocation);
abortIfDryRun(mainPackageVersion, isDryRun, isForced);
const cwd = process.cwd();
process.chdir(subpackageLocationWithSlash);
await setPackageVersion(mode, mainPackageVersion);
process.chdir(cwd);
const branchName = getGitBranch();
const filename = getSubpackageFilename(mode, subpackageLocationWithSlash);
gitAdd(`${subpackageLocationWithSlash}${filename}`);
sh('git status');
const subpackageName = await getSubpackageName(mode, subpackageLocationWithSlash);
gitCommit(`Update ${subpackageName} version to v${mainPackageVersion}\n\n[skip ci]`);
gitPush('origin', branchName);
return true;
}
export function getShortDoc(): string {
return DOC.trim().split('\n')[0];
}
export function printHelp(): void {
console.log(`Usage: ci_tools ${COMMAND_NAME} <subpackageLocation> [--dry] [--force] [--mode <MODE>]`);
console.log('');
console.log(DOC.trim());
}
async function abortIfRetryRun(mode: string, mainPackageVersion: string, subpackageLocation: string): Promise<void> {
const subpackageVersion = await getSubpackageVersion(mode, subpackageLocation);
if (subpackageVersion === mainPackageVersion) {
console.error(chalk.yellow(`${BADGE}Subpackage version is already "${mainPackageVersion}".`));
console.error(chalk.yellowBright(`${BADGE}Nothing to do here, since this is the current package version!`));
process.exit(0);
}
}
async function getSubpackageVersion(mode: string, subpackageLocation: string): Promise<string> {
const cwd = process.cwd();
process.chdir(subpackageLocation);
const subpackageVersion = await getPackageVersion(mode);
process.chdir(cwd);
return subpackageVersion;
}
async function getSubpackageName(mode: string, subpackageLocation: string): Promise<string> {
const subpackage = await getSubpackage(mode, subpackageLocation);
switch (mode) {
case PACKAGE_MODE_DOTNET:
const propertyGroup = subpackage?.Project?.PropertyGroup;
const name = Array.isArray(propertyGroup) ? propertyGroup[0]?.Product[0] : null;
if (name == null) {
return subpackageLocation;
}
return name;
case PACKAGE_MODE_NODE:
return subpackage.name;
case PACKAGE_MODE_PYTHON:
return subpackageLocation;
default:
break;
}
}
async function getSubpackage(mode: string, subpackageLocation: string): Promise<any> {
switch (mode) {
case PACKAGE_MODE_DOTNET:
return getSubpackageDotnet(subpackageLocation);
case PACKAGE_MODE_NODE:
return getSubpackageNode(subpackageLocation);
case PACKAGE_MODE_PYTHON:
return null;
default:
throw new Error(`Unknown value for \`mode\`: ${mode}`);
}
}
function getSubpackageNode(subpackageLocation: string): any {
const rawdata = fs.readFileSync(`${subpackageLocation}package.json`).toString();
const packageJson = JSON.parse(rawdata);
return packageJson;
}
async function getSubpackageDotnet(subpackageLocation: string): Promise<any> {
const cwd = process.cwd();
process.chdir(subpackageLocation);
const filename = getCsprojPath();
const json = await getCsprojAsObject(filename);
process.chdir(cwd);
if (json == null) {
throw new Error(`Could not convert csproj to JSON: ${filename}`);
}
return json;
}
function getSubpackageFilename(mode: string, subpackageLocation: string): string {
switch (mode) {
case PACKAGE_MODE_DOTNET:
const cwd = process.cwd();
process.chdir(subpackageLocation);
const filename = getCsprojPath();
process.chdir(cwd);
return filename;
case PACKAGE_MODE_NODE:
return 'package.json';
case PACKAGE_MODE_PYTHON:
return 'setup.py';
default:
break;
}
}
function getSubpackageLocationFromArgs(args): string | undefined {
for (const arg of args) {
console.log(arg);
console.log(existsSync(arg));
if (existsSync(arg)) {
return arg;
}
}
return undefined;
}
function abortIfSubpackageLocationIsMissing(subpackageLocation): void {
if (subpackageLocation == null) {
console.error(chalk.red(`${BADGE}Can not proceed since the subpackage location is missing.`));
process.exit(1);
}
}
function abortIfDryRun(nextVersion: string, isDryRun: boolean, isForced: boolean): void {
if (isDryRun) {
console.log(chalk.yellow(`${BADGE}I would write version ${nextVersion} to package.json.`));
console.log(chalk.yellow(`${BADGE}Aborting due to --dry.`));
if (isForced) {
console.error(chalk.yellow(`${BADGE}Even though --force was provided, --dry takes precedence.`));
}
process.exit(1);
}
}
async function printInfo(mode: string, nextVersion: string, isDryRun: boolean, isForced: boolean): Promise<void> {
const packageVersion = await getPackageVersion(mode);
const packageVersionTag = getVersionTag(packageVersion);
const branchName = getGitBranch();
const gitTagList = getGitTagList();
console.log(`${BADGE}isDryRun:`, isDryRun);
console.log(`${BADGE}isForced:`, isForced);
console.log('');
console.log(`${BADGE}packageVersion:`, packageVersion);
console.log(`${BADGE}packageVersionTag:`, packageVersionTag);
console.log(`${BADGE}branchName:`, branchName);
console.log(`${BADGE}gitTagList:`);
printMultiLineString(gitTagList);
console.log(`${BADGE}tagsForHEAD:`);
printMultiLineString(getGitTagsFromCommit('HEAD'));
console.log(`${BADGE}nextVersionTag:`, getVersionTag(nextVersion));
console.log('');
}