mirror of
https://github.com/orhun/git-cliff.git
synced 2024-09-19 03:08:30 +03:00
feat(bump): support bumping to a specific semver type (#744)
* feat: support bump a specific version type * let --bump accept optional enum * doc: update document for --bump * test: add bump version fixtures tests * refactor: polish implementation * refactor: fix typo --------- Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
This commit is contained in:
parent
e2fb043078
commit
9dbf47bac5
27
.github/fixtures/test-bump-version-major/cliff.toml
vendored
Normal file
27
.github/fixtures/test-bump-version-major/cliff.toml
vendored
Normal file
@ -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
|
9
.github/fixtures/test-bump-version-major/commit.sh
vendored
Executable file
9
.github/fixtures/test-bump-version-major/commit.sh
vendored
Executable file
@ -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"
|
19
.github/fixtures/test-bump-version-major/expected.md
vendored
Normal file
19
.github/fixtures/test-bump-version-major/expected.md
vendored
Normal file
@ -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 -->
|
27
.github/fixtures/test-bump-version-minor/cliff.toml
vendored
Normal file
27
.github/fixtures/test-bump-version-minor/cliff.toml
vendored
Normal file
@ -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
|
9
.github/fixtures/test-bump-version-minor/commit.sh
vendored
Executable file
9
.github/fixtures/test-bump-version-minor/commit.sh
vendored
Executable file
@ -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"
|
22
.github/fixtures/test-bump-version-minor/expected.md
vendored
Normal file
22
.github/fixtures/test-bump-version-minor/expected.md
vendored
Normal file
@ -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 -->
|
27
.github/fixtures/test-bump-version-patch/cliff.toml
vendored
Normal file
27
.github/fixtures/test-bump-version-patch/cliff.toml
vendored
Normal file
@ -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
|
9
.github/fixtures/test-bump-version-patch/commit.sh
vendored
Executable file
9
.github/fixtures/test-bump-version-patch/commit.sh
vendored
Executable file
@ -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"
|
22
.github/fixtures/test-bump-version-patch/expected.md
vendored
Normal file
22
.github/fixtures/test-bump-version-patch/expected.md
vendored
Normal file
@ -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 -->
|
6
.github/workflows/test-fixtures.yml
vendored
6
.github/workflows/test-fixtures.yml
vendored
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
})?
|
||||
);
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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) =
|
||||
|
@ -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"
|
||||
```
|
||||
|
@ -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=]
|
||||
|
@ -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`),
|
||||
|
Loading…
Reference in New Issue
Block a user