Skip to content

Commit

Permalink
feat(commit): add commit author and committer to the context (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
orhun committed Aug 15, 2022
1 parent d453d4c commit 940065b
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 41 deletions.
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
- [Conventional Commits](#conventional-commits)
- [Footers](#footers)
- [Breaking Changes](#breaking-changes)
- [Committer vs Author](#committer-vs-author)
- [Non-Conventional Commits](#non-conventional-commits)
- [Syntax](#syntax)
- [Examples](#examples-1)
Expand Down Expand Up @@ -706,7 +707,17 @@ following context is generated to use for templating:
"breaking_description": "<description>",
"breaking": false,
"conventional": true,
"links": [{"text": "(set by link_parsers)", "href": "(set by link_parsers)"}]
"links": [{"text": "(set by link_parsers)", "href": "(set by link_parsers)"}],
"author": {
"name": "User Name",
"email": "[email protected]",
"timestamp": 1660330071
},
"committer": {
"name": "User Name",
"email": "[email protected]",
"timestamp": 1660330071
},
}
],
"commit_id": "a440c6eb26404be4877b7e3ad592bfaa5d4eb210 (release commit)",
Expand Down Expand Up @@ -756,6 +767,12 @@ BREAKING CHANGE: this is a breaking change
If the `BREAKING CHANGE:` footer is present, the footer will also be included in
`commit.footers`.

##### Committer vs Author

From [Git docs](https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History):

> You may be wondering what the difference is between author and committer. The author is the person who originally wrote the work, whereas the committer is the person who last applied the work. So, if you send in a patch to a project and one of the core members applies the patch, both of you get credit — you as the author, and the core member as the committer.
#### Non-Conventional Commits

> conventional_commits = **false**
Expand All @@ -772,7 +789,17 @@ If [conventional_commits](#conventional_commits) is set to `false`, then some of
"scope": "(overrided by commit_parsers)",
"message": "(full commit message including description, footers, etc.)",
"conventional": false,
"links": [{"text": "(set by link_parsers)", "href": "(set by link_parsers)"}]
"links": [{"text": "(set by link_parsers)", "href": "(set by link_parsers)"}],
"author": {
"name": "User Name",
"email": "[email protected]",
"timestamp": 1660330071
},
"committer": {
"name": "User Name",
"email": "[email protected]",
"timestamp": 1660330071
},
}
],
"commit_id": "a440c6eb26404be4877b7e3ad592bfaa5d4eb210 (release commit)",
Expand Down
120 changes: 81 additions & 39 deletions git-cliff-core/src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ use crate::error::{
Error as AppError,
Result,
};
use git2::Commit as GitCommit;
use git_conventional::Commit as ConventionalCommit;
use git2::{
Commit as GitCommit,
Signature as CommitSignature,
};
use git_conventional::{
Commit as ConventionalCommit,
Footer as ConventionalFooter,
};
use lazy_regex::{
lazy_regex,
Lazy,
Expand All @@ -26,28 +32,6 @@ use serde::ser::{
/// separated by a whitespace.
static SHA1_REGEX: Lazy<Regex> = lazy_regex!(r#"^\b([a-f0-9]{40})\b (.*)$"#);

/// Common commit object that is parsed from a repository.
#[derive(Debug, Clone, PartialEq, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Commit<'a> {
/// Commit ID.
pub id: String,
/// Commit message including title, description and summary.
pub message: String,
/// Conventional commit.
#[serde(skip_deserializing)]
pub conv: Option<ConventionalCommit<'a>>,
/// Commit group based on a commit parser or its conventional type.
pub group: Option<String>,
/// Default commit scope based on (inherited from) conventional type or a
/// commit parser.
pub default_scope: Option<String>,
/// Commit scope for overriding the default one.
pub scope: Option<String>,
/// A list of links found in the commit
pub links: Vec<Link>,
}

/// Object representing a link
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -76,8 +60,8 @@ struct Footer<'a> {
breaking: bool,
}

impl<'a> From<&'a git_conventional::Footer<'a>> for Footer<'a> {
fn from(footer: &'a git_conventional::Footer<'a>) -> Self {
impl<'a> From<&'a ConventionalFooter<'a>> for Footer<'a> {
fn from(footer: &'a ConventionalFooter<'a>) -> Self {
Self {
token: footer.token().as_str(),
separator: footer.separator().as_str(),
Expand All @@ -87,26 +71,86 @@ impl<'a> From<&'a git_conventional::Footer<'a>> for Footer<'a> {
}
}

/// Commit signature that indicates authorship.
#[derive(
Debug, Default, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize,
)]
pub struct Signature {
/// Name on the signature.
name: Option<String>,
/// Email on the signature.
email: Option<String>,
/// Time of the signature.
timestamp: i64,
}

impl<'a> From<CommitSignature<'a>> for Signature {
fn from(signature: CommitSignature<'a>) -> Self {
Self {
name: signature.name().map(|v| v.to_string()),
email: signature.email().map(|v| v.to_string()),
timestamp: signature.when().seconds(),
}
}
}

/// Common commit object that is parsed from a repository.
#[derive(Debug, Default, Clone, PartialEq, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Commit<'a> {
/// Commit ID.
pub id: String,
/// Commit message including title, description and summary.
pub message: String,
/// Conventional commit.
#[serde(skip_deserializing)]
pub conv: Option<ConventionalCommit<'a>>,
/// Commit group based on a commit parser or its conventional type.
pub group: Option<String>,
/// Default commit scope based on (inherited from) conventional type or a
/// commit parser.
pub default_scope: Option<String>,
/// Commit scope for overriding the default one.
pub scope: Option<String>,
/// A list of links found in the commit
pub links: Vec<Link>,
/// Commit author.
pub author: Signature,
/// Committer.
pub committer: Signature,
}

impl<'a> From<String> for Commit<'a> {
fn from(s: String) -> Self {
if let Some(captures) = SHA1_REGEX.captures(&s) {
fn from(message: String) -> Self {
if let Some(captures) = SHA1_REGEX.captures(&message) {
if let (Some(id), Some(message)) = (
captures.get(1).map(|v| v.as_str()),
captures.get(2).map(|v| v.as_str()),
) {
return Commit::new(id.to_string(), message.to_string());
return Commit {
id: id.to_string(),
message: message.to_string(),
..Default::default()
};
}
}
Commit::new(String::new(), s)
Commit {
id: String::new(),
message,
..Default::default()
}
}
}

impl<'a> From<&GitCommit<'a>> for Commit<'a> {
fn from(commit: &GitCommit<'a>) -> Self {
Self::new(
commit.id().to_string(),
commit.message().unwrap_or_default().to_string(),
)
Commit {
id: commit.id().to_string(),
message: commit.message().unwrap_or_default().to_string(),
author: commit.author().into(),
committer: commit.committer().into(),
..Default::default()
}
}
}

Expand All @@ -116,11 +160,7 @@ impl Commit<'_> {
Self {
id,
message,
conv: None,
group: None,
default_scope: None,
scope: None,
links: vec![],
..Default::default()
}
}

Expand Down Expand Up @@ -328,6 +368,8 @@ impl Serialize for Commit<'_> {
}
}
commit.serialize_field("links", &self.links)?;
commit.serialize_field("author", &self.author)?;
commit.serialize_field("committer", &self.committer)?;
commit.serialize_field("conventional", &self.conv.is_some())?;
commit.end()
}
Expand Down

0 comments on commit 940065b

Please sign in to comment.