From 3d96357d23c10e509a8b9c59afcfe4af398a50cc Mon Sep 17 00:00:00 2001 From: Khanh Duong Quoc Date: Mon, 14 Oct 2024 06:55:28 +0900 Subject: [PATCH] fix(changelog): fix missing commit fields in context (#837) * feat(commit): add `raw_message` to `Commit` * test(fixtures): add test generate all fields in conventional commits * test(fixtures): add test do not discard missing fields in conventional commits when reading from context * docs(website): add `raw_message` fields to `context.md` --- .../test-conventional-commit/cliff.toml | 35 ++ .../test-conventional-commit/commit.sh | 52 +++ .../test-conventional-commit/expected.md | 35 ++ .../cliff.toml | 35 ++ .../commit.sh | 52 +++ .../context.json | 373 ++++++++++++++++++ .../expected.md | 35 ++ .github/workflows/test-fixtures.yml | 3 + git-cliff-core/src/commit.rs | 37 +- git-cliff-core/src/release.rs | 2 + website/docs/templating/context.md | 6 +- 11 files changed, 661 insertions(+), 4 deletions(-) create mode 100644 .github/fixtures/test-conventional-commit/cliff.toml create mode 100755 .github/fixtures/test-conventional-commit/commit.sh create mode 100644 .github/fixtures/test-conventional-commit/expected.md create mode 100644 .github/fixtures/test-from-context-does-not-discard-fields/cliff.toml create mode 100755 .github/fixtures/test-from-context-does-not-discard-fields/commit.sh create mode 100644 .github/fixtures/test-from-context-does-not-discard-fields/context.json create mode 100644 .github/fixtures/test-from-context-does-not-discard-fields/expected.md diff --git a/.github/fixtures/test-conventional-commit/cliff.toml b/.github/fixtures/test-conventional-commit/cliff.toml new file mode 100644 index 0000000000..847a4cc86a --- /dev/null +++ b/.github/fixtures/test-conventional-commit/cliff.toml @@ -0,0 +1,35 @@ +[changelog] +# template for the changelog footer +header = """ +# Changelog\n +All notable changes to this project will be documented in this file. +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{% for group, commits in commits | group_by(attribute="group") %} + ## {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ + {% if commit.breaking %}[**breaking**]: {{ commit.breaking_description }}{% endif %} + {{ commit.message }}: {{ commit.body }}\ + {% for footer in commit.footers %} + - {{ footer.token }}{{ footer.separator }} {{ footer.value }}\ + {% endfor %} + {% endfor %}\ +{% endfor %}\n +""" +# template for the changelog footer +footer = """ + +""" + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# process each line of a commit as an individual commit +split_commits = false +commit_parsers = [ + { message = "^feat", group = "Features", default_scope = "app" }, + { message = "^fix" }, +] diff --git a/.github/fixtures/test-conventional-commit/commit.sh b/.github/fixtures/test-conventional-commit/commit.sh new file mode 100755 index 0000000000..b55c2524a3 --- /dev/null +++ b/.github/fixtures/test-conventional-commit/commit.sh @@ -0,0 +1,52 @@ +#!/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(web): feature 1, breaking change in footer + +Body feature 1 + +BREAKING CHANGE: breaking change description feature 1 +Signed-off-by: user1 +Reviewed-by: user2 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:10" git commit --allow-empty -m \ + "feat(web)!: feature 2, breaking chain in description + +Body feature 2 + +Signed-off-by: user3 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:11" git commit --allow-empty -m \ + "feat!: feature 3, use default scope = app + +Body feature 2 + +Signed-off-by: user3 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:12" git commit --allow-empty -m \ + "fix(scope): fix 1, use scope as group + +Body fix 1 + +Fix: #1 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:13" git commit --allow-empty -m \ + "fix(front-end): fix 2, no footer + +Body fix 2 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:14" git commit --allow-empty -m \ + "fix(front-end): fix 3 and 4, no body but footer + +Fix: #3 +Fix: #4 +" + +git tag v0.1.0 diff --git a/.github/fixtures/test-conventional-commit/expected.md b/.github/fixtures/test-conventional-commit/expected.md new file mode 100644 index 0000000000..aefd3fa0c5 --- /dev/null +++ b/.github/fixtures/test-conventional-commit/expected.md @@ -0,0 +1,35 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## Features + +*(web)* [**breaking**]: breaking change description feature 1 +feature 1, breaking change in footer: Body feature 1 +- BREAKING CHANGE: breaking change description feature 1 +- Signed-off-by: user1 +- Reviewed-by: user2 + +*(web)* [**breaking**]: feature 2, breaking chain in description +feature 2, breaking chain in description: Body feature 2 +- Signed-off-by: user3 + +*(app)* [**breaking**]: feature 3, use default scope = app +feature 3, use default scope = app: Body feature 2 +- Signed-off-by: user3 + +## Fix + +*(scope)* +fix 1, use scope as group: Body fix 1 +- Fix: #1 + +*(front-end)* +fix 2, no footer: Body fix 2 + +*(front-end)* +fix 3 and 4, no body but footer: +- Fix: #3 +- Fix: #4 + + diff --git a/.github/fixtures/test-from-context-does-not-discard-fields/cliff.toml b/.github/fixtures/test-from-context-does-not-discard-fields/cliff.toml new file mode 100644 index 0000000000..847a4cc86a --- /dev/null +++ b/.github/fixtures/test-from-context-does-not-discard-fields/cliff.toml @@ -0,0 +1,35 @@ +[changelog] +# template for the changelog footer +header = """ +# Changelog\n +All notable changes to this project will be documented in this file. +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{% for group, commits in commits | group_by(attribute="group") %} + ## {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ + {% if commit.breaking %}[**breaking**]: {{ commit.breaking_description }}{% endif %} + {{ commit.message }}: {{ commit.body }}\ + {% for footer in commit.footers %} + - {{ footer.token }}{{ footer.separator }} {{ footer.value }}\ + {% endfor %} + {% endfor %}\ +{% endfor %}\n +""" +# template for the changelog footer +footer = """ + +""" + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# process each line of a commit as an individual commit +split_commits = false +commit_parsers = [ + { message = "^feat", group = "Features", default_scope = "app" }, + { message = "^fix" }, +] diff --git a/.github/fixtures/test-from-context-does-not-discard-fields/commit.sh b/.github/fixtures/test-from-context-does-not-discard-fields/commit.sh new file mode 100755 index 0000000000..b55c2524a3 --- /dev/null +++ b/.github/fixtures/test-from-context-does-not-discard-fields/commit.sh @@ -0,0 +1,52 @@ +#!/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(web): feature 1, breaking change in footer + +Body feature 1 + +BREAKING CHANGE: breaking change description feature 1 +Signed-off-by: user1 +Reviewed-by: user2 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:10" git commit --allow-empty -m \ + "feat(web)!: feature 2, breaking chain in description + +Body feature 2 + +Signed-off-by: user3 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:11" git commit --allow-empty -m \ + "feat!: feature 3, use default scope = app + +Body feature 2 + +Signed-off-by: user3 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:12" git commit --allow-empty -m \ + "fix(scope): fix 1, use scope as group + +Body fix 1 + +Fix: #1 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:13" git commit --allow-empty -m \ + "fix(front-end): fix 2, no footer + +Body fix 2 +" + +GIT_COMMITTER_DATE="2022-04-06 01:25:14" git commit --allow-empty -m \ + "fix(front-end): fix 3 and 4, no body but footer + +Fix: #3 +Fix: #4 +" + +git tag v0.1.0 diff --git a/.github/fixtures/test-from-context-does-not-discard-fields/context.json b/.github/fixtures/test-from-context-does-not-discard-fields/context.json new file mode 100644 index 0000000000..9fe23d59f3 --- /dev/null +++ b/.github/fixtures/test-from-context-does-not-discard-fields/context.json @@ -0,0 +1,373 @@ +[ + { + "version": "v0.1.0", + "message": null, + "commits": [ + { + "id": "ea74aebaa74be73f5aae2f3ce3b23dc6d62979bf", + "message": "Initial commit", + "group": "Other (unconventional)", + "scope": null, + "links": [], + "author": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1728938297 + }, + "committer": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1649175908 + }, + "conventional": false, + "merge_commit": false, + "extra": null, + "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 + }, + "raw_message": "Initial commit" + }, + { + "id": "ab06a042344dbd1c4af974ef393049b44ad0ae28", + "message": "feat(web): feature 1, breaking change in footer\n\nBody feature 1\n\nBREAKING CHANGE: breaking change description feature 1\nSigned-off-by: user1 \nReviewed-by: user2", + "group": "Features", + "scope": "app", + "links": [], + "author": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1728938297 + }, + "committer": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1649175909 + }, + "conventional": false, + "merge_commit": false, + "extra": null, + "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 + }, + "raw_message": "feat(web): feature 1, breaking change in footer\n\nBody feature 1\n\nBREAKING CHANGE: breaking change description feature 1\nSigned-off-by: user1 \nReviewed-by: user2" + }, + { + "id": "a87599e6ecaf05e80ac4d87edd9a852fd8cad189", + "message": "feat(web)!: feature 2, breaking chain in description\n\nBody feature 2\n\nSigned-off-by: user3 ", + "group": "Features", + "scope": "app", + "links": [], + "author": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1728938297 + }, + "committer": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1649175910 + }, + "conventional": false, + "merge_commit": false, + "extra": null, + "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 + }, + "raw_message": "feat(web)!: feature 2, breaking chain in description\n\nBody feature 2\n\nSigned-off-by: user3 " + }, + { + "id": "9d83e631a1c57eec825f724283041662edd9230b", + "message": "feat!: feature 3, use default scope = app\n\nBody feature 2\n\nSigned-off-by: user3 ", + "group": "Features", + "scope": "app", + "links": [], + "author": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1728938297 + }, + "committer": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1649175911 + }, + "conventional": false, + "merge_commit": false, + "extra": null, + "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 + }, + "raw_message": "feat!: feature 3, use default scope = app\n\nBody feature 2\n\nSigned-off-by: user3 " + }, + { + "id": "3bb5b6f741fd40cc71f09d3c6a339e4b5d0843cc", + "message": "fix(scope): fix 1, use scope as group\n\nBody fix 1\n\nFix: #1", + "group": null, + "scope": null, + "links": [], + "author": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1728938297 + }, + "committer": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1649175912 + }, + "conventional": false, + "merge_commit": false, + "extra": null, + "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 + }, + "raw_message": "fix(scope): fix 1, use scope as group\n\nBody fix 1\n\nFix: #1" + }, + { + "id": "856472f0e5b238278fe331dcc151a96982c5bbad", + "message": "fix(front-end): fix 2, no footer\n\nBody fix 2", + "group": null, + "scope": null, + "links": [], + "author": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1728938297 + }, + "committer": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1649175913 + }, + "conventional": false, + "merge_commit": false, + "extra": null, + "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 + }, + "raw_message": "fix(front-end): fix 2, no footer\n\nBody fix 2" + }, + { + "id": "6e7a2b8e670a348ccfbae696fd850d8769c54360", + "message": "fix(front-end): fix 3 and 4, no body but footer\n\nFix: #3\nFix: #4", + "group": null, + "scope": null, + "links": [], + "author": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1728938297 + }, + "committer": { + "name": "github-actions[bot]", + "email": "github-actions[bot]@users.noreply.github.com", + "timestamp": 1649175914 + }, + "conventional": false, + "merge_commit": false, + "extra": null, + "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 + }, + "raw_message": "fix(front-end): fix 3 and 4, no body but footer\n\nFix: #3\nFix: #4" + } + ], + "commit_id": "6e7a2b8e670a348ccfbae696fd850d8769c54360", + "timestamp": 1649175914, + "previous": { + "version": null, + "message": null, + "commits": [], + "commit_id": null, + "timestamp": 0, + "previous": null, + "repository": null, + "extra": null, + "github": { "contributors": [] }, + "gitlab": { "contributors": [] }, + "gitea": { "contributors": [] }, + "bitbucket": { "contributors": [] } + }, + "repository": "/path/to/repository", + "extra": null, + "github": { "contributors": [] }, + "gitlab": { "contributors": [] }, + "gitea": { "contributors": [] }, + "bitbucket": { "contributors": [] } + } +] diff --git a/.github/fixtures/test-from-context-does-not-discard-fields/expected.md b/.github/fixtures/test-from-context-does-not-discard-fields/expected.md new file mode 100644 index 0000000000..aefd3fa0c5 --- /dev/null +++ b/.github/fixtures/test-from-context-does-not-discard-fields/expected.md @@ -0,0 +1,35 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## Features + +*(web)* [**breaking**]: breaking change description feature 1 +feature 1, breaking change in footer: Body feature 1 +- BREAKING CHANGE: breaking change description feature 1 +- Signed-off-by: user1 +- Reviewed-by: user2 + +*(web)* [**breaking**]: feature 2, breaking chain in description +feature 2, breaking chain in description: Body feature 2 +- Signed-off-by: user3 + +*(app)* [**breaking**]: feature 3, use default scope = app +feature 3, use default scope = app: Body feature 2 +- Signed-off-by: user3 + +## Fix + +*(scope)* +fix 1, use scope as group: Body fix 1 +- Fix: #1 + +*(front-end)* +fix 2, no footer: Body fix 2 + +*(front-end)* +fix 3 and 4, no body but footer: +- Fix: #3 +- Fix: #4 + + diff --git a/.github/workflows/test-fixtures.yml b/.github/workflows/test-fixtures.yml index 6512af6280..09e7d138d8 100644 --- a/.github/workflows/test-fixtures.yml +++ b/.github/workflows/test-fixtures.yml @@ -33,6 +33,7 @@ jobs: command: --latest - fixtures-name: test-commit-footers - fixtures-name: test-commit-preprocessors + - fixtures-name: test-conventional-commit - fixtures-name: test-custom-scope - fixtures-name: test-limit-commits - fixtures-name: test-skip-breaking-changes @@ -93,6 +94,8 @@ jobs: command: --bump --unreleased --with-tag-message "Some text" - fixtures-name: test-from-context command: --from-context context.json + - fixtures-name: test-from-context-does-not-discard-fields + command: --from-context context.json - fixtures-name: test-always-render-unreleased command: --unreleased - fixtures-name: test-always-render diff --git a/git-cliff-core/src/commit.rs b/git-cliff-core/src/commit.rs index 0f349efa36..31637d391e 100644 --- a/git-cliff-core/src/commit.rs +++ b/git-cliff-core/src/commit.rs @@ -28,6 +28,7 @@ use serde::ser::{ }; use serde::{ Deserialize, + Deserializer, Serialize, }; use serde_json::value::Value; @@ -143,6 +144,14 @@ pub struct Commit<'a> { #[cfg(feature = "bitbucket")] #[deprecated(note = "Use `remote` field instead")] pub bitbucket: crate::contributor::RemoteContributor, + + /// Raw message of the normal commit, works as a placeholder for converting + /// normal commit into conventional commit. + /// + /// Despite the name, it is not actually a raw message. + /// In fact, it is pre-processed by [`Commit::preprocess`], and only be + /// generated when serializing into `context` the first time. + pub raw_message: Option, } impl<'a> From for Commit<'a> { @@ -191,6 +200,11 @@ impl Commit<'_> { } } + /// Get raw message for converting into conventional commit. + pub fn raw_message(&self) -> &str { + self.raw_message.as_deref().unwrap_or(&self.message) + } + /// Processes the commit. /// /// * converts commit to a conventional commit @@ -226,7 +240,7 @@ impl Commit<'_> { /// Returns the commit with its conventional type set. pub fn into_conventional(mut self) -> Result { match ConventionalCommit::parse(Box::leak( - self.message.to_string().into_boxed_str(), + self.raw_message().to_string().into_boxed_str(), )) { Ok(conv) => { self.conv = Some(conv); @@ -423,7 +437,7 @@ impl Serialize for Commit<'_> { } } - let mut commit = serializer.serialize_struct("Commit", 9)?; + let mut commit = serializer.serialize_struct("Commit", 20)?; commit.serialize_field("id", &self.id)?; if let Some(conv) = &self.conv { commit.serialize_field("message", conv.description())?; @@ -472,10 +486,29 @@ impl Serialize for Commit<'_> { if let Some(remote) = &self.remote { commit.serialize_field("remote", remote)?; } + commit.serialize_field("raw_message", &self.raw_message())?; commit.end() } } +/// Deserialize commits into conventional commits if they are convertible. +/// +/// Serialized commits cannot be deserialized into commits that have +/// [`Commit::conv`]. Thus, we need to manually convert them using +/// [`Commit::into_conventional`]. +/// +/// This function is to be used only in [`crate::release::Release::commits`]. +pub(crate) fn commits_to_conventional_commits<'de, 'a, D: Deserializer<'de>>( + deserializer: D, +) -> std::result::Result>, D::Error> { + let commits = Vec::>::deserialize(deserializer)?; + let commits = commits + .into_iter() + .map(|commit| commit.clone().into_conventional().unwrap_or(commit)) + .collect(); + Ok(commits) +} + #[cfg(test)] mod test { use super::*; diff --git a/git-cliff-core/src/release.rs b/git-cliff-core/src/release.rs index fec293f51f..dbf1d64568 100644 --- a/git-cliff-core/src/release.rs +++ b/git-cliff-core/src/release.rs @@ -1,3 +1,4 @@ +use crate::commit::commits_to_conventional_commits; use crate::error::Result; use crate::{ commit::Commit, @@ -34,6 +35,7 @@ pub struct Release<'a> { /// git tag's message. pub message: Option, /// Commits made for the release. + #[serde(deserialize_with = "commits_to_conventional_commits")] pub commits: Vec>, /// Commit ID of the tag. #[serde(rename = "commit_id")] diff --git a/website/docs/templating/context.md b/website/docs/templating/context.md index 8fe863a4ed..a2d53c7931 100644 --- a/website/docs/templating/context.md +++ b/website/docs/templating/context.md @@ -57,7 +57,8 @@ following context is generated to use for templating: "name": "User Name", "email": "user.email@example.com", "timestamp": 1660330071 - } + }, + "raw_message": "[scope]: \n[body]\n[footer(s)]" } ], "commit_id": "a440c6eb26404be4877b7e3ad592bfaa5d4eb210 (release commit)", @@ -152,7 +153,8 @@ If [`conventional_commits`](/docs/configuration/git#conventional_commits) is set "name": "User Name", "email": "user.email@example.com", "timestamp": 1660330071 - } + }, + "raw_message": "(full commit message including description, footers, etc.)" } ], "commit_id": "a440c6eb26404be4877b7e3ad592bfaa5d4eb210 (release commit)",