mirror of
https://github.com/orhun/git-cliff.git
synced 2024-10-05 19:27:27 +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
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
|
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -521,6 +521,12 @@ dependencies = [
|
||||
"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]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
@ -586,6 +592,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "fastrand"
|
||||
version = "2.0.2"
|
||||
@ -761,6 +777,7 @@ dependencies = [
|
||||
"config",
|
||||
"dirs",
|
||||
"document-features",
|
||||
"expect-test",
|
||||
"futures",
|
||||
"git-conventional",
|
||||
"git2",
|
||||
|
@ -80,6 +80,7 @@ features = ["debug-embed", "compression"]
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
expect-test = "1.5.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -28,10 +28,11 @@ use std::time::{
|
||||
#[derive(Debug)]
|
||||
pub struct Changelog<'a> {
|
||||
/// Releases that the changelog will contain.
|
||||
pub releases: Vec<Release<'a>>,
|
||||
body_template: Template,
|
||||
footer_template: Option<Template>,
|
||||
config: &'a Config,
|
||||
pub releases: Vec<Release<'a>>,
|
||||
body_template: Template,
|
||||
footer_template: Option<Template>,
|
||||
config: &'a Config,
|
||||
additional_context: HashMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
impl<'a> Changelog<'a> {
|
||||
@ -54,12 +55,30 @@ impl<'a> Changelog<'a> {
|
||||
None => None,
|
||||
},
|
||||
config,
|
||||
additional_context: HashMap::new(),
|
||||
};
|
||||
changelog.process_commits();
|
||||
changelog.process_releases();
|
||||
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.
|
||||
fn process_commit(
|
||||
commit: Commit<'a>,
|
||||
@ -232,8 +251,11 @@ impl<'a> Changelog<'a> {
|
||||
/// Generates the changelog and writes it to the given output.
|
||||
pub fn generate<W: Write>(&self, out: &mut W) -> Result<()> {
|
||||
debug!("Generating changelog...");
|
||||
let mut additional_context = HashMap::new();
|
||||
additional_context.insert("remote", self.config.remote.clone());
|
||||
let mut additional_context = self.additional_context.clone();
|
||||
additional_context.insert(
|
||||
"remote".to_string(),
|
||||
serde_json::to_value(self.config.remote.clone())?,
|
||||
);
|
||||
#[cfg(feature = "github")]
|
||||
let (github_commits, github_pull_requests) = self.get_github_metadata()?;
|
||||
let postprocessors = self
|
||||
@ -818,4 +840,87 @@ chore(deps): fix broken deps
|
||||
);
|
||||
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.
|
||||
pub fn render<C: Serialize, T: Serialize, S: Into<String> + Copy>(
|
||||
pub fn render<C: Serialize, T: Serialize, S: Into<String> + Clone>(
|
||||
&self,
|
||||
context: &C,
|
||||
additional_context: Option<&HashMap<S, T>>,
|
||||
@ -152,7 +152,7 @@ impl Template {
|
||||
let mut context = TeraContext::from_serialize(context)?;
|
||||
if let Some(additional_context) = additional_context {
|
||||
for (key, value) in additional_context {
|
||||
context.insert(*key, &value);
|
||||
context.insert(key.clone(), &value);
|
||||
}
|
||||
}
|
||||
match self.tera.render("template", &context) {
|
||||
|
Loading…
Reference in New Issue
Block a user