Merge pull request #178 from PaulHatch/conventional-commits

feat!: Change default version patterns to follow Conventional Commits
This commit is contained in:
Paul Hatcherian 2025-10-15 06:47:03 -04:00 committed by GitHub
commit b1025b26f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 37 additions and 35 deletions

View file

@ -23,7 +23,7 @@ inputs:
major_pattern: major_pattern:
description: "A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression." description: "A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression."
required: true required: true
default: "(MAJOR)" default: "/!:|BREAKING CHANGE:/"
major_regexp_flags: major_regexp_flags:
description: "A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs" description: "A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs"
required: false required: false
@ -31,7 +31,7 @@ inputs:
minor_pattern: minor_pattern:
description: "A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression." description: "A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression."
required: true required: true
default: "(MINOR)" default: "/feat:/"
minor_regexp_flags: minor_regexp_flags:
description: "A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs" description: "A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs"
required: false required: false

View file

@ -13,11 +13,11 @@ class ActionConfig {
/** If true, the branch will be used to select the maximum version. */ /** If true, the branch will be used to select the maximum version. */
this.versionFromBranch = false; this.versionFromBranch = false;
/** A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression. */ /** A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression. */
this.majorPattern = "(MAJOR)"; this.majorPattern = "/!:|BREAKING CHANGE:/";
/** A string which indicates the flags used by the `majorPattern` regular expression. */ /** A string which indicates the flags used by the `majorPattern` regular expression. */
this.majorFlags = ""; this.majorFlags = "";
/** A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression. */ /** A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression. */
this.minorPattern = "(MINOR)"; this.minorPattern = "/feat:/";
/** A string which indicates the flags used by the `minorPattern` regular expression. */ /** A string which indicates the flags used by the `minorPattern` regular expression. */
this.minorFlags = ""; this.minorFlags = "";
/** Pattern to use when formatting output version */ /** Pattern to use when formatting output version */

View file

@ -13,8 +13,9 @@ automatically while publishing version that only increment by one value per
release. To accomplish this, the next version number is calculated along with release. To accomplish this, the next version number is calculated along with
a commit increment indicating the number of commits for this version. The a commit increment indicating the number of commits for this version. The
commit messages are inspected to determine the type of version change the next commit messages are inspected to determine the type of version change the next
version represents. Including the term `(MAJOR)` or `(MINOR)` in the commit version represents. By default, this action follows [Conventional Commits](https://www.conventionalcommits.org/)
message alters the type of change the next version will represent. patterns: commits with `feat:` trigger minor version bumps, and commits with a `!` suffix
(e.g., `feat!:`, `fix!:`) or containing `BREAKING CHANGE:` trigger major version bumps.
# Background # Background
@ -50,7 +51,8 @@ _Unless the current commit is already tagged, the version produced by this actio
## Major and Minor Versions ## Major and Minor Versions
The commit messages for the span of commits from the last tag are checked for the The commit messages for the span of commits from the last tag are checked for the
presence of the designated terms (`(MAJOR)` or `(MINOR)` by default), if a term presence of version bump patterns. By default, `feat:` triggers a minor version bump,
while `!:` (e.g., `feat!:`, `fix!:`) or `BREAKING CHANGE:` triggers a major version bump. If a pattern
is encountered that commit is treated as the start of a major or minor version is encountered that commit is treated as the start of a major or minor version
instead of the default patch level. As with normal commits the implied version instead of the default patch level. As with normal commits the implied version
will only increment by one value since the last tag regardless of how many major will only increment by one value since the last tag regardless of how many major
@ -79,11 +81,11 @@ it will be given the new version if the build were to be retriggered, for exampl
tag_prefix: "v" tag_prefix: "v"
# A string which, if present in a git commit, indicates that a change represents a # A string which, if present in a git commit, indicates that a change represents a
# major (breaking) change, supports regular expressions wrapped with '/' # major (breaking) change, supports regular expressions wrapped with '/'
major_pattern: "(MAJOR)" major_pattern: "/!:|BREAKING CHANGE:/"
# A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs # A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs
major_regexp_flags: "" major_regexp_flags: ""
# Same as above except indicating a minor change, supports regular expressions wrapped with '/' # Same as above except indicating a minor change, supports regular expressions wrapped with '/'
minor_pattern: "(MINOR)" minor_pattern: "/feat:/"
# A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs # A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs
minor_regexp_flags: "" minor_regexp_flags: ""
# A string to determine the format of the version output # A string to determine the format of the version output

View file

@ -9,11 +9,11 @@ export class ActionConfig {
/** If true, the branch will be used to select the maximum version. */ /** If true, the branch will be used to select the maximum version. */
public versionFromBranch: string | boolean = false; public versionFromBranch: string | boolean = false;
/** A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression. */ /** A string which, if present in a git commit, indicates that a change represents a major (breaking) change. Wrap with '/' to match using a regular expression. */
public majorPattern: string = "(MAJOR)"; public majorPattern: string = "/!:|BREAKING CHANGE:/";
/** A string which indicates the flags used by the `majorPattern` regular expression. */ /** A string which indicates the flags used by the `majorPattern` regular expression. */
public majorFlags: string = ""; public majorFlags: string = "";
/** A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression. */ /** A string which, if present in a git commit, indicates that a change represents a minor (feature) change. Wrap with '/' to match using a regular expression. */
public minorPattern: string = "(MINOR)"; public minorPattern: string = "/feat:/";
/** A string which indicates the flags used by the `minorPattern` regular expression. */ /** A string which indicates the flags used by the `minorPattern` regular expression. */
public minorFlags: string = ""; public minorFlags: string = "";
/** Pattern to use when formatting output version */ /** Pattern to use when formatting output version */

View file

@ -121,7 +121,7 @@ test('Minor update bumps minor version and resets increment', async () => {
const repo = createTestRepo(); // 0.0.0+0 const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0 repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit (MINOR)'); // 0.1.0+0 repo.makeCommit('feat: Second Commit'); // 0.1.0+0
const result = await repo.runAction(); const result = await repo.runAction();
expect(result.formattedVersion).toBe('0.1.0+0'); expect(result.formattedVersion).toBe('0.1.0+0');
@ -131,7 +131,7 @@ test('Major update bumps major version and resets increment', async () => {
const repo = createTestRepo(); // 0.0.0+0 const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0 repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit (MAJOR)'); // 1.0.0+0 repo.makeCommit('feat!: Second Commit'); // 1.0.0+0
const result = await repo.runAction(); const result = await repo.runAction();
@ -142,8 +142,8 @@ test('Multiple major commits are idempotent', async () => {
const repo = createTestRepo(); // 0.0.0+0 const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0 repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit (MAJOR)'); // 1.0.0+0 repo.makeCommit('feat!: Second Commit'); // 1.0.0+0
repo.makeCommit('Third Commit (MAJOR)'); // 1.0.0+1 repo.makeCommit('fix!: Third Commit'); // 1.0.0+1
const result = await repo.runAction(); const result = await repo.runAction();
@ -154,8 +154,8 @@ test('Minor commits after a major commit are ignored', async () => {
const repo = createTestRepo(); // 0.0.0+0 const repo = createTestRepo(); // 0.0.0+0
repo.makeCommit('Initial Commit'); // 0.0.1+0 repo.makeCommit('Initial Commit'); // 0.0.1+0
repo.makeCommit('Second Commit (MAJOR)'); // 1.0.0+0 repo.makeCommit('feat!: Second Commit'); // 1.0.0+0
repo.makeCommit('Third Commit (MINOR)'); // 1.0.0+1 repo.makeCommit('feat: Third Commit'); // 1.0.0+1
const result = await repo.runAction(); const result = await repo.runAction();
expect(result.formattedVersion).toBe('1.0.0+1'); expect(result.formattedVersion).toBe('1.0.0+1');
@ -433,11 +433,11 @@ test('Bump each commit works', async () => {
expect((await repo.runAction()).formattedVersion).toBe('0.0.2+0'); expect((await repo.runAction()).formattedVersion).toBe('0.0.2+0');
repo.makeCommit('Third Commit'); repo.makeCommit('Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.3+0'); expect((await repo.runAction()).formattedVersion).toBe('0.0.3+0');
repo.makeCommit('Fourth Commit (MINOR)'); repo.makeCommit('feat: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.0+0'); expect((await repo.runAction()).formattedVersion).toBe('0.1.0+0');
repo.makeCommit('Fifth Commit'); repo.makeCommit('Fifth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.1+0'); expect((await repo.runAction()).formattedVersion).toBe('0.1.1+0');
repo.makeCommit('Sixth Commit (MAJOR)'); repo.makeCommit('feat!: Sixth Commit');
expect((await repo.runAction()).formattedVersion).toBe('1.0.0+0'); expect((await repo.runAction()).formattedVersion).toBe('1.0.0+0');
repo.makeCommit('Seventh Commit'); repo.makeCommit('Seventh Commit');
expect((await repo.runAction()).formattedVersion).toBe('1.0.1+0'); expect((await repo.runAction()).formattedVersion).toBe('1.0.1+0');
@ -700,7 +700,7 @@ test('Correct previous version is returned when directly tagged with multiple pr
test('Prerelease suffixes are ignored', async () => { test('Prerelease suffixes are ignored', async () => {
const repo = createTestRepo(); const repo = createTestRepo();
repo.makeCommit('Initial Commit (MAJOR)'); repo.makeCommit('feat!: Initial Commit');
repo.makeCommit(`Second Commit`); repo.makeCommit(`Second Commit`);
repo.exec('git tag v1.0.0-alpha.1') repo.exec('git tag v1.0.0-alpha.1')
repo.makeCommit(`Third Commit`); repo.makeCommit(`Third Commit`);
@ -712,7 +712,7 @@ test('Prerelease suffixes are ignored', async () => {
test('Prerelease suffixes are ignored when namespaces are set', async () => { test('Prerelease suffixes are ignored when namespaces are set', async () => {
const repo = createTestRepo({ namespace: 'test' }); const repo = createTestRepo({ namespace: 'test' });
repo.makeCommit('Initial Commit (MAJOR)'); repo.makeCommit('feat!: Initial Commit');
repo.exec('git tag v1.0.0-test') repo.exec('git tag v1.0.0-test')
repo.makeCommit(`Second Commit`); repo.makeCommit(`Second Commit`);
repo.exec('git tag v1.0.1-test-alpha.1') repo.exec('git tag v1.0.1-test-alpha.1')
@ -956,12 +956,12 @@ test('Pre-release mode does not update major version if major version is 0', asy
repo.makeCommit('Initial Commit'); repo.makeCommit('Initial Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1'); expect((await repo.runAction()).formattedVersion).toBe('0.0.1');
repo.makeCommit('Second Commit (MINOR)'); repo.makeCommit('feat: Second Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1'); expect((await repo.runAction()).formattedVersion).toBe('0.0.1');
repo.makeCommit('Third Commit (MAJOR)'); repo.makeCommit('feat!: Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.0'); expect((await repo.runAction()).formattedVersion).toBe('0.1.0');
repo.exec('git tag 0.1.0'); repo.exec('git tag 0.1.0');
repo.makeCommit('Fourth Commit (MAJOR)'); repo.makeCommit('feat!: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.2.0'); expect((await repo.runAction()).formattedVersion).toBe('0.2.0');
}, timeout); }, timeout);
@ -972,12 +972,12 @@ test('Pre-release mode updates major version if major version is not 0', async (
repo.exec('git tag 1.0.0'); repo.exec('git tag 1.0.0');
repo.makeCommit('Second Commit'); repo.makeCommit('Second Commit');
expect((await repo.runAction()).formattedVersion).toBe('1.0.1'); expect((await repo.runAction()).formattedVersion).toBe('1.0.1');
repo.makeCommit('Third Commit (MINOR)'); repo.makeCommit('feat: Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('1.1.0'); expect((await repo.runAction()).formattedVersion).toBe('1.1.0');
repo.makeCommit('Fourth Commit (MAJOR)'); repo.makeCommit('feat!: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('2.0.0'); expect((await repo.runAction()).formattedVersion).toBe('2.0.0');
repo.exec('git tag 2.0.0'); repo.exec('git tag 2.0.0');
repo.makeCommit('Fifth Commit (MAJOR)'); repo.makeCommit('feat!: Fifth Commit');
expect((await repo.runAction()).formattedVersion).toBe('3.0.0'); expect((await repo.runAction()).formattedVersion).toBe('3.0.0');
}, timeout); }, timeout);
@ -995,12 +995,12 @@ test('Tagged commit is flagged as release', async () => {
expect(result.formattedVersion).toBe('1.0.1-prerelease.0') expect(result.formattedVersion).toBe('1.0.1-prerelease.0')
expect(result.isTagged).toBe(false); expect(result.isTagged).toBe(false);
repo.makeCommit('Third Commit (MINOR)'); repo.makeCommit('feat: Third Commit');
result = await repo.runAction(); result = await repo.runAction();
expect(result.formattedVersion).toBe('1.1.0-prerelease.0'); expect(result.formattedVersion).toBe('1.1.0-prerelease.0');
expect(result.isTagged).toBe(false); expect(result.isTagged).toBe(false);
repo.makeCommit('Fourth Commit (MINOR)'); repo.makeCommit('feat: Fourth Commit');
repo.exec('git tag v1.1.0') repo.exec('git tag v1.1.0')
result = await repo.runAction(); result = await repo.runAction();
expect(result.formattedVersion).toBe('1.1.0-prerelease.1'); expect(result.formattedVersion).toBe('1.1.0-prerelease.1');
@ -1013,12 +1013,12 @@ test('Pre-release mode with bump each commit does not update major version if ma
repo.makeCommit('Initial Commit'); repo.makeCommit('Initial Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1'); expect((await repo.runAction()).formattedVersion).toBe('0.0.1');
repo.makeCommit('Second Commit (MINOR)'); repo.makeCommit('feat: Second Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.0'); expect((await repo.runAction()).formattedVersion).toBe('0.1.0');
repo.makeCommit('Third Commit (MAJOR)'); repo.makeCommit('feat!: Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.2.0'); expect((await repo.runAction()).formattedVersion).toBe('0.2.0');
repo.exec('git tag 0.1.0'); repo.exec('git tag 0.1.0');
repo.makeCommit('Fourth Commit (MAJOR)'); repo.makeCommit('feat!: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.2.0'); expect((await repo.runAction()).formattedVersion).toBe('0.2.0');
}, timeout); }, timeout);
@ -1037,7 +1037,7 @@ test('Pre-release mode with bump each commit does not update major version if ma
expect((await repo.runAction()).formattedVersion).toBe('0.0.1.1'); expect((await repo.runAction()).formattedVersion).toBe('0.0.1.1');
repo.makeCommit('Third Commit'); repo.makeCommit('Third Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.0.1.2'); expect((await repo.runAction()).formattedVersion).toBe('0.0.1.2');
repo.makeCommit('Fourth Commit (MAJOR)'); repo.makeCommit('feat!: Fourth Commit');
expect((await repo.runAction()).formattedVersion).toBe('0.1.0.0'); expect((await repo.runAction()).formattedVersion).toBe('0.1.0.0');
}, timeout); }, timeout);
@ -1133,12 +1133,12 @@ test('Prerelease mode does not increment to 1.x.x', async () => {
expect(result.formattedVersion).toBe('1.0.1-prerelease.0') expect(result.formattedVersion).toBe('1.0.1-prerelease.0')
expect(result.isTagged).toBe(false); expect(result.isTagged).toBe(false);
repo.makeCommit('Third Commit (MINOR)'); repo.makeCommit('feat: Third Commit');
result = await repo.runAction(); result = await repo.runAction();
expect(result.formattedVersion).toBe('1.1.0-prerelease.0'); expect(result.formattedVersion).toBe('1.1.0-prerelease.0');
expect(result.isTagged).toBe(false); expect(result.isTagged).toBe(false);
repo.makeCommit('Fourth Commit (MINOR)'); repo.makeCommit('feat: Fourth Commit');
repo.exec('git tag v1.1.0') repo.exec('git tag v1.1.0')
result = await repo.runAction(); result = await repo.runAction();
expect(result.formattedVersion).toBe('1.1.0-prerelease.1'); expect(result.formattedVersion).toBe('1.1.0-prerelease.1');