Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(parser): allow whole commit context to be used in commit parsers #758

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/fixtures/test-regex-label-grouping/cliff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[changelog]
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
body = """
### What's changed
{% for group, commits in commits | group_by(attribute="group") %}
#### {{ group }}
{% for commit in commits -%}
- {{ commit.message }}
{% endfor -%}\n
{% endfor %}\n
"""
footer = """
<!-- generated by git-cliff -->
"""
trim = true

[git]
commit_parsers = [
{ field = "author.name", pattern = "testa", group = "<!-- 0 -->TEST A" },
{ field = "author.name", pattern = "testb", group = "<!-- 1 -->TEST B" },
{ field = "author.name", pattern = "testc", group = "<!-- 2 -->TEST C" },
]
10 changes: 10 additions & 0 deletions .github/fixtures/test-regex-label-grouping/commit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -e

GIT_COMMITTER_DATE="2022-04-06 01:25:08" git commit --allow-empty -m "Initial commit"
GIT_COMMITTER_DATE="2022-04-06 01:25:09" git commit --allow-empty --author="testa <[email protected]>" -m "feat: add feature 1"
GIT_COMMITTER_DATE="2022-04-06 01:25:10" git commit --allow-empty --author="testa <[email protected]>" -m "feat: add feature 2"
GIT_COMMITTER_DATE="2022-04-06 01:25:11" git commit --allow-empty --author="testb <[email protected]>" -m "feat: add feature 3"
GIT_COMMITTER_DATE="2022-04-06 01:25:12" git commit --allow-empty --author="testb <[email protected]>" -m "feat: add feature 4"
GIT_COMMITTER_DATE="2022-04-06 01:25:13" git commit --allow-empty --author="testc <[email protected]>" -m "feat: add feature 5"
GIT_COMMITTER_DATE="2022-04-06 01:25:14" git commit --allow-empty --author="testc <[email protected]>" -m "feat: add feature 6"
19 changes: 19 additions & 0 deletions .github/fixtures/test-regex-label-grouping/expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Changelog

All notable changes to this project will be documented in this file.

### What's changed

#### <!-- 0 -->TEST A
- add feature 1
- add feature 2

#### <!-- 1 -->TEST B
- add feature 3
- add feature 4

#### <!-- 2 -->TEST C
- add feature 5
- add feature 6

<!-- generated by git-cliff -->
2 changes: 1 addition & 1 deletion git-cliff-core/src/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ impl<'a> Changelog<'a> {
config,
additional_context: HashMap::new(),
};
changelog.add_remote_data()?;
orhun marked this conversation as resolved.
Show resolved Hide resolved
changelog.process_commits();
changelog.process_releases();
changelog.add_remote_data()?;
Ok(changelog)
}

