Repository: orhun/git-cliff
Pull request #744 (2024-07-05 01:57:46)

feat(bump): support bumping to a specific semver type
## Description

Support bumping to a specific semver type with `--bump major/minor/patch`

## Motivation and Context

Allow user bumping the version by specifying the type including major, minor and patch

## How Has This Been Tested?

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Screenshots / Logs (if applicable)

## Types of Changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation (no code change)
- [ ] Refactor (refactoring production code)
- [ ] Other <!--- (provide information) -->

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [x] My code follows the code style of this project.
- [x] I have updated the documentation accordingly.
- [x] I have formatted the code with [rustfmt](https://github.com/rust-lang/rustfmt).
- [x] I checked the lints with [clippy](https://github.com/rust-lang/rust-clippy).
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.

<!--- Thank you for contributing to git-cliff! ⛰️  -->


welcome[bot]: Thanks for opening this pull request! Please check out our contributing guidelines! ⛰️

braineo: hi @orhun this is still a experimental draft that i would like to see if the approach if right to add an option to specify the bump type. 

this change has similar effect of `--release-as`  in [standard-version cli](https://github.com/conventional-changelog/standard-version?tab=readme-ov-file#release-as-a-target-type-imperatively-npm-version-like)
codecov-commenter: :warning: Please install the !['codecov app svg image'](https://github.com/codecov/engineering-team/assets/152432831/e90313f4-9d3a-4b63-8b54-cfe14e7ec20d) to ensure uploads and comments are reliably processed by Codecov.

## [Codecov](https://app.codecov.io/gh/orhun/git-cliff/pull/744?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) Report
Attention: Patch coverage is `31.25000%` with `11 lines` in your changes missing coverage. Please review.
> Project coverage is 36.54%. Comparing base [(`227a307`)](https://app.codecov.io/gh/orhun/git-cliff/commit/227a307d8563e942f4d1e97b53e21953148395f6?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) to head [(`b030f9b`)](https://app.codecov.io/gh/orhun/git-cliff/commit/b030f9b64e8ac00acf1c26277e3ce535df140ced?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z).

| [Files](https://app.codecov.io/gh/orhun/git-cliff/pull/744?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) | Patch % | Lines |
|---|---|---|
| [git-cliff-core/src/release.rs](https://app.codecov.io/gh/orhun/git-cliff/pull/744?src=pr&el=tree&filepath=git-cliff-core%2Fsrc%2Frelease.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z#diff-Z2l0LWNsaWZmLWNvcmUvc3JjL3JlbGVhc2UucnM=) | 33.34% | [10 Missing :warning: ](https://app.codecov.io/gh/orhun/git-cliff/pull/744?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) |
| [git-cliff/src/lib.rs](https://app.codecov.io/gh/orhun/git-cliff/pull/744?src=pr&el=tree&filepath=git-cliff%2Fsrc%2Flib.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z#diff-Z2l0LWNsaWZmL3NyYy9saWIucnM=) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/orhun/git-cliff/pull/744?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) |

:exclamation: Your organization needs to install the [Codecov GitHub app](https://github.com/apps/codecov/installations/select_target) to enable full functionality.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #744      +/-   ##
==========================================
- Coverage   36.71%   36.54%   -0.17%     
==========================================
  Files          19       19              
  Lines        1501     1511      +10     
==========================================
+ Hits          551      552       +1     
- Misses        950      959       +9     
```

| [Flag](https://app.codecov.io/gh/orhun/git-cliff/pull/744/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) | Coverage Δ | |
|---|---|---|
| [unit-tests](https://app.codecov.io/gh/orhun/git-cliff/pull/744/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) | `36.54% <31.25%> (-0.17%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/orhun/git-cliff/pull/744?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z).

braineo: hi @orhun I wonder if you have taken a look at the pr and can provide some feedback on it. thanks!

Patch:
diff --git a/config/cliff.toml b/config/cliff.toml
index ba12c0b..078f667 100644
--- a/config/cliff.toml
+++ b/config/cliff.toml
@@ -6,7 +6,7 @@
 # See documentation for more information on available options.
 
 [changelog]
-# template for the changelog footer
+# template for the changelog header
 header = """
 # Changelog\n
 All notable changes to this project will be documented in this file.\n
diff --git a/git-cliff-core/src/config.rs b/git-cliff-core/src/config.rs
index eea7392..0f34ef4 100644
--- a/git-cliff-core/src/config.rs
+++ b/git-cliff-core/src/config.rs
@@ -174,6 +174,17 @@ impl Remote {
 	}
 }
 
+/// Version bump type.
+#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
+pub enum BumpType {
+	/// Bump major version.
+	Major,
+	/// Bump minor version.
+	Minor,
+	/// Bump patch version.
+	Patch,
+}
+
 /// Bump version configuration.
 #[derive(Debug, Default, Clone, Serialize, Deserialize)]
 pub struct Bump {
@@ -218,6 +229,9 @@ pub struct Bump {
 	///
 	/// `commit type` according to the spec is only `[a-zA-Z]+`
 	pub custom_minor_increment_regex: Option<String>,
+
+	/// Force to always bump in major, minor or patch.
+	pub bump_type: Option<BumpType>,
 }
 
 /// Parser for grouping commits.
diff --git a/git-cliff-core/src/release.rs b/git-cliff-core/src/release.rs
index 9ee2383..2e681bf 100644
--- a/git-cliff-core/src/release.rs
+++ b/git-cliff-core/src/release.rs
@@ -1,5 +1,3 @@
-use crate::commit::Commit;
-use crate::config::Bump;
 use crate::error::Result;
 #[cfg(feature = "remote")]
 use crate::remote::{
@@ -8,7 +6,16 @@ use crate::remote::{
 	RemotePullRequest,
 	RemoteReleaseMetadata,
 };
-use next_version::VersionUpdater;
+use crate::{
+	commit::Commit,
+	config::Bump,
+	config::BumpType,
+};
+
+use next_version::{
+	NextVersion,
+	VersionUpdater,
+};
 use semver::Version;
 use serde::{
 	Deserialize,
@@ -124,15 +131,23 @@ impl<'a> Release<'a> {
 						custom_minor_increment_regex,
 					)?;
 				}
-				let next_version = next_version
-					.increment(
-						&semver?,
-						self.commits
-							.iter()
-							.map(|commit| commit.message.trim_end().to_string())
-							.collect::<Vec<String>>(),
-					)
-					.to_string();
+				let next_version = if let Some(bump_type) = &config.bump_type {
+					match bump_type {
+						BumpType::Major => semver?.increment_major().to_string(),
+						BumpType::Minor => semver?.increment_minor().to_string(),
+						BumpType::Patch => semver?.increment_patch().to_string(),
+					}
+				} else {
+					next_version
+						.increment(
+							&semver?,
+							self.commits
+								.iter()
+								.map(|commit| commit.message.trim_end().to_string())
+								.collect::<Vec<String>>(),
+						)
+						.to_string()
+				};
 				if let Some(prefix) = prefix {
 					Ok(format!("{prefix}{next_version}"))
 				} else {
@@ -282,6 +297,7 @@ mod test {
 					initial_tag:                  None,
 					custom_major_increment_regex: None,
 					custom_minor_increment_regex: None,
+					bump_type:                    None,
 				})?;
 			assert_eq!(expected_version, &next_version);
 		}
@@ -305,6 +321,7 @@ mod test {
 					initial_tag:                  None,
 					custom_major_increment_regex: None,
 					custom_minor_increment_regex: None,
+					bump_type:                    None,
 				})?;
 			assert_eq!(expected_version, &next_version);
 		}
@@ -328,6 +345,7 @@ mod test {
 					initial_tag:                  None,
 					custom_major_increment_regex: None,
 					custom_minor_increment_regex: None,
+					bump_type:                    None,
 				})?;
 			assert_eq!(expected_version, &next_version);
 		}
@@ -351,6 +369,7 @@ mod test {
 					initial_tag:                  None,
 					custom_major_increment_regex: None,
 					custom_minor_increment_regex: None,
+					bump_type:                    None,
 				})?
 			);
 		}
diff --git a/git-cliff/src/args.rs b/git-cliff/src/args.rs
index 4c76985..f0decb7 100644
--- a/git-cliff/src/args.rs
+++ b/git-cliff/src/args.rs
@@ -13,6 +13,7 @@ use clap::{
 	ValueEnum,
 };
 use git_cliff_core::{
+	config::BumpType,
 	config::Remote,
 	DEFAULT_CONFIG,
 	DEFAULT_OUTPUT,
@@ -190,9 +191,16 @@ pub struct Opt {
 		allow_hyphen_values = true
 	)]
 	pub tag:              Option<String>,
-	/// Bumps the version for unreleased changes.
-	#[arg(long, help_heading = Some("FLAGS"))]
-	pub bump:             bool,
+	/// Bumps the version for unreleased changes. Optionally with specified
+	/// version.
+	#[arg(
+        long,
+        value_name = "BUMP",
+        value_enum,
+        num_args = 0..=1,
+        default_missing_value = "auto",
+        value_parser = clap::value_parser!(BumpOption))]
+	pub bump:             Option<BumpOption>,
 	/// Prints bumped version for unreleased changes.
 	#[arg(long, help_heading = Some("FLAGS"))]
 	pub bumped_version:   bool,
@@ -352,6 +360,54 @@ impl TypedValueParser for RemoteValueParser {
 	}
 }
 
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum BumpOption {
+	Auto,
+	Specific(BumpType),
+}
+
+impl ValueParserFactory for BumpOption {
+	type Parser = BumpOptionParser;
+	fn value_parser() -> Self::Parser {
+		BumpOptionParser
+	}
+}
+
+/// Parser for bump type.
+#[derive(Clone, Debug)]
+pub struct BumpOptionParser;
+
+impl TypedValueParser for BumpOptionParser {
+	type Value = BumpOption;
+	fn parse_ref(
+		&self,
+		cmd: &clap::Command,
+		arg: Option<&clap::Arg>,
+		value: &std::ffi::OsStr,
+	) -> Result<Self::Value, clap::Error> {
+		let inner = clap::builder::StringValueParser::new();
+		let value = inner.parse_ref(cmd, arg, value)?;
+		match value.as_str() {
+			"auto" => Ok(BumpOption::Auto),
+			"major" => Ok(BumpOption::Specific(BumpType::Major)),
+			"minor" => Ok(BumpOption::Specific(BumpType::Minor)),
+			"patch" => Ok(BumpOption::Specific(BumpType::Patch)),
+			_ => {
+				let mut err =
+					clap::Error::new(ErrorKind::ValueValidation).with_cmd(cmd);
+				if let Some(arg) = arg {
+					err.insert(
+						ContextKind::InvalidArg,
+						ContextValue::String(arg.to_string()),
+					);
+				}
+				err.insert(ContextKind::InvalidValue, ContextValue::String(value));
+				Err(err)
+			}
+		}
+	}
+}
+
 impl Opt {
 	/// Custom string parser for directories.
 	///
@@ -409,4 +465,29 @@ mod tests {
 			.is_err());
 		Ok(())
 	}
+
+	#[test]
+	fn bump_option_parser() -> Result<(), clap::Error> {
+		let bump_option_parser = BumpOptionParser;
+		assert_eq!(
+			BumpOption::Auto,
+			bump_option_parser.parse_ref(
+				&Opt::command(),
+				None,
+				OsStr::new("auto")
+			)?
+		);
+		assert!(bump_option_parser
+			.parse_ref(&Opt::command(), None, OsStr::new("test"))
+			.is_err());
+		assert_eq!(
+			BumpOption::Specific(BumpType::Major),
+			bump_option_parser.parse_ref(
+				&Opt::command(),
+				None,
+				OsStr::new("major")
+			)?
+		);
+		Ok(())
+	}
 }
diff --git a/git-cliff/src/lib.rs b/git-cliff/src/lib.rs
index a42da54..d9541a0 100644
--- a/git-cliff/src/lib.rs
+++ b/git-cliff/src/lib.rs
@@ -14,6 +14,7 @@ pub mod logger;
 extern crate log;
 
 use args::{
+	BumpOption,
 	Opt,
 	Sort,
 	Strip,
@@ -546,10 +547,13 @@ pub fn run(mut args: Opt) -> Result<()> {
 	}
 
 	// Process commits and releases for the changelog.
+	if let Some(BumpOption::Specific(bump_type)) = args.bump {
+		config.bump.bump_type = Some(bump_type)
+	}
 	let mut changelog = Changelog::new(releases, &config)?;
 
 	// Print the result.
-	if args.bump || args.bumped_version {
+	if args.bump.is_some() || args.bumped_version {
 		let next_version = if let Some(next_version) = changelog.bump_version()? {
 			next_version
 		} else if let Some(last_version) =
diff --git a/website/docs/configuration/bump.md b/website/docs/configuration/bump.md
index 5f0f5bc..3ef9881 100644
--- a/website/docs/configuration/bump.md
+++ b/website/docs/configuration/bump.md
@@ -81,3 +81,14 @@ git-cliff --bumped-version
 
 0.2.0
 ```
+
+### bump_type
+
+When set, it forces to always bump in major, minor or patch.
+
+e.g.
+
+```toml
+[bump]
+bump_type = "minor"
+```
diff --git a/website/docs/usage/args.md b/website/docs/usage/args.md
index efd9b3e..c4926f3 100644
--- a/website/docs/usage/args.md
+++ b/website/docs/usage/args.md
@@ -14,7 +14,6 @@ git-cliff [FLAGS] [OPTIONS] [--] [RANGE]
 -h, --help            Prints help information
 -V, --version         Prints version information
 -v, --verbose...      Increases the logging verbosity
-    --bump            Bumps the version for unreleased changes
     --bumped-version  Prints bumped version for unreleased changes
 -l, --latest          Processes the commits starting from the latest tag
     --current         Processes the commits that belong to the current tag
@@ -28,6 +27,7 @@ git-cliff [FLAGS] [OPTIONS] [--] [RANGE]
 
 ```
 -i, --init [<CONFIG>]              Writes the default configuration file to cliff.toml
+    --bump                         Bumps the version for unreleased changes [default: auto] [possible values: auto, major, minor, patch]
 -c, --config <PATH>                Sets the configuration file [env: GIT_CLIFF_CONFIG=] [default: cliff.toml]
 -w, --workdir <PATH>               Sets the working directory [env: GIT_CLIFF_WORKDIR=]
 -r, --repository <PATH>...         Sets the git repository [env: GIT_CLIFF_REPOSITORY=]
diff --git a/website/docs/usage/bump-version.md b/website/docs/usage/bump-version.md
index 6478af9..6feb82a 100644
--- a/website/docs/usage/bump-version.md
+++ b/website/docs/usage/bump-version.md
@@ -22,18 +22,32 @@ How it works is that for a semantic versioning such as `<MAJOR>.<MINOR>.<PATCH>`
 - "feat:" -> increments `MINOR`
 - "scope!" (breaking changes) -> increments `MAJOR`
 
+## Get version
+
 You can also calculate and print the next semantic version to `stdout`:
 
 ```bash
 git cliff --bumped-version
 ```
 
-Tip: you can also get the bumped version [from the context](/docs/usage/print-context) as follows:
+:::tip
+
+You can also get the bumped version [from the context](/docs/usage/print-context) as follows:
 
 ```bash
 git cliff --unreleased --bump --context | jq -r .[0].version
 ```
 
+:::
+
+## Bump to a specific version type
+
+Optionally, you can specify a bump type in `--bump`:
+
+```bash
+git cliff --bump [major|minor|patch]
+```
+
 ## Zero-based versioning scheme
 
 When working with a zero-based versioning scheme (i.e., `0.x.y` or `0.0.x`),


Test patch:
diff --git a/.github/fixtures/test-bump-version-major/cliff.toml b/.github/fixtures/test-bump-version-major/cliff.toml
new file mode 100644
index 00000000..c48526d
--- /dev/null
+++ b/.github/fixtures/test-bump-version-major/cliff.toml
@@ -0,0 +1,27 @@
+[changelog]
+# template for the changelog footer
+header = """
+# Changelog\n
+All notable changes to this project will be documented in this file.\n
+"""
+# template for the changelog body
+# https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version %}\
+    ## [{{ version | trim_start_matches(pat="v") }}]
+{% else %}\
+    ## [unreleased]
+{% endif %}\
+{% for group, commits in commits | group_by(attribute="group") %}
+    ### {{ group | upper_first }}
+    {% for commit in commits %}
+        - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
+    {% endfor %}
+{% endfor %}\n
+"""
+# template for the changelog footer
+footer = """
+<!-- generated by git-cliff -->
+"""
+# remove the leading and trailing whitespace from the templates
+trim = true
diff --git a/.github/fixtures/test-bump-version-major/commit.sh b/.github/fixtures/test-bump-version-major/commit.sh
new file mode 100755
index 00000000..3d7ef47
--- /dev/null
+++ b/.github/fixtures/test-bump-version-major/commit.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -e
+
+GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 1"
+GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 2"
+git tag v0.1.0
+
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "fix: fix feature 1"
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "fix: fix feature 2"
diff --git a/.github/fixtures/test-bump-version-major/expected.md b/.github/fixtures/test-bump-version-major/expected.md
new file mode 100644
index 00000000..84bb0ad
--- /dev/null
+++ b/.github/fixtures/test-bump-version-major/expected.md
@@ -0,0 +1,19 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [1.0.0]
+
+### Fix
+
+- Fix feature 1
+- Fix feature 2
+
+## [0.1.0]
+
+### Feat
+
+- Add feature 1
+- Add feature 2
+
+<!-- generated by git-cliff -->
diff --git a/.github/fixtures/test-bump-version-minor/cliff.toml b/.github/fixtures/test-bump-version-minor/cliff.toml
new file mode 100644
index 00000000..c48526d
--- /dev/null
+++ b/.github/fixtures/test-bump-version-minor/cliff.toml
@@ -0,0 +1,27 @@
+[changelog]
+# template for the changelog footer
+header = """
+# Changelog\n
+All notable changes to this project will be documented in this file.\n
+"""
+# template for the changelog body
+# https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version %}\
+    ## [{{ version | trim_start_matches(pat="v") }}]
+{% else %}\
+    ## [unreleased]
+{% endif %}\
+{% for group, commits in commits | group_by(attribute="group") %}
+    ### {{ group | upper_first }}
+    {% for commit in commits %}
+        - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
+    {% endfor %}
+{% endfor %}\n
+"""
+# template for the changelog footer
+footer = """
+<!-- generated by git-cliff -->
+"""
+# remove the leading and trailing whitespace from the templates
+trim = true
diff --git a/.github/fixtures/test-bump-version-minor/commit.sh b/.github/fixtures/test-bump-version-minor/commit.sh
new file mode 100755
index 00000000..0fd84c2
--- /dev/null
+++ b/.github/fixtures/test-bump-version-minor/commit.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -e
+
+GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 1"
+GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 2"
+git tag v0.1.0
+
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "feat!: add breaking feature"
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "fix: fix feature 2"
diff --git a/.github/fixtures/test-bump-version-minor/expected.md b/.github/fixtures/test-bump-version-minor/expected.md
new file mode 100644
index 00000000..b222642
--- /dev/null
+++ b/.github/fixtures/test-bump-version-minor/expected.md
@@ -0,0 +1,22 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [0.2.0]
+
+### Feat
+
+- [**breaking**] Add breaking feature
+
+### Fix
+
+- Fix feature 2
+
+## [0.1.0]
+
+### Feat
+
+- Add feature 1
+- Add feature 2
+
+<!-- generated by git-cliff -->
diff --git a/.github/fixtures/test-bump-version-patch/cliff.toml b/.github/fixtures/test-bump-version-patch/cliff.toml
new file mode 100644
index 00000000..c48526d
--- /dev/null
+++ b/.github/fixtures/test-bump-version-patch/cliff.toml
@@ -0,0 +1,27 @@
+[changelog]
+# template for the changelog footer
+header = """
+# Changelog\n
+All notable changes to this project will be documented in this file.\n
+"""
+# template for the changelog body
+# https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version %}\
+    ## [{{ version | trim_start_matches(pat="v") }}]
+{% else %}\
+    ## [unreleased]
+{% endif %}\
+{% for group, commits in commits | group_by(attribute="group") %}
+    ### {{ group | upper_first }}
+    {% for commit in commits %}
+        - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
+    {% endfor %}
+{% endfor %}\n
+"""
+# template for the changelog footer
+footer = """
+<!-- generated by git-cliff -->
+"""
+# remove the leading and trailing whitespace from the templates
+trim = true
diff --git a/.github/fixtures/test-bump-version-patch/commit.sh b/.github/fixtures/test-bump-version-patch/commit.sh
new file mode 100755
index 00000000..0fd84c2
--- /dev/null
+++ b/.github/fixtures/test-bump-version-patch/commit.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -e
+
+GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 1"
+GIT_COMMITTER_DATE="2021-01-23 01:23:45" git commit --allow-empty -m "feat: add feature 2"
+git tag v0.1.0
+
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "feat!: add breaking feature"
+GIT_COMMITTER_DATE="2021-01-23 01:23:46" git commit --allow-empty -m "fix: fix feature 2"
diff --git a/.github/fixtures/test-bump-version-patch/expected.md b/.github/fixtures/test-bump-version-patch/expected.md
new file mode 100644
index 00000000..9a8c825
--- /dev/null
+++ b/.github/fixtures/test-bump-version-patch/expected.md
@@ -0,0 +1,22 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1]
+
+### Feat
+
+- [**breaking**] Add breaking feature
+
+### Fix
+
+- Fix feature 2
+
+## [0.1.0]
+
+### Feat
+
+- Add feature 1
+- Add feature 2
+
+<!-- generated by git-cliff -->
diff --git a/.github/workflows/test-fixtures.yml b/.github/workflows/test-fixtures.yml
index 77e30ca..f732dc1 100644
--- a/.github/workflows/test-fixtures.yml
+++ b/.github/workflows/test-fixtures.yml
@@ -38,6 +38,12 @@ jobs:
           - fixtures-name: test-split-commits
           - fixtures-name: test-bump-version
             command: --bump
+          - fixtures-name: test-bump-version-major
+            command: --bump major
+          - fixtures-name: test-bump-version-minor
+            command: --bump minor
+          - fixtures-name: test-bump-version-patch
+            command: --bump patch
           - fixtures-name: test-bump-version-custom-minor
             command: --bump
           - fixtures-name: test-bumped-version