mirror of
https://github.com/locomotivemtl/locomotive-boilerplate.git
synced 2026-01-15 00:55:08 +08:00
Improve asset versioning task
Add support for "increment" format to increment an integer version number with support for "increment:semver" to increment the build or patch of a SemVer version number.
Usage:
```json
"versions": [
{
"format": "increment",
"key": "version",
"outfile": "assets.json"
}
]
```
```jsonc
{
"version": 16 // → 17
}
```
```json
"versions": [
{
"format": "increment:semver",
"key": "version",
"outfile": "assets.json"
}
]
```
```jsonc
{
"version": "1.0.0" // → 1.0.1
}
```
```jsonc
{
"version": "1.0.0+1" // → 1.0.0+2
}
```
This commit is contained in:
@@ -21,6 +21,8 @@ import {
|
||||
} from 'node:path';
|
||||
import readline from 'node:readline';
|
||||
|
||||
export const REGEXP_SEMVER = /^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
||||
|
||||
/**
|
||||
* @typedef {object} VersionOptions
|
||||
* @property {string|number|null} prettyPrint - A string or number to insert
|
||||
@@ -135,32 +137,64 @@ export default async function bumpVersions(versionOptions = null) {
|
||||
/**
|
||||
* Creates a formatted version number or string.
|
||||
*
|
||||
* @param {string} format - The version format.
|
||||
* @param {string} format - The version format.
|
||||
* @param {?string} [oldValue] - The old version value.
|
||||
* @return {string|number}
|
||||
* @throws TypeError If the format or value are invalid.
|
||||
*/
|
||||
function createVersionNumber(format) {
|
||||
function createVersionNumber(format, oldValue = null) {
|
||||
let [ type, modifier ] = format.split(':', 2);
|
||||
|
||||
switch (type) {
|
||||
case 'hex':
|
||||
case 'hexadecimal':
|
||||
modifier = Number.parseInt(modifier);
|
||||
try {
|
||||
modifier = Number.parseInt(modifier);
|
||||
|
||||
if (Number.isNaN(modifier)) {
|
||||
modifier = 6;
|
||||
if (Number.isNaN(modifier)) {
|
||||
modifier = 6;
|
||||
}
|
||||
|
||||
return randomBytes(modifier).toString('hex');
|
||||
} catch (err) {
|
||||
throw new TypeError(
|
||||
`${err.message} for \'format\' type "hexadecimal"`,
|
||||
{ cause: err }
|
||||
);
|
||||
}
|
||||
|
||||
return randomBytes(modifier).toString('hex');
|
||||
case 'inc':
|
||||
case 'increment':
|
||||
try {
|
||||
if (modifier === 'semver') {
|
||||
return incrementSemVer(oldValue, [ 'buildmetadata', 'patch' ]);
|
||||
}
|
||||
|
||||
return incrementNumber(oldValue, modifier);
|
||||
} catch (err) {
|
||||
throw new TypeError(
|
||||
`${err.message} for \'format\' type "increment"`,
|
||||
{ cause: err }
|
||||
);
|
||||
}
|
||||
|
||||
case 'regex':
|
||||
return new RegExp(modifier);
|
||||
case 'regexp':
|
||||
try {
|
||||
return new RegExp(modifier);
|
||||
} catch (err) {
|
||||
throw new TypeError(
|
||||
`${err.message} for \'format\' type "regexp"`,
|
||||
{ cause: err }
|
||||
);
|
||||
}
|
||||
|
||||
case 'timestamp':
|
||||
return Date.now().valueOf();
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
'Expected \'format\' to be either "timestamp" or "hexadecimal"'
|
||||
'Expected \'format\' to be either "timestamp", "increment", or "hexadecimal"'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -221,9 +255,7 @@ async function handleBumpVersionInJson(outfile, label, options) {
|
||||
await mkdir(dirname(outfile), { recursive: true });
|
||||
}
|
||||
|
||||
const version = createVersionNumber(options.format);
|
||||
|
||||
json[options.key] = version;
|
||||
json[options.key] = createVersionNumber(options.format, json?.[options.key]);
|
||||
|
||||
return await writeFile(
|
||||
outfile,
|
||||
@@ -254,7 +286,7 @@ async function handleBumpVersionWithRegExp(outfile, label, options) {
|
||||
input: createReadStream(bckfile),
|
||||
});
|
||||
|
||||
const version = createVersionNumber(options.format);
|
||||
let newVersion = null;
|
||||
|
||||
const writeStream = createWriteStream(outfile, { encoding: 'utf8' });
|
||||
|
||||
@@ -262,12 +294,12 @@ async function handleBumpVersionWithRegExp(outfile, label, options) {
|
||||
const found = line.match(options.key);
|
||||
|
||||
if (found) {
|
||||
const groups = (found.groups ?? {});
|
||||
const replace = found[0].replace(
|
||||
(groups.build ?? groups.version ?? found[1] ?? found[0]),
|
||||
version
|
||||
);
|
||||
line = line.replace(found[0], replace);
|
||||
const groups = (found.groups ?? {});
|
||||
const oldVersion = (groups.build ?? groups.version ?? found[1] ?? found[0]);
|
||||
const newVersion = createVersionNumber(options.format, oldVersion);
|
||||
const replacement = found[0].replace(oldVersion, newVersion);
|
||||
|
||||
line = line.replace(found[0], replacement);
|
||||
}
|
||||
|
||||
writeStream.write(line + "\n");
|
||||
@@ -285,6 +317,88 @@ async function handleBumpVersionWithRegExp(outfile, label, options) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the given integer.
|
||||
*
|
||||
* @param {string|int} value - The number to increment.
|
||||
* @param {string|int} [increment=1] - The amount to increment by.
|
||||
* @return {int}
|
||||
* @throws TypeError If the version number is invalid.
|
||||
*/
|
||||
function incrementNumber(value, increment = 1) {
|
||||
const version = Number.parseInt(value);
|
||||
if (Number.isNaN(version)) {
|
||||
throw new TypeError(
|
||||
`Expected an integer version number, received [${value}]`
|
||||
);
|
||||
}
|
||||
|
||||
increment = Number.parseInt(increment);
|
||||
if (Number.isNaN(increment)) {
|
||||
throw new TypeError(
|
||||
'Expected an integer increment number'
|
||||
);
|
||||
}
|
||||
|
||||
return (version + increment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the given SemVer version number.
|
||||
*
|
||||
* @param {string} value - The version to mutate.
|
||||
* @param {string|string[]} [target] - The segment to increment, one of:
|
||||
* 'major', 'minor', 'patch', ~~'prerelease'~~, 'buildmetadata'.
|
||||
* @param {string|int} [increment=1] - The amount to increment by.
|
||||
* @return {string}
|
||||
* @throws TypeError If the version or target are invalid.
|
||||
*/
|
||||
function incrementSemVer(value, target = 'patch', increment = 1) {
|
||||
const found = value.match(REGEXP_SEMVER);
|
||||
if (!found) {
|
||||
throw new TypeError(
|
||||
`Expected a SemVer version number, received [${value}]`
|
||||
);
|
||||
}
|
||||
|
||||
if (Array.isArray(target)) {
|
||||
for (const group of target) {
|
||||
if (found.groups[group] != null) {
|
||||
target = group;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!target || !found.groups[target]) {
|
||||
throw new TypeError(
|
||||
`Expected a supported SemVer segment, received [${target}]`
|
||||
);
|
||||
}
|
||||
|
||||
const segments = {
|
||||
'major': '',
|
||||
'minor': '.',
|
||||
'patch': '.',
|
||||
'prerelease': '-',
|
||||
'buildmetadata': '+',
|
||||
};
|
||||
|
||||
let replacement = '';
|
||||
|
||||
for (const [ segment, delimiter ] of Object.entries(segments)) {
|
||||
if (found.groups?.[segment] != null) {
|
||||
const newVersion = (segment === target)
|
||||
? incrementNumber(found.groups[segment], increment)
|
||||
: found.groups[segment];
|
||||
|
||||
replacement += `${delimiter}${newVersion}`;
|
||||
}
|
||||
}
|
||||
|
||||
return value.replace(found[0], replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the version key.
|
||||
*
|
||||
|
||||
@@ -338,8 +338,8 @@ See [`svgs.js`](../build/tasks/svgs.js) for details.
|
||||
|
||||
A task to create and update values for use in versioning assets.
|
||||
|
||||
Can generate a hexadecimal value (using random bytes) or
|
||||
use the current timestamp.
|
||||
Can generate a hexadecimal value (using random bytes), use the current timestamp,
|
||||
or increment a number.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -355,6 +355,11 @@ Example:
|
||||
"format": "hex:8",
|
||||
"key": "hex",
|
||||
"outfile": "./assets.json"
|
||||
},
|
||||
{
|
||||
"format": "inc:semver",
|
||||
"key": "inc",
|
||||
"outfile": "./assets.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -363,7 +368,8 @@ Example:
|
||||
```json
|
||||
{
|
||||
"now": 1665071717350,
|
||||
"hex": "6ef54181c4ba"
|
||||
"hex": "6ef54181c4ba",
|
||||
"hex": "1.0.2"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user