bash.origin.lib
Version:
bash.origin.lib ===============
277 lines (196 loc) • 10.3 kB
JavaScript
exports.inf = async function (INF, ALIAS) {
const NCU = require('npm-check-updates');
const SEMVER = require('semver');
const SIMPLE_GIT = require('simple-git');
// @see https://github.com/steveukx/git-js
const repository = SIMPLE_GIT(__dirname);
INF.LIB.Promise.promisifyAll(repository);
const packsPath = INF.LIB.PATH.join(__dirname, 'packs');
const packNames = await INF.LIB.FS.readdirAsync(packsPath);
function makeVersionIncrementer () {
const segmentChanged = {
"major": false,
"minor": false,
"patch": false,
"prerelease": false
};
return {
check: function (beforeVersion, afterVersion) {
if (SEMVER.major(beforeVersion) !== SEMVER.major(afterVersion)) {
segmentChanged.major = true;
} else
if (SEMVER.minor(beforeVersion) !== SEMVER.minor(afterVersion)) {
segmentChanged.minor = true;
} else
if (SEMVER.patch(beforeVersion) !== SEMVER.patch(afterVersion)) {
segmentChanged.patch = true;
} else
if (JSON.stringify(SEMVER.prerelease(beforeVersion)) !== JSON.stringify(SEMVER.prerelease(afterVersion))) {
segmentChanged.prerelease = true;
}
},
incrementVersion: function (version) {
if (segmentChanged.major) {
version = SEMVER.inc(version, "major");
} else
if (segmentChanged.minor) {
version = SEMVER.inc(version, "minor");
} else
if (
segmentChanged.patch ||
segmentChanged.prerelease
) {
version = SEMVER.inc(version, "patch");
}
return version;
}
};
}
async function updatePackage (basePath) {
const descriptorPath = INF.LIB.PATH.join(basePath, 'package.json');
const descriptorBefore = await INF.LIB.FS.readJSONAsync(descriptorPath);
// @see https://github.com/tjunnone/npm-check-updates
await NCU.run({
upgrade: true,
packageFile: descriptorPath
});
const descriptorAfter = await INF.LIB.FS.readJSONAsync(descriptorPath);
const versionIncrementer = makeVersionIncrementer();
[
'dependencies',
'devDependencies'
].forEach(function (type) {
if (!descriptorBefore[type]) {
return;
}
Object.keys(descriptorBefore[type]).forEach(function (name) {
if (descriptorBefore[type][name] === descriptorAfter[type][name]) {
// no change
return;
}
const beforeVersion = SEMVER.coerce(descriptorBefore[type][name]).version;
const afterVersion = SEMVER.coerce(descriptorAfter[type][name]).version;
console.log(`[bash.origin.lib] Package version selector '${name}' has changed from '${descriptorBefore[type][name]}' to '${descriptorAfter[type][name]}'`);
versionIncrementer.check(beforeVersion, afterVersion);
});
});
let version = versionIncrementer.incrementVersion(descriptorAfter.version);
if (version === descriptorAfter.version) {
return;
}
console.log(`[bash.origin.lib] Declaring package version has been incremented from '${descriptorAfter.version}' to '${version}'`);
descriptorAfter.version = version;
await INF.LIB.FS.outputFileAsync(descriptorPath, JSON.stringify(descriptorAfter, null, 2) + "\n", "utf8");
return version;
}
async function commitIfChanged (filepath, message) {
await repository.addAsync(filepath);
if ((await repository.statusAsync()).staged.indexOf(filepath) === -1) {
return;
}
console.log(`[bash.origin.lib] Committing changes to '${filepath}'`);
await repository.commitAsync(message);
}
async function savePackageDescriptorTagAndPush (version) {
let versionMatch = version.match(/^([0-9\.]+)(-pre\.\d+)?$/);
await commitIfChanged(`package.json`, `Bumped 'bash.origin.lib' package version to '${version}'`);
await repository.addTagAsync(`v${version}`);
console.log("[bash.origin.lib] Pushing changes to git origin ...");
await repository.pushAsync("origin", "master");
await repository.pushTagsAsync("origin");
console.log("[bash.origin.lib] Publishing npm package ...");
await new Promise(function (resolve, reject) {
const args = [
'publish'
];
if (versionMatch[2]) {
args.push('--tag', 'pre');
}
const proc = INF.LIB.CHILD_PROCESS.spawn('npm', args, {
cwd: __dirname,
stdio: 'inherit'
});
proc.on('close', (code) => {
// TODO: Retry on error?
if (code != 0) return reject(new Error(`There was an error while running 'npm publish' at '${__dirname}'!`));
resolve();
});
});
}
return {
invoke: async function (pointer, value) {
if (pointer === "run()") {
if (value.value === "update") {
if ((await repository.statusAsync()).modified.length) {
throw new Error("Cannot update as there are modified files in git! Commit modifications first.");
}
console.log("[bash.origin.lib] Updating bash.origin.lib package ...");
const version = await updatePackage(__dirname);
await commitIfChanged("package.json", `Bumped 'bash.origin.lib' package version to '${version}'`);
console.log("[bash.origin.lib] Updating packs ...");
await INF.LIB.Promise.mapSeries(packNames, async function (packName) {
console.log(`[bash.origin.lib] Updating packages for pack '${packName}' ...`);
const version = await updatePackage(INF.LIB.PATH.join(packsPath, packName));
await commitIfChanged(`packs/${packName}/package.json`, `Bumped '${packName}' pack version to '${version}'`);
});
} else
if (value.value === "release-preview") {
if ((await repository.statusAsync()).modified.length) {
throw new Error("Cannot release preview as there are modified files in git! Commit modifications first.");
}
const versionIncrementer = makeVersionIncrementer();
const latestTag = (await repository.tagsAsync()).latest;
await INF.LIB.Promise.mapSeries(packNames, async function (packName) {
versionIncrementer.check(
JSON.parse(await repository.showAsync([`${latestTag}:packs/${packName}/package.json`])).version,
JSON.parse(await repository.showAsync([`master:packs/${packName}/package.json`])).version
);
});
const descriptorPath = INF.LIB.PATH.join(__dirname, 'package.json');
const descriptor = await INF.LIB.FS.readJSONAsync(descriptorPath);
let versionMatch = descriptor.version.match(/^([0-9\.]+)(-pre\.\d+)?$/);
let version = versionIncrementer.incrementVersion(versionMatch[1]);
if (
version === versionMatch[1] &&
versionMatch[2]
) {
version = SEMVER.inc(`${version}${versionMatch[2]}`, "prerelease");
} else
if (version === versionMatch[1]) {
version = SEMVER.inc(version, "patch");
version += "-pre.0";
} else
if (versionMatch[2]) {
version += "-pre.0";
}
descriptor.version = version;
await INF.LIB.FS.outputFileAsync(descriptorPath, JSON.stringify(descriptor, null, 2) + "\n", "utf8");
await savePackageDescriptorTagAndPush(descriptor.version);
return true;
} else
if (value.value === "release-to-all") {
if ((await repository.statusAsync()).modified.length) {
throw new Error("Cannot release as there are modified files in git! Commit modifications first.");
}
const latestTag = (await repository.tagsAsync()).latest;
const latestTagHash = (await repository.revparseAsync([latestTag]));
const masterHash = (await repository.revparseAsync(["master"]));
if (latestTagHash !== masterHash) {
throw new Error("Cannot release. The last commit is not a release preview! Create one first.");
}
const descriptorPath = INF.LIB.PATH.join(__dirname, 'package.json');
const descriptor = await INF.LIB.FS.readJSONAsync(descriptorPath);
let versionMatch = descriptor.version.match(/^([0-9\.]+)(-pre\.\d+)?$/);
if (!versionMatch[2]) {
throw new Error("Cannot release. The last commit is already a release! Create a new release preview first.");
}
descriptor.version = versionMatch[1];
await INF.LIB.FS.outputFileAsync(descriptorPath, JSON.stringify(descriptor, null, 2) + "\n", "utf8");
await savePackageDescriptorTagAndPush(descriptor.version);
return true;
}
return true;
}
}
};
}