Skip to content

Commit

Permalink
Implements incr-version command
Browse files Browse the repository at this point in the history
  • Loading branch information
tailhook committed Jul 9, 2017
1 parent 0f9f69f commit d30798c
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 9 deletions.
20 changes: 18 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ enum Action {
RepoAdd,
GetVersion,
SetVersion,
IncrVersion,
CheckVersion,
WithVersion,
}
Expand Down Expand Up @@ -75,6 +76,17 @@ impl FromStr for Action {
"verset" => Ok(Action::SetVersion),
"versionset" => Ok(Action::SetVersion),

"incr-version" => Ok(Action::IncrVersion),
"inc-version" => Ok(Action::IncrVersion),
"version-incr" => Ok(Action::IncrVersion),
"version-inc" => Ok(Action::IncrVersion),
"incr" => Ok(Action::IncrVersion),
"bump-version" => Ok(Action::IncrVersion),
"version-bump" => Ok(Action::IncrVersion),
"bumpver" => Ok(Action::IncrVersion),
"bump-ver" => Ok(Action::IncrVersion),
"bump" => Ok(Action::IncrVersion),

"check-version" => Ok(Action::CheckVersion),
"version-check" => Ok(Action::CheckVersion),

Expand All @@ -97,8 +109,8 @@ fn main() {
ap.refer(&mut command)
.add_argument("command", Store, "
Command to run. Supported commands: \
pack, repo-add, get-version, set-version, check-version, \
with-version");
pack, repo-add, get-version, set-version, incr-version, \
check-version, with-version");
ap.refer(&mut args)
.add_argument("arguments", List,
"Arguments for the command");
Expand Down Expand Up @@ -130,6 +142,10 @@ fn main() {
args.insert(0, "bulk set-version".to_string());
ver::set_version(args);
}
Action::IncrVersion => {
args.insert(0, "bulk incr-version".to_string());
ver::incr_version(args);
}
Action::CheckVersion => {
args.insert(0, "bulk check-version".to_string());
ver::check_version(args);
Expand Down
147 changes: 147 additions & 0 deletions src/ver/bump.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
use std::cmp::min;
use version::{Version, Component};

#[derive(Debug, Clone, Copy)]
pub enum Bump {
Patch,
Minor,
Major,
Component(u8),
}

quick_error! {
#[derive(Debug)]
pub enum Error {
NonNumericComponent(val: String) {
description("component we're trying to increment is non-numeric")
display("component {:?} is non-numeric", val)
}
}
}

pub fn bump_version<T: AsRef<str>>(ver: &Version<T>, how: Bump)
-> Result<Version<String>, Error>
{
match how {
Bump::Component(i) => {
let mut result = Vec::new();
let mut iter = ver.components();
for n in iter.by_ref().take((i-1) as usize) {
result.push(n);
}
while result.len() < (i-1) as usize {
result.push(Component::Numeric(0));
}
let n: u64 = match iter.next() {
Some(Component::Numeric(x)) => x+1,
Some(Component::String(x)) => {
return Err(Error::NonNumericComponent(x.into()));
},
None => 1,
};
result.push(Component::Numeric(n));
while result.len() < 3 {
result.push(Component::Numeric(0));
}
let mut buf = format!("v{}", result[0]);
for i in &result[1..] {
use std::fmt::Write;
write!(&mut buf, ".{}", i).unwrap();
}
Ok(Version(buf))
}
Bump::Major|Bump::Minor|Bump::Patch => {
let idx = ver.components()
.position(|x| matches!(x, Component::Numeric(y) if y > 0))
// If version is v0.0.0 we consider major bump is v0.0.1
.unwrap_or(2)
+1; // 1-based index
let cmp = match (idx, how) {
(idx, Bump::Major) => min(idx, 3),
(1, Bump::Minor) => 2,
(_, _) => 3,
};
return bump_version(ver, Bump::Component(cmp as u8));
}
}
}

#[cfg(test)]
mod test {
use super::bump_version;
use super::Bump;
use super::Bump::*;
use version::Version;

fn bump_component(ver: &str, bump: u8) -> String {
format!("{}",
bump_version(&Version(ver), Bump::Component(bump))
.unwrap())
}
fn bump_semver(ver: &str, bump: Bump) -> String {
format!("{}",
bump_version(&Version(ver), bump)
.unwrap())
}
#[test]
fn test_cmp1() {
assert_eq!(bump_component("v1.2.0", 1), "v2.0.0");
assert_eq!(bump_component("v0.0.0", 1), "v1.0.0");
assert_eq!(bump_component("v0", 1), "v1.0.0");
assert_eq!(bump_component("v7.38.96", 1), "v8.0.0");
assert_eq!(bump_component("v9.38.96", 1), "v10.0.0");
assert_eq!(bump_component("v12.38.96", 1), "v13.0.0");
}
#[test]
fn test_cmp2() {
assert_eq!(bump_component("v1.2.0", 2), "v1.3.0");
assert_eq!(bump_component("v0.0.0", 2), "v0.1.0");
assert_eq!(bump_component("v0", 2), "v0.1.0");
assert_eq!(bump_component("v7.38.96", 2), "v7.39.0");
assert_eq!(bump_component("v7.9.96", 2), "v7.10.0");
assert_eq!(bump_component("v12.38.96", 2), "v12.39.0");
}
#[test]
fn test_cmp3() {
assert_eq!(bump_component("v1.2.0", 3), "v1.2.1");
assert_eq!(bump_component("v0.0.0", 3), "v0.0.1");
assert_eq!(bump_component("v0", 3), "v0.0.1");
assert_eq!(bump_component("v7.38.96", 3), "v7.38.97");
assert_eq!(bump_component("v7.13.99", 3), "v7.13.100");
}

#[test]
fn test_major() {
assert_eq!(bump_semver("v1.2.0", Major), "v2.0.0");
assert_eq!(bump_semver("v0.0.0", Major), "v0.0.1");
assert_eq!(bump_semver("v0.0.99", Major), "v0.0.100");
assert_eq!(bump_semver("v0", Major), "v0.0.1");
assert_eq!(bump_semver("v7.38.96", Major), "v8.0.0");
assert_eq!(bump_semver("v9.38.96", Major), "v10.0.0");
assert_eq!(bump_semver("v12.38.96", Major), "v13.0.0");
assert_eq!(bump_semver("v0.3.7", Major), "v0.4.0");
assert_eq!(bump_semver("v0.9.17", Major), "v0.10.0");
}
#[test]
fn test_minor() {
assert_eq!(bump_semver("v1.2.0", Minor), "v1.3.0");
assert_eq!(bump_semver("v0.0.0", Minor), "v0.0.1");
assert_eq!(bump_semver("v0.0.99", Minor), "v0.0.100");
assert_eq!(bump_semver("v0", Minor), "v0.0.1");
assert_eq!(bump_semver("v7.38.96", Minor), "v7.39.0");
assert_eq!(bump_semver("v9.38.96", Minor), "v9.39.0");
assert_eq!(bump_semver("v12.38.96", Minor), "v12.39.0");
assert_eq!(bump_semver("v0.3.7", Minor), "v0.3.8");
assert_eq!(bump_semver("v0.9.17", Minor), "v0.9.18");
}

#[test]
fn test_patch() {
assert_eq!(bump_semver("v1.2.0", Patch), "v1.2.1");
assert_eq!(bump_semver("v0.0.0", Patch), "v0.0.1");
assert_eq!(bump_semver("v0.0.99", Patch), "v0.0.100");
assert_eq!(bump_semver("v0", Patch), "v0.0.1");
assert_eq!(bump_semver("v7.38.96", Patch), "v7.38.97");
assert_eq!(bump_semver("v7.13.99", Patch), "v7.13.100");
}
}
75 changes: 71 additions & 4 deletions src/ver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ use std::error::Error;
use std::process::{Command, exit};
use std::collections::HashMap;

use config::{Config};
use version::Version;
use argparse::{ArgumentParser, Parse, StoreTrue, List, StoreConst};

use self::scanner::{Scanner, Lines, Iter};
use config::{Config};
use version::{Version};
use ver::scanner::{Scanner, Lines, Iter};
use ver::bump::Bump;

mod scanner;
mod bump;


#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
Expand All @@ -21,7 +23,6 @@ enum Verbosity {
Verbose,
}


fn _get(config: &Path, dir: &Path) -> Result<Version<String>, Box<Error>> {
let cfg = try!(Config::parse_file(&config));
get(&cfg, dir)
Expand Down Expand Up @@ -318,6 +319,72 @@ pub fn set_version(args: Vec<String>) {
}
}

pub fn incr_version(args: Vec<String>) {
let mut config = PathBuf::from("bulk.yaml");
let mut dir = PathBuf::from(".");
let mut bump = Bump::Patch;
let mut dry_run = false;
{
let mut ap = ArgumentParser::new();
ap.refer(&mut config)
.add_option(&["-c", "--config"], Parse,
"Package configuration file");
ap.refer(&mut dir)
.add_option(&["--base-dir"], Parse, "
Base directory for all paths in config. \
Current working directory by default.");
ap.refer(&mut dry_run)
.add_option(&["--dry-run"], StoreTrue, "
Don't write version, just show changes");
ap.refer(&mut bump)
.add_option(&["--breaking", "-b"], StoreConst(Bump::Major), "
Bump semver breaking (major) version")
.add_option(&["--feature", "-f"], StoreConst(Bump::Minor), "
Bump semver feature (minor) version")
.add_option(&["--bugfix", "-x"], StoreConst(Bump::Patch), "
Bump semver bugfix (patch) version")
.add_option(&["-1"], StoreConst(Bump::Component(1)), "
Bump first component of a version")
.add_option(&["-2"], StoreConst(Bump::Component(2)), "
Bump second component of a version")
.add_option(&["-3"], StoreConst(Bump::Component(3)), "
Bump third component of a version")
.required();

match ap.parse(args, &mut stdout(), &mut stderr()) {
Ok(()) => {}
Err(x) => exit(x),
}
}

let ver = match _get(&config, &dir) {
Ok(ver) => ver,
Err(text) => {
writeln!(&mut stderr(), "Error: {}", text).ok();
exit(1);
}
};
let nver = match bump::bump_version(&ver, bump) {
Ok(x) => x,
Err(e) => {
writeln!(&mut stderr(), "Can't bump version {:?}: {}", ver, e)
.ok();
exit(1);
}
};
println!("Bumping {} -> {}", ver, nver);

match _set(&config, &dir, Version(nver).num(), dry_run, false,
Verbosity::Verbose)
{
Ok(_) => {}
Err(text) => {
writeln!(&mut stderr(), "Error: {}", text).ok();
exit(1);
}
}
}

pub fn check_version(args: Vec<String>) {
let mut config = PathBuf::from("bulk.yaml");
let mut dir = PathBuf::from(".");
Expand Down
16 changes: 13 additions & 3 deletions src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_serialize::{Decodable, Decoder};

#[derive(Debug, Clone)]
pub struct Version<T: AsRef<str>>(pub T);
struct Components<'a>(&'a str, Peekable<CharIndices<'a>>);
pub struct Components<'a>(&'a str, Peekable<CharIndices<'a>>);

impl Decodable for Version<String> {
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
Expand All @@ -16,7 +16,7 @@ impl Decodable for Version<String> {
}

#[derive(Debug, Eq, PartialEq, Clone)]
enum Component<'a> {
pub enum Component<'a> {
Numeric(u64),
String(&'a str),
}
Expand All @@ -27,6 +27,15 @@ impl<T: AsRef<str>> ::std::fmt::Display for Version<T> {
}
}

impl<'a> ::std::fmt::Display for Component<'a> {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
Component::Numeric(v) => v.fmt(fmt),
Component::String(v) => v.fmt(fmt),
}
}
}

impl<T: AsRef<str>> AsRef<str> for Version<T> {
fn as_ref(&self) -> &str {
self.0.as_ref()
Expand All @@ -42,7 +51,7 @@ impl<T: AsRef<str>> Version<T> {
s
}
}
fn components(&self) -> Components {
pub fn components(&self) -> Components {
let mut ch = self.0.as_ref().char_indices().peekable();
if ch.peek() == Some(&(0, 'v')) {
ch.next();
Expand All @@ -51,6 +60,7 @@ impl<T: AsRef<str>> Version<T> {
}
}


impl<'a> Iterator for Components<'a> {
type Item = Component<'a>;
fn next(&mut self) -> Option<Component<'a>> {
Expand Down

0 comments on commit d30798c

Please sign in to comment.