feat: with conventional parse
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
parent
62cafa4a9e
commit
51e3ea3e2f
152
Cargo.lock
generated
152
Cargo.lock
generated
@ -120,6 +120,15 @@ version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
@ -191,6 +200,16 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "conventional_commit_parser"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58660f9e1d5eeeeec9c33d1473ea8bba000c673a2189edaeedb4523ec7d6f7cb"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
@ -207,12 +226,32 @@ version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cuddle-please"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"conventional_commit_parser",
|
||||
"dotenv",
|
||||
"reqwest",
|
||||
"semver",
|
||||
@ -225,6 +264,16 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenv"
|
||||
version = "0.15.0"
|
||||
@ -351,6 +400,16 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.3"
|
||||
@ -740,6 +799,50 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.10"
|
||||
@ -991,6 +1094,17 @@ dependencies = [
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
@ -1075,6 +1189,26 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
@ -1253,6 +1387,18 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
@ -1309,6 +1455,12 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
|
@ -16,6 +16,7 @@ url = {version = "*"}
|
||||
serde_yaml = {version = "*"}
|
||||
serde = {version = "*", features = ["derive"]}
|
||||
semver = "1.0.18"
|
||||
conventional_commit_parser = "0.9.4"
|
||||
|
||||
reqwest = {version = "*"}
|
||||
|
||||
|
@ -15,6 +15,8 @@ serde.workspace = true
|
||||
reqwest = {workspace = true, features = ["blocking", "json"]}
|
||||
url.workspace = true
|
||||
semver.workspace = true
|
||||
conventional_commit_parser.workspace = true
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-test = {workspace = true, features = ["no-env-filter"]}
|
||||
|
191
crates/cuddle-please/src/versioning/conventional_parse.rs
Normal file
191
crates/cuddle-please/src/versioning/conventional_parse.rs
Normal file
@ -0,0 +1,191 @@
|
||||
use conventional_commit_parser::commit::{CommitType, ConventionalCommit};
|
||||
use semver::Version;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum VersionIncrement {
|
||||
Major,
|
||||
Minor,
|
||||
Patch,
|
||||
Prerelease,
|
||||
}
|
||||
|
||||
impl VersionIncrement {
|
||||
pub fn from<C>(cur_version: &Version, commits: C) -> Option<Self>
|
||||
where
|
||||
C: IntoIterator,
|
||||
C::Item: AsRef<str>,
|
||||
{
|
||||
let mut commits = commits.into_iter().peekable();
|
||||
if commits.peek().is_none() {
|
||||
return None;
|
||||
}
|
||||
if let Some(prerelease) = Self::is_prerelease(cur_version) {
|
||||
return Some(prerelease);
|
||||
}
|
||||
|
||||
let commits: Vec<ConventionalCommit> = Self::parse_commits::<C>(commits);
|
||||
|
||||
return Some(Self::from_conventional_commits(commits));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parse_commits<C>(
|
||||
commits: std::iter::Peekable<<C as IntoIterator>::IntoIter>,
|
||||
) -> Vec<ConventionalCommit>
|
||||
where
|
||||
C: IntoIterator,
|
||||
C::Item: AsRef<str>,
|
||||
{
|
||||
commits
|
||||
.filter_map(|c| conventional_commit_parser::parse(c.as_ref()).ok())
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Find most significant change
|
||||
fn from_conventional_commits(commits: Vec<ConventionalCommit>) -> VersionIncrement {
|
||||
let found_breaking = || commits.iter().any(|c| c.is_breaking_change);
|
||||
let found_feature = || {
|
||||
commits
|
||||
.iter()
|
||||
.any(|c| matches!(c.commit_type, CommitType::Feature))
|
||||
};
|
||||
|
||||
match (found_breaking(), found_feature()) {
|
||||
(true, _) => Self::Major,
|
||||
(_, true) => Self::Minor,
|
||||
(_, false) => Self::Patch,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_prerelease(cur_version: &Version) -> Option<VersionIncrement> {
|
||||
if !cur_version.pre.is_empty() {
|
||||
return Some(Self::Prerelease);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::versioning::conventional_parse::VersionIncrement;
|
||||
use semver::Version;
|
||||
use tracing_test::traced_test;
|
||||
|
||||
use crate::{environment::get_from_environment, gitea_client::Commit};
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_prerelease() {
|
||||
let mut version = Version::parse("0.0.0-alpha.1").unwrap();
|
||||
|
||||
let commits = vec![
|
||||
"feat: something",
|
||||
"fix: something",
|
||||
"feat(something): something",
|
||||
"feat(breaking): some
|
||||
|
||||
BREAKING CHANGE: something",
|
||||
];
|
||||
|
||||
let actual = VersionIncrement::from(&version, commits).unwrap();
|
||||
assert_eq!(VersionIncrement::Prerelease, actual);
|
||||
}
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_patch() {
|
||||
let mut version = Version::parse("0.0.1").unwrap();
|
||||
|
||||
let commits = vec![
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
];
|
||||
|
||||
let actual = VersionIncrement::from(&version, commits).unwrap();
|
||||
assert_eq!(VersionIncrement::Patch, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_minor() {
|
||||
let mut version = Version::parse("0.1.0").unwrap();
|
||||
|
||||
let commits = vec![
|
||||
"feat: something",
|
||||
"feat: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
];
|
||||
|
||||
let actual = VersionIncrement::from(&version, commits).unwrap();
|
||||
assert_eq!(VersionIncrement::Minor, actual);
|
||||
}
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_major() {
|
||||
let mut version = Version::parse("0.1.0").unwrap();
|
||||
|
||||
let commits = vec![
|
||||
"feat: something",
|
||||
"feat: something
|
||||
|
||||
BREAKING CHANGE: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
"fix: something",
|
||||
];
|
||||
|
||||
let actual = VersionIncrement::from(&version, commits).unwrap();
|
||||
assert_eq!(VersionIncrement::Major, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn chore_is_patch() {
|
||||
let mut version = Version::parse("0.1.0").unwrap();
|
||||
|
||||
let commits = vec!["chore: something"];
|
||||
|
||||
let actual = VersionIncrement::from(&version, commits).unwrap();
|
||||
assert_eq!(VersionIncrement::Patch, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn refactor_is_patch() {
|
||||
let mut version = Version::parse("0.1.0").unwrap();
|
||||
|
||||
let commits = vec!["refactor: something"];
|
||||
|
||||
let actual = VersionIncrement::from(&version, commits).unwrap();
|
||||
assert_eq!(VersionIncrement::Patch, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn unknown_commits_are_patch() {
|
||||
let mut version = Version::parse("0.1.0").unwrap();
|
||||
|
||||
let commits = vec!["blablabla some commit"];
|
||||
|
||||
let actual = VersionIncrement::from(&version, commits).unwrap();
|
||||
assert_eq!(VersionIncrement::Patch, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn nothing_returns_none() {
|
||||
let mut version = Version::parse("0.1.0").unwrap();
|
||||
|
||||
let commits: Vec<&str> = Vec::new();
|
||||
|
||||
let actual = VersionIncrement::from(&version, commits).is_none();
|
||||
assert_eq!(true, actual);
|
||||
}
|
||||
}
|
@ -1 +1,3 @@
|
||||
pub mod conventional_parse;
|
||||
pub mod next_version;
|
||||
pub mod semver;
|
||||
|
170
crates/cuddle-please/src/versioning/next_version.rs
Normal file
170
crates/cuddle-please/src/versioning/next_version.rs
Normal file
@ -0,0 +1,170 @@
|
||||
use semver::{Prerelease, Version};
|
||||
|
||||
use super::conventional_parse::VersionIncrement;
|
||||
|
||||
pub trait NextVersion {
|
||||
fn next<I>(&self, commits: I) -> Self
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<str>;
|
||||
}
|
||||
|
||||
impl NextVersion for Version {
|
||||
fn next<I>(&self, commits: I) -> Self
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<str>,
|
||||
{
|
||||
let increment = VersionIncrement::from(self, commits);
|
||||
|
||||
match increment {
|
||||
Some(increment) => match increment {
|
||||
VersionIncrement::Major => Self {
|
||||
major: self.major + 1,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
pre: Prerelease::EMPTY,
|
||||
..self.clone()
|
||||
},
|
||||
VersionIncrement::Minor => Self {
|
||||
minor: self.minor + 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::EMPTY,
|
||||
..self.clone()
|
||||
},
|
||||
VersionIncrement::Patch => Self {
|
||||
patch: self.patch + 1,
|
||||
pre: Prerelease::EMPTY,
|
||||
..self.clone()
|
||||
},
|
||||
VersionIncrement::Prerelease => Self {
|
||||
pre: {
|
||||
let release = &self.pre;
|
||||
let release_version = match release.rsplit_once(".") {
|
||||
Some((tag, version)) => match version.parse::<usize>() {
|
||||
Ok(version) => format!("{tag}.{}", version + 1),
|
||||
Err(_) => format!("{tag}.1"),
|
||||
},
|
||||
None => format!("{release}.1"),
|
||||
};
|
||||
Prerelease::new(&release_version).expect("prerelease is not valid semver")
|
||||
},
|
||||
..self.clone()
|
||||
},
|
||||
},
|
||||
None => self.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use semver::Version;
|
||||
use tracing_test::traced_test;
|
||||
|
||||
use crate::versioning::next_version::NextVersion;
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_no_bump() {
|
||||
let version = Version::parse("0.0.0-prerelease").unwrap();
|
||||
let commits: Vec<&str> = vec![];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("0.0.0-prerelease", actual.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_prerelease_initial() {
|
||||
let version = Version::parse("0.0.0-prerelease").unwrap();
|
||||
let commits: Vec<&str> = vec!["feat: something"];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("0.0.0-prerelease.1", actual.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_prerelease_invalid() {
|
||||
let version = Version::parse("0.0.0-prerelease.invalid").unwrap();
|
||||
let commits: Vec<&str> = vec!["feat: something"];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("0.0.0-prerelease.1", actual.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_prerelease_next() {
|
||||
let version = Version::parse("0.0.0-prerelease.1").unwrap();
|
||||
let commits: Vec<&str> = vec!["feat: something"];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("0.0.0-prerelease.2", actual.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_patch() {
|
||||
let version = Version::parse("0.0.0").unwrap();
|
||||
let commits: Vec<&str> = vec!["fix: something"];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("0.0.1", actual.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_minor() {
|
||||
let version = Version::parse("0.1.0").unwrap();
|
||||
let commits: Vec<&str> = vec!["feat: something"];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("0.2.0", actual.to_string())
|
||||
}
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_minor_clears_patch() {
|
||||
let version = Version::parse("0.1.1").unwrap();
|
||||
let commits: Vec<&str> = vec!["feat: something"];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("0.2.0", actual.to_string())
|
||||
}
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_major() {
|
||||
let version = Version::parse("0.0.0").unwrap();
|
||||
let commits: Vec<&str> = vec![
|
||||
"feat: something
|
||||
|
||||
BREAKING CHANGE: something",
|
||||
];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("1.0.0", actual.to_string())
|
||||
}
|
||||
#[test]
|
||||
#[traced_test]
|
||||
fn is_major_clears_minor_patch() {
|
||||
let version = Version::parse("1.2.3").unwrap();
|
||||
let commits: Vec<&str> = vec![
|
||||
"feat: something
|
||||
|
||||
BREAKING CHANGE: something",
|
||||
];
|
||||
|
||||
let actual = version.next(commits);
|
||||
|
||||
assert_eq!("2.0.0", actual.to_string())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user