diff --git a/src/common.rs b/src/common.rs index 0c999f8..13685ea 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,11 +1,17 @@ use std::fmt; use std::collections::HashMap; -#[derive(Debug, PartialEq, Clone)] -pub enum CommitType { - Feature, - Fix, - Unknown +// Creates an enum where the poritions inside the '(' and ')' act as aliases for that +// commit type. The only one you MUST specify is 'Unknown ()' +// +// Later you can call CommitType::Fix.aliases() to get all the aliases as a Vec<'statci str> +commit_type_enum!{ + #[derive(Debug, PartialEq, Clone)] + pub enum CommitType { + Feature ( feat, ft ), + Fix ( fix, fx), + Unknown () + } } #[derive(Clone)] diff --git a/src/git.rs b/src/git.rs index 02b468e..2e0dc06 100644 --- a/src/git.rs +++ b/src/git.rs @@ -5,6 +5,7 @@ use std::borrow::ToOwned; use semver; + #[derive(Debug)] pub struct LogReaderConfig { pub grep: String, @@ -75,11 +76,10 @@ fn parse_raw_commit(commit_str:&str) -> LogEntry { let (subject, component, commit_type) = match lines.next().and_then(|s| commit_pattern.captures(s)) { Some(caps) => { - let commit_type = match caps.at(1) { - Some("feat") => CommitType::Feature, - Some("fix") => CommitType::Fix, - _ => CommitType::Unknown - }; + // The macro that made the CommitType automatically implements std::str::FromStr + // with all aliases or falls back to CommitType::Unknown on failure so we can + // call unwrap(). + let commit_type = caps.at(1).unwrap_or("").parse::().unwrap(); let component = caps.at(2); let subject = caps.at(3); (subject, component, commit_type) diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..d6982e3 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,46 @@ +// regex cheat thanks to https://github.com/BurntSushi +macro_rules! regex( + ($s:expr) => (::regex::Regex::new($s).unwrap()); +); + +// A macro creating an entry types, and their aliases +// +// This is a little hacky, because it expects an Unknown () variant +// +// TODO: de-dup with recursive calls +macro_rules! commit_type_enum { + (#[derive($($d:ident),+)] pub enum $e:ident { $($v:ident ( $($a:ident),* ) ),+ }) => { + #[derive($($d,)+)] + pub enum $e { + $($v,)+ + } + + impl $e { + #[allow(dead_code)] + pub fn aliases(&self) -> Vec<&'static str> { + match *self { + $($e::$v => vec![ + $( stringify!($a) ),* + ],)+ + } + } + #[allow(dead_code)] + pub fn all_aliases() -> Vec<&'static str> { + vec![ + $( $( stringify!($a),)* )+ + ] + } + } + impl ::std::str::FromStr for $e { + type Err = $e; + + #[allow(dead_code)] + fn from_str(s: &str) -> Result { + match s { + $(stringify!($v) $( | stringify!($a) )* => Ok($e::$v),)+ + _ => Err($e::Unknown) + } + } + } + }; +} diff --git a/src/main.rs b/src/main.rs index c201f25..539065f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,20 +7,19 @@ extern crate semver; #[macro_use] extern crate clap; -use git::LogReaderConfig; -use log_writer::{ LogWriter, LogWriterOptions }; use std::fs::File; use std::io::Read; use std::path::Path; use std::borrow::ToOwned; -use clap::{App, Arg}; +use common::CommitType; +use git::LogReaderConfig; +use log_writer::{ LogWriter, LogWriterOptions }; -// regex cheat thanks to https://github.com/BurntSushi -macro_rules! regex( - ($s:expr) => (::regex::Regex::new($s).unwrap()); -); +use clap::{App, Arg}; +#[macro_use] +mod macros; mod common; mod git; mod log_writer; @@ -50,7 +49,7 @@ fn main () { let start_nsec = time::get_time().nsec; let log_reader_config = LogReaderConfig { - grep: "^feat|^fix|BREAKING'".to_owned(), + grep: format!("{}BREAKING'", CommitType::all_aliases().iter().fold(String::new(),|acc, al| acc + &format!("^{}|", al)[..])), format: "%H%n%s%n%b%n==END==".to_owned(), from: if matches.is_present("from-latest-tag") { Some(git::get_latest_tag()) } else { matches.value_of("from").map(|v| v.to_owned()) }, to: matches.value_of("to").unwrap_or("").to_owned()