Skip to content

Commit

Permalink
feat: Add new option for appending a build suffix to prereleases
Browse files Browse the repository at this point in the history
  • Loading branch information
adambullmer authored and JTeeuwissen committed Feb 15, 2024
1 parent fd99438 commit c4b7d86
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 5 deletions.
1 change: 1 addition & 0 deletions cli.js
Expand Up @@ -37,6 +37,7 @@ Usage:
.option("debug", { describe: "Output debugging information", type: "boolean", group: "Options" })
.option("d", { alias: "dry-run", describe: "Skip publishing", type: "boolean", group: "Options" })
.option("h", { alias: "help", group: "Options" })
.option("prerelease-build-format", {describe: "Prerelease build number format", type: "string", group: "Options"})
.strict(false)
.exitProcess(false);

Expand Down
19 changes: 19 additions & 0 deletions docs/usage/configuration.md
Expand Up @@ -115,6 +115,25 @@ The [Git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) format used by

**Note**: The `tagFormat` must contain the `version` variable exactly once and compile to a [valid Git reference](https://git-scm.com/docs/git-check-ref-format#_description).

### prereleaseBuildFormat

Type: `String`<br>
Default: `undefined`<br>
CLI arguments: `--prerelease-build-format`

The format used by **semantic-release** when appending prerelease build information after the auto increment prerelease number. If left unspecified, no build information will be appended, otherwise the parsed value of this formatter will be appended after a `+` in the resulting version, so there is no need to add one yourself. Using this option is useful if you want extra insight into which version of the project has been released, or if you need to avoid tag conflicts caused by more complex git workflows, like ones that utilize history rewrites. The build number is generated with [Lodash template](https://lodash.com/docs#template) and will be compiled with the following variables.

- `commit` The current commit hash. Can use `commit.substr(0,7)` to use the short hash.
- `build` The current CI build number. This is useful when you need atomically increasing build numbers.

**Examples**:

| Previous Version | Prerelease Build Format | Branch | Commit Sha | Result |
| ---------------------- | ----------------------- | ------- | ---------- | ----------------------- |
| `1.1.3` | `${commit}` | `alpha` | `1a2b3c4` | `1.2.3-alpha.1+1a2b3c4` |
| `1.2.3-alpha.1+abcdef` | `${commit}` | `alpha` | `4d5e6f7` | `1.2.3-alpha.2+4d5e6f7` |
| `1.1.3` | | `alpha` | `1a2b3c4` | `1.2.3-alpha.1` |

### plugins

Type: `Array`<br>
Expand Down
1 change: 1 addition & 0 deletions index.js
Expand Up @@ -182,6 +182,7 @@ async function run(context, plugins) {
}

context.nextRelease = nextRelease;
context.prereleaseBuildFormat = options.prereleaseBuildFormat;
nextRelease.version = getNextVersion(context);
nextRelease.gitTag = makeTag(options.tagFormat, nextRelease.version);
nextRelease.name = nextRelease.gitTag;
Expand Down
20 changes: 16 additions & 4 deletions lib/get-next-version.js
@@ -1,8 +1,16 @@
import semver from "semver";
const {template} = require('lodash');
import { FIRST_RELEASE, FIRSTPRERELEASE } from "./definitions/constants.js";
import { getLatestVersion, highest, isSameChannel, tagsToVersions } from "./utils.js";

export default ({ branch, nextRelease: { type, channel }, lastRelease, logger }) => {
module.exports = ({
branch,
envCi: {commit, build},
nextRelease: {type, channel},
lastRelease,
logger,
prereleaseBuildFormat
}) => {
let version;
if (lastRelease.version) {
const { major, minor, patch } = semver.parse(lastRelease.version);
Expand All @@ -24,12 +32,16 @@ export default ({ branch, nextRelease: { type, channel }, lastRelease, logger })
} else {
version = semver.inc(lastRelease.version, type);
}

logger.log("The next release version is %s", version);
} else {
version = branch.type === "prerelease" ? `${FIRST_RELEASE}-${branch.prerelease}.${FIRSTPRERELEASE}` : FIRST_RELEASE;
logger.log(`There is no previous release, the next release version is ${version}`);
logger.log("There is no previous release");
}

if (branch.type === "prerelease" && prereleaseBuildFormat) {
version += `+${template(prereleaseBuildFormat)({build, commit})}`;
}

logger.log('The next release version is %s', version);

return version;
};
75 changes: 75 additions & 0 deletions test/get-next-version.test.js
Expand Up @@ -12,6 +12,7 @@ test("Increase version for patch release", (t) => {
t.is(
getNextVersion({
branch: { name: "master", type: "release", tags: [{ gitTag: "v1.0.0", version: "1.0.0", channels: [null] }] },
envCi: {},
nextRelease: { type: "patch" },
lastRelease: { version: "1.0.0", channels: [null] },
logger: t.context.logger,
Expand All @@ -24,6 +25,7 @@ test("Increase version for minor release", (t) => {
t.is(
getNextVersion({
branch: { name: "master", type: "release", tags: [{ gitTag: "v1.0.0", version: "1.0.0", channels: [null] }] },
envCi: {},
nextRelease: { type: "minor" },
lastRelease: { version: "1.0.0", channels: [null] },
logger: t.context.logger,
Expand All @@ -36,6 +38,7 @@ test("Increase version for major release", (t) => {
t.is(
getNextVersion({
branch: { name: "master", type: "release", tags: [{ gitTag: "v1.0.0", version: "1.0.0", channels: [null] }] },
envCi: {},
nextRelease: { type: "major" },
lastRelease: { version: "1.0.0", channels: [null] },
logger: t.context.logger,
Expand All @@ -48,6 +51,7 @@ test("Return 1.0.0 if there is no previous release", (t) => {
t.is(
getNextVersion({
branch: { name: "master", type: "release", tags: [] },
envCi: {},
nextRelease: { type: "minor" },
lastRelease: {},
logger: t.context.logger,
Expand All @@ -65,6 +69,7 @@ test("Increase version for patch release on prerelease branch", (t) => {
prerelease: "beta",
tags: [{ gitTag: "v1.0.0", version: "1.0.0", channels: [null] }],
},
envCi: {},
nextRelease: { type: "patch", channel: "beta" },
lastRelease: { version: "1.0.0", channels: [null] },
logger: t.context.logger,
Expand All @@ -83,6 +88,7 @@ test("Increase version for patch release on prerelease branch", (t) => {
{ gitTag: "v1.0.1-beta.1", version: "1.0.1-beta.1", channels: ["beta"] },
],
},
envCi: {},
nextRelease: { type: "patch", channel: "beta" },
lastRelease: { version: "1.0.1-beta.1", channels: ["beta"] },
logger: t.context.logger,
Expand All @@ -98,6 +104,7 @@ test("Increase version for patch release on prerelease branch", (t) => {
prerelease: "alpha",
tags: [{ gitTag: "v1.0.1-beta.1", version: "1.0.1-beta.1", channels: ["beta"] }],
},
envCi: {},
nextRelease: { type: "patch", channel: "alpha" },
lastRelease: { version: "1.0.1-beta.1", channels: ["beta"] },
logger: t.context.logger,
Expand All @@ -115,6 +122,7 @@ test("Increase version for minor release on prerelease branch", (t) => {
prerelease: "beta",
tags: [{ gitTag: "v1.0.0", version: "1.0.0", channels: [null] }],
},
envCi: {},
nextRelease: { type: "minor", channel: "beta" },
lastRelease: { version: "1.0.0", channels: [null] },
logger: t.context.logger,
Expand All @@ -133,6 +141,7 @@ test("Increase version for minor release on prerelease branch", (t) => {
{ gitTag: "v1.1.0-beta.1", version: "1.1.0-beta.1", channels: ["beta"] },
],
},
envCi: {},
nextRelease: { type: "minor", channel: "beta" },
lastRelease: { version: "1.1.0-beta.1", channels: ["beta"] },
logger: t.context.logger,
Expand All @@ -148,6 +157,7 @@ test("Increase version for minor release on prerelease branch", (t) => {
prerelease: "alpha",
tags: [{ gitTag: "v1.1.0-beta.1", version: "1.1.0-beta.1", channels: ["beta"] }],
},
envCi: {},
nextRelease: { type: "minor", channel: "alpha" },
lastRelease: { version: "1.1.0-beta.1", channels: ["beta"] },
logger: t.context.logger,
Expand All @@ -165,6 +175,7 @@ test("Increase version for major release on prerelease branch", (t) => {
prerelease: "beta",
tags: [{ gitTag: "v1.0.0", version: "1.0.0", channels: [null] }],
},
envCi: {},
nextRelease: { type: "major", channel: "beta" },
lastRelease: { version: "1.0.0", channels: [null] },
logger: t.context.logger,
Expand All @@ -183,6 +194,7 @@ test("Increase version for major release on prerelease branch", (t) => {
{ gitTag: "v2.0.0-beta.1", version: "2.0.0-beta.1", channels: ["beta"] },
],
},
envCi: {},
nextRelease: { type: "major", channel: "beta" },
lastRelease: { version: "2.0.0-beta.1", channels: ["beta"] },
logger: t.context.logger,
Expand All @@ -198,6 +210,7 @@ test("Increase version for major release on prerelease branch", (t) => {
prerelease: "alpha",
tags: [{ gitTag: "v2.0.0-beta.1", version: "2.0.0-beta.1", channels: ["beta"] }],
},
envCi: {},
nextRelease: { type: "major", channel: "alpha" },
lastRelease: { version: "2.0.0-beta.1", channels: ["beta"] },
logger: t.context.logger,
Expand All @@ -210,6 +223,7 @@ test("Return 1.0.0 if there is no previous release on prerelease branch", (t) =>
t.is(
getNextVersion({
branch: { name: "beta", type: "prerelease", prerelease: "beta", tags: [] },
envCi: {},
nextRelease: { type: "minor" },
lastRelease: {},
logger: t.context.logger,
Expand All @@ -231,6 +245,7 @@ test("Increase version for release on prerelease branch after previous commits w
{ gitTag: "v1.1.0-beta.1", version: "1.1.0-beta.1", channels: [null, "beta"] },
],
},
envCi: {},
nextRelease: { type: "minor" },
lastRelease: { version: "1.1.0", channels: [null] },
logger: t.context.logger,
Expand All @@ -251,6 +266,7 @@ test("Increase version for release on prerelease branch based on highest commit
{ gitTag: "v1.1.0-beta.1", version: "1.1.0-beta.1", channels: [null, "beta"] },
],
},
envCi: {},
nextRelease: { type: "major" },
lastRelease: { version: "v1.1.0-beta.1", channels: [null] },
logger: t.context.logger,
Expand All @@ -268,6 +284,7 @@ test("Increase version for release on prerelease branch when there is no regular
prerelease: "beta",
tags: [{ gitTag: "v1.0.0-beta.1", version: "1.0.0-beta.1", channels: ["beta"] }],
},
envCi: {},
nextRelease: { type: "minor", channel: "beta" },
lastRelease: { version: "v1.0.0-beta.1", channels: ["beta"] },
logger: t.context.logger,
Expand All @@ -289,10 +306,68 @@ test("Increase patch when previous version shares HEAD with other releases", (t)
{ gitTag: "v1.0.0-alpha.1", version: "1.0.0-alpha.1", channels: ["alpha", "beta"] },
],
},
envCi: {},
nextRelease: { type: "patch", channel: "alpha" },
lastRelease: { version: "v1.0.0-alpha.1", channels: ["alpha", "beta"] },
logger: t.context.logger,
}),
"1.0.0-alpha.2"
);
});

test("Append commit build number to prerelease version", (t) => {
t.is(
getNextVersion({
branch: {
name: "beta",
type: "prerelease",
prerelease: "beta",
tags: [{gitTag: "v1.0.0", version: "1.0.0", channels: [null]}],
},
envCi: {commit: "1a2b3c4", build: "1234"},
nextRelease: {type: "minor"},
lastRelease: {version: "1.0.0", channels: [null]},
logger: t.context.logger,
prereleaseBuildFormat: `\${commit}`,
}),
"1.1.0-beta.1+1a2b3c4"
);
});

test("Append CI build number to prerelease version", (t) => {
t.is(
getNextVersion({
branch: {
name: "beta",
type: "prerelease",
prerelease: "beta",
tags: [{gitTag: "v1.0.0", version: "1.0.0", channels: [null]}],
},
envCi: {commit: "1a2b3c4", build: "1234"},
nextRelease: {type: "minor"},
lastRelease: {version: "1.0.0", channels: [null]},
logger: t.context.logger,
prereleaseBuildFormat: `\${build}`,
}),
"1.1.0-beta.1+1234"
);
});

test("Append new commit build number to next prerelease version", (t) => {
t.is(
getNextVersion({
branch: {
name: "beta",
type: "prerelease",
prerelease: "beta",
tags: [{gitTag: "v1.1.0-beta.1+1a2b3c4", version: "1.1.0-beta.1+1a2b3c4", channels: ["beta"]}],
},
envCi: {commit: "4d5e6f7", build: "1234"},
nextRelease: {type: "minor", channel: "beta"},
lastRelease: {version: "v1.1.0-beta.1+1a2b3c4", channels: ["beta"]},
logger: t.context.logger,
prereleaseBuildFormat: `\${commit}`,
}),
"1.1.0-beta.2+4d5e6f7"
);
});
3 changes: 2 additions & 1 deletion test/integration.test.js
Expand Up @@ -398,7 +398,8 @@ test("Dry-run", async (t) => {
await gitCommits(["feat: Initial commit"], { cwd });
t.log("$ semantic-release -d");
const { stdout, exitCode } = await execa(cli, ["-d"], { env, cwd, extendEnv: false });
t.regex(stdout, new RegExp(`There is no previous release, the next release version is ${version}`));
t.regex(stdout, /There is no previous release/);
t.regex(stdout, new RegExp(`The next release version is ${version}`));
t.regex(stdout, new RegExp(`Release note for version ${version}`));
t.regex(stdout, /Initial commit/);
t.is(exitCode, 0);
Expand Down

0 comments on commit c4b7d86

Please sign in to comment.