release-please
Version:
generate release PRs based on the conventionalcommits.org spec
186 lines • 8.06 kB
JavaScript
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.Generic = exports.DEFAULT_DATE_FORMAT = void 0;
const default_1 = require("./default");
const logger_1 = require("../util/logger");
const VERSION_REGEX = /(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(-(?<preRelease>[\w.]+))?(\+(?<build>[-\w.]+))?/;
const SINGLE_VERSION_REGEX = /\b\d+\b/;
const INLINE_UPDATE_REGEX = /x-release-please-(?<scope>major|minor|patch|version-date|version|date)/;
const BLOCK_START_REGEX = /x-release-please-start-(?<scope>major|minor|patch|version-date|version|date)/;
const BLOCK_END_REGEX = /x-release-please-end/;
const DATE_FORMAT_REGEX = /%[Ymd]/g;
exports.DEFAULT_DATE_FORMAT = '%Y-%m-%d';
/**
* The Generic updater looks for well known patterns and replaces
* content. The well known patterns are:
*
* 1. `x-release-please-version` if this string is found on the line,
* then replace a semver-looking string on that line with the next
* version
* 2. `x-release-please-major` if this string is found on the line,
* then replace an integer looking value with the next version's
* major
* 3. `x-release-please-minor` if this string is found on the line,
* then replace an integer looking value with the next version's
* minor
* 4. `x-release-please-patch` if this string is found on the line,
* then replace an integer looking value with the next version's
* patch
* 5. `x-release-please-date` if this string is found on the line,
* then replace the date with the date of the last commit
* 6. `x-release-please-version-date` if this string is found on the line,
* then replace the both date and version
*
* You can also use a block-based replacement. Content between the
* opening `x-release-please-start-version` and `x-release-please-end` will
* be considered for version replacement. You can also open these blocks
* with `x-release-please-start-<major|minor|patch|version-date>` to replace
* single numbers
*/
class Generic extends default_1.DefaultUpdater {
constructor(options) {
var _a, _b, _c, _d, _e;
super(options);
this.inlineUpdateRegex = (_a = options.inlineUpdateRegex) !== null && _a !== void 0 ? _a : INLINE_UPDATE_REGEX;
this.blockStartRegex = (_b = options.blockStartRegex) !== null && _b !== void 0 ? _b : BLOCK_START_REGEX;
this.blockEndRegex = (_c = options.blockEndRegex) !== null && _c !== void 0 ? _c : BLOCK_END_REGEX;
this.date = (_d = options.date) !== null && _d !== void 0 ? _d : new Date();
this.dateFormat = (_e = options.dateFormat) !== null && _e !== void 0 ? _e : exports.DEFAULT_DATE_FORMAT;
}
/**
* Given initial file contents, return updated contents.
* @param {string} content The initial content
* @returns {string} The updated content
*/
updateContent(content, logger = logger_1.logger) {
if (!content) {
return '';
}
const newLines = [];
let blockScope;
function replaceVersion(line, scope, version, date, dateFormat) {
const dateRegex = createDateRegex(dateFormat);
const formattedDate = formatDate(dateFormat, date);
switch (scope) {
case 'date':
if (isValidDate(formattedDate, dateFormat)) {
newLines.push(line.replace(dateRegex, formattedDate));
}
else {
logger.warn(`Invalid date format: ${formattedDate}`);
newLines.push(line);
}
return;
case 'version-date':
if (isValidDate(formattedDate, dateFormat)) {
line = line.replace(dateRegex, formattedDate);
}
else {
logger.warn(`Invalid date format: ${formattedDate}`);
}
newLines.push(line.replace(VERSION_REGEX, version.toString()));
return;
case 'major':
newLines.push(line.replace(SINGLE_VERSION_REGEX, `${version.major}`));
return;
case 'minor':
newLines.push(line.replace(SINGLE_VERSION_REGEX, `${version.minor}`));
return;
case 'patch':
newLines.push(line.replace(SINGLE_VERSION_REGEX, `${version.patch}`));
return;
case 'version':
newLines.push(line.replace(VERSION_REGEX, version.toString()));
return;
default:
logger.warn(`unknown block scope: ${scope}`);
newLines.push(line);
}
}
content.split(/\r?\n/).forEach(line => {
var _a, _b;
let match = line.match(this.inlineUpdateRegex);
if (match) {
// replace inline versions
replaceVersion(line, (((_a = match.groups) === null || _a === void 0 ? void 0 : _a.scope) || 'version'), this.version, this.date, this.dateFormat);
}
else if (blockScope) {
// in a block, so try to replace versions
replaceVersion(line, blockScope, this.version, this.date, this.dateFormat);
if (line.match(this.blockEndRegex)) {
blockScope = undefined;
}
}
else {
// look for block start line
match = line.match(this.blockStartRegex);
if (match) {
if ((_b = match.groups) === null || _b === void 0 ? void 0 : _b.scope) {
blockScope = match.groups.scope;
}
else {
blockScope = 'version';
}
}
newLines.push(line);
}
});
return newLines.join('\n');
}
}
exports.Generic = Generic;
function createDateRegex(format) {
const regexString = format.replace(DATE_FORMAT_REGEX, match => {
switch (match) {
case '%Y':
return '(\\d{4})';
case '%m':
return '(\\d{2})';
case '%d':
return '(\\d{2})';
default:
return match;
}
});
return new RegExp(regexString);
}
function formatDate(format, date) {
return format.replace(DATE_FORMAT_REGEX, match => {
switch (match) {
case '%Y':
return date.getFullYear().toString();
case '%m':
return ('0' + (date.getMonth() + 1)).slice(-2);
case '%d':
return ('0' + date.getDate()).slice(-2);
default:
return match;
}
});
}
function isValidDate(dateString, format) {
const dateParts = dateString.match(/\d+/g);
if (!dateParts)
return false;
const year = parseInt(dateParts[format.indexOf('%Y') / 3], 10);
const month = parseInt(dateParts[format.indexOf('%m') / 3], 10);
const day = parseInt(dateParts[format.indexOf('%d') / 3], 10);
if (year < 1 || month < 1 || month > 12 || day < 1 || day > 31)
return false;
const daysInMonth = new Date(year, month, 0).getDate();
return day <= daysInMonth;
}
//# sourceMappingURL=generic.js.map
;