Skip to content

Commit

Permalink
feat: allow bumping with other commit types
Browse files Browse the repository at this point in the history
Closes #213
  • Loading branch information
oknozor committed Nov 16, 2023
1 parent 8e05d9c commit 49d586a
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 75 deletions.
16 changes: 8 additions & 8 deletions src/command/bump/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,10 @@ impl Release<'_> {
// won't affect the version number.
let mut non_bump_commits: Vec<&CommitType> = conventional_commits
.iter()
.filter_map(|commit| match &commit.message.commit_type {
.filter_map(|commit| match &commit.conventional.commit_type {
CommitType::Feature | CommitType::BugFix => None,
_commit_type if commit.message.is_breaking_change => None,
_ => Some(&commit.message.commit_type),
_commit_type if commit.conventional.is_breaking_change => None,
_ => Some(&commit.conventional.commit_type),
})
.collect();

Expand All @@ -350,20 +350,20 @@ impl Release<'_> {
let bump_commits =
conventional_commits
.iter()
.filter(|commit| match &commit.message.commit_type {
.filter(|commit| match &commit.conventional.commit_type {
CommitType::Feature | CommitType::BugFix => true,
_commit_type if commit.message.is_breaking_change => true,
_commit_type if commit.conventional.is_breaking_change => true,
_ => false,
});

for commit in bump_commits {
match &commit.message.commit_type {
_commit_type if commit.message.is_breaking_change => {
match &commit.conventional.commit_type {
_commit_type if commit.conventional.is_breaking_change => {
info!(
"\t Found {} commit {} with type: {}",
"BREAKING CHANGE".red(),
commit.shorthand().blue(),
commit.message.commit_type.as_ref().yellow()
commit.conventional.commit_type.as_ref().yellow()
)
}
CommitType::Feature => {
Expand Down
139 changes: 107 additions & 32 deletions src/conventional/bump.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::conventional::error::BumpError;
use crate::conventional::version::Increment;
use crate::{Commit, IncrementCommand, Repository, RevspecPattern, Tag, SETTINGS};
use conventional_commit_parser::commit::CommitType;
use std::str::FromStr;

use git2::Commit as Git2Commit;
use once_cell::sync::Lazy;
use semver::{BuildMetadata, Prerelease, Version};
use std::str::FromStr;

use crate::conventional::error::BumpError;
use crate::conventional::version::Increment;
use crate::{Commit, IncrementCommand, Repository, RevspecPattern, Tag, SETTINGS};

static FILTER_MERGE_COMMITS: Lazy<fn(&&git2::Commit) -> bool> = Lazy::new(|| {
|commit| {
Expand Down Expand Up @@ -259,24 +260,11 @@ impl Tag {
&self,
commits: &[Commit],
) -> Result<Increment, BumpError> {
let is_major_bump = || {
self.version.major != 0
&& commits
.iter()
.any(|commit| commit.message.is_breaking_change)
};
let is_major_bump = || self.version.major != 0 && commits.iter().any(Commit::is_major_bump);

let is_minor_bump = || {
commits
.iter()
.any(|commit| commit.message.commit_type == CommitType::Feature)
};
let is_minor_bump = || commits.iter().any(Commit::is_minor_bump);

let is_patch_bump = || {
commits
.iter()
.any(|commit| commit.message.commit_type == CommitType::BugFix)
};
let is_patch_bump = || commits.iter().any(Commit::is_patch_bump);

// At this point, it is not a major, minor or patch bump but we might have found conventional commits
// -> Must be only chore, docs, refactor ... which means commits that don't require bump but shouldn't throw error
Expand All @@ -298,29 +286,32 @@ impl Tag {

#[cfg(test)]
mod test {
use crate::conventional::bump::Bump;
use crate::conventional::commit::Commit;
use crate::conventional::error::BumpError;
use crate::conventional::version::{Increment, IncrementCommand};
use crate::git::repository::Repository;
use crate::git::tag::Tag;
use crate::settings::{MonoRepoPackage, Settings};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;

use anyhow::Result;
use chrono::Utc;
use cmd_lib::run_cmd;
use conventional_commit_parser::commit::{CommitType, ConventionalCommit};
use sealed_test::prelude::*;
use semver::Version;
use speculoos::prelude::*;
use std::collections::HashMap;
use std::path::PathBuf;
use std::str::FromStr;

use crate::conventional::bump::Bump;
use crate::conventional::commit::{Commit, CommitConfig};
use crate::conventional::error::BumpError;
use crate::conventional::version::{Increment, IncrementCommand};
use crate::git::repository::Repository;
use crate::git::tag::Tag;
use crate::settings::{MonoRepoPackage, Settings};

impl Commit {
fn commit_fixture(commit_type: CommitType, is_breaking_change: bool) -> Self {
Commit {
oid: "1234".to_string(),
message: ConventionalCommit {
conventional: ConventionalCommit {
commit_type,
scope: None,
body: None,
Expand Down Expand Up @@ -538,6 +529,90 @@ mod test {
Ok(())
}

#[sealed_test]
fn should_get_next_auto_version_minor_with_custom_commit_type() -> Result<()> {
// Arrange
Repository::init(".")?;
let mut commit_types = HashMap::new();
commit_types.insert("ex".to_string(), CommitConfig::new("Ex").with_minor_bump());
let settings = Settings {
commit_types,
..Default::default()
};

let settings = toml::to_string(&settings)?;
fs::write("cog.toml", settings)?;

let patch = Commit::commit_fixture(CommitType::BugFix, false);
let feature = Commit::commit_fixture(CommitType::Custom("ex".to_string()), false);
let base_version = Tag::from_str("0.1.0", None)?;

// Act
let version = base_version.version_increment_from_commit_history(&[patch, feature]);

// Assert
assert_that!(version).is_ok().is_equal_to(Increment::Minor);

Ok(())
}

#[sealed_test]
fn should_get_next_auto_version_patch_with_custom_commit_type() -> Result<()> {
// Arrange
Repository::init(".")?;
let mut commit_types = HashMap::new();
commit_types.insert("ex".to_string(), CommitConfig::new("Ex").with_patch_bump());
let settings = Settings {
commit_types,
..Default::default()
};

let settings = toml::to_string(&settings)?;
fs::write("cog.toml", settings)?;

let patch = Commit::commit_fixture(CommitType::Chore, false);
let feature = Commit::commit_fixture(CommitType::Custom("ex".to_string()), false);
let base_version = Tag::from_str("0.1.0", None)?;

// Act
let version = base_version.version_increment_from_commit_history(&[patch, feature]);

// Assert
assert_that!(version).is_ok().is_equal_to(Increment::Patch);

Ok(())
}

#[sealed_test]
fn should_override_bump_behavior_for_existing_commit_type() -> Result<()> {
// Arrange
Repository::init(".")?;
let mut commit_types = HashMap::new();
commit_types.insert(
"perf".to_string(),
CommitConfig::new("Perf").with_minor_bump(),
);
let settings = Settings {
commit_types,
..Default::default()
};

let settings = toml::to_string(&settings)?;
fs::write("cog.toml", settings)?;

let patch = Commit::commit_fixture(CommitType::Chore, false);
let feature = Commit::commit_fixture(CommitType::Performances, false);
let base_version = Tag::from_str("0.1.0", None)?;

// Act
let version = base_version.version_increment_from_commit_history(&[patch, feature]);

// Assert
assert_that!(version).is_ok().is_equal_to(Increment::Minor);

Ok(())
}

#[test]
fn should_not_fail_without_feature_bug_fix_or_breaking_change_commit() -> Result<()> {
// Arrange
Expand Down
6 changes: 3 additions & 3 deletions src/conventional/changelog/release.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ mod test {
author_username: Some("oknozor"),
commit: Commit {
oid: a_commit_hash.to_string(),
message: ConventionalCommit {
conventional: ConventionalCommit {
commit_type: CommitType::BugFix,
scope: Some("parser".to_string()),
summary: "fix parser implementation".to_string(),
Expand All @@ -581,7 +581,7 @@ mod test {
author_username: None,
commit: Commit {
oid: a_commit_hash.to_string(),
message: ConventionalCommit {
conventional: ConventionalCommit {
commit_type: CommitType::Feature,
scope: None,
summary: "awesome feature".to_string(),
Expand All @@ -601,7 +601,7 @@ mod test {
author_username: Some("oknozor"),
commit: Commit {
oid: a_commit_hash.to_string(),
message: ConventionalCommit {
conventional: ConventionalCommit {
commit_type: CommitType::Feature,
scope: Some("parser".to_string()),
summary: "implement the changelog generator".to_string(),
Expand Down
19 changes: 11 additions & 8 deletions src/conventional/changelog/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,30 @@ impl Serialize for ChangelogCommit<'_> {

let footers = &self
.commit
.message
.conventional
.footers
.iter()
.map(ChangelogFooter::from)
.collect::<Vec<ChangelogFooter>>();

let commit_type = &COMMITS_METADATA
.iter()
.find(|(commit_type, _config)| *commit_type == &self.commit.message.commit_type)
.find(|(commit_type, _config)| *commit_type == &self.commit.conventional.commit_type)
.map(|meta| meta.1.changelog_title.clone())
.unwrap_or_else(|| self.commit.message.commit_type.to_string());
.unwrap_or_else(|| self.commit.conventional.commit_type.to_string());

commit.serialize_field("id", &self.commit.oid)?;
commit.serialize_field("author", &self.author_username)?;
commit.serialize_field("signature", &self.commit.author)?;
commit.serialize_field("type", commit_type)?;
commit.serialize_field("date", &self.commit.date)?;
commit.serialize_field("scope", &self.commit.message.scope)?;
commit.serialize_field("summary", &self.commit.message.summary)?;
commit.serialize_field("body", &self.commit.message.body)?;
commit.serialize_field("breaking_change", &self.commit.message.is_breaking_change)?;
commit.serialize_field("scope", &self.commit.conventional.scope)?;
commit.serialize_field("summary", &self.commit.conventional.summary)?;
commit.serialize_field("body", &self.commit.conventional.body)?;
commit.serialize_field(
"breaking_change",
&self.commit.conventional.is_breaking_change,
)?;
commit.serialize_field("footer", footers)?;
commit.end()
}
Expand Down Expand Up @@ -99,7 +102,7 @@ mod test {
author_username: Some("Jm Doudou"),
commit: Commit {
oid: "1234567890".to_string(),
message: ConventionalCommit {
conventional: ConventionalCommit {
commit_type: CommitType::BugFix,
scope: Some("parser".to_string()),
summary: "fix parser implementation".to_string(),
Expand Down

0 comments on commit 49d586a

Please sign in to comment.