Repository: orhun/git-cliff
Pull request #795 (2024-08-12 23:05:57)

chore(deps): bump the patch group across 1 directory with 2 updates
Bumps the patch group with 2 updates in the /website directory: [@easyops-cn/docusaurus-search-local](https://github.com/easyops-cn/docusaurus-search-local/tree/HEAD/packages/docusaurus-search-local) and [typescript](https://github.com/Microsoft/TypeScript).

Updates `@easyops-cn/docusaurus-search-local` from 0.44.2 to 0.44.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/easyops-cn/docusaurus-search-local/releases"><code>@​easyops-cn/docusaurus-search-local</code>'s releases</a>.</em></p>
<blockquote>
<h2>v0.44.5</h2>
<h2><a href="https://github.com/easyops-cn/docusaurus-search-local/compare/v0.44.4...v0.44.5">0.44.5</a> (2024-08-12)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>update cheerio to 1.0.0, closes <a href="https://redirect.github.com/easyops-cn/docusaurus-search-local/issues/444">#444</a> (<a href="https://github.com/easyops-cn/docusaurus-search-local/commit/0d70f63cb170bac2b51461c0dd6f66a53dff4483">0d70f63</a>)</li>
</ul>
<h2>v0.44.4</h2>
<h2><a href="https://github.com/easyops-cn/docusaurus-search-local/compare/v0.44.3...v0.44.4">0.44.4</a> (2024-07-19)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>do not initialize lunr multiple times, fixes <a href="https://redirect.github.com/easyops-cn/docusaurus-search-local/issues/155">#155</a> (<a href="https://github.com/easyops-cn/docusaurus-search-local/commit/0b323d97fbc238692e68368582bce72908fd66b0">0b323d9</a>)</li>
</ul>
<h2>v0.44.3</h2>
<h2><a href="https://github.com/easyops-cn/docusaurus-search-local/compare/v0.44.2...v0.44.3">0.44.3</a> (2024-07-08)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>append a <code>/</code> to the search link. (<a href="https://redirect.github.com/easyops-cn/docusaurus-search-local/issues/432">#432</a>) (<a href="https://github.com/easyops-cn/docusaurus-search-local/commit/60c23d43c5c9b3ecc6ceb7319762a9c4acb9e32e">60c23d4</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/easyops-cn/docusaurus-search-local/commits/v0.44.5/packages/docusaurus-search-local">compare view</a></li>
</ul>
</details>
<br />

Updates `typescript` from 5.5.2 to 5.5.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/Microsoft/TypeScript/releases">typescript's releases</a>.</em></p>
<blockquote>
<h2>TypeScript 5.5.4</h2>
<p>For release notes, check out the <a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/">release announcement</a>.</p>
<p>For the complete list of fixed issues, check out the</p>
<ul>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.4%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.4 (Stable)</a>.</li>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.3%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.3 (Stable)</a>.</li>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.2%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.2 (Stable)</a>.</li>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.1%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.1 (RC)</a>.</li>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.0%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.0 (Beta)</a>.</li>
</ul>
<p>Downloads are available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/typescript">npm</a></li>
<li><a href="https://www.nuget.org/packages/Microsoft.TypeScript.MSBuild">NuGet package</a> (soon!)</li>
</ul>
<h2>TypeScript 5.5.3</h2>
<p>For release notes, check out the <a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/">release announcement</a>.</p>
<p>For the complete list of fixed issues, check out the</p>
<ul>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.3%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.3 (Stable)</a>.</li>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.2%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.2 (Stable)</a>.</li>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.1%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.1 (RC)</a>.</li>
<li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+milestone%3A%22TypeScript+5.5.0%22+is%3Aclosed+">fixed issues query for TypeScript v5.5.0 (Beta)</a>.</li>
</ul>
<p>Downloads are available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/typescript">npm</a></li>
<li><a href="https://www.nuget.org/packages/Microsoft.TypeScript.MSBuild">NuGet package</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/microsoft/TypeScript/commit/c8a7d589e647e19c94150d9892909f3aa93e48eb"><code>c8a7d58</code></a> Bump version to 5.5.4 and LKG</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/c0ded048e0e83709704c808fadbf5c14a29b8153"><code>c0ded04</code></a> 🤖 Pick PR <a href="https://redirect.github.com/Microsoft/TypeScript/issues/58771">#58771</a> (Allow references to the global Symb...) into release-5.5 (#...</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/5ba41e221a7be2cf6d832b073371021fdddabb64"><code>5ba41e2</code></a> 🤖 Pick PR <a href="https://redirect.github.com/Microsoft/TypeScript/issues/59208">#59208</a> (Write non-missing undefined on mapp...) into release-5.5 (#...</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/b075332c4ba2e0be750a4f975f258fe60445b93e"><code>b075332</code></a> 🤖 Pick PR <a href="https://redirect.github.com/Microsoft/TypeScript/issues/59337">#59337</a> (Allow declarationMap to be emitted ...) into release-5.5 (#...</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/9dd6f917448286ec32b4202274424a4ea482cf8e"><code>9dd6f91</code></a> Cherry-pick &quot;Stop using latest Node in CI&quot; to release-5.5 (<a href="https://redirect.github.com/Microsoft/TypeScript/issues/59348">#59348</a>)</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/bf0ddaf6e63b3808ee4ced302830cbd9460de7cd"><code>bf0ddaf</code></a> 🤖 Pick PR <a href="https://redirect.github.com/Microsoft/TypeScript/issues/59070">#59070</a> (Delay the calculation of common sou...) into release-5.5 (#...</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/a44e2d925cdf3bfa51b8b65ca15f9007d1fde979"><code>a44e2d9</code></a> 🤖 Pick PR <a href="https://redirect.github.com/Microsoft/TypeScript/issues/59160">#59160</a> (Fixed crash on authored import type...) into release-5.5 (#...</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/f35206d2029ec65b04dba854620bfd4d3dc23951"><code>f35206d</code></a> 🤖 Pick PR <a href="https://redirect.github.com/Microsoft/TypeScript/issues/59325">#59325</a> (Don't skip markLinkedReferences on ...) into release-5.5 (#...</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/1109550e2c36d1f6c87222d7c4f996b23f05b3f5"><code>1109550</code></a> Fix baselines on release-5.5 (<a href="https://redirect.github.com/Microsoft/TypeScript/issues/59330">#59330</a>)</li>
<li><a href="https://github.com/microsoft/TypeScript/commit/8794318ac96856933f1b0886900409813875283f"><code>8794318</code></a> 🤖 Pick PR <a href="https://redirect.github.com/Microsoft/TypeScript/issues/59215">#59215</a> (Fix codefix crash on circular alias...) into release-5.5 (#...</li>
<li>Additional commits viewable in <a href="https://github.com/Microsoft/TypeScript/compare/v5.5.2...v5.5.4">compare view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions


</details>


Patch:
diff --git a/README.md b/README.md
index 3c72e3f..5c3a874 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,22 @@
 <p align="center">
     <a href="https://git-cliff.org">
-        <img src="https://raw.githubusercontent.com/orhun/git-cliff/main/website/static/img/git-cliff-logo.png" width="300"></a>
+        <img src="https://raw.githubusercontent.com/orhun/git-cliff/main/website/static/img/git-cliff-logo.png" width="300"></a><!-- </a> being on the same line as the <img> tag is intentional! -->
     <br>
     <a href="https://github.com/orhun/git-cliff/releases">
-        <img src="https://img.shields.io/github/v/release/orhun/git-cliff?style=flat&labelColor=1C2C2E&color=C96329&logo=GitHub&logoColor=white">
-    </a>
+        <img src="https://img.shields.io/github/v/release/orhun/git-cliff?style=flat&labelColor=1C2C2E&color=C96329&logo=GitHub&logoColor=white"></a>
     <a href="https://crates.io/crates/git-cliff/">
-        <img src="https://img.shields.io/crates/v/git-cliff?style=flat&labelColor=1C2C2E&color=C96329&logo=Rust&logoColor=white">
-    </a>
+        <img src="https://img.shields.io/crates/v/git-cliff?style=flat&labelColor=1C2C2E&color=C96329&logo=Rust&logoColor=white"></a>
     <a href="https://codecov.io/gh/orhun/git-cliff">
-        <img src="https://img.shields.io/codecov/c/gh/orhun/git-cliff?style=flat&labelColor=1C2C2E&color=C96329&logo=Codecov&logoColor=white">
-    </a>
+        <img src="https://img.shields.io/codecov/c/gh/orhun/git-cliff?style=flat&labelColor=1C2C2E&color=C96329&logo=Codecov&logoColor=white"></a>
     <br>
     <a href="https://github.com/orhun/git-cliff/actions?query=workflow%3A%22Continuous+Integration%22">
-        <img src="https://img.shields.io/github/actions/workflow/status/orhun/git-cliff/ci.yml?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=GitHub%20Actions&logoColor=BEC5C9">
-    </a>
+        <img src="https://img.shields.io/github/actions/workflow/status/orhun/git-cliff/ci.yml?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=GitHub%20Actions&logoColor=BEC5C9"></a>
     <a href="https://github.com/orhun/git-cliff/actions?query=workflow%3A%22Continuous+Deployment%22">
-        <img src="https://img.shields.io/github/actions/workflow/status/orhun/git-cliff/cd.yml?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=GitHub%20Actions&logoColor=BEC5C9&label=deploy">
-    </a>
+        <img src="https://img.shields.io/github/actions/workflow/status/orhun/git-cliff/cd.yml?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=GitHub%20Actions&logoColor=BEC5C9&label=deploy"></a>
     <a href="https://hub.docker.com/r/orhunp/git-cliff">
-        <img src="https://img.shields.io/github/actions/workflow/status/orhun/git-cliff/docker.yml?style=flat&labelColor=1C2C2E&color=BEC5C9&label=docker&logo=Docker&logoColor=BEC5C9">
-    </a>
+        <img src="https://img.shields.io/github/actions/workflow/status/orhun/git-cliff/docker.yml?style=flat&labelColor=1C2C2E&color=BEC5C9&label=docker&logo=Docker&logoColor=BEC5C9"></a>
     <a href="https://docs.rs/git-cliff-core/">
-        <img src="https://img.shields.io/docsrs/git-cliff-core?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=Rust&logoColor=BEC5C9">
-    </a>
+        <img src="https://img.shields.io/docsrs/git-cliff-core?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=Rust&logoColor=BEC5C9"></a>
     <br>
 </p>
 
@@ -81,21 +74,16 @@ Made with [contrib.rocks](https://contrib.rocks).
 ## Socials
 
 <a href="https://discord.gg/W3mAwMDWH4">
-    <img src="https://discord.com/api/guilds/1093977388892819553/embed.png?style=banner2">
-</a>
+    <img src="https://discord.com/api/guilds/1093977388892819553/embed.png?style=banner2"></a> <!-- </a> being on the same line as the <img> tag is intentional! -->
 <br>
 <a href="https://matrix.to/#/#git-cliff:matrix.org">
-    <img src="https://img.shields.io/matrix/git-cliff:matrix.org?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=matrix&logoColor=BEC5C9&label=join%20matrix">
-</a>
+    <img src="https://img.shields.io/matrix/git-cliff:matrix.org?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=matrix&logoColor=BEC5C9&label=join%20matrix"></a>
 <a href="https://discord.gg/W3mAwMDWH4">
-    <img src="https://img.shields.io/discord/1093977388892819553?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=discord&logoColor=BEC5C9&label=join%20discord">
-</a>
+    <img src="https://img.shields.io/discord/1093977388892819553?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=discord&logoColor=BEC5C9&label=join%20discord"></a>
 <a href="https://twitter.com/git_cliff">
-    <img src="https://img.shields.io/twitter/follow/git_cliff?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=twitter&logoColor=BEC5C9">
-</a>
+    <img src="https://img.shields.io/twitter/follow/git_cliff?style=flat&labelColor=1C2C2E&color=BEC5C9&logo=twitter&logoColor=BEC5C9"></a>
 <a href="https://fosstodon.org/@git_cliff">
-    <img src="https://img.shields.io/mastodon/follow/111545487385097711?domain=https%3A%2F%2Ffosstodon.org&style=flat&labelColor=1C2C2E&color=BEC5C9&logo=mastodon&logoColor=BEC5C9">
-</a>
+    <img src="https://img.shields.io/mastodon/follow/111545487385097711?domain=https%3A%2F%2Ffosstodon.org&style=flat&labelColor=1C2C2E&color=BEC5C9&logo=mastodon&logoColor=BEC5C9"></a>
 
 ## License
 
diff --git a/git-cliff-core/src/changelog.rs b/git-cliff-core/src/changelog.rs
index 2961872..3a42697 100644
--- a/git-cliff-core/src/changelog.rs
+++ b/git-cliff-core/src/changelog.rs
@@ -18,7 +18,10 @@ use crate::remote::github::GitHubClient;
 use crate::remote::gitlab::GitLabClient;
 use crate::template::Template;
 use std::collections::HashMap;
-use std::io::Write;
+use std::io::{
+	Read,
+	Write,
+};
 use std::time::{
 	SystemTime,
 	UNIX_EPOCH,
@@ -39,8 +42,17 @@ pub struct Changelog<'a> {
 impl<'a> Changelog<'a> {
 	/// Constructs a new instance.
 	pub fn new(releases: Vec<Release<'a>>, config: &'a Config) -> Result<Self> {
+		let mut changelog = Changelog::build(releases, config)?;
+		changelog.add_remote_data()?;
+		changelog.process_commits();
+		changelog.process_releases();
+		Ok(changelog)
+	}
+
+	/// Builds a changelog from releases and config.
+	fn build(releases: Vec<Release<'a>>, config: &'a Config) -> Result<Self> {
 		let trim = config.changelog.trim.unwrap_or(true);
-		let mut changelog = Self {
+		Ok(Self {
 			releases,
 			header_template: match &config.changelog.header {
 				Some(header) => Some(Template::new(header.to_string(), trim)?),
@@ -61,11 +73,12 @@ impl<'a> Changelog<'a> {
 			},
 			config,
 			additional_context: HashMap::new(),
-		};
-		changelog.add_remote_data()?;
-		changelog.process_commits();
-		changelog.process_releases();
-		Ok(changelog)
+		})
+	}
+
+	/// Constructs an instance from a serialized context object.
+	pub fn from_context<R: Read>(input: &mut R, config: &'a Config) -> Result<Self> {
+		Changelog::build(serde_json::from_reader(input)?, config)
 	}
 
 	/// Adds a key value pair to the template context.
@@ -821,6 +834,7 @@ mod test {
 		let test_release = Release {
 			version: Some(String::from("v1.0.0")),
 			message: None,
+			extra: None,
 			commits: vec![
 				Commit::new(
 					String::from("coffee"),
@@ -917,6 +931,7 @@ mod test {
 			Release {
 				version: None,
 				message: None,
+				extra: None,
 				commits: vec![
 					Commit::new(
 						String::from("abc123"),
diff --git a/git-cliff-core/src/commit.rs b/git-cliff-core/src/commit.rs
index 0474772..ba51396 100644
--- a/git-cliff-core/src/commit.rs
+++ b/git-cliff-core/src/commit.rs
@@ -30,6 +30,7 @@ use serde::{
 	Deserialize,
 	Serialize,
 };
+use serde_json::value::Value;
 
 /// Regular expression for matching SHA1 and a following commit message
 /// separated by a whitespace.
@@ -37,7 +38,7 @@ static SHA1_REGEX: Lazy<Regex> = lazy_regex!(r#"^\b([a-f0-9]{40})\b (.*)$"#);
 
 /// Object representing a link
 #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
+#[serde(rename_all(serialize = "camelCase"))]
 pub struct Link {
 	/// Text of the link.
 	pub text: String,
@@ -98,7 +99,7 @@ impl<'a> From<CommitSignature<'a>> for Signature {
 
 /// Common commit object that is parsed from a repository.
 #[derive(Debug, Default, Clone, PartialEq, Deserialize)]
-#[serde(rename_all = "camelCase")]
+#[serde(rename_all(serialize = "camelCase"))]
 pub struct Commit<'a> {
 	/// Commit ID.
 	pub id:            String,
@@ -122,6 +123,8 @@ pub struct Commit<'a> {
 	pub committer:     Signature,
 	/// Whether if the commit has two or more parents.
 	pub merge_commit:  bool,
+	/// Arbitrary data to be used with the `--from-context` CLI option.
+	pub extra:         Option<Value>,
 	/// GitHub metadata of the commit.
 	#[cfg(feature = "github")]
 	pub github:        crate::remote::RemoteContributor,
@@ -454,6 +457,7 @@ impl Serialize for Commit<'_> {
 		commit.serialize_field("committer", &self.committer)?;
 		commit.serialize_field("conventional", &self.conv.is_some())?;
 		commit.serialize_field("merge_commit", &self.merge_commit)?;
+		commit.serialize_field("extra", &self.extra)?;
 		#[cfg(feature = "github")]
 		commit.serialize_field("github", &self.github)?;
 		#[cfg(feature = "gitlab")]
diff --git a/git-cliff-core/src/release.rs b/git-cliff-core/src/release.rs
index 204cdf4..3c9fcab 100644
--- a/git-cliff-core/src/release.rs
+++ b/git-cliff-core/src/release.rs
@@ -21,10 +21,11 @@ use serde::{
 	Deserialize,
 	Serialize,
 };
+use serde_json::value::Value;
 
 /// Representation of a release.
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
+#[serde(rename_all(serialize = "camelCase"))]
 pub struct Release<'a> {
 	/// Release version, git tag.
 	pub version:    Option<String>,
@@ -41,6 +42,8 @@ pub struct Release<'a> {
 	pub previous:   Option<Box<Release<'a>>>,
 	/// Repository path.
 	pub repository: Option<String>,
+	/// Arbitrary data to be used with the `--from-context` CLI option.
+	pub extra:      Option<Value>,
 	/// Contributors.
 	#[cfg(feature = "github")]
 	pub github:     RemoteReleaseMetadata,
@@ -182,6 +185,7 @@ mod test {
 			Release {
 				version: None,
 				message: None,
+				extra: None,
 				commits: commits
 					.iter()
 					.map(|v| Commit::from(v.to_string()))
@@ -377,6 +381,7 @@ mod test {
 		let mut release = Release {
 			version: None,
 			message: None,
+			extra: None,
 			commits: vec![
 				Commit::from(String::from(
 					"1d244937ee6ceb8e0314a4a201ba93a7a61f2071 add github \
@@ -664,6 +669,7 @@ mod test {
 		let mut release = Release {
 			version: None,
 			message: None,
+			extra: None,
 			commits: vec![
 				Commit::from(String::from(
 					"1d244937ee6ceb8e0314a4a201ba93a7a61f2071 add github \
@@ -1009,6 +1015,7 @@ mod test {
 		let mut release = Release {
 			version: None,
 			message: None,
+			extra: None,
 			commits: vec![
 				Commit::from(String::from(
 					"1d244937ee6ceb8e0314a4a201ba93a7a61f2071 add github \
diff --git a/git-cliff-core/src/template.rs b/git-cliff-core/src/template.rs
index 6d2e611..f8c724d 100644
--- a/git-cliff-core/src/template.rs
+++ b/git-cliff-core/src/template.rs
@@ -101,6 +101,13 @@ impl Template {
 				for node in &forloop.empty_body.clone().unwrap_or_default() {
 					Self::find_identifiers(node, names);
 				}
+				for (_, expr) in
+					forloop.container.filters.iter().flat_map(|v| v.args.iter())
+				{
+					if let ast::ExprVal::String(ref v) = expr.val {
+						names.insert(v.clone());
+					}
+				}
 			}
 			ast::Node::If(cond, _) => {
 				for (_, expr, nodes) in &cond.conditions {
@@ -128,6 +135,7 @@ impl Template {
 		for node in ast {
 			Self::find_identifiers(node, &mut variables);
 		}
+		trace!("Template variables: {variables:?}");
 		Ok(variables.into_iter().collect())
 	}
 
@@ -190,6 +198,7 @@ mod test {
 		Release {
 			version: Some(String::from("1.0")),
 			message: None,
+			extra: None,
 			commits: vec![
 				Commit::new(
 					String::from("123123"),
diff --git a/git-cliff/src/args.rs b/git-cliff/src/args.rs
index 444af6d..1b8beb6 100644
--- a/git-cliff/src/args.rs
+++ b/git-cliff/src/args.rs
@@ -234,6 +234,14 @@ pub struct Opt {
 	/// Prints changelog context as JSON.
 	#[arg(short = 'x', long, help_heading = Some("FLAGS"))]
 	pub context:          bool,
+	/// Generates changelog from a JSON context.
+	#[arg(
+        long,
+	    value_name = "PATH",
+	    value_parser = Opt::parse_dir,
+		env = "GIT_CLIFF_CONTEXT",
+    )]
+	pub from_context:     Option<PathBuf>,
 	/// Strips the given parts from the changelog.
 	#[arg(short, long, value_name = "PART", value_enum)]
 	pub strip:            Option<Strip>,
diff --git a/git-cliff/src/lib.rs b/git-cliff/src/lib.rs
index 878a278..f689b0e 100644
--- a/git-cliff/src/lib.rs
+++ b/git-cliff/src/lib.rs
@@ -521,49 +521,63 @@ pub fn run(mut args: Opt) -> Result<()> {
 	if args.count_tags.is_some() {
 		config.git.count_tags.clone_from(&args.count_tags);
 	}
-	// Process the repositories.
-	let repositories = args.repository.clone().unwrap_or(vec![env::current_dir()?]);
-	let mut releases = Vec::<Release>::new();
-	for repository in repositories {
-		// Skip commits
-		let mut skip_list = Vec::new();
-		let ignore_file = repository.join(IGNORE_FILE);
-		if ignore_file.exists() {
-			let contents = fs::read_to_string(ignore_file)?;
-			let commits = contents
-				.lines()
-				.filter(|v| !(v.starts_with('#') || v.trim().is_empty()))
-				.map(|v| String::from(v.trim()))
-				.collect::<Vec<String>>();
-			skip_list.extend(commits);
-		}
-		if let Some(ref skip_commit) = args.skip_commit {
-			skip_list.extend(skip_commit.clone());
-		}
-		if let Some(commit_parsers) = config.git.commit_parsers.as_mut() {
-			for sha1 in skip_list {
-				commit_parsers.insert(0, CommitParser {
-					sha: Some(sha1.to_string()),
-					skip: Some(true),
-					..Default::default()
-				})
-			}
-		}
-
-		// Process the repository.
-		let repository = Repository::init(repository)?;
-		releases.extend(process_repository(
-			Box::leak(Box::new(repository)),
-			&mut config,
-			&args,
-		)?);
-	}
 
 	// Process commits and releases for the changelog.
 	if let Some(BumpOption::Specific(bump_type)) = args.bump {
 		config.bump.bump_type = Some(bump_type)
 	}
-	let mut changelog = Changelog::new(releases, &config)?;
+
+	// Generate changelog from context.
+	let mut changelog: Changelog = if let Some(context_path) = args.from_context {
+		let mut input: Box<dyn io::Read> = if context_path == Path::new("-") {
+			Box::new(io::stdin())
+		} else {
+			Box::new(File::open(context_path)?)
+		};
+		let mut changelog = Changelog::from_context(&mut input, &config)?;
+		changelog.add_remote_data()?;
+		changelog
+	} else {
+		// Process the repositories.
+		let repositories =
+			args.repository.clone().unwrap_or(vec![env::current_dir()?]);
+		let mut releases = Vec::<Release>::new();
+		for repository in repositories {
+			// Skip commits
+			let mut skip_list = Vec::new();
+			let ignore_file = repository.join(IGNORE_FILE);
+			if ignore_file.exists() {
+				let contents = fs::read_to_string(ignore_file)?;
+				let commits = contents
+					.lines()
+					.filter(|v| !(v.starts_with('#') || v.trim().is_empty()))
+					.map(|v| String::from(v.trim()))
+					.collect::<Vec<String>>();
+				skip_list.extend(commits);
+			}
+			if let Some(ref skip_commit) = args.skip_commit {
+				skip_list.extend(skip_commit.clone());
+			}
+			if let Some(commit_parsers) = config.git.commit_parsers.as_mut() {
+				for sha1 in skip_list {
+					commit_parsers.insert(0, CommitParser {
+						sha: Some(sha1.to_string()),
+						skip: Some(true),
+						..Default::default()
+					})
+				}
+			}
+
+			// Process the repository.
+			let repository = Repository::init(repository)?;
+			releases.extend(process_repository(
+				Box::leak(Box::new(repository)),
+				&mut config,
+				&args,
+			)?);
+		}
+		Changelog::new(releases, &config)?
+	};
 
 	// Print the result.
 	let mut out: Box<dyn io::Write> = if let Some(path) = &args.output {
diff --git a/website/docs/usage/args.md b/website/docs/usage/args.md
index 9c50095..6b3f657 100644
--- a/website/docs/usage/args.md
+++ b/website/docs/usage/args.md
@@ -43,6 +43,7 @@ git-cliff [FLAGS] [OPTIONS] [--] [RANGE]
 -o, --output [<PATH>]              Writes output to the given file [env: GIT_CLIFF_OUTPUT=]
 -t, --tag <TAG>                    Sets the tag for the latest version [env: GIT_CLIFF_TAG=]
 -b, --body <TEMPLATE>              Sets the template for the changelog body [env: GIT_CLIFF_TEMPLATE=]
+    --from-context <PATH>          Generates changelog from a JSON context [env: GIT_CLIFF_CONTEXT=]
 -s, --strip <PART>                 Strips the given parts from the changelog [possible values: header, footer, all]
     --sort <SORT>                  Sets sorting of the commits inside sections [default: oldest] [possible values: oldest, newest]
     --github-token <TOKEN>         Sets the GitHub API token [env: GITHUB_TOKEN]
diff --git a/website/docs/usage/load-context.md b/website/docs/usage/load-context.md
new file mode 100644
index 00000000..fd4a5a8
--- /dev/null
+++ b/website/docs/usage/load-context.md
@@ -0,0 +1,36 @@
+---
+sidebar_position: 11
+---
+
+# Load context
+
+:::tip
+
+This is useful if you want to [print context](/docs/usage/print-context), modify it with an external tool and then "pipe" it back into **git-cliff**.
+
+:::
+
+To load a context from a file and output the generated changelog:
+
+```bash
+# create a context
+git cliff --context -o context.json
+
+# process context and generate a changelog
+git cliff --from-context context.json
+
+# process context loaded from stdin
+git cliff --from-context -
+```
+
+Free-form metadata can be added to release objects and commit objects in the context using the `extra` field:
+
+```json
+{
+  "id": "5061081d6272b1da2146fab49d803c193db309d9",
+  "message": "commit message",
+  "extra": {
+    "note": "this is some arbitrary data"
+  }
+}
+```
diff --git a/website/package-lock.json b/website/package-lock.json
index 9354c1f..475735a 100644
--- a/website/package-lock.json
+++ b/website/package-lock.json
@@ -11,7 +11,7 @@
       "dependencies": {
         "@docusaurus/core": "^3.4.0",
         "@docusaurus/preset-classic": "^3.4.0",
-        "@easyops-cn/docusaurus-search-local": "^0.44.2",
+        "@easyops-cn/docusaurus-search-local": "^0.44.5",
         "@mdx-js/react": "^3.0.1",
         "clsx": "^2.1.1",
         "prism-react-renderer": "^2.3.0",
@@ -21,7 +21,7 @@
       "devDependencies": {
         "@docusaurus/module-type-aliases": "^3.4.0",
         "@docusaurus/tsconfig": "^3.4.0",
-        "typescript": "^5.5.2"
+        "typescript": "^5.5.4"
       },
       "engines": {
         "node": ">=18.0"
@@ -2738,9 +2738,9 @@
       }
     },
     "node_modules/@easyops-cn/docusaurus-search-local": {
-      "version": "0.44.2",
-      "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.2.tgz",
-      "integrity": "sha512-4tMBU54R1O6ITxkMGwOEifSHNkZLa2fb4ajGc8rd6TYZ0a8+jlu/u/5gYtw1s6sGGMRkwyG+QI6HD0bEnCRa1w==",
+      "version": "0.44.5",
+      "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.5.tgz",
+      "integrity": "sha512-jT3wuYVzRoeB1gea+2iDtOMme0fD2h3M8HDVgs3garITO6vRxvEraFRVlYkfjLN9BkmzjMlz9nn7MI4qIx8utw==",
       "dependencies": {
         "@docusaurus/plugin-content-docs": "^2 || ^3",
         "@docusaurus/theme-translations": "^2 || ^3",
@@ -2749,7 +2749,7 @@
         "@docusaurus/utils-validation": "^2 || ^3",
         "@easyops-cn/autocomplete.js": "^0.38.1",
         "@node-rs/jieba": "^1.6.0",
-        "cheerio": "^1.0.0-rc.3",
+        "cheerio": "^1.0.0",
         "clsx": "^1.1.1",
         "debug": "^4.2.0",
         "fs-extra": "^10.0.0",
@@ -4820,20 +4820,24 @@
       }
     },
     "node_modules/cheerio": {
-      "version": "1.0.0-rc.12",
-      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
-      "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
+      "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==",
       "dependencies": {
         "cheerio-select": "^2.1.0",
         "dom-serializer": "^2.0.0",
         "domhandler": "^5.0.3",
-        "domutils": "^3.0.1",
-        "htmlparser2": "^8.0.1",
-        "parse5": "^7.0.0",
-        "parse5-htmlparser2-tree-adapter": "^7.0.0"
+        "domutils": "^3.1.0",
+        "encoding-sniffer": "^0.2.0",
+        "htmlparser2": "^9.1.0",
+        "parse5": "^7.1.2",
+        "parse5-htmlparser2-tree-adapter": "^7.0.0",
+        "parse5-parser-stream": "^7.1.2",
+        "undici": "^6.19.5",
+        "whatwg-mimetype": "^4.0.0"
       },
       "engines": {
-        "node": ">= 6"
+        "node": ">=18.17"
       },
       "funding": {
         "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
@@ -6036,6 +6040,29 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/encoding-sniffer": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
+      "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==",
+      "dependencies": {
+        "iconv-lite": "^0.6.3",
+        "whatwg-encoding": "^3.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
+      }
+    },
+    "node_modules/encoding-sniffer/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/enhanced-resolve": {
       "version": "5.17.0",
       "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz",
@@ -7582,9 +7609,9 @@
       }
     },
     "node_modules/htmlparser2": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
-      "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
+      "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
       "funding": [
         "https://github.com/fb55/htmlparser2?sponsor=1",
         {
@@ -7595,8 +7622,8 @@
       "dependencies": {
         "domelementtype": "^2.3.0",
         "domhandler": "^5.0.3",
-        "domutils": "^3.0.1",
-        "entities": "^4.4.0"
+        "domutils": "^3.1.0",
+        "entities": "^4.5.0"
       }
     },
     "node_modules/http-cache-semantics": {
@@ -11113,6 +11140,17 @@
         "url": "https://github.com/inikulin/parse5?sponsor=1"
       }
     },
+    "node_modules/parse5-parser-stream": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
+      "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
+      "dependencies": {
+        "parse5": "^7.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
     "node_modules/parseurl": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -13885,9 +13923,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.5.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz",
-      "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==",
+      "version": "5.5.4",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
+      "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
       "bin": {
         "tsc": "bin/tsc",
         "tsserver": "bin/tsserver"
@@ -13896,6 +13934,14 @@
         "node": ">=14.17"
       }
     },
+    "node_modules/undici": {
+      "version": "6.19.8",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz",
+      "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==",
+      "engines": {
+        "node": ">=18.17"
+      }
+    },
     "node_modules/undici-types": {
       "version": "5.26.5",
       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
@@ -14731,6 +14777,36 @@
         "node": ">=0.8.0"
       }
     },
+    "node_modules/whatwg-encoding": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+      "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+      "dependencies": {
+        "iconv-lite": "0.6.3"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/whatwg-encoding/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/whatwg-mimetype": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+      "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/website/package.json b/website/package.json
index b7b0c01..ef29882 100644
--- a/website/package.json
+++ b/website/package.json
@@ -18,7 +18,7 @@
   "dependencies": {
     "@docusaurus/core": "^3.4.0",
     "@docusaurus/preset-classic": "^3.4.0",
-    "@easyops-cn/docusaurus-search-local": "^0.44.2",
+    "@easyops-cn/docusaurus-search-local": "^0.44.5",
     "@mdx-js/react": "^3.0.1",
     "clsx": "^2.1.1",
     "prism-react-renderer": "^2.3.0",
@@ -28,7 +28,7 @@
   "devDependencies": {
     "@docusaurus/module-type-aliases": "^3.4.0",
     "@docusaurus/tsconfig": "^3.4.0",
-    "typescript": "^5.5.2"
+    "typescript": "^5.5.4"
   },
   "browserslist": {
     "production": [
diff --git a/website/yarn.lock b/website/yarn.lock
index 023a8d8..a6a76aa 100644
--- a/website/yarn.lock
+++ b/website/yarn.lock
@@ -1671,10 +1671,10 @@
     cssesc "^3.0.0"
     immediate "^3.2.3"
 
-"@easyops-cn/docusaurus-search-local@^0.44.2":
-  version "0.44.2"
-  resolved "https://registry.yarnpkg.com/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.2.tgz#580925d8b94220cecbe30c466bdc0b32cb275cf6"
-  integrity sha512-4tMBU54R1O6ITxkMGwOEifSHNkZLa2fb4ajGc8rd6TYZ0a8+jlu/u/5gYtw1s6sGGMRkwyG+QI6HD0bEnCRa1w==
+"@easyops-cn/docusaurus-search-local@^0.44.5":
+  version "0.44.5"
+  resolved "https://registry.yarnpkg.com/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.5.tgz#13ae433868809a3e5dd92dbf44a2b1e6b2061b91"
+  integrity sha512-jT3wuYVzRoeB1gea+2iDtOMme0fD2h3M8HDVgs3garITO6vRxvEraFRVlYkfjLN9BkmzjMlz9nn7MI4qIx8utw==
   dependencies:
     "@docusaurus/plugin-content-docs" "^2 || ^3"
     "@docusaurus/theme-translations" "^2 || ^3"
@@ -1683,7 +1683,7 @@
     "@docusaurus/utils-validation" "^2 || ^3"
     "@easyops-cn/autocomplete.js" "^0.38.1"
     "@node-rs/jieba" "^1.6.0"
-    cheerio "^1.0.0-rc.3"
+    cheerio "^1.0.0"
     clsx "^1.1.1"
     debug "^4.2.0"
     fs-extra "^10.0.0"
@@ -3104,18 +3104,22 @@ cheerio-select@^2.1.0:
     domhandler "^5.0.3"
     domutils "^3.0.1"
 
-cheerio@^1.0.0-rc.12, cheerio@^1.0.0-rc.3:
-  version "1.0.0-rc.12"
-  resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz"
-  integrity sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==
+cheerio@^1.0.0, cheerio@^1.0.0-rc.12:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0.tgz#1ede4895a82f26e8af71009f961a9b8cb60d6a81"
+  integrity sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==
   dependencies:
     cheerio-select "^2.1.0"
     dom-serializer "^2.0.0"
     domhandler "^5.0.3"
-    domutils "^3.0.1"
-    htmlparser2 "^8.0.1"
-    parse5 "^7.0.0"
+    domutils "^3.1.0"
+    encoding-sniffer "^0.2.0"
+    htmlparser2 "^9.1.0"
+    parse5 "^7.1.2"
     parse5-htmlparser2-tree-adapter "^7.0.0"
+    parse5-parser-stream "^7.1.2"
+    undici "^6.19.5"
+    whatwg-mimetype "^4.0.0"
 
 chokidar@^3.4.2, chokidar@^3.5.3:
   version "3.6.0"
@@ -3788,7 +3792,7 @@ domutils@^2.5.2, domutils@^2.8.0:
     domelementtype "^2.2.0"
     domhandler "^4.2.0"
 
-domutils@^3.0.1:
+domutils@^3.0.1, domutils@^3.1.0:
   version "3.1.0"
   resolved "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz"
   integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
@@ -3862,6 +3866,14 @@ encodeurl@~1.0.2:
   resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz"
   integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
 
+encoding-sniffer@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz#799569d66d443babe82af18c9f403498365ef1d5"
+  integrity sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==
+  dependencies:
+    iconv-lite "^0.6.3"
+    whatwg-encoding "^3.1.1"
+
 enhanced-resolve@^5.17.0:
   version "5.17.0"
   resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz"
@@ -3875,7 +3887,7 @@ entities@^2.0.0:
   resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz"
   integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
 
-entities@^4.2.0, entities@^4.4.0:
+entities@^4.2.0, entities@^4.4.0, entities@^4.5.0:
   version "4.5.0"
   resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz"
   integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
@@ -4760,15 +4772,15 @@ htmlparser2@^6.1.0:
     domutils "^2.5.2"
     entities "^2.0.0"
 
-htmlparser2@^8.0.1:
-  version "8.0.2"
-  resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz"
-  integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
+htmlparser2@^9.1.0:
+  version "9.1.0"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-9.1.0.tgz#cdb498d8a75a51f739b61d3f718136c369bc8c23"
+  integrity sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==
   dependencies:
     domelementtype "^2.3.0"
     domhandler "^5.0.3"
-    domutils "^3.0.1"
-    entities "^4.4.0"
+    domutils "^3.1.0"
+    entities "^4.5.0"
 
 http-cache-semantics@^4.1.1:
   version "4.1.1"
@@ -4846,6 +4858,13 @@ iconv-lite@0.4.24:
   dependencies:
     safer-buffer ">= 2.1.2 < 3"
 
+iconv-lite@0.6.3, iconv-lite@^0.6.3:
+  version "0.6.3"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
+  integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3.0.0"
+
 icss-utils@^5.0.0, icss-utils@^5.1.0:
   version "5.1.0"
   resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz"
@@ -6489,7 +6508,14 @@ parse5-htmlparser2-tree-adapter@^7.0.0:
     domhandler "^5.0.2"
     parse5 "^7.0.0"
 
-parse5@^7.0.0:
+parse5-parser-stream@^7.1.2:
+  version "7.1.2"
+  resolved "https://registry.yarnpkg.com/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz#d7c20eadc37968d272e2c02660fff92dd27e60e1"
+  integrity sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==
+  dependencies:
+    parse5 "^7.0.0"
+
+parse5@^7.0.0, parse5@^7.1.2:
   version "7.1.2"
   resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz"
   integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==
@@ -7463,7 +7489,7 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
   resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
 
-"safer-buffer@>= 2.1.2 < 3":
+"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
   version "2.1.2"
   resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
   integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -8085,16 +8111,21 @@ typedarray-to-buffer@^3.1.5:
   dependencies:
     is-typedarray "^1.0.0"
 
-typescript@^5.5.2:
-  version "5.5.2"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.2.tgz#c26f023cb0054e657ce04f72583ea2d85f8d0507"
-  integrity sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==
+typescript@^5.5.4:
+  version "5.5.4"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba"
+  integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
 
 undici-types@~5.26.4:
   version "5.26.5"
   resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"
   integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
 
+undici@^6.19.5:
+  version "6.19.8"
+  resolved "https://registry.yarnpkg.com/undici/-/undici-6.19.8.tgz#002d7c8a28f8cc3a44ff33c3d4be4d85e15d40e1"
+  integrity sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==
+
 unicode-canonical-property-names-ecmascript@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz"
@@ -8463,6 +8494,18 @@ websocket-extensions@>=0.1.1:
   resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz"
   integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
 
+whatwg-encoding@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5"
+  integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==
+  dependencies:
+    iconv-lite "0.6.3"
+
+whatwg-mimetype@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a"
+  integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==
+
 which@^1.3.1:
   version "1.3.1"
   resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz"


Test patch:
diff --git a/.github/fixtures/test-from-context/cliff.toml b/.github/fixtures/test-from-context/cliff.toml
new file mode 100644
index 00000000..c533b79
--- /dev/null
+++ b/.github/fixtures/test-from-context/cliff.toml
@@ -0,0 +1,34 @@
+[changelog]
+# template for the changelog footer
+header = """
+# Changelog\n
+All notable changes to this project will be documented in this file.\n
+"""
+# template for the changelog body
+# https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version %}\
+    ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}{% if extra.note %} - {{ extra.note }}{% endif %}
+{% else %}\
+    ## [unreleased]
+{% endif %}\
+{% for group, commits in commits | group_by(attribute="group") %}
+    ### {{ group | upper_first }}
+    {% for commit in commits %}
+        - {{ commit.message | upper_first }}{% if commit.extra.note %} ({{ commit.extra.note }}){% endif %}\
+    {% endfor %}
+{% endfor %}\n
+"""
+# template for the changelog footer
+footer = """
+<!-- generated by git-cliff -->
+"""
+# remove the leading and trailing whitespace from the templates
+trim = true
+
+[git]
+# regex for parsing and grouping commits
+commit_parsers = [
+    { message = "^feat", group = "Features", default_scope = "app" },
+    { message = "^fix", group = "Bug Fixes", scope = "cli" },
+]
diff --git a/.github/fixtures/test-from-context/commit.sh b/.github/fixtures/test-from-context/commit.sh
new file mode 100755
index 00000000..86dc2c5
--- /dev/null
+++ b/.github/fixtures/test-from-context/commit.sh
@@ -0,0 +1,11 @@
+#!/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 -m "feat: add feature 1"
+GIT_COMMITTER_DATE="2022-04-06 01:25:10" git commit --allow-empty -m "fix: fix feature 1"
+git tag v0.1.0
+GIT_COMMITTER_DATE="2022-04-06 01:25:11" git commit --allow-empty -m "feat(gui): add feature 2"
+GIT_COMMITTER_DATE="2022-04-06 01:25:12" git commit --allow-empty -m "fix(gui): fix feature 2 SHOULD NOT BE IN THE CHANGELOG"
+git tag v0.2.0
+GIT_COMMITTER_DATE="2022-04-06 01:25:13" git commit --allow-empty -m "test: add tests"
diff --git a/.github/fixtures/test-from-context/context.json b/.github/fixtures/test-from-context/context.json
new file mode 100644
index 00000000..5dee19a
--- /dev/null
+++ b/.github/fixtures/test-from-context/context.json
@@ -0,0 +1,626 @@
+[
+    {
+        "version": null,
+        "message": null,
+        "commits": [
+            {
+                "id": "c7541276668616c136d12a9ccd87087314d66fb6",
+                "message": "add tests",
+                "body": null,
+                "footers": [],
+                "group": "test",
+                "breaking_description": null,
+                "breaking": false,
+                "scope": null,
+                "links": [],
+                "author": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1723730666
+                },
+                "committer": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1649201113
+                },
+                "conventional": true,
+                "merge_commit": false,
+                "github": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitlab": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitea": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "bitbucket": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                }
+            }
+        ],
+        "commit_id": null,
+        "timestamp": 0,
+        "previous": {
+            "version": "v0.2.0",
+            "message": null,
+            "commits": [
+                {
+                    "id": "ce8cecc9834e5cbdb5b4e79c8260cace3c0dd949",
+                    "message": "feat(gui): add feature 2\n",
+                    "group": null,
+                    "scope": null,
+                    "links": [],
+                    "author": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1723730666
+                    },
+                    "committer": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1649201111
+                    },
+                    "conventional": false,
+                    "merge_commit": false,
+                    "github": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitlab": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitea": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "bitbucket": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    }
+                },
+                {
+                    "id": "5061081d6272b1da2146fab49d803c193db309d9",
+                    "message": "fix(gui): fix feature 2\n",
+                    "group": null,
+                    "scope": null,
+                    "links": [],
+                    "author": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1723730666
+                    },
+                    "committer": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1649201112
+                    },
+                    "conventional": false,
+                    "merge_commit": false,
+                    "github": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitlab": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitea": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "bitbucket": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    }
+                }
+            ],
+            "commit_id": "5061081d6272b1da2146fab49d803c193db309d9",
+            "timestamp": 1649201112,
+            "previous": null,
+            "repository": "/home/johndoe/repo/",
+            "github": {
+                "contributors": []
+            },
+            "gitlab": {
+                "contributors": []
+            },
+            "gitea": {
+                "contributors": []
+            },
+            "bitbucket": {
+                "contributors": []
+            }
+        },
+        "repository": "/home/johndoe/repo/",
+        "github": {
+            "contributors": []
+        },
+        "gitlab": {
+            "contributors": []
+        },
+        "gitea": {
+            "contributors": []
+        },
+        "bitbucket": {
+            "contributors": []
+        }
+    },
+    {
+        "version": "v0.2.0",
+        "message": null,
+        "commits": [
+            {
+                "id": "ce8cecc9834e5cbdb5b4e79c8260cace3c0dd949",
+                "message": "add feature 2",
+                "body": null,
+                "footers": [],
+                "group": "Features",
+                "breaking_description": null,
+                "breaking": false,
+                "scope": "gui",
+                "links": [],
+                "author": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1723730666
+                },
+                "committer": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1649201111
+                },
+                "conventional": true,
+                "merge_commit": false,
+                "github": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitlab": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitea": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "bitbucket": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                }
+            },
+            {
+                "id": "5061081d6272b1da2146fab49d803c193db309d9",
+                "message": "fix feature 2",
+                "body": null,
+                "footers": [],
+                "group": "Bug Fixes",
+                "breaking_description": null,
+                "breaking": false,
+                "scope": "cli",
+                "links": [],
+                "author": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1723730666
+                },
+                "committer": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1649201112
+                },
+                "conventional": true,
+                "merge_commit": false,
+                "extra": {
+                    "note": "that was a tough one"
+                },
+                "github": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitlab": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitea": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "bitbucket": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                }
+            }
+        ],
+        "commit_id": "5061081d6272b1da2146fab49d803c193db309d9",
+        "timestamp": 1649201112,
+        "previous": {
+            "version": "v0.1.0",
+            "message": null,
+            "commits": [
+                {
+                    "id": "c6ba7fe73c3b639ff2f934f3f98e5f50350ab463",
+                    "message": "Initial commit\n",
+                    "group": null,
+                    "scope": null,
+                    "links": [],
+                    "author": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1723730666
+                    },
+                    "committer": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1649201108
+                    },
+                    "conventional": false,
+                    "merge_commit": false,
+                    "github": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitlab": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitea": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "bitbucket": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    }
+                },
+                {
+                    "id": "9c10e506bf103998e303d8164c7b4a1a841e2471",
+                    "message": "feat: add feature 1\n",
+                    "group": null,
+                    "scope": null,
+                    "links": [],
+                    "author": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1723730666
+                    },
+                    "committer": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1649201109
+                    },
+                    "conventional": false,
+                    "merge_commit": false,
+                    "github": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitlab": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitea": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "bitbucket": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    }
+                },
+                {
+                    "id": "98b1464c2f99a0c6812ce6d3ea4a5b953dd35fe2",
+                    "message": "fix: fix feature 1\n",
+                    "group": null,
+                    "scope": null,
+                    "links": [],
+                    "author": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1723730666
+                    },
+                    "committer": {
+                        "name": "John Doe",
+                        "email": "john@doe.com",
+                        "timestamp": 1649201110
+                    },
+                    "conventional": false,
+                    "merge_commit": false,
+                    "github": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitlab": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "gitea": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    },
+                    "bitbucket": {
+                        "username": null,
+                        "pr_title": null,
+                        "pr_number": null,
+                        "pr_labels": [],
+                        "is_first_time": false
+                    }
+                }
+            ],
+            "commit_id": "98b1464c2f99a0c6812ce6d3ea4a5b953dd35fe2",
+            "timestamp": 1649201110,
+            "previous": null,
+            "repository": "/home/johndoe/repo/",
+            "github": {
+                "contributors": []
+            },
+            "gitlab": {
+                "contributors": []
+            },
+            "gitea": {
+                "contributors": []
+            },
+            "bitbucket": {
+                "contributors": []
+            }
+        },
+        "extra": {
+            "note": "This is so awesome!"
+        },
+        "repository": "/home/johndoe/repo/",
+        "github": {
+            "contributors": []
+        },
+        "gitlab": {
+            "contributors": []
+        },
+        "gitea": {
+            "contributors": []
+        },
+        "bitbucket": {
+            "contributors": []
+        }
+    },
+    {
+        "version": "v0.1.0",
+        "message": null,
+        "commits": [
+            {
+                "id": "9c10e506bf103998e303d8164c7b4a1a841e2471",
+                "message": "add feature 1",
+                "body": null,
+                "footers": [],
+                "group": "Features",
+                "breaking_description": null,
+                "breaking": false,
+                "scope": "app",
+                "links": [],
+                "author": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1723730666
+                },
+                "committer": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1649201109
+                },
+                "conventional": true,
+                "merge_commit": false,
+                "github": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitlab": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitea": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "bitbucket": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                }
+            },
+            {
+                "id": "98b1464c2f99a0c6812ce6d3ea4a5b953dd35fe2",
+                "message": "fix feature 1",
+                "body": null,
+                "footers": [],
+                "group": "Bug Fixes",
+                "breaking_description": null,
+                "breaking": false,
+                "scope": "cli",
+                "links": [],
+                "author": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1723730666
+                },
+                "committer": {
+                    "name": "John Doe",
+                    "email": "john@doe.com",
+                    "timestamp": 1649201110
+                },
+                "conventional": true,
+                "merge_commit": false,
+                "github": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitlab": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "gitea": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                },
+                "bitbucket": {
+                    "username": null,
+                    "pr_title": null,
+                    "pr_number": null,
+                    "pr_labels": [],
+                    "is_first_time": false
+                }
+            }
+        ],
+        "commit_id": "98b1464c2f99a0c6812ce6d3ea4a5b953dd35fe2",
+        "timestamp": 1649201110,
+        "previous": {
+            "version": null,
+            "message": null,
+            "commits": [],
+            "commit_id": null,
+            "timestamp": 0,
+            "previous": null,
+            "repository": null,
+            "github": {
+                "contributors": []
+            },
+            "gitlab": {
+                "contributors": []
+            },
+            "gitea": {
+                "contributors": []
+            },
+            "bitbucket": {
+                "contributors": []
+            }
+        },
+        "repository": "/home/johndoe/repo/",
+        "github": {
+            "contributors": []
+        },
+        "gitlab": {
+            "contributors": []
+        },
+        "gitea": {
+            "contributors": []
+        },
+        "bitbucket": {
+            "contributors": []
+        }
+    }
+]
diff --git a/.github/fixtures/test-from-context/expected.md b/.github/fixtures/test-from-context/expected.md
new file mode 100644
index 00000000..5e0ff03
--- /dev/null
+++ b/.github/fixtures/test-from-context/expected.md
@@ -0,0 +1,31 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [unreleased]
+
+### Test
+
+- Add tests
+
+## [0.2.0] - 2022-04-05 - This is so awesome!
+
+### Bug Fixes
+
+- Fix feature 2 (that was a tough one)
+
+### Features
+
+- Add feature 2
+
+## [0.1.0] - 2022-04-05
+
+### Bug Fixes
+
+- Fix feature 1
+
+### Features
+
+- Add feature 1
+
+<!-- generated by git-cliff -->
diff --git a/.github/workflows/test-fixtures.yml b/.github/workflows/test-fixtures.yml
index ba9daa2..69b74e2 100644
--- a/.github/workflows/test-fixtures.yml
+++ b/.github/workflows/test-fixtures.yml
@@ -91,6 +91,8 @@ jobs:
           - fixtures-name: test-tag-message
           - fixtures-name: test-bump-unreleased-with-tag-message-arg
             command: --bump --unreleased --with-tag-message "Some text"
+          - fixtures-name: test-from-context
+            command: --from-context context.json
 
     steps:
       - name: Checkout
diff --git a/git-cliff-core/tests/integration_test.rs b/git-cliff-core/tests/integration_test.rs
index 355dd11..58141a9 100644
--- a/git-cliff-core/tests/integration_test.rs
+++ b/git-cliff-core/tests/integration_test.rs
@@ -151,6 +151,7 @@ fn generate_changelog() -> Result<()> {
 		Release {
 			version:   Some(String::from("v2.0.0")),
 			message: None,
+            extra: None,
 			commits:   vec![
 
 				Commit::new(
@@ -216,6 +217,7 @@ fn generate_changelog() -> Result<()> {
 		Release {
 			version:   Some(String::from("v1.0.0")),
 			message: None,
+            extra: None,
 			commits:   vec![
 				Commit::new(
 					String::from("0bc123"),