Skip to content

Commit

Permalink
Fix PubGrub's bump to be strictly higher for pre-releases
Browse files Browse the repository at this point in the history
  • Loading branch information
maxdeviant committed May 28, 2024
1 parent 907f240 commit db05a90
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 1 deletion.
90 changes: 89 additions & 1 deletion src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,96 @@ impl pubgrub::version::Version for Version {
}

fn bump(&self) -> Self {
self.bump_patch()
if self.is_pre() {
let mut pre = self.pre.clone();
let last_component = pre
.last_mut()
// This `.expect` is safe, as we know there to be at least
// one pre-release component.
.expect("no pre-release components");

match last_component {
Identifier::Numeric(pre) => *pre += 1,
Identifier::AlphaNumeric(pre) => {
let mut segments = split_alphanumeric(&pre);
let last_segment = segments.last_mut().unwrap();

match last_segment {
AlphaOrNumeric::Numeric(n) => *n += 1,
AlphaOrNumeric::Alpha(alpha) => {
// We should potentially be smarter about this (for instance, pick the next letter in the
// alphabetic sequence), however, this seems like it could be quite a bit more complex.
alpha.push_str("1")
}
}

*pre = segments
.into_iter()
.map(|segment| match segment {
AlphaOrNumeric::Alpha(segment) => segment,
AlphaOrNumeric::Numeric(segment) => segment.to_string(),
})
.collect::<Vec<_>>()
.join("");
}
}

Self {
major: self.major,
minor: self.minor,
patch: self.patch,
pre,
build: None,
}
} else {
self.bump_patch()
}
}
}

enum AlphaOrNumeric {
Alpha(String),
Numeric(u32),
}

/// Splits the given string into alphabetic and numeric segments.
fn split_alphanumeric(str: &str) -> Vec<AlphaOrNumeric> {
let mut segments = Vec::new();
let mut current_segment = String::new();
let mut previous_char_was_numeric = None;

for char in str.chars() {
let is_numeric = char.is_ascii_digit();
match previous_char_was_numeric {
Some(previous_char_was_numeric) if previous_char_was_numeric == is_numeric => {
current_segment.push(char)
}
_ => {
if !current_segment.is_empty() {
if current_segment.chars().any(|char| char.is_ascii_digit()) {
segments.push(AlphaOrNumeric::Numeric(current_segment.parse().unwrap()));
} else {
segments.push(AlphaOrNumeric::Alpha(current_segment));
}

current_segment = String::new();
}

current_segment.push(char);
previous_char_was_numeric = Some(is_numeric);
}
}
}

if !current_segment.is_empty() {
if current_segment.chars().any(|char| char.is_ascii_digit()) {
segments.push(AlphaOrNumeric::Numeric(current_segment.parse().unwrap()));
} else {
segments.push(AlphaOrNumeric::Alpha(current_segment));
}
}

segments
}

impl<'a> TryFrom<&'a str> for Version {
Expand Down
26 changes: 26 additions & 0 deletions src/version/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::{
collections::HashMap,
};

use pubgrub::version::Version as _;

use crate::{ApiError, Release, RetirementReason, RetirementStatus};

use super::{
Expand Down Expand Up @@ -389,6 +391,30 @@ assert_order!(ord_pre_smaller_than_zero_flip, "1.0.0-rc1", Less, "1.0.0");

assert_order!(ord_pre_rc1_2, "1.0.0-rc1", Less, "1.0.0-rc2");

#[test]
fn test_pubgrub_bump_patch() {
assert_eq!(
Version::parse("1.0.0").unwrap().bump(),
Version::parse("1.0.1").unwrap()
);
}

#[test]
fn test_pubgrub_bump_prerelease_ending_with_a_number() {
assert_eq!(
Version::parse("1.0.0-rc2").unwrap().bump(),
Version::parse("1.0.0-rc3").unwrap()
);
}

#[test]
fn test_pubgrub_bump_prerelease_ending_with_a_letter() {
assert_eq!(
Version::parse("1.0.0-rc2a").unwrap().bump(),
Version::parse("1.0.0-rc2a1").unwrap()
);
}

struct Remote {
deps: HashMap<String, Package>,
}
Expand Down

0 comments on commit db05a90

Please sign in to comment.