Expand Down
89 changes: 71 additions & 18 deletions git-cliff-core/src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ impl Commit<'_> {
protect_breaking: bool,
filter: bool,
) -> Result<Self> {
let lookup_context = serde_json::to_value(&self).map_err(|e| {
AppError::FieldError(format!(
"failed to convert context into value: {e}",
))
})?;
for parser in parsers {
let mut regex_checks = Vec::new();
if let Some(message_regex) = parser.message.as_ref() {
Expand All @@ -287,25 +292,22 @@ impl Commit<'_> {
if let (Some(field_name), Some(pattern_regex)) =
(parser.field.as_ref(), parser.pattern.as_ref())
{
regex_checks.push((
pattern_regex,
match field_name.as_str() {
"id" => Some(self.id.clone()),
"message" => Some(self.message.clone()),
"body" => body,
"author.name" => self.author.name.clone(),
"author.email" => self.author.email.clone(),
"committer.name" => self.committer.name.clone(),
"committer.email" => self.committer.email.clone(),
_ => None,
let value = if field_name == "body" {
body.clone()
} else {
tera::dotted_pointer(&lookup_context, field_name)
.map(|v| v.to_string())
};
match value {
Some(value) => {
regex_checks.push((pattern_regex, value));
}
.ok_or_else(|| {
AppError::FieldError(format!(
"field {} does not have a value",
field_name
))
})?,
));
None => {
return Err(AppError::FieldError(format!(
"field {field_name} does not have a value",
)));
}
}
}
if parser.sha.clone().map(|v| v.to_lowercase()).as_deref() ==
Some(&self.id)
Expand Down Expand Up @@ -728,4 +730,55 @@ mod test {

Ok(())
}

#[test]
fn field_name_regex() -> Result<()> {
DerTiedemann marked this conversation as resolved.
Show resolved Hide resolved
let commit = Commit {
message: String::from("feat: do something"),
author: Signature {
name: Some("John Doe".to_string()),
email: None,
timestamp: 0x0,
},
..Default::default()
};
let parsed_commit = commit.clone().parse(
&[CommitParser {
sha: None,
message: None,
body: None,
footer: None,
group: Some(String::from("Test group")),
default_scope: None,
scope: None,
skip: None,
field: Some(String::from("author.name")),
pattern: Regex::new("Something else").ok(),
}],
false,
true,
);

assert!(parsed_commit.is_err());

let parsed_commit = commit.parse(
&[CommitParser {
sha: None,
message: None,
body: None,
footer: None,
group: Some(String::from("Test group")),
default_scope: None,
scope: None,
skip: None,
field: Some(String::from("author.name")),
pattern: Regex::new("John Doe").ok(),
}],
false,
false,
)?;

assert_eq!(Some(String::from("Test group")), parsed_commit.group);
Ok(())
}
}
2 changes: 1 addition & 1 deletion git-cliff-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub enum Error {
#[error("Failed to parse integer: `{0}`")]
IntParseError(#[from] std::num::TryFromIntError),
/// Error that may occur while processing parsers that define field and
/// value matchers
/// value matchers.
#[error("Field error: `{0}`")]
FieldError(String),
/// Error that may occur while parsing a SemVer version or version
Expand Down
7 changes: 5 additions & 2 deletions website/docs/configuration/git.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,17 @@ Examples:
- `{ sha = "f6f2472bdf0bbb5f9fcaf2d72c1fa9f98f772bb2", group = "Stuff" }`
- Set the group of the commit by using its SHA1.
- `{ field = "author.name", pattern = "John Doe", group = "John's stuff" }`
- If the author's name attribute of the commit matches the pattern "John Doe" (as a regex), override the scope with "John' stuff". Supported commit attributes are:
- If the author's name attribute of the commit matches the pattern "John Doe" (as a regex), override the scope with "John's stuff".
- All values that are part of the commit context can be used. Nested fields can be accessed via the [dot notation](https://keats.github.io/tera/docs/#dot-notation). Some commonly used ones are:
- `id`
- `message`
- `body`
- `author.name`
- `author.email`
- `committer.email`
- `committer.name`
- `body` is a special field which contains the body of a convetional commit, if applicable.
- Be aware that all fields are converted to JSON strings before they are parsed by the given regex, especially when dealing with arrays.


### protect_breaking_commits

Expand Down
31 changes: 23 additions & 8 deletions website/docs/tips-and-tricks.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,6 @@ Then strip the tags in the template with the series of filters:
{% for group, commits in commits | filter(attribute="merge_commit", value=false) %}
```

## Skip commits by PR label

```jinja2
{% if commit.github.pr_labels is containing("skip-release-notes") %}
{% continue %}
{% endif %}
```

## Remove gitmoji

```toml
Expand All @@ -69,3 +61,26 @@ commit_parsers = [
{ body = "$^", skip = true },
]
```

## Skip commits by GitHub PR label

```jinja2
{% if commit.github.pr_labels is containing("skip-release-notes") %}
{% continue %}
{% endif %}
```

## Use GitHub PR labels as groups

```toml
[git]
commit_parsers = [
{ field = "github.pr_labels", pattern = "breaking-change", group = "<!-- 0 --> πŸ—οΈ Breaking changes" },
{ field = "github.pr_labels", pattern = "type/enhancement", group = "<!-- 1 --> πŸš€ Features" },
{ field = "github.pr_labels", pattern = "type/bug", group = "<!-- 2 --> πŸ› Fixes" },
{ field = "github.pr_labels", pattern = "type/update", group = "<!-- 3 --> πŸ§ͺ Dependencies" },
{ field = "github.pr_labels", pattern = "type/refactor", group = "<!-- 4 --> 🏭 Refactor" },
{ field = "github.pr_labels", pattern = "area/documentation", group = "<!-- 5 --> πŸ“ Documentation" },
{ field = "github.pr_labels", pattern = ".*", group = "<!-- 6 --> πŸŒ€ Miscellaneous" },
]
```
Loading