Skip to content

Commit

Permalink
feat(changelog): support bumping the semantic version via --bump (#309
Browse files Browse the repository at this point in the history
)
  • Loading branch information
orhun authored Oct 13, 2023
1 parent a6a890a commit bcfcd1f
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 2 deletions.
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions git-cliff-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ tera = "1.19.1"
indexmap = { version = "2.0.2", optional = true }
toml = "0.8.2"
lazy-regex = "3.0.2"
next_version = "0.2.8"
semver = "1.0.19"

[dependencies.git2]
version = "0.18.1"
Expand Down
7 changes: 7 additions & 0 deletions git-cliff-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ pub enum Error {
/// Error that may occur while parsing integers.
#[error("Failed to parse integer: `{0}`")]
IntParseError(#[from] std::num::TryFromIntError),
/// Error that may occur while parsing a SemVer version or version
/// requirement.
#[error("Semver error: `{0}`")]
SemverError(#[from] semver::Error),
/// Error that may occur when a version is not found for the next release.
#[error("Previous version is not found for calculating the next release.")]
PreviousVersionNotFound,
}

/// Result type of the core library.
Expand Down
57 changes: 56 additions & 1 deletion git-cliff-core/src/release.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use crate::commit::Commit;
use crate::error::Result;
use crate::error::{
Error,
Result,
};
use next_version::NextVersion;
use semver::Version;
use serde::{
Deserialize,
Serialize,
Expand All @@ -22,6 +27,26 @@ pub struct Release<'a> {
pub previous: Option<Box<Release<'a>>>,
}

impl<'a> Release<'a> {
/// Calculates the next version based on the commits.
pub fn calculate_next_version(&self) -> Result<String> {
let version = self
.previous
.as_ref()
.and_then(|release| release.version.clone())
.ok_or_else(|| Error::PreviousVersionNotFound)?;
let next_version = Version::parse(version.trim_start_matches('v'))?
.next(
self.commits
.iter()
.map(|commit| commit.message.to_string())
.collect::<Vec<String>>(),
)
.to_string();
Ok(next_version)
}
}

/// Representation of a list of releases.
pub struct Releases<'a>(pub &'a Vec<Release<'a>>);

Expand All @@ -31,3 +56,33 @@ impl<'a> Releases<'a> {
Ok(serde_json::to_string(self.0)?)
}
}

#[cfg(test)]
mod test {
use super::*;
#[test]
fn bump_version() -> Result<()> {
for (expected_version, commits) in [
("1.1.0", vec!["feat: add xyz", "fix: fix xyz"]),
("1.0.1", vec!["fix: add xyz", "fix: aaaaaa"]),
("2.0.0", vec!["feat!: add xyz", "feat: zzz"]),
] {
let release = Release {
version: None,
commits: commits
.into_iter()
.map(|v| Commit::from(v.to_string()))
.collect(),
commit_id: None,
timestamp: 0,
previous: Some(Box::new(Release {
version: Some(String::from("1.0.0")),
..Default::default()
})),
};
let next_version = release.calculate_next_version()?;
assert_eq!(expected_version, next_version);
}
Ok(())
}
}
3 changes: 3 additions & 0 deletions git-cliff/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ 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,
/// Sets the template for the changelog body.
#[arg(
short,
Expand Down
11 changes: 11 additions & 0 deletions git-cliff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,17 @@ fn process_repository<'a>(
}
}

// Bump the version.
if args.bump && releases[release_index].version.is_none() {
let next_version = releases[release_index].calculate_next_version()?;
debug!("Bumping the version to {next_version}");
releases[release_index].version = Some(next_version.to_string());
releases[release_index].timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_secs()
.try_into()?;
}

Ok(releases)
}

Expand Down
10 changes: 9 additions & 1 deletion website/docs/usage/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,21 @@ Then simply create a changelog at your projects git root directory:
git cliff
```

Set a tag for the "unreleased" changes:
Set a tag for the unreleased changes:

```bash
# it doesn't have to be an existing tag
git cliff --tag 1.0.0
```

Calculate and set the next semantic version (i.e. _bump the version_) for the unreleased changes:

```bash
# Semver: {MAJOR}.{MINOR}.{PATCH}
# "fix:" increments PATCH, "feat:" increments MINOR and "scope!" (breaking changes) increments MAJOR
git cliff --bump
```

Generate a changelog for a certain part of git history:

```bash
Expand Down
2 changes: 2 additions & 0 deletions website/docs/usage/usage.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
sidebar_position: 3
---

# Usage

```
Expand All @@ -13,6 +14,7 @@ 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
-i, --init Writes the default configuration file to cliff.toml
-l, --latest Processes the commits starting from the latest tag
--current Processes the commits that belong to the current tag
Expand Down

0 comments on commit bcfcd1f

Please sign in to comment.