add custom_release_rules and more tests
This commit is contained in:
parent
169b215c7c
commit
158d2b0407
|
@ -28,6 +28,9 @@ inputs:
|
|||
custom_tag:
|
||||
description: "Custom tag name. If specified, it overrides bump settings."
|
||||
required: false
|
||||
custom_release_rules:
|
||||
description: "Comma separated list of release rules. Format: `<keyword>:<release_type>`. Example: `hotfix:patch,pre-feat:preminor`."
|
||||
required: false
|
||||
release_branches:
|
||||
description: "Comma separated list of branches (bash reg exp accepted) that will generate the release tags. Other branches and pull-requests generate versions postfixed with the commit hash and do not generate any tag. Examples: `master` or `.*` or `release.*,hotfix.*,master`..."
|
||||
required: false
|
||||
|
@ -36,11 +39,11 @@ inputs:
|
|||
description: "Comma separated list of branches (bash reg exp accepted) that will generate pre-release tags."
|
||||
required: false
|
||||
create_annotated_tag:
|
||||
description: "Boolean to create an annotated tag rather than lightweight"
|
||||
description: "Boolean to create an annotated tag rather than lightweight."
|
||||
required: false
|
||||
default: "false"
|
||||
dry_run:
|
||||
description: "Do not perform tagging, just calculate next version and changelog, then exit"
|
||||
description: "Do not perform tagging, just calculate next version and changelog, then exit."
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
|
|
80
src/main.ts
80
src/main.ts
|
@ -1,7 +1,7 @@
|
|||
import * as core from "@actions/core";
|
||||
import { gte, inc, parse, ReleaseType, SemVer, valid } from "semver";
|
||||
import { analyzeCommits } from "@semantic-release/commit-analyzer";
|
||||
import { generateNotes } from "@semantic-release/release-notes-generator";
|
||||
import * as core from '@actions/core';
|
||||
import { gte, inc, parse, ReleaseType, SemVer, valid } from 'semver';
|
||||
import { analyzeCommits } from '@semantic-release/commit-analyzer';
|
||||
import { generateNotes } from '@semantic-release/release-notes-generator';
|
||||
import {
|
||||
getBranchFromRef,
|
||||
getCommits,
|
||||
|
@ -9,20 +9,20 @@ import {
|
|||
getLatestTag,
|
||||
getValidTags,
|
||||
mapCustomReleaseRules,
|
||||
} from "./utils";
|
||||
import { createTag } from "./github";
|
||||
} from './utils';
|
||||
import { createTag } from './github';
|
||||
|
||||
export default async () => {
|
||||
try {
|
||||
const defaultBump = core.getInput("default_bump") as ReleaseType | "false";
|
||||
const tagPrefix = core.getInput("tag_prefix");
|
||||
const customTag = core.getInput("custom_tag");
|
||||
const releaseBranches = core.getInput("release_branches");
|
||||
const preReleaseBranches = core.getInput("pre_release_branches");
|
||||
const appendToPreReleaseTag = core.getInput("append_to_pre_release_tag");
|
||||
const createAnnotatedTag = !!core.getInput("create_annotated_tag");
|
||||
const dryRun = core.getInput("dry_run");
|
||||
const customReleaseRules = core.getInput("custom_release_rules");
|
||||
const defaultBump = core.getInput('default_bump') as ReleaseType | 'false';
|
||||
const tagPrefix = core.getInput('tag_prefix');
|
||||
const customTag = core.getInput('custom_tag');
|
||||
const releaseBranches = core.getInput('release_branches');
|
||||
const preReleaseBranches = core.getInput('pre_release_branches');
|
||||
const appendToPreReleaseTag = core.getInput('append_to_pre_release_tag');
|
||||
const createAnnotatedTag = !!core.getInput('create_annotated_tag');
|
||||
const dryRun = core.getInput('dry_run');
|
||||
const customReleaseRules = core.getInput('custom_release_rules');
|
||||
|
||||
let mappedReleaseRules;
|
||||
if (customReleaseRules) {
|
||||
|
@ -32,21 +32,21 @@ export default async () => {
|
|||
const { GITHUB_REF, GITHUB_SHA } = process.env;
|
||||
|
||||
if (!GITHUB_REF) {
|
||||
core.setFailed("Missing GITHUB_REF.");
|
||||
core.setFailed('Missing GITHUB_REF.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GITHUB_SHA) {
|
||||
core.setFailed("Missing GITHUB_SHA.");
|
||||
core.setFailed('Missing GITHUB_SHA.');
|
||||
return;
|
||||
}
|
||||
|
||||
const currentBranch = getBranchFromRef(GITHUB_REF);
|
||||
const isReleaseBranch = releaseBranches
|
||||
.split(",")
|
||||
.split(',')
|
||||
.some((branch) => currentBranch.match(branch));
|
||||
const isPreReleaseBranch = preReleaseBranches
|
||||
.split(",")
|
||||
.split(',')
|
||||
.some((branch) => currentBranch.match(branch));
|
||||
const isPrerelease = !isReleaseBranch && isPreReleaseBranch;
|
||||
|
||||
|
@ -55,7 +55,7 @@ export default async () => {
|
|||
const latestTag = getLatestTag(validTags);
|
||||
const latestPrereleaseTag = getLatestPrereleaseTag(
|
||||
validTags,
|
||||
identifier
|
||||
identifier,
|
||||
);
|
||||
|
||||
const commits = await getCommits(latestTag.commit.sha);
|
||||
|
@ -72,30 +72,34 @@ export default async () => {
|
|||
previousTag = parse(
|
||||
gte(latestTag.name, latestPrereleaseTag.name)
|
||||
? latestTag.name
|
||||
: latestPrereleaseTag.name
|
||||
: latestPrereleaseTag.name,
|
||||
);
|
||||
}
|
||||
|
||||
if (!previousTag) {
|
||||
core.setFailed("Could not parse previous tag.");
|
||||
core.setFailed('Could not parse previous tag.');
|
||||
return;
|
||||
}
|
||||
|
||||
core.info(`Previous tag was ${previousTag}.`);
|
||||
core.setOutput("previous_tag", previousTag.version);
|
||||
core.setOutput('previous_tag', previousTag.version);
|
||||
|
||||
const bump = await analyzeCommits(
|
||||
let bump = await analyzeCommits(
|
||||
{ releaseRules: mappedReleaseRules },
|
||||
{ commits, logger: { log: console.info.bind(console) } }
|
||||
{ commits, logger: { log: console.info.bind(console) } },
|
||||
);
|
||||
|
||||
if (!bump && defaultBump === "false") {
|
||||
core.debug(
|
||||
"No commit specifies the version bump. Skipping the tag creation."
|
||||
);
|
||||
if (!bump && defaultBump === 'false') {
|
||||
core.debug('No commit specifies the version bump. Skipping the tag creation.');
|
||||
return;
|
||||
}
|
||||
|
||||
// If somebody uses custom release rules on a prerelease branch they might create a 'preprepatch' bump.
|
||||
const preReg = /^pre/;
|
||||
if (isPrerelease && preReg.test(bump)) {
|
||||
bump = bump.replace(preReg,'');
|
||||
}
|
||||
|
||||
const releaseType: ReleaseType = isPrerelease
|
||||
? `pre${bump || defaultBump}`
|
||||
: bump || defaultBump;
|
||||
|
@ -103,11 +107,11 @@ export default async () => {
|
|||
const incrementedVersion = inc(
|
||||
previousTag,
|
||||
releaseType,
|
||||
identifier
|
||||
identifier,
|
||||
);
|
||||
|
||||
if (!incrementedVersion) {
|
||||
core.setFailed("Could not increment version.");
|
||||
core.setFailed('Could not increment version.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -120,11 +124,11 @@ export default async () => {
|
|||
}
|
||||
|
||||
core.info(`New version is ${newVersion}.`);
|
||||
core.setOutput("new_version", newVersion);
|
||||
core.setOutput('new_version', newVersion);
|
||||
|
||||
const newTag = `${tagPrefix}${newVersion}`;
|
||||
core.info(`New tag after applying prefix is ${newTag}.`);
|
||||
core.setOutput("new_tag", newTag);
|
||||
core.setOutput('new_tag', newTag);
|
||||
|
||||
const changelog = await generateNotes(
|
||||
{},
|
||||
|
@ -136,25 +140,25 @@ export default async () => {
|
|||
},
|
||||
lastRelease: { gitTag: latestTag.name },
|
||||
nextRelease: { gitTag: newTag, version: newVersion },
|
||||
}
|
||||
},
|
||||
);
|
||||
core.info(`Changelog is ${changelog}.`);
|
||||
core.setOutput("changelog", changelog);
|
||||
core.setOutput('changelog', changelog);
|
||||
|
||||
if (!isReleaseBranch && !isPreReleaseBranch) {
|
||||
core.info(
|
||||
"This branch is neither a release nor a pre-release branch. Skipping the tag creation."
|
||||
'This branch is neither a release nor a pre-release branch. Skipping the tag creation.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (validTags.map((tag) => tag.name).includes(newTag)) {
|
||||
core.info("This tag already exists. Skipping the tag creation.");
|
||||
core.info('This tag already exists. Skipping the tag creation.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (/true/i.test(dryRun)) {
|
||||
core.info("Dry run: not performing tag action.");
|
||||
core.info('Dry run: not performing tag action.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,33 @@ describe('github-tag-action', () => {
|
|||
expect(mockCreateTag).toHaveBeenCalledWith('v2.0.0', expect.any(Boolean), expect.any(String));
|
||||
expect(mockSetFailed).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('does create tag using custom release types but non-custom commit message', async () => {
|
||||
/*
|
||||
* Given
|
||||
*/
|
||||
setInput('custom_release_rules', 'james:patch,bond:major');
|
||||
const commits = [{ message: 'fix: is the new cool guy' }, { message: 'feat: is his last name' }];
|
||||
jest
|
||||
.spyOn(utils, 'getCommits')
|
||||
.mockImplementation(async (sha) => commits);
|
||||
|
||||
const validTags = [{ name: 'v1.2.3', commit: { sha: '012345' } }];
|
||||
jest
|
||||
.spyOn(utils, 'getValidTags')
|
||||
.mockImplementation(async () => validTags);
|
||||
|
||||
/*
|
||||
* When
|
||||
*/
|
||||
await main();
|
||||
|
||||
/*
|
||||
* Then
|
||||
*/
|
||||
expect(mockCreateTag).toHaveBeenCalledWith('v1.3.0', expect.any(Boolean), expect.any(String));
|
||||
expect(mockSetFailed).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('release branches', () => {
|
||||
|
@ -212,6 +239,66 @@ describe('github-tag-action', () => {
|
|||
expect(mockCreateTag).toHaveBeenCalledWith('v2.0.0', expect.any(Boolean), expect.any(String));
|
||||
expect(mockSetFailed).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('does create tag when pre-release tag is newer', async () => {
|
||||
/*
|
||||
* Given
|
||||
*/
|
||||
const commits = [{ message: 'feat: some new feature on a release branch' }];
|
||||
jest
|
||||
.spyOn(utils, 'getCommits')
|
||||
.mockImplementation(async (sha) => commits);
|
||||
|
||||
const validTags = [
|
||||
{ name: 'v1.2.3', commit: { sha: '012345' } },
|
||||
{ name: 'v2.1.3-prerelease.0', commit: { sha: '678901' } },
|
||||
{ name: 'v2.1.3-prerelease.1', commit: { sha: '234567' } },
|
||||
];
|
||||
jest
|
||||
.spyOn(utils, 'getValidTags')
|
||||
.mockImplementation(async () => validTags);
|
||||
|
||||
/*
|
||||
* When
|
||||
*/
|
||||
await main();
|
||||
|
||||
/*
|
||||
* Then
|
||||
*/
|
||||
expect(mockCreateTag).toHaveBeenCalledWith('v2.2.0', expect.any(Boolean), expect.any(String));
|
||||
expect(mockSetFailed).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('does create tag with custom release rules', async () => {
|
||||
/*
|
||||
* Given
|
||||
*/
|
||||
setInput('custom_release_rules', 'james:preminor')
|
||||
const commits = [
|
||||
{ message: 'feat: some new feature on a pre-release branch' },
|
||||
{ message: 'james: this should make a preminor' },
|
||||
];
|
||||
jest
|
||||
.spyOn(utils, 'getCommits')
|
||||
.mockImplementation(async (sha) => commits);
|
||||
|
||||
const validTags = [{ name: 'v1.2.3', commit: { sha: '012345' } }];
|
||||
jest
|
||||
.spyOn(utils, 'getValidTags')
|
||||
.mockImplementation(async () => validTags);
|
||||
|
||||
/*
|
||||
* When
|
||||
*/
|
||||
await main();
|
||||
|
||||
/*
|
||||
* Then
|
||||
*/
|
||||
expect(mockCreateTag).toHaveBeenCalledWith('v1.3.0', expect.any(Boolean), expect.any(String));
|
||||
expect(mockSetFailed).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('pre-release branches', () => {
|
||||
|
@ -298,6 +385,66 @@ describe('github-tag-action', () => {
|
|||
expect(mockCreateTag).toHaveBeenCalledWith('v2.0.0-prerelease.0', expect.any(Boolean), expect.any(String));
|
||||
expect(mockSetFailed).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('does create tag when release tag is newer', async () => {
|
||||
/*
|
||||
* Given
|
||||
*/
|
||||
const commits = [{ message: 'feat: some new feature on a pre-release branch' }];
|
||||
jest
|
||||
.spyOn(utils, 'getCommits')
|
||||
.mockImplementation(async (sha) => commits);
|
||||
|
||||
const validTags = [
|
||||
{ name: 'v1.2.3-prerelease.0', commit: { sha: '012345' } },
|
||||
{ name: 'v3.1.2-feature.0', commit: { sha: '012345' } },
|
||||
{ name: 'v2.1.4', commit: { sha: '234567' } },
|
||||
];
|
||||
jest
|
||||
.spyOn(utils, 'getValidTags')
|
||||
.mockImplementation(async () => validTags);
|
||||
|
||||
/*
|
||||
* When
|
||||
*/
|
||||
await main();
|
||||
|
||||
/*
|
||||
* Then
|
||||
*/
|
||||
expect(mockCreateTag).toHaveBeenCalledWith('v2.2.0-prerelease.0', expect.any(Boolean), expect.any(String));
|
||||
expect(mockSetFailed).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('does create tag with custom release rules', async () => {
|
||||
/*
|
||||
* Given
|
||||
*/
|
||||
setInput('custom_release_rules', 'james:preminor')
|
||||
const commits = [
|
||||
{ message: 'feat: some new feature on a pre-release branch' },
|
||||
{ message: 'james: this should make a preminor' },
|
||||
];
|
||||
jest
|
||||
.spyOn(utils, 'getCommits')
|
||||
.mockImplementation(async (sha) => commits);
|
||||
|
||||
const validTags = [{ name: 'v1.2.3', commit: { sha: '012345' } }];
|
||||
jest
|
||||
.spyOn(utils, 'getValidTags')
|
||||
.mockImplementation(async () => validTags);
|
||||
|
||||
/*
|
||||
* When
|
||||
*/
|
||||
await main();
|
||||
|
||||
/*
|
||||
* Then
|
||||
*/
|
||||
expect(mockCreateTag).toHaveBeenCalledWith('v1.3.0-prerelease.0', expect.any(Boolean), expect.any(String));
|
||||
expect(mockSetFailed).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('other branches', () => {
|
||||
|
|
Loading…
Reference in New Issue