From bdf790836438c7de55da67fe8ad37f6d7cc4c6d1 Mon Sep 17 00:00:00 2001 From: Paul Hatcherian <1835615+PaulHatch@users.noreply.github.com> Date: Sat, 19 Jul 2025 07:50:19 +0200 Subject: [PATCH] feat!: Change default version patterns to follow Conventional Commits --- action.yml | 4 ++-- guide.md | 2 +- lib/ActionConfig.js | 4 ++-- readme.md | 12 +++++++----- src/ActionConfig.ts | 4 ++-- src/main.test.ts | 48 ++++++++++++++++++++++----------------------- 6 files changed, 38 insertions(+), 36 deletions(-) diff --git a/action.yml b/action.yml index 1a300c8..80f26c3 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ inputs: 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." required: true - default: "(MAJOR)" + default: "/!:|BREAKING CHANGE:/" major_regexp_flags: description: "A string which indicates the flags used by the `major_pattern` regular expression. Supported flags: idgs" required: false @@ -31,7 +31,7 @@ inputs: 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." required: true - default: "(MINOR)" + default: "/feat:/" minor_regexp_flags: description: "A string which indicates the flags used by the `minor_pattern` regular expression. Supported flags: idgs" required: false diff --git a/guide.md b/guide.md index b24b072..a194557 100644 --- a/guide.md +++ b/guide.md @@ -100,7 +100,7 @@ If your project contains multiple services which you wish to version independent | Value | Description | | --- | --- | | `tag_prefix` | The prefix to use for the tag. Defaults to `v`, generally you will use either `v` or an empty string. Note that the tag format is distinct from the version. Tags used for versioning must always follow the pattern `{tag_prefix}{major}.{minor}.{patch}` with and optional `-{namespace}` suffix. | -| `major_pattern` and `minor_pattern` | These strings are used to determine the type of version to create. If any commit message sincematches the `major_pattern` the major version will be incremented, if it matches the `minor_pattern` the minor version will be incremented. If neither pattern matches, the patch version will be incremented. These can be specified either as strings or as regular expression by wrapping the expression in `/`. | +| `major_pattern` and `minor_pattern` | These strings are used to determine the type of version to create. If any commit message since matches the `major_pattern` the major version will be incremented, if it matches the `minor_pattern` the minor version will be incremented. If neither pattern matches, the patch version will be incremented. These can be specified either as strings or as regular expression by wrapping the expression in `/`. The defaults follow [Conventional Commits](https://www.conventionalcommits.org/): `/!:|BREAKING CHANGE:/` for major and `/feat:/` for minor. | | `version_format` | A value such as `${major}.${minor}.${patch}-prerelease${increment}` that will be used to format the version value of the output, **formatting this value is the only effect of this input parameter!** It is not used for parsing or any other purpose. It is a convenient alternative to formatting the output in a subsequent step. | | `user_format_type` | Indicates the format of the `authors` output. Can be `json` or `yaml`. | | `enable_prerelease_mode` | If true, major changes to versions starting with 0 will result in a minor change, preventing ths initial version `1.0.0`` from being created automatically by someone checking in a commit with the major pattern. | \ No newline at end of file diff --git a/lib/ActionConfig.js b/lib/ActionConfig.js index 826d418..8b48ac6 100644 --- a/lib/ActionConfig.js +++ b/lib/ActionConfig.js @@ -13,11 +13,11 @@ class ActionConfig { /** If true, the branch will be used to select the maximum version. */ 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. */ - this.majorPattern = "(MAJOR)"; + this.majorPattern = "/!:|BREAKING CHANGE:/"; /** A string which indicates the flags used by the `majorPattern` regular expression. */ 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. */ - this.minorPattern = "(MINOR)"; + this.minorPattern = "/feat:/"; /** A string which indicates the flags used by the `minorPattern` regular expression. */ this.minorFlags = ""; /** Pattern to use when formatting output version */ diff --git a/readme.md b/readme.md index 7393064..7466284 100644 --- a/readme.md +++ b/readme.md @@ -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 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 -version represents. Including the term `(MAJOR)` or `(MINOR)` in the commit -message alters the type of change the next version will represent. +version represents. By default, this action follows [Conventional Commits](https://www.conventionalcommits.org/) +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 @@ -50,7 +51,8 @@ _Unless the current commit is already tagged, the version produced by this actio ## Major and Minor Versions 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 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 @@ -79,11 +81,11 @@ it will be given the new version if the build were to be retriggered, for exampl tag_prefix: "v" # A string which, if present in a git commit, indicates that a change represents a # 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 major_regexp_flags: "" # 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 minor_regexp_flags: "" # A string to determine the format of the version output diff --git a/src/ActionConfig.ts b/src/ActionConfig.ts index aee4e8d..a00b2c9 100644 --- a/src/ActionConfig.ts +++ b/src/ActionConfig.ts @@ -9,11 +9,11 @@ export class ActionConfig { /** If true, the branch will be used to select the maximum version. */ 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. */ - public majorPattern: string = "(MAJOR)"; + public majorPattern: string = "/!:|BREAKING CHANGE:/"; /** A string which indicates the flags used by the `majorPattern` regular expression. */ 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. */ - public minorPattern: string = "(MINOR)"; + public minorPattern: string = "/feat:/"; /** A string which indicates the flags used by the `minorPattern` regular expression. */ public minorFlags: string = ""; /** Pattern to use when formatting output version */ diff --git a/src/main.test.ts b/src/main.test.ts index b6f8950..5e22ca1 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -121,7 +121,7 @@ test('Minor update bumps minor version and resets increment', async () => { const repo = createTestRepo(); // 0.0.0+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(); 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 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(); @@ -142,8 +142,8 @@ test('Multiple major commits are idempotent', async () => { const repo = createTestRepo(); // 0.0.0+0 repo.makeCommit('Initial Commit'); // 0.0.1+0 - repo.makeCommit('Second Commit (MAJOR)'); // 1.0.0+0 - repo.makeCommit('Third Commit (MAJOR)'); // 1.0.0+1 + repo.makeCommit('feat!: Second Commit'); // 1.0.0+0 + repo.makeCommit('fix!: Third Commit'); // 1.0.0+1 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 repo.makeCommit('Initial Commit'); // 0.0.1+0 - repo.makeCommit('Second Commit (MAJOR)'); // 1.0.0+0 - repo.makeCommit('Third Commit (MINOR)'); // 1.0.0+1 + repo.makeCommit('feat!: Second Commit'); // 1.0.0+0 + repo.makeCommit('feat: Third Commit'); // 1.0.0+1 const result = await repo.runAction(); 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'); repo.makeCommit('Third Commit'); 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'); repo.makeCommit('Fifth Commit'); 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'); repo.makeCommit('Seventh Commit'); 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 () => { const repo = createTestRepo(); - repo.makeCommit('Initial Commit (MAJOR)'); + repo.makeCommit('feat!: Initial Commit'); repo.makeCommit(`Second Commit`); repo.exec('git tag v1.0.0-alpha.1') repo.makeCommit(`Third Commit`); @@ -712,7 +712,7 @@ test('Prerelease suffixes are ignored', async () => { test('Prerelease suffixes are ignored when namespaces are set', async () => { const repo = createTestRepo({ namespace: 'test' }); - repo.makeCommit('Initial Commit (MAJOR)'); + repo.makeCommit('feat!: Initial Commit'); repo.exec('git tag v1.0.0-test') repo.makeCommit(`Second Commit`); 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'); 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'); - repo.makeCommit('Third Commit (MAJOR)'); + repo.makeCommit('feat!: Third Commit'); expect((await repo.runAction()).formattedVersion).toBe('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'); }, 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.makeCommit('Second Commit'); 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'); - repo.makeCommit('Fourth Commit (MAJOR)'); + repo.makeCommit('feat!: Fourth Commit'); expect((await repo.runAction()).formattedVersion).toBe('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'); }, timeout); @@ -995,12 +995,12 @@ test('Tagged commit is flagged as release', async () => { expect(result.formattedVersion).toBe('1.0.1-prerelease.0') expect(result.isTagged).toBe(false); - repo.makeCommit('Third Commit (MINOR)'); + repo.makeCommit('feat: Third Commit'); result = await repo.runAction(); expect(result.formattedVersion).toBe('1.1.0-prerelease.0'); expect(result.isTagged).toBe(false); - repo.makeCommit('Fourth Commit (MINOR)'); + repo.makeCommit('feat: Fourth Commit'); repo.exec('git tag v1.1.0') result = await repo.runAction(); 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'); 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'); - repo.makeCommit('Third Commit (MAJOR)'); + repo.makeCommit('feat!: Third Commit'); expect((await repo.runAction()).formattedVersion).toBe('0.2.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'); }, 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'); repo.makeCommit('Third Commit'); 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'); }, 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.isTagged).toBe(false); - repo.makeCommit('Third Commit (MINOR)'); + repo.makeCommit('feat: Third Commit'); result = await repo.runAction(); expect(result.formattedVersion).toBe('1.1.0-prerelease.0'); expect(result.isTagged).toBe(false); - repo.makeCommit('Fourth Commit (MINOR)'); + repo.makeCommit('feat: Fourth Commit'); repo.exec('git tag v1.1.0') result = await repo.runAction(); expect(result.formattedVersion).toBe('1.1.0-prerelease.1');