Repository: orhun/git-cliff
Pull request #1190 (2025-06-24 13:03:47)

fix: ensure skip_tags condition is evaluated first
## Description

This PR refactors the logic that determines whether to skip a tag during changelog generation.
Previously, some skip conditions were nested or not independently evaluated.
Now, all conditions are flattened and evaluated, making the behavior more predictable and consistent.

## Motivation and Context

The prior implementation may have skipped tags inconsistently if some conditions short-circuited the evaluation.

Fixes or relates to: #1181 

## How Has This Been Tested?

 - Added a test fixture.

## Screenshots / Logs (if applicable)

N/A

## Types of Changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation (no code change)
- [ ] Refactor (refactoring production code)
- [ ] Other <!--- (provide information) -->

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [x] My code follows the code style of this project.
- [x] I have updated the documentation accordingly.
- [x] I have formatted the code with [rustfmt](https://github.com/rust-lang/rustfmt).
- [x] I checked the lints with [clippy](https://github.com/rust-lang/rust-clippy).
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.

<!--- Thank you for contributing to git-cliff! ⛰️  -->


codecov-commenter: ## [Codecov](https://app.codecov.io/gh/orhun/git-cliff/pull/1190?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) Report
Attention: Patch coverage is `35.71429%` with `9 lines` in your changes missing coverage. Please review.
> Project coverage is 41.88%. Comparing base [(`6db7d49`)](https://app.codecov.io/gh/orhun/git-cliff/commit/6db7d49488a248a2fab010480cb955621d4bcf5a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) to head [(`853e6fe`)](https://app.codecov.io/gh/orhun/git-cliff/commit/853e6fee384f6ec4ccb123a1d8a418d8f33fed90?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z).

| [Files with missing lines](https://app.codecov.io/gh/orhun/git-cliff/pull/1190?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) | Patch % | Lines |
|---|---|---|
| [git-cliff-core/src/changelog.rs](https://app.codecov.io/gh/orhun/git-cliff/pull/1190?src=pr&el=tree&filepath=git-cliff-core%2Fsrc%2Fchangelog.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z#diff-Z2l0LWNsaWZmLWNvcmUvc3JjL2NoYW5nZWxvZy5ycw==) | 35.72% | [9 Missing :warning: ](https://app.codecov.io/gh/orhun/git-cliff/pull/1190?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1190      +/-   ##
==========================================
- Coverage   41.92%   41.88%   -0.03%     
==========================================
  Files          21       21              
  Lines        2009     2013       +4     
==========================================
+ Hits          842      843       +1     
- Misses       1167     1170       +3     
```

| [Flag](https://app.codecov.io/gh/orhun/git-cliff/pull/1190/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) | Coverage Δ | |
|---|---|---|
| [unit-tests](https://app.codecov.io/gh/orhun/git-cliff/pull/1190/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z) | `41.88% <35.72%> (-0.03%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/orhun/git-cliff/pull/1190?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Orhun+Parmaks%C4%B1z).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>

Patch:
diff --git a/git-cliff-core/src/changelog.rs b/git-cliff-core/src/changelog.rs
index fcf2e19..bf983f8 100644
--- a/git-cliff-core/src/changelog.rs
+++ b/git-cliff-core/src/changelog.rs
@@ -195,28 +195,25 @@ impl<'a> Changelog<'a> {
 			.into_iter()
 			.rev()
 			.filter(|release| {
+				if let Some(version) = &release.version {
+					if skip_regex.is_some_and(|r| r.is_match(version)) {
+						skipped_tags.push(version.clone());
+						trace!("Skipping release: {}", version);
+						return false;
+					}
+				}
 				if release.commits.is_empty() {
 					if let Some(version) = release.version.clone() {
 						trace!("Release doesn't have any commits: {}", version);
 					}
 					match &release.previous {
 						Some(prev_release) if prev_release.commits.is_empty() => {
-							self.config.changelog.render_always
+							return self.config.changelog.render_always;
 						}
-						_ => false,
+						_ => return false,
 					}
-				} else if let Some(version) = &release.version {
-					!skip_regex.is_some_and(|r| {
-						let skip_tag = r.is_match(version);
-						if skip_tag {
-							skipped_tags.push(version.clone());
-							trace!("Skipping release: {}", version);
-						}
-						skip_tag
-					})
-				} else {
-					true
 				}
+				true
 			})
 			.map(|release| release.with_statistics())
 			.collect();
@@ -1268,6 +1265,7 @@ mod test {
 	#[test]
 	fn changelog_generator() -> Result<()> {
 		let (config, releases) = get_test_data();
+
 		let mut changelog = Changelog::new(releases, &config, None)?;
 		changelog.bump_version()?;
 		changelog.releases[0].timestamp = Some(0);
@@ -1358,6 +1356,41 @@ mod test {
 			.replace("			", ""),
 			str::from_utf8(&out).unwrap_or_default()
 		);
+
+		Ok(())
+	}
+
+	#[test]
+	fn changelog_generator_render_always() -> Result<()> {
+		let (mut config, mut releases) = get_test_data();
+		config.changelog.render_always = true;
+
+		releases[0].commits = Vec::new();
+		releases[2].commits = Vec::new();
+		releases[2].previous = Some(Box::new(releases[0].clone()));
+		let changelog = Changelog::new(releases, &config, None)?;
+		let mut out = Vec::new();
+		changelog.generate(&mut out)?;
+		assert_eq!(
+			String::from(
+				r#"# Changelog
+
+			## Unreleased
+
+			### Commit Statistics
+
+			- 0 commit(s) contributed to the release.
+			- 0 day(s) passed between the first and last commit.
+			- 0 commit(s) parsed as conventional.
+			- 0 linked issue(s) detected in commits.
+			- -578 day(s) passed between releases.
+			-- total releases: 1 --
+			"#
+			)
+			.replace("			", ""),
+			str::from_utf8(&out).unwrap_or_default()
+		);
+
 		Ok(())
 	}
 
@@ -1367,7 +1400,6 @@ mod test {
 		config.git.split_commits = true;
 		config.git.filter_unconventional = false;
 		config.git.protect_breaking_commits = true;
-
 		for parser in config
 			.git
 			.commit_parsers
@@ -1522,6 +1554,7 @@ chore(deps): fix broken deps
 			.replace("			", ""),
 			str::from_utf8(&out).unwrap_or_default()
 		);
+
 		Ok(())
 	}
 


Test patch:
diff --git a/.github/fixtures/test-skip-tags/cliff.toml b/.github/fixtures/test-skip-tags/cliff.toml
new file mode 100644
index 00000000..4e62b2f
--- /dev/null
+++ b/.github/fixtures/test-skip-tags/cliff.toml
@@ -0,0 +1,25 @@
+# git-cliff ~ configuration file
+# https://git-cliff.org/docs/configuration
+
+[changelog]
+# A Tera template to be rendered for each release in the changelog.
+# See https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version %}\
+    ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
+{% else %}\
+    ## [unreleased]
+{% endif %}\
+{% for group, commits in commits | group_by(attribute="group") %}
+    ### {{ group | upper_first }}
+    {% for commit in commits %}
+        - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
+    {% endfor %}
+{% endfor %}\n
+"""
+
+[git]
+# Regex to select git tags that do not represent proper releases.
+# Takes precedence over `tag_pattern`.
+# Changes belonging to these releases will be included in the next release.
+skip_tags = "v0.0.1"
diff --git a/.github/fixtures/test-skip-tags/commit.sh b/.github/fixtures/test-skip-tags/commit.sh
new file mode 100755
index 00000000..2320865
--- /dev/null
+++ b/.github/fixtures/test-skip-tags/commit.sh
@@ -0,0 +1,8 @@
+set -e
+
+GIT_COMMITTER_DATE="2025-06-24 21:01:21" git commit --allow-empty -m "init"
+git tag v0.0.1
+
+GIT_COMMITTER_DATE="2025-06-24 21:01:22" git commit --allow-empty -m "feat: add feature 0"
+GIT_COMMITTER_DATE="2025-06-24 21:01:23" git commit --allow-empty -m "feat: add feature 1"
+git tag v0.1.0
diff --git a/.github/fixtures/test-skip-tags/expected.md b/.github/fixtures/test-skip-tags/expected.md
new file mode 100644
index 00000000..a8a9dfd
--- /dev/null
+++ b/.github/fixtures/test-skip-tags/expected.md
@@ -0,0 +1,7 @@
+## [0.1.0] - 2025-06-24
+
+### <!-- 0 -->🚀 Features
+
+- Add feature 0
+- Add feature 1
+