Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/#145 default_draft_bump #177

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:

- **default_bump** _(optional)_ - Which type of bump to use when [none is explicitly provided](#bumping) when commiting to a release branch (default: `patch`). You can also set `false` to avoid generating a new tag when none is explicitly provided. Can be `patch, minor or major`.
- **default_prerelease_bump** _(optional)_ - Which type of bump to use when [none is explicitly provided](#bumping) when commiting to a prerelease branch (default: `prerelease`). You can also set `false` to avoid generating a new tag when none is explicitly provided. Can be `prerelease, prepatch, preminor or premajor`.
- **default_draft_bump** _(optional)_ - Which type of bump to use when [none is explicitly provided](#bumping) when commiting to a prerelease branch with no previous prerelease version (default: `prerelease`). You can also set `false` to avoid generating a new tag when none is explicitly provided. Can be `prerelease, patch, minor or major`.
- **custom_tag** _(optional)_ - Custom tag name. If specified, it overrides bump settings.
- **create_annotated_tag** _(optional)_ - Boolean to create an annotated rather than a lightweight one (default: `false`).
- **tag_prefix** _(optional)_ - A prefix to the tag name (default: `v`).
Expand Down
5 changes: 5 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ inputs:
description: "Which type of bump to use when none explicitly provided when commiting to a release branch (default: `patch`)."
required: false
default: "patch"
default_draft_bump:
description: |
Which type of bump to use when none explicitly provided when commiting to a prerelease branch with no previous prerelease version (default: same as `default_prerelease_bump`).
Defaults to prerelease for backward-compatibility with previous behaviour. Might make more sense to set it to the same as `default_bump`.
required: false
default_prerelease_bump:
description: "Which type of bump to use when none explicitly provided when commiting to a prerelease branch (default: `prerelease`)."
required: false
Expand Down
12 changes: 11 additions & 1 deletion src/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export default async function main() {
const defaultPreReleaseBump = core.getInput('default_prerelease_bump') as
| ReleaseType
| 'false';
const defaultDraftBump =
(core.getInput('default_draft_bump') as ReleaseType | 'false') ||
defaultPreReleaseBump;
const tagPrefix = core.getInput('tag_prefix');
const customTag = core.getInput('custom_tag');
const releaseBranches = core.getInput('release_branches');
Expand Down Expand Up @@ -120,6 +123,7 @@ export default async function main() {
);
core.setOutput('previous_version', previousVersion.version);
core.setOutput('previous_tag', previousTag.name);
const previousWasPrerelease = previousVersion.prerelease.length != 0;

commits = await getCommits(previousTag.commit.sha, commitRef);

Expand All @@ -136,6 +140,8 @@ export default async function main() {
// Determine if we should continue with tag creation based on main vs prerelease branch
let shouldContinue = true;
if (isPrerelease) {
if (!bump && !previousWasPrerelease && defaultDraftBump === 'false')
shouldContinue = false;
if (!bump && defaultPreReleaseBump === 'false') {
shouldContinue = false;
}
Expand All @@ -155,9 +161,13 @@ export default async function main() {

// If we don't have an automatic bump for the prerelease, just set our bump as the default
if (isPrerelease && !bump) {
bump = defaultPreReleaseBump;
if (!previousWasPrerelease)
// previous version is a prerelease -> draft a new version with the default bump and make it a prerelease
bump = defaultDraftBump;
else bump = defaultPreReleaseBump;
}

// TODO: these next 10 lines are horrible!! why we have preminor as bump type at all if it is always striped away?
// If somebody uses custom release rules on a prerelease branch they might create a 'preprepatch' bump.
const preReg = /^pre/;
if (isPrerelease && preReg.test(bump)) {
Expand Down
229 changes: 229 additions & 0 deletions tests/action.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ describe('github-tag-action', () => {
beforeEach(() => {
jest.clearAllMocks();
setBranch('prerelease');
loadDefaultInputs();
setInput('pre_release_branches', 'prerelease');
});

Expand Down Expand Up @@ -527,6 +528,234 @@ describe('github-tag-action', () => {
expect(mockSetFailed).not.toBeCalled();
});

/** 1.3.0 commit =[minor, minor, prerelease]=> 1.4.0-pre.0 */
it('does create prerelease tag respecting default_draft_bump', async () => {
/*
* Given
*/
const commits = [{ message: 'this is a commit', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);

const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);

/*
* When
*/
setInput('default_bump', 'minor');
setInput('default_draft_bump', 'minor');
setInput('default_prerelease_bump', 'prerelease');
await action();

/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.3.0-prerelease.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});

/** 1.3.0-pre.0 + commit =[minor, minor, prerelease]=> 1.3.0-pre.1 */
it('does update prerelease tag respecting default_draft_bump', async () => {
/*
* Given
*/
const commits = [{ message: 'this is a commit', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);

const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v1.3.0-prerelease.0',
commit: { sha: '123456', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);

/*
* When
*/
setInput('default_bump', 'minor');
setInput('default_draft_bump', 'minor');
setInput('default_prerelease_bump', 'prerelease');
await action();

/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.3.0-prerelease.1',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});

/** 1.3.0-pre.0 + commit =[minor, minor, preminor]=> 1.4.0-pre.0 */
it('does update prerelease tag with preminor', async () => {
/*
* Given
*/
const commits = [{ message: 'this is a commit', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);

const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
{
name: 'v1.3.0-prerelease.0',
commit: { sha: '123456', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);

/*
* When
*/
setInput('default_bump', 'minor');
setInput('default_draft_bump', 'minor');
setInput('default_prerelease_bump', 'preminor');
await action();

/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.4.0-prerelease.0',
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});

/**
* 1.2.3 commit =[minor, -, prerelease]=> 1.2.4-pre.0
* according to semver, a prerelease increment on a non-prerelease version drafts a new minor version
*/
it('default_draft_bump defaults to default_prerelease_bump (prerelease)', async () => {
/*
* Given
*/
const commits = [{ message: 'this is a commit', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);

const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);

/*
* When
*/
setInput('default_bump', 'minor');
setInput('default_prerelease_bump', 'prerelease');
await action();

/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.2.4-prerelease.0', // prerelease drafts patch upgrades
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});

/**
* 1.2.3 commit =[minor, -, prerelease]=> 1.2.4-pre.0
* according to semver, a prerelease increment on a non-prerelease version drafts a new minor version
*/
it('default_draft_bump defaults to default_prerelease_bump (preminor)', async () => {
/*
* Given
*/
const commits = [{ message: 'this is a commit', hash: null }];
jest
.spyOn(utils, 'getCommits')
.mockImplementation(async (sha) => commits);

const validTags = [
{
name: 'v1.2.3',
commit: { sha: '012345', url: '' },
zipball_url: '',
tarball_url: 'string',
node_id: 'string',
},
];
jest
.spyOn(utils, 'getValidTags')
.mockImplementation(async () => validTags);

/*
* When
*/
setInput('default_bump', 'minor');
setInput('default_prerelease_bump', 'preminor');
await action();

/*
* Then
*/
expect(mockCreateTag).toHaveBeenCalledWith(
'v1.3.0-prerelease.0', // prerelease drafts patch upgrades
expect.any(Boolean),
expect.any(String)
);
expect(mockSetFailed).not.toBeCalled();
});

it('does create prepatch tag', async () => {
/*
* Given
Expand Down
9 changes: 8 additions & 1 deletion tests/helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ export function setInputs(map: { [key: string]: string }) {
Object.keys(map).forEach((key) => setInput(key, map[key]));
}

export function resetInputs(map: { [key: string]: string }) {
Object.keys(process.env)
.filter((k) => k.startsWith('INPUT_'))
.forEach((k) => delete process.env[k]);
Object.keys(map).forEach((key) => setInput(key, map[key]));
}

export function loadDefaultInputs() {
const actionYaml = fs.readFileSync(
path.join(process.cwd(), 'action.yml'),
Expand All @@ -40,7 +47,7 @@ export function loadDefaultInputs() {
(obj, key) => ({ ...obj, [key]: actionJson['inputs'][key].default }),
{}
);
setInputs(defaultInputs);
resetInputs(defaultInputs);
}

// Don't know how to have this file only for test but not have 'tsc' complain. So I made it a test file...
Expand Down