Skip to content

Commit

Permalink
fix(bump): fix target changelog tag on bump
Browse files Browse the repository at this point in the history
  • Loading branch information
oknozor committed Nov 30, 2021
1 parent 9b5a591 commit 0618192
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 46 deletions.
12 changes: 9 additions & 3 deletions src/conventional/changelog/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub(crate) mod renderer;
pub(crate) mod serde;
pub mod template;

const CHANGELOG_SEPARATOR: &str = "- - -";

const DEFAULT_HEADER: &str =
"# Changelog\nAll notable changes to this project will be documented in this file. \
See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.\n\n- - -\n";
Expand All @@ -30,11 +32,15 @@ impl Release<'_> {
let mut changelog_content = fs::read_to_string(path.as_ref())
.unwrap_or_else(|_| [DEFAULT_HEADER, DEFAULT_FOOTER].join(""));

let separator_idx = changelog_content.find("- - -");
let separator_idx = changelog_content.find(CHANGELOG_SEPARATOR);

if let Some(idx) = separator_idx {
changelog_content.insert_str(idx + 5, &changelog);
changelog_content.insert_str(idx + 5 + changelog.len(), "\n- - -");
changelog_content.insert(idx + CHANGELOG_SEPARATOR.len(), '\n');
changelog_content.insert_str(idx + CHANGELOG_SEPARATOR.len() + 1, &changelog);
changelog_content.insert_str(
idx + CHANGELOG_SEPARATOR.len() + 1 + changelog.len(),
"\n- - -\n",
);
fs::write(path.as_ref(), changelog_content)?;

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions src/conventional/changelog/release.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,12 @@ mod test {
let a_commit_hash = "17f7e23081db15e9318aeb37529b1d473cf41cbe";
let version = Tag::new(
"1.0.0",
Oid::from_str("9bb5facac5724bc81385fdd740fedbb49056da00").unwrap(),
Some(Oid::from_str("9bb5facac5724bc81385fdd740fedbb49056da00").unwrap()),
)
.unwrap();
let from = Tag::new(
"0.1.0",
Oid::from_str("fae3a288a1bc69b14f85a1d5fe57cee1964acd60").unwrap(),
Some(Oid::from_str("fae3a288a1bc69b14f85a1d5fe57cee1964acd60").unwrap()),
)
.unwrap();
Release {
Expand Down
2 changes: 1 addition & 1 deletion src/conventional/changelog/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Renderer {
let mut release = self.render_release(&version)?;
let mut version = version;
while let Some(previous) = version.previous.map(|v| *v) {
release.push_str("\n- - -\n");
release.push_str("\n\n- - -\n\n");
release.push_str(self.render_release(&previous)?.as_str());
version = previous;
}
Expand Down
5 changes: 2 additions & 3 deletions src/conventional/changelog/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,10 @@ impl Serialize for OidOf {
where
S: Serializer,
{
let mut oidof = serializer.serialize_struct("OidOf", 3)?;
let mut oidof = serializer.serialize_struct("OidOf", 1)?;
match self {
OidOf::Tag(tag) => {
oidof.serialize_field("tag", &tag.to_string_with_prefix())?;
oidof.serialize_field("id", &tag.oid().to_string())?
}
OidOf::Head(oid) | OidOf::Other(oid) => {
oidof.serialize_field("id", &oid.to_string())?
Expand All @@ -82,7 +81,7 @@ mod test {

#[test]
fn should_serialize_tag() {
let tag = Tag::new("1.0.0", Oid::from_str("1234567890").unwrap()).unwrap();
let tag = Tag::new("1.0.0", Some(Oid::from_str("1234567890").unwrap())).unwrap();

let result = toml::to_string(&tag);

Expand Down
2 changes: 1 addition & 1 deletion src/git/oid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum OidOf {
impl OidOf {
pub fn oid(&self) -> &Oid {
match self {
OidOf::Tag(t) => t.oid(),
OidOf::Tag(t) => t.oid_unchecked(),
OidOf::Head(o) => o,
OidOf::Other(o) => o,
}
Expand Down
48 changes: 28 additions & 20 deletions src/git/revspec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ impl Repository {
// No target tag provided, check if HEAD is tagged
None => {
let head = self.get_head_commit_oid()?;

self.get_latest_tag().ok().filter(|tag| *tag.oid() == head)
self.get_latest_tag()
.ok()
.filter(|tag| *tag.oid_unchecked() == head)
}
// Try to resolve a tag from the provided range, ex: ..1.0.0
Some(to) => self.resolve_tag(to).ok(),
Expand Down Expand Up @@ -190,17 +191,24 @@ impl Repository {
}

fn resolve_oid_of(&self, from: &str) -> OidOf {
// either we have a tag name
self.resolve_tag(from)
.ok()
.map(OidOf::Tag)
// No tag found, this is an oid
.unwrap_or_else(|| {
let oid = self
.0
.revparse_single(from)
.expect("Expected oid or tag")
.id();
OidOf::Other(oid)
// Or an oid
.unwrap_or_else(|_| {
let object = self.0.revparse_single(from).expect("Expected oid or tag");

// Is the oid pointing to a tag ?
let tag = self
.all_tags()
.expect("Error trying to get repository tags")
.into_iter()
.find(|tag| *tag.oid_unchecked() == object.id());

match tag {
None => OidOf::Other(object.id()),
Some(tag) => OidOf::Tag(tag),
}
})
}

Expand Down Expand Up @@ -240,7 +248,7 @@ impl Repository {
let name = String::from_utf8_lossy(name);
let name = name.as_ref().strip_prefix("refs/tags/").unwrap();
if range.contains(&oid) {
if let Ok(tag) = Tag::new(name, oid) {
if let Ok(tag) = Tag::new(name, Some(oid)) {
tags.push(tag);
};
};
Expand Down Expand Up @@ -387,9 +395,9 @@ mod test {
// Arrange
let repo = Repository::open(&context.current_dir)?;
let v1_0_0 = Oid::from_str("549070fa99986b059cbaa9457b6b6f065bbec46b")?;
let v1_0_0 = OidOf::Tag(Tag::new("1.0.0", v1_0_0)?);
let v1_0_0 = OidOf::Tag(Tag::new("1.0.0", Some(v1_0_0))?);
let v3_0_0 = Oid::from_str("c6508e243e2816e2d2f58828ee0c6721502958dd")?;
let v3_0_0 = OidOf::Tag(Tag::new("3.0.0", v3_0_0)?);
let v3_0_0 = OidOf::Tag(Tag::new("3.0.0", Some(v3_0_0))?);

// Act
let range = repo.get_commit_range(&RevspecPattern::from("1.0.0..3.0.0"))?;
Expand All @@ -410,7 +418,7 @@ mod test {
let head = repo.get_head_commit_oid()?;
let head = OidOf::Other(head);
let v1_0_0 = Oid::from_str("549070fa99986b059cbaa9457b6b6f065bbec46b")?;
let v1_0_0 = OidOf::Tag(Tag::new("1.0.0", v1_0_0)?);
let v1_0_0 = OidOf::Tag(Tag::new("1.0.0", Some(v1_0_0))?);

// Act
let range = repo.get_commit_range(&RevspecPattern::from("1.0.0.."))?;
Expand Down Expand Up @@ -449,9 +457,9 @@ mod test {
// Arrange
let repo = Repository::open(&context.current_dir)?;
let v2_1_1 = Oid::from_str("9dcf728d2eef6b5986633dd52ecbe9e416234898")?;
let v2_1_1 = OidOf::Tag(Tag::new("2.1.1", v2_1_1)?);
let v2_1_1 = OidOf::Tag(Tag::new("2.1.1", Some(v2_1_1))?);
let v3_0_0 = Oid::from_str("c6508e243e2816e2d2f58828ee0c6721502958dd")?;
let v3_0_0 = OidOf::Tag(Tag::new("3.0.0", v3_0_0)?);
let v3_0_0 = OidOf::Tag(Tag::new("3.0.0", Some(v3_0_0))?);

// Act
let range = repo.get_commit_range(&RevspecPattern::from("..3.0.0"))?;
Expand All @@ -472,11 +480,11 @@ mod test {
let tag_count = repo.0.tag_names(None)?.len();

// Act
let mut realease = repo.get_release_range(RevspecPattern::from(".."))?;
let mut release = repo.get_release_range(RevspecPattern::from(".."))?;
let mut count = 0;

while let Some(previous) = realease.previous {
realease = *previous;
while let Some(previous) = release.previous {
release = *previous;
count += 1;
}

Expand Down
47 changes: 34 additions & 13 deletions src/git/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ use anyhow::{anyhow, ensure, Result};
use colored::Colorize;
use git2::string_array::StringArray;
use git2::Oid;
use git2::Tag as Git2Tag;
use semver::Version;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::fmt;
use std::fmt::Formatter;

Expand All @@ -32,7 +34,7 @@ impl Repository {
self.0
.resolve_reference_from_short_name(tag)
.map(|reference| reference.target().unwrap())
.map(|oid| Tag::new(tag, oid))?
.map(|oid| Tag::new(tag, Some(oid)))?
}

pub(crate) fn create_tag(&self, name: &str) -> Result<()> {
Expand All @@ -57,23 +59,29 @@ impl Repository {
}

pub(crate) fn get_latest_tag(&self) -> Result<Tag> {
let latest_tag: Option<Tag> = self
let tags: Vec<Tag> = self.all_tags()?;

let latest_tag: Option<&Tag> = tags.iter().max();

match latest_tag {
Some(tag) => Ok(tag.to_owned()),
None => Err(anyhow!("Unable to get any tag")),
}
}

pub(crate) fn all_tags(&self) -> Result<Vec<Tag>> {
Ok(self
.tags()?
.iter()
.flatten()
.map(|tag| self.resolve_lightweight_tag(tag))
.filter_map(Result::ok)
.max();

match latest_tag {
Some(tag) => Ok(tag),
None => Err(anyhow!("Unable to get any tag")),
}
.collect())
}

pub(crate) fn get_latest_tag_oid(&self) -> Result<Oid> {
self.get_latest_tag()
.map(|tag| tag.oid().to_owned())
.map(|tag| tag.oid_unchecked().to_owned())
.map_err(|err| anyhow!("Could not resolve latest tag:{}", err))
}

Expand All @@ -92,15 +100,28 @@ impl Repository {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Tag {
tag: String,
oid: Oid,
oid: Option<Oid>,
}

impl TryFrom<Git2Tag<'_>> for Tag {
type Error = anyhow::Error;

fn try_from(tag: Git2Tag) -> std::prelude::rust_2015::Result<Self, Self::Error> {
let name = tag.name().expect("Unexpected unnamed tag");
Self::new(name, Some(tag.id()))
}
}

impl Tag {
pub(crate) fn oid(&self) -> &Oid {
&self.oid
// Tag always contains an oid unless it was created before the tag exist.
// The only case where we do that is while creating the changelog during `cog bump`.
// In this situation we need a tag to generate the changelog but this tag does not exist in the
// repo yet.
pub(crate) fn oid_unchecked(&self) -> &Oid {
self.oid.as_ref().unwrap()
}

pub(crate) fn new(name: &str, oid: Oid) -> Result<Tag> {
pub(crate) fn new(name: &str, oid: Option<Oid>) -> Result<Tag> {
let tag = match SETTINGS.tag_prefix.as_ref() {
None => Ok(name),
Some(prefix) => name
Expand Down
28 changes: 25 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ use settings::{HookType, Settings};

use crate::conventional::changelog::release::Release;
use crate::conventional::changelog::template::Template;
use crate::git::oid::OidOf;
use crate::git::revspec::RevspecPattern;
use crate::git::tag::Tag;
use crate::hook::HookVersion;

pub mod conventional;
Expand Down Expand Up @@ -430,7 +432,7 @@ impl CocoGitto {

let mut next_version = increment
.bump(&current_version)
.map_err(|err| anyhow!("Cannot bump version:{}", err))?;
.map_err(|err| anyhow!("Cannot bump version: {}", err))?;

if next_version.le(&current_version) || next_version.eq(&current_version) {
let comparison = format!("{} <= {}", current_version, next_version).red();
Expand All @@ -455,14 +457,14 @@ impl CocoGitto {
let origin = if current_version == Version::new(0, 0, 0) {
self.repository.get_first_commit()?.to_string()
} else {
current_tag?.oid().to_string()
current_tag?.oid_unchecked().to_string()
};

let target = self.repository.get_head_commit_oid()?.to_string();
let pattern = (origin.as_str(), target.as_str());

let pattern = RevspecPattern::from(pattern);
let changelog = self.get_changelog(pattern, false)?;
let changelog = self.get_changelog_with_target_version(pattern, &version_str)?;

let path = settings::changelog_path();

Expand Down Expand Up @@ -533,6 +535,26 @@ impl CocoGitto {
.map_err(|err| anyhow!(err))
}

/// Used for cog bump. the target version
/// is not created yet when generating the changelog.
pub fn get_changelog_with_target_version(
&self,
pattern: RevspecPattern,
target_version: &str,
) -> Result<Release> {
let commit_range = self.repository.get_commit_range(&pattern).map_err(|err| {
anyhow!(
"Could not get commit range for pattern '{}': {}",
pattern,
err
)
})?;

let mut release = Release::from(commit_range);
release.version = OidOf::Tag(Tag::new(target_version, None)?);
Ok(release)
}

/// ## Get a changelog between two oids
/// - `from` default value:latest tag or else first commit
/// - `to` default value:`HEAD` or else first commit
Expand Down
12 changes: 12 additions & 0 deletions tests/cog_tests/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@ fn get_changelog_range() -> Result<()> {
- tag, conventional commit and license badges to readme - (da6f63d) - oknozor
#### Miscellaneous Chores
- **(version)** 0.32.3 - (0939f4c) - *oknozor*
- - -
## 0.32.2 - {today}
#### Bug Fixes
- **(cd)** bump setup-rust-action to v1.3.3 - (5350b11) - *oknozor*
#### Documentation
- add corrections to README - (9a33516) - oknozor
#### Miscellaneous Chores
- **(version)** 0.32.2 - (ef4803b) - *oknozor*
- - -
## 0.32.1 - {today}
#### Bug Fixes
- **(cd)** fix ci cross build command bin args - (7f04a98) - *oknozor*
Expand All @@ -59,7 +63,9 @@ fn get_changelog_range() -> Result<()> {
- update Cargo.toml - (72bd1e4) - oknozor
#### Refactoring
- change config name to cog.toml - (d4aa61b) - oknozor
- - -
## 0.30.0 - {today}
#### Continuous Integration
- **(cd)** fix publish action script - (d0d0ae9) - *oknozor*
Expand Down Expand Up @@ -142,7 +148,9 @@ fn get_changelog_from_tagged_repo() -> Result<()> {
"## Unreleased ({commit_two}..{commit_two})
#### Bug Fixes
- bug fix - ({commit_two}) - Tom
- - -
## 1.0.0 - {today}
#### Features
- **(taef)** feature - ({commit_one}) - Tom
Expand Down Expand Up @@ -236,7 +244,9 @@ fn get_changelog_with_tag_prefix() -> Result<()> {
"## Unreleased ({commit_two}..{commit_two})
#### Bug Fixes
- bug fix 1 - ({commit_two}) - Tom
- - -
## v1.0.0 - {today}
#### Features
- feature 1 - ({commit_one}) - Tom
Expand Down Expand Up @@ -344,7 +354,9 @@ fn get_changelog_from_tag_to_tagged_head() -> Result<()> {
- feature 2 - ({commit_three}) - Tom
#### Miscellaneous Chores
- **(version)** 2.0.0 - ({commit_five}) - Tom
- - -
## 1.0.0 - {today}
#### Features
- feature 1 - ({commit_two}) - Tom
Expand Down

0 comments on commit 0618192

Please sign in to comment.