Skip to content

Commit

Permalink
feat: support repos with no existing tags
Browse files Browse the repository at this point in the history
Repos with no existing tags will instead use the root commit as the
start, and behave as if it was tagged with `0.0.0`. This allows for a
changelog to be generated from everything but the first commit. For my
projects, I do an empty commit as the first one so this is perfect.
  • Loading branch information
justinrubek committed May 16, 2024
1 parent 45b6865 commit 350d9a4
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
30 changes: 25 additions & 5 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bomper::{
cargo::CargoReplacer, file::FileReplacer, search::SearchReplacer, simple::SimpleReplacer,
Replacer, VersionReplacement,
},
versioning::{get_commits_between_tags, get_commits_since_tag, get_latest_tag, Tag},
versioning::{get_commits_between_tags, get_commits_since_tag, get_latest_tag, Commit, Tag},
};
use console::{style, Style};
use gix::refs::transaction::PreviousValue;
Expand All @@ -29,8 +29,7 @@ impl App {
pub fn bump(&self, opts: &Bump) -> Result<()> {
let repo = gix::discover(".")?;

let tag = get_latest_tag(&repo)?;
let commits = get_commits_since_tag(&repo, &tag)?;
let (tag, commits) = changelog_commits(&repo)?;

let increment = opts.options.determine_increment(&commits, &tag.version)?;
let new_tag = tag.increment_version(increment);
Expand Down Expand Up @@ -101,8 +100,7 @@ impl App {
println!("{}", changelog_entry);
}
None => {
let tag = get_latest_tag(&repo)?;
let commits = get_commits_since_tag(&repo, &tag)?;
let (_, commits) = changelog_commits(&repo)?;
let changelog_entry = generate_changelog_entry(
&repo,
&commits,
Expand Down Expand Up @@ -388,3 +386,25 @@ fn prompt_for_description() -> Result<Option<String>> {
}
}
}

/// Retrieve all the commits that should be included in a new changelog entry.
/// This will start at the current head commit and walk back to the latest tag.
/// The latest tag is determined by the highest semver tag in the repository.
/// If no tags are found, the root commit will be used as the starting point and a version of `0.0.0` will be used.
fn changelog_commits(repo: &gix::Repository) -> Result<(Tag, Vec<Commit>)> {
let tag = match get_latest_tag(repo)? {
Some(tag) => tag,
None => {
let head = repo.head_commit()?;
let ancestors = head.ancestors();
let root_commit = ancestors.all()?.last();
Tag {
version: semver::Version::new(0, 0, 0),
commit_id: root_commit.unwrap().unwrap().id().into(),
prefix_v: false,
}
}
};
let commits = get_commits_since_tag(repo, &tag)?;
Ok((tag, commits))
}
34 changes: 28 additions & 6 deletions src/versioning.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;

use crate::error::{Error, Result};
use crate::error::Result;
use conventional_commit_parser::commit::{CommitType, ConventionalCommit};

#[derive(Clone, Debug, Eq)]
Expand Down Expand Up @@ -95,11 +95,8 @@ pub enum VersionIncrement {
Patch,
}

pub fn get_latest_tag(repo: &gix::Repository) -> Result<Tag> {
let tag = Tag::get_version_tags(repo)?
.into_iter()
.max()
.ok_or_else(|| Error::TagError)?;
pub fn get_latest_tag(repo: &gix::Repository) -> Result<Option<Tag>> {
let tag = Tag::get_version_tags(repo)?.into_iter().max();
Ok(tag)
}

Expand Down Expand Up @@ -144,6 +141,31 @@ pub fn get_commits_since_tag(repo: &gix::Repository, tag: &Tag) -> Result<Vec<Co
Ok(parsed_commits)
}

pub fn get_commits_since_initial_commit(repo: &gix::Repository) -> Result<Vec<Commit>> {
let head = repo.head_commit()?;
let ancestors = head.ancestors();
let mut parsed_commits = Vec::new();
for commit in ancestors.all()? {
let commit = commit.unwrap();
let object = commit.object().unwrap();
let message = object.message().unwrap();
let mut full_message = String::new();
full_message.push_str(message.title.to_string().trim());
if let Some(body) = message.body {
full_message.push_str("\n\n");
full_message.push_str(&body.to_string());
}
let parsed = conventional_commit_parser::parse(&full_message)?;
parsed_commits.push(Commit {
commit_id: commit.id().into(),
conventional_commit: parsed,
signature: object.author().to_owned()?.into(),
});
}

Ok(parsed_commits)
}

pub fn get_commits_between_tags(
repo: &gix::Repository,
from: &Tag,
Expand Down

0 comments on commit 350d9a4

Please sign in to comment.