extern crate changelog;
#[macro_use]
extern crate clap;
extern crate console;
extern crate env_logger;
extern crate failure;
#[macro_use]
extern crate log;
use clap::{App, AppSettings};
use std::env::args_os;
use std::ffi::OsString;
use std::process::exit;
use console::style;
use env_logger::LogBuilder;
use log::{LogLevelFilter, LogRecord};
use changelog::{ChangeLog, Configuration, Result};
fn main() {
exit(show(run(args_os().collect())));
}
fn run(args: Vec<OsString>) -> Result<String> {
let yml = load_yaml!("assets/git-changelog.yml");
let app = App::from_yaml(yml)
.setting(AppSettings::ColoredHelp)
.setting(AppSettings::DisableVersion)
.version(crate_version!())
.about(crate_description!())
.author(crate_authors!());
let cli = app.get_matches_from(args);
initialize_logging(cli.occurrences_of("debug"));
changelog::in_git_repository()?;
let mut config = Configuration::from_file(cli.value_of("config"))?;
config.output.json = cli.is_present("json");
let cmd = cli.value_of("remote").map(str::to_owned);
config.output.remote = cmd.or(config.output.remote);
let cmd = cli.value_of("template").map(str::to_owned);
config.output.template = cmd.or(config.output.template);
debug!("{:#?}", config);
let range = cli.values_of_lossy("range").unwrap_or_default();
let changelog = ChangeLog::from_log(range, &config);
trace!("{:#?}", changelog);
changelog::render(&changelog, &config.output)
}
fn show(result: Result<String>) -> i32 {
match result {
Ok(out) => {
for line in out.lines() {
if line.starts_with('#') {
let (header, heading) = line.split_at(line.find(' ').unwrap_or(0));
println!("{}{}", style(header).bold().cyan(), style(heading).cyan())
} else {
println!("{}", line)
}
}
0
}
Err(e) => {
error!("{}", e);
1
}
}
}
fn initialize_logging(verbosity: u64) {
let level = match verbosity {
1 => LogLevelFilter::Info,
2 => LogLevelFilter::Debug,
n if n > 2 => LogLevelFilter::Trace,
_ => LogLevelFilter::Warn,
};
let format = |r: &LogRecord| format!("{}: {}", r.level(), r.args());
LogBuilder::new()
.filter(Some("git_changelog"), level)
.filter(Some("changelog"), level)
.format(format)
.init()
.ok();
}
#[cfg(test)]
mod tests {
use std::ffi::OsString;
use failure::err_msg;
fn to_args(cmd: &str) -> Vec<OsString> {
cmd.split_whitespace().map(OsString::from).collect()
}
#[test]
fn run() {
assert!(super::run(to_args("git-changelog v0.1.1..v0.2.1")).is_ok());
assert!(super::run(to_args("git-changelog -d v0.1.1..v0.2.1")).is_ok());
assert!(super::run(to_args("git-changelog -dd v0.1.1..v0.2.1")).is_ok());
assert!(super::run(to_args("git-changelog -ddd -j")).is_ok());
}
#[test]
fn show() {
assert_eq!(
super::show(super::run(to_args("git-changelog v0.1.1..v0.2.1"))),
0
);
assert_eq!(super::show(Ok(String::from("foo"))), 0);
assert_eq!(super::show(Err(err_msg("foo"))), 1);
}
}