@theo.gravity/changelog-version
Version:
Creates / updates a changelog with customizable options, including version / timestamp / CI support.
170 lines (136 loc) • 5.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _dateformat = _interopRequireDefault(require("dateformat"));
var _BaseStamper = _interopRequireDefault(require("./BaseStamper"));
var _errors = require("../errors");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const debug = require('debug')('version-stamper');
class VersionStamper extends _BaseStamper.default {
/**
* Finds the unreleased tag in a changelog file and stamps it with the version / time info.
*
* @param {string} [options.packageFile] The relative path to package.json, or a JSON file that
* contains the "version" field from projectRoot. Default is "package.json"
* @param {string} [options.unreleasedTag] The text to find in the changelog which would get
* replaced with the version / time. Defaults to "[UNRELEASED]"
* @param {string} [options.dateFormat] Date mask to use from the "dateformat" library when
* replacing the versionTag. Default is "default".
* @param {string} [options.unreleasedTagFormat] Format to replace unreleasedTag with. Available tags are
* "{version}" and "{date}". Default is '{version} - {date}'
* @param {boolean} [options.requireUnreleasedEntry] If true, will throw an error if the unreleasedTag
* is not found in the changelog content.
* @param {string} [options.requireUnreleasedEntryFailMsg] A custom message to render when
* requireUnreleasedEntry is true and the validation check fails
* @param {function} [options.onBeforeRelease] This is called before doing the version stamping.
* @param {function} [options.onAfterRelease] This is called after the version stamping is complete.
* This function is called with the following params:
* - version: Release version that the changelog stamp used
* - date: Formatted date that the changelog stamp used
* - releaseStamp: Release text that the changelog was stamped with
*/
constructor(options = {}) {
super(options);
this.packageFile = options.packageFile || 'package.json';
this.dateFormat = options.dateFormat || 'default';
this.unreleasedTag = options.unreleasedTag || '[UNRELEASED]';
this.unreleasedTagFormat = options.unreleasedTagFormat || '{version} - {date}';
this.requireUnreleasedEntry = options.requireUnreleasedEntry || false;
this.requireUnreleasedEntryFailMsg = options.requireUnreleasedEntryFailMsg || null;
this.onBeforeRelease = options.onBeforeRelease || function () {};
this.onAfterRelease = options.onAfterRelease || function () {};
}
/**
* - Throws if requireUnreleasedEntry is true and the release tag is not found
* - Reads the packageFile and finds the "version" field
* - Reads the changelogFile file and finds the unreleasedTag
* - Generates the version stamp using unreleasedTagFormat
* - Replaces the specified unreleasedTag with unreleasedTagFormat
* @return {Promise<void>}
*/
async release() {
await this.onBeforeRelease();
const changelogContents = await this._readFileContents(this.changelogFile);
const packageFileContents = await this._readFileContents(this.packageFile);
if (this.requireUnreleasedEntry) {
await this._throwIfReleaseTagNotFound(changelogContents);
}
const date = this._getReleaseDate();
const version = this._getVersion(packageFileContents);
const releaseStamp = this._getReleaseStamp(version, date);
const newChangelogData = this._replaceUnreleasedTag(changelogContents, releaseStamp);
await this._writeChangelog(newChangelogData);
await this.onAfterRelease({
version,
date,
releaseStamp
});
}
/**
* Replaces the specified unreleasedTag in the changelog data with the release stamp.
* @param {string} changelogData The changelog text
* @param {string} releaseStamp The data to replace unreleasedTag with
* @return {string} Updated changelog text with the release stamp
* @private
*/
_replaceUnreleasedTag(changelogData, releaseStamp) {
return changelogData.replace(this.unreleasedTag, releaseStamp);
}
/**
* Returns the formatted release date.
* @returns {string}
* @private
*/
_getReleaseDate() {
return (0, _dateformat.default)(new Date(), this.dateFormat);
}
/**
* Generates the release tag
* @returns {string} The generated tag which will be used to replace unreleasedTag.
* @private
*/
_getReleaseStamp(version, releaseDate) {
let releaseStamp = this.unreleasedTagFormat.replace('{version}', version);
releaseStamp = releaseStamp.replace('{date}', releaseDate);
return releaseStamp;
}
/**
* Given a JSON string, parses it to an object and returns the "version" value from it.
* @param {string} jsonData JSON string containing the "version" field
* @returns {string} The version
* @private
*/
_getVersion(jsonData) {
let obj = null;
try {
obj = JSON.parse(jsonData);
} catch (e) {
debug(e);
throw new Error('Unable to JSON parse the package file data');
}
if (!obj.version) {
throw new Error('Package file data is missing the "version" field.');
}
return obj.version;
}
/**
* Throws if the release tag was not found
* @return {Promise<void>}
*/
async _throwIfReleaseTagNotFound(changelogData) {
if (!changelogData.includes(this.unreleasedTag)) {
throw new _errors.UnreleasedEntryNotFound(this.unreleasedTag, this.requireUnreleasedEntryFailMsg);
}
}
/**
* Throws UnreleasedEntryNotFound if the changelog does not contain the unreleasedTag.
* @return {Promise<void>}
*/
async verify() {
const changelogContents = await this._readFileContents(this.changelogFile);
await this._throwIfReleaseTagNotFound(changelogContents);
}
}
exports.default = VersionStamper;