mirror of
https://github.com/orhun/git-cliff.git
synced 2024-08-16 02:10:29 +03:00
feat(changelog): allow adding custom context (#613)
* feat: allow adding custom context * chore: add test * fix: lint * fix: lint * fix: lint * docs: contributing * chore: polish implementation --------- Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
This commit is contained in:
parent
ade9eae7c0
commit
522bd536a4
@ -31,7 +31,13 @@ cargo build
|
|||||||
cargo test
|
cargo test
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Make sure [rustfmt](https://github.com/rust-lang/rustfmt) and [clippy](https://github.com/rust-lang/rust-clippy) don't complain about your changes.
|
6. If needed, update the snapshot tests (i.e. tests using `expect_test`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
env UPDATE_EXPECT=1 cargo test
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Make sure [rustfmt](https://github.com/rust-lang/rustfmt) and [clippy](https://github.com/rust-lang/rust-clippy) don't complain about your changes.
|
||||||
|
|
||||||
We use the `nightly` channel for `rustfmt` so please set the appropriate settings for your editor/IDE for that.
|
We use the `nightly` channel for `rustfmt` so please set the appropriate settings for your editor/IDE for that.
|
||||||
|
|
||||||
|
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -521,6 +521,12 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dissimilar"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "doc-comment"
|
name = "doc-comment"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -586,6 +592,16 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "expect-test"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0"
|
||||||
|
dependencies = [
|
||||||
|
"dissimilar",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
@ -761,6 +777,7 @@ dependencies = [
|
|||||||
"config",
|
"config",
|
||||||
"dirs",
|
"dirs",
|
||||||
"document-features",
|
"document-features",
|
||||||
|
"expect-test",
|
||||||
"futures",
|
"futures",
|
||||||
"git-conventional",
|
"git-conventional",
|
||||||
"git2",
|
"git2",
|
||||||
|
@ -80,6 +80,7 @@ features = ["debug-embed", "compression"]
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
|
expect-test = "1.5.0"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
@ -32,6 +32,7 @@ pub struct Changelog<'a> {
|
|||||||
body_template: Template,
|
body_template: Template,
|
||||||
footer_template: Option<Template>,
|
footer_template: Option<Template>,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
|
additional_context: HashMap<String, serde_json::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Changelog<'a> {
|
impl<'a> Changelog<'a> {
|
||||||
@ -54,12 +55,30 @@ impl<'a> Changelog<'a> {
|
|||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
config,
|
config,
|
||||||
|
additional_context: HashMap::new(),
|
||||||
};
|
};
|
||||||
changelog.process_commits();
|
changelog.process_commits();
|
||||||
changelog.process_releases();
|
changelog.process_releases();
|
||||||
Ok(changelog)
|
Ok(changelog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a key value pair to the template context.
|
||||||
|
///
|
||||||
|
/// These values will be used when generating the changelog.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This operation fails if the deserialization fails.
|
||||||
|
pub fn add_context(
|
||||||
|
&mut self,
|
||||||
|
key: impl Into<String>,
|
||||||
|
value: impl serde::Serialize,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.additional_context
|
||||||
|
.insert(key.into(), serde_json::to_value(value)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Processes a single commit and returns/logs the result.
|
/// Processes a single commit and returns/logs the result.
|
||||||
fn process_commit(
|
fn process_commit(
|
||||||
commit: Commit<'a>,
|
commit: Commit<'a>,
|
||||||
@ -232,8 +251,11 @@ impl<'a> Changelog<'a> {
|
|||||||
/// Generates the changelog and writes it to the given output.
|
/// Generates the changelog and writes it to the given output.
|
||||||
pub fn generate<W: Write>(&self, out: &mut W) -> Result<()> {
|
pub fn generate<W: Write>(&self, out: &mut W) -> Result<()> {
|
||||||
debug!("Generating changelog...");
|
debug!("Generating changelog...");
|
||||||
let mut additional_context = HashMap::new();
|
let mut additional_context = self.additional_context.clone();
|
||||||
additional_context.insert("remote", self.config.remote.clone());
|
additional_context.insert(
|
||||||
|
"remote".to_string(),
|
||||||
|
serde_json::to_value(self.config.remote.clone())?,
|
||||||
|
);
|
||||||
#[cfg(feature = "github")]
|
#[cfg(feature = "github")]
|
||||||
let (github_commits, github_pull_requests) = self.get_github_metadata()?;
|
let (github_commits, github_pull_requests) = self.get_github_metadata()?;
|
||||||
let postprocessors = self
|
let postprocessors = self
|
||||||
@ -818,4 +840,87 @@ chore(deps): fix broken deps
|
|||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn changelog_adds_additional_context() -> Result<()> {
|
||||||
|
let (mut config, releases) = get_test_data();
|
||||||
|
// add `{{ custom_field }}` to the template
|
||||||
|
config.changelog.body = Some(
|
||||||
|
r#"{% if version %}
|
||||||
|
## {{ custom_field }} [{{ version }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||||
|
{% if commit_id %}({{ commit_id }}){% endif %}{% else %}
|
||||||
|
## Unreleased{% endif %}
|
||||||
|
{% for group, commits in commits | group_by(attribute="group") %}
|
||||||
|
### {{ group }}{% for group, commits in commits | group_by(attribute="scope") %}
|
||||||
|
#### {{ group }}{% for commit in commits %}
|
||||||
|
- {{ commit.message }}{% endfor %}
|
||||||
|
{% endfor %}{% endfor %}"#
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
let mut changelog = Changelog::new(releases, &config)?;
|
||||||
|
changelog.add_context("custom_field", "Hello")?;
|
||||||
|
let mut out = Vec::new();
|
||||||
|
changelog.generate(&mut out)?;
|
||||||
|
expect_test::expect![[r#"
|
||||||
|
# Changelog
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
#### app
|
||||||
|
- fix abc
|
||||||
|
|
||||||
|
### New features
|
||||||
|
#### app
|
||||||
|
- add xyz
|
||||||
|
|
||||||
|
### Other
|
||||||
|
#### app
|
||||||
|
- document zyx
|
||||||
|
|
||||||
|
#### ui
|
||||||
|
- do exciting stuff
|
||||||
|
|
||||||
|
## Hello [v1.0.0] - 1971-08-02
|
||||||
|
(0bc123)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
#### ui
|
||||||
|
- fix more stuff
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
#### documentation
|
||||||
|
- update docs
|
||||||
|
- add some documentation
|
||||||
|
|
||||||
|
### I love tea
|
||||||
|
#### app
|
||||||
|
- damn right
|
||||||
|
|
||||||
|
### Matched (group)
|
||||||
|
#### group
|
||||||
|
- support regex-replace for groups
|
||||||
|
|
||||||
|
### New features
|
||||||
|
#### app
|
||||||
|
- add cool features
|
||||||
|
|
||||||
|
#### other
|
||||||
|
- support unscoped commits
|
||||||
|
- support breaking commits
|
||||||
|
|
||||||
|
### Other
|
||||||
|
#### app
|
||||||
|
- do nothing
|
||||||
|
|
||||||
|
#### other
|
||||||
|
- support unconventional commits
|
||||||
|
- this commit is preprocessed
|
||||||
|
|
||||||
|
#### ui
|
||||||
|
- make good stuff
|
||||||
|
-- total releases: 2 --
|
||||||
|
"#]]
|
||||||
|
.assert_eq(str::from_utf8(&out).unwrap_or_default());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ impl Template {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the template.
|
/// Renders the template.
|
||||||
pub fn render<C: Serialize, T: Serialize, S: Into<String> + Copy>(
|
pub fn render<C: Serialize, T: Serialize, S: Into<String> + Clone>(
|
||||||
&self,
|
&self,
|
||||||
context: &C,
|
context: &C,
|
||||||
additional_context: Option<&HashMap<S, T>>,
|
additional_context: Option<&HashMap<S, T>>,
|
||||||
@ -152,7 +152,7 @@ impl Template {
|
|||||||
let mut context = TeraContext::from_serialize(context)?;
|
let mut context = TeraContext::from_serialize(context)?;
|
||||||
if let Some(additional_context) = additional_context {
|
if let Some(additional_context) = additional_context {
|
||||||
for (key, value) in additional_context {
|
for (key, value) in additional_context {
|
||||||
context.insert(*key, &value);
|
context.insert(key.clone(), &value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.tera.render("template", &context) {
|
match self.tera.render("template", &context) {
|
||||||
|
Loading…
Reference in New Issue
Block a user