Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(changelog): support generating changelog for different branches #808

Merged
merged 12 commits into from
Sep 9, 2024
1 change: 1 addition & 0 deletions git-cliff-core/src/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,7 @@ mod test {
skip_tags: Regex::new("v3.*").ok(),
ignore_tags: None,
count_tags: None,
use_branch_tags: Some(false),
topo_order: Some(false),
sort_commits: Some(String::from("oldest")),
link_parsers: None,
Expand Down
2 changes: 2 additions & 0 deletions git-cliff-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ pub struct GitConfig {
/// Regex to count matched tags.
#[serde(with = "serde_regex", default)]
pub count_tags: Option<Regex>,
/// Include only the tags that belong to the current branch.
pub use_branch_tags: Option<bool>,
/// Whether to sort tags topologically.
pub topo_order: Option<bool>,
/// Sorting of the commits inside sections.
Expand Down
35 changes: 33 additions & 2 deletions git-cliff-core/src/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,35 @@ impl Repository {
None
}

/// Decide whether to include tag
///
/// `head_commit` is the `latest` commit to generate changelog. It can be a
/// branch head or a detached head. `tag_commit` is a tagged commit. If the
/// commit is in the descendant graph of the head_commit or is the
/// head_commit itself, Changelog should include the tag.
fn should_include_tag(
braineo marked this conversation as resolved.
Show resolved Hide resolved
&self,
head_commit: &Commit,
tag_commit: &Commit,
) -> Result<bool> {
Ok(self
.inner
.graph_descendant_of(head_commit.id(), tag_commit.id())? ||
head_commit.id() == tag_commit.id())
}

/// Parses and returns a commit-tag map.
///
/// It collects lightweight and annotated tags.
pub fn tags(
&self,
pattern: &Option<Regex>,
topo_order: bool,
use_branch_tags: bool,
) -> Result<IndexMap<String, Tag>> {
let mut tags: Vec<(Commit, Tag)> = Vec::new();
let tag_names = self.inner.tag_names(None)?;
let head_commit = self.inner.head()?.peel_to_commit()?;
for name in tag_names
.iter()
.flatten()
Expand All @@ -330,6 +349,12 @@ impl Repository {
{
let obj = self.inner.revparse_single(&name)?;
if let Ok(commit) = obj.clone().into_commit() {
if use_branch_tags &&
!self.should_include_tag(&head_commit, &commit)?
{
continue;
}

tags.push((commit, Tag {
name,
message: None,
Expand All @@ -340,6 +365,11 @@ impl Repository {
.ok()
.and_then(|target| target.into_commit().ok())
{
if use_branch_tags &&
!self.should_include_tag(&head_commit, &commit)?
{
continue;
}
tags.push((commit, Tag {
name: tag.name().map(String::from).unwrap_or(name),
message: tag.message().map(|msg| {
Expand Down Expand Up @@ -468,15 +498,15 @@ mod test {
#[test]
fn get_latest_tag() -> Result<()> {
let repository = get_repository()?;
let tags = repository.tags(&None, false)?;
let tags = repository.tags(&None, false, false)?;
assert_eq!(get_last_tag()?, tags.last().expect("no tags found").1.name);
Ok(())
}

#[test]
fn git_tags() -> Result<()> {
let repository = get_repository()?;
let tags = repository.tags(&None, true)?;
let tags = repository.tags(&None, true, false)?;
assert_eq!(
tags.get("2b8b4d3535f29231e05c3572e919634b9af907b6")
.expect(
Expand All @@ -500,6 +530,7 @@ mod test {
.expect("the regex is not valid"),
),
true,
false,
)?;
assert_eq!(
tags.get("2b8b4d3535f29231e05c3572e919634b9af907b6")
Expand Down
1 change: 1 addition & 0 deletions git-cliff-core/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ fn generate_changelog() -> Result<()> {
skip_tags: None,
ignore_tags: None,
count_tags: None,
use_branch_tags: None,
topo_order: None,
sort_commits: None,
link_parsers: Some(vec![
Expand Down
3 changes: 3 additions & 0 deletions git-cliff/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ pub struct Opt {
/// Sorts the tags topologically.
#[arg(long, help_heading = Some("FLAGS"))]
pub topo_order: bool,
/// Include only the tags that belong to the current branch.
#[arg(long, help_heading = Some("FLAGS"))]
pub use_branch_tags: bool,
/// Disables the external command execution.
#[arg(long, help_heading = Some("FLAGS"))]
pub no_exec: bool,
Expand Down
6 changes: 5 additions & 1 deletion git-cliff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ fn process_repository<'a>(
config: &mut Config,
args: &Opt,
) -> Result<Vec<Release<'a>>> {
let mut tags = repository.tags(&config.git.tag_pattern, args.topo_order)?;
let mut tags = repository.tags(
&config.git.tag_pattern,
args.topo_order,
args.use_branch_tags,
)?;
let skip_regex = config.git.skip_tags.as_ref();
let ignore_regex = config.git.ignore_tags.as_ref();
let count_tags = config.git.count_tags.as_ref();
Expand Down
21 changes: 11 additions & 10 deletions website/docs/usage/args.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ git-cliff [FLAGS] [OPTIONS] [--] [RANGE]
## Flags

```
-h, --help Prints help information
-V, --version Prints version information
-v, --verbose... Increases the logging verbosity
--bumped-version Prints bumped version for unreleased changes
-l, --latest Processes the commits starting from the latest tag
--current Processes the commits that belong to the current tag
-u, --unreleased Processes the commits that do not belong to a tag
--topo-order Sorts the tags topologically
--no-exec Disables the external command execution
-x, --context Prints changelog context as JSON
-h, --help Prints help information
-V, --version Prints version information
-v, --verbose... Increases the logging verbosity
--bumped-version Prints bumped version for unreleased changes
-l, --latest Processes the commits starting from the latest tag
--current Processes the commits that belong to the current tag
-u, --unreleased Processes the commits that do not belong to a tag
--topo-order Sorts the tags topologically
--use-branch-tags Include only the tags that belong to the current branch
--no-exec Disables the external command execution
-x, --context Prints changelog context as JSON
```

## Options
Expand Down
6 changes: 6 additions & 0 deletions website/docs/usage/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ git cliff v2.2.1..
git cliff v0.1.0..HEAD
```

Only include the tags from the current branch:

```bash
git cliff --use-branch-tags
```

Sort the commits inside sections:

```bash
Expand Down
Loading