@frsource/release-it-config
Version:
Release-it configuration files used across the FRSOURCE organization.
94 lines (81 loc) • 2.91 kB
JavaScript
import { Plugin } from 'release-it';
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir, EOL } from 'node:os';
const VERSION_BUMP_INFO_PATH = join(tmpdir(), 'FRSOURCE_VERSION_BUMP');
const docs = 'https://git.io/release-it-git';
const toUnique = (array) => [...new Set(array)];
const flattenDependencies = (infoObj, result = []) => {
if (infoObj?.dependencies) {
for (const [key, internalInfoObj] of Object.entries(infoObj.dependencies)) {
result.push(key);
flattenDependencies(internalInfoObj, result);
}
}
return result;
};
const e = (message, docs, fail = true) => {
const error = new Error(
docs ? `${message}${EOL}Documentation: ${docs}${EOL}` : message,
);
error.code = fail ? 1 : 0;
error.cause = fail ? 'ERROR' : 'INFO';
return error;
};
export default class CrossDepsVersionPlugin extends Plugin {
async getLatestVersion() {
this.log.log('Reading version file from:', VERSION_BUMP_INFO_PATH);
const gitOptions = this.config.getContext()?.git ?? {};
const shouldBeIncremented = await this.shouldBeIncremented();
const commitsSinceLatestTag = await this.getCommitsSinceLatestTag(
gitOptions.commitsPath,
);
// check commit requirement only when package doesn't need to be bumped because of workspace cross-dependencies
if (!shouldBeIncremented && commitsSinceLatestTag === 0) {
throw e(
`There are no commits since the latest tag.`,
docs,
gitOptions.requireCommitsFail,
);
}
}
afterRelease() {
writeFileSync(
VERSION_BUMP_INFO_PATH,
`${this.config.getContext('name')}\n`,
{ flag: 'as' },
);
}
async shouldBeIncremented() {
const recentlyBumpedPackages = this.getRecentlyBumpedPackages();
const workspaceDependencies = await this.getWorkspaceDependencies();
this.debug({ recentlyBumpedPackages, workspaceDependencies });
return workspaceDependencies.some((depName) =>
recentlyBumpedPackages.includes(depName),
);
}
async getWorkspaceDependencies() {
const packageInfoRaw = await this.exec(
'pnpm list --only-projects --depth Infinity --json -P',
{ options: { write: false } },
);
const packageInfo = toUnique(JSON.parse(packageInfoRaw));
return flattenDependencies(packageInfo?.[0]);
}
getRecentlyBumpedPackages() {
if (!existsSync(VERSION_BUMP_INFO_PATH)) return [];
return toUnique(
readFileSync(VERSION_BUMP_INFO_PATH, 'utf-8')
.split('\n')
.slice(1)
.filter(Boolean),
);
}
async getCommitsSinceLatestTag(commitsPath = '') {
const { latestTag } = this.config.getContext();
const ref = latestTag ? `${latestTag}..HEAD` : 'HEAD';
return this.exec(`git rev-list ${ref} --count ${commitsPath}`, {
options: { write: false },
}).then(Number);
}
}