Skip to content

Commit

Permalink
feat: update to new conventional commit parser
Browse files Browse the repository at this point in the history
The new parser uses the [Nom] library for improved accuracy and zero
allocations with fewer dependencies.

[nom]: https://docs.rs/nom
  • Loading branch information
JeanMertz committed Aug 17, 2019
1 parent f9cf172 commit 9ca8143
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 64 deletions.
48 changes: 21 additions & 27 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -14,7 +14,7 @@ edition = "2018"
Inflector = { version = "0.11", default-features = false }
boolinator = "2"
chrono = { version = "0.4", default-features = false, features = ["serde"] }
conventional-commit = "0.1"
conventional = "0.3"
git2 = { version = "0.9", default-features = false }
lazy_static = "1"
ron = "0.5"
Expand Down
21 changes: 14 additions & 7 deletions src/changelog.rs
Expand Up @@ -13,29 +13,36 @@ use crate::{Config, Error};
use serde::Serialize;

#[derive(Debug, Serialize)]
pub struct Changelog {
pub struct Changelog<'a> {
config: Config,
unreleased: ChangeSet,
releases: Vec<Release>,
unreleased: ChangeSet<'a>,
releases: Vec<Release<'a>>,
}

impl Changelog {
pub fn new(config: Config, mut commits: Vec<Commit>, tags: Vec<Tag>) -> Result<Self, Error> {
impl<'a> Changelog<'a> {
pub fn new(config: Config, commits: &'a [Commit], tags: Vec<Tag>) -> Result<Self, Error> {
let mut offset = 0;

let mut releases = tags
.into_iter()
.map(Release::new)
.collect::<Result<Vec<_>, _>>()?;

for release in &mut releases {
let mut changeset = ChangeSet::default();
changeset.take_commits(&mut commits, &config.accept_types, Some(release.tag()))?;
offset = changeset.take_commits(
offset,
&commits,
&config.accept_types,
Some(release.tag()),
)?;
release.with_changeset(changeset);
}

releases.reverse();

let mut unreleased = ChangeSet::default();
unreleased.take_commits(&mut commits, &config.accept_types, None)?;
unreleased.take_commits(offset, &commits, &config.accept_types, None)?;

Ok(Self {
config,
Expand Down
17 changes: 8 additions & 9 deletions src/changelog/change.rs
@@ -1,22 +1,21 @@
use crate::changelog::Contributor;
use crate::git::Commit;
use crate::Error;
use conventional_commit::ConventionalCommit;
use conventional::{Commit as CCommit, Simple as _};
use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize;
use std::collections::HashMap;
use std::str::FromStr;

/// A single change in the change log.
#[derive(Debug)]
pub(crate) struct Change {
commit: Commit,
conventional: ConventionalCommit,
pub(crate) struct Change<'a> {
commit: &'a Commit,
conventional: CCommit<'a>,
}

impl Change {
pub(crate) fn new(commit: Commit) -> Result<Self, Error> {
let conventional = ConventionalCommit::from_str(&commit.message)?;
impl<'a> Change<'a> {
pub(crate) fn new(commit: &'a Commit) -> Result<Self, Error> {
let conventional = CCommit::new(&commit.message)?;

Ok(Self {
commit,
Expand Down Expand Up @@ -62,7 +61,7 @@ impl Change {
}
}

impl Serialize for Change {
impl Serialize for Change<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Expand Down
28 changes: 17 additions & 11 deletions src/changelog/changeset.rs
Expand Up @@ -6,12 +6,12 @@ use serde::Serialize;

/// A set of changes belonging together.
#[derive(Debug, Default)]
pub(crate) struct ChangeSet {
pub(crate) struct ChangeSet<'a> {
/// Internal reference to the changes in this change set.
changes: Vec<Change>,
changes: Vec<Change<'a>>,
}

impl ChangeSet {
impl<'a> ChangeSet<'a> {
/// Given a set of Git commits, take all commits belonging to this change
/// set.
///
Expand Down Expand Up @@ -47,36 +47,42 @@ impl ChangeSet {
/// If any of the Git operations fail, an error is returned.
pub(crate) fn take_commits(
&mut self,
commits: &mut Vec<Commit>,
mut offset: usize,
commits: &'a [Commit],
accept_types: &Option<Vec<String>>,
tag: Option<&Tag>,
) -> Result<(), Error> {
) -> Result<usize, Error> {
if commits.is_empty() {
return Ok(());
return Ok(offset);
}

let idx = match tag {
None => Some(commits.len().checked_sub(1).unwrap_or_default()),
Some(tag) => commits
.iter()
.enumerate()
.skip(offset)
.skip_while(|(_, c)| c.id != tag.commit.id)
.map(|(idx, _)| idx)
.next(),
};

let changes = match idx {
None => return Ok(()),
None => return Ok(offset),
Some(idx) => commits
.drain(0..=idx)
.filter_map(|commit| match Change::new(commit) {
.iter()
.skip(offset)
.take(idx)
.filter_map(|commit| match Change::new(&commit) {
Err(Error::InvalidCommitType) => None,
Err(err) => Some(Err(err)),
Ok(change) => Some(Ok(change)),
})
.collect::<Result<Vec<_>, _>>()?,
};

offset += idx.unwrap_or_default();

self.changes.append(
&mut changes
.into_iter()
Expand All @@ -91,7 +97,7 @@ impl ChangeSet {
.collect(),
);

Ok(())
Ok(offset)
}

/// Return the list of changes in this change set.
Expand All @@ -115,7 +121,7 @@ impl ChangeSet {
}
}

impl Serialize for ChangeSet {
impl Serialize for ChangeSet<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Expand Down
10 changes: 5 additions & 5 deletions src/changelog/release.rs
Expand Up @@ -7,18 +7,18 @@ use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize;

#[derive(Debug)]
pub(crate) struct Release {
pub(crate) struct Release<'a> {
/// The version of the release.
version: Version,

/// Internal reference to the Git tag of this release.
tag: Tag,

/// Internal reference to the change set of this release.
changeset: ChangeSet,
changeset: ChangeSet<'a>,
}

impl Serialize for Release {
impl Serialize for Release<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Expand All @@ -33,7 +33,7 @@ impl Serialize for Release {
}
}

impl Release {
impl<'a> Release<'a> {
pub(crate) fn new(tag: Tag) -> Result<Self, Error> {
let version = Version::parse(&tag.name[1..])?;

Expand All @@ -45,7 +45,7 @@ impl Release {
}

/// Add a set of changes to the release.
pub(crate) fn with_changeset(&mut self, changeset: ChangeSet) {
pub(crate) fn with_changeset(&mut self, changeset: ChangeSet<'a>) {
self.changeset = changeset;
}

Expand Down
6 changes: 3 additions & 3 deletions src/error.rs
Expand Up @@ -8,7 +8,7 @@ pub enum Error {
Config(ron::de::Error),

/// The commit does not adhere to the conventional spec.
ConventionalCommit(conventional_commit::Error),
ConventionalCommit(conventional::Error),

/// A formatting error.
Format(fmt::Error),
Expand Down Expand Up @@ -119,8 +119,8 @@ impl From<fmt::Error> for Error {
}
}

impl From<conventional_commit::Error> for Error {
fn from(err: conventional_commit::Error) -> Self {
impl From<conventional::Error> for Error {
fn from(err: conventional::Error) -> Self {
Error::ConventionalCommit(err)
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Expand Up @@ -13,6 +13,7 @@ fn main() {
fn run() -> Result<String, Error> {
let repo = git2::Repository::open(".")?;
let config = Config::from_environment()?;
let commits = git::commits(&repo)?;

Changelog::new(config, git::commits(&repo)?, git::tags(&repo)?)?.render()
Changelog::new(config, &commits, git::tags(&repo)?)?.render()
}

0 comments on commit 9ca8143

Please sign in to comment.