Skip to content

Commit

Permalink
feat: add verify command
Browse files Browse the repository at this point in the history
  • Loading branch information
oknozor committed Sep 10, 2020
1 parent ab054a3 commit d7508af
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 43 deletions.
3 changes: 2 additions & 1 deletion coco.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
changelog_file = "CHANGELOG.md"
sort_commit = "by_type"
sort_commit = "by_type"
semver = true
98 changes: 73 additions & 25 deletions src/bin/cog.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::Result;
use clap::{App, AppSettings, Arg, SubCommand};
use cocogitto::CocoGitto;
use std::process::exit;

const APP_SETTINGS: &[AppSettings] = &[
AppSettings::SubcommandRequiredElseHelp,
Expand All @@ -17,6 +18,7 @@ const SUBCOMMAND_SETTINGS: &[AppSettings] = &[

const PUBLISH: &str = "publish";
const CHECK: &str = "check";
const VERIFY: &str = "verify";
const CHANGELOG: &str = "changelog";

fn main() -> Result<()> {
Expand All @@ -43,54 +45,100 @@ fn main() -> Result<()> {
.long_about("Conventional Commit Git Terminal Overlord is a tool to help you use the conventional commit specification")
.subcommand(
SubCommand::with_name(CHECK)
.about("")
.about("Verify all commit message against the conventional commit specification")
.arg(Arg::with_name("edit")
.help("Interactively rename invalid commit message")
.short("e")
.long("edit")
)
)
.subcommand(
SubCommand::with_name(VERIFY)
.about("Verify a single commit message")
.arg(Arg::with_name("message").help("The commit message"))
)
.subcommand(
SubCommand::with_name(PUBLISH)
.settings(SUBCOMMAND_SETTINGS)
.about("")
.arg(Arg::with_name("minor")
.help("")
.about("Commit changelog from latest tag to HEAD and create a new tag")
.arg(Arg::with_name("version")
.help("Manually set the next version")
.short("m")
.long("minor")
.required_unless_one(&["major", "patch"])
.long("version")
.required_unless_one(&["auto", "major", "patch", "minor"])
)
.arg(Arg::with_name("auto")
.help("Atomatically suggest the next version")
.short("a")
.long("auto")
.required_unless_one(&["version", "major", "patch", "minor"])
)
.arg(Arg::with_name("major")
.help("")
.help("Increment the major version")
.short("M")
.long("major")
.required_unless_one(&["minor", "patch"])
.required_unless_one(&["version", "auto", "patch", "minor"])
)
.arg(Arg::with_name("patch")
.help("")
.help("Increment the patch version")
.short("p")
.long("patch")
.required_unless_one(&["minor", "major"])
))
.subcommand(SubCommand::with_name(CHANGELOG)
.settings(SUBCOMMAND_SETTINGS)
.about("Display a changelog for a given commit oid range")
.arg(Arg::with_name("from")
.help("Generate the changelog from this commit or tag ref, default latest tag")
.short("f")
.long("from")
.takes_value(true)
.required_unless_one(&["version", "auto", "major", "minor"])
)
.arg(Arg::with_name("minor")
.help("Increment the minor version")
.short("m")
.long("minor")
.required_unless_one(&["version", "auto", "patch", "major"])
)
)
.arg(Arg::with_name("to")
.help("Generate the changelog to this commit or tag ref, default HEAD")
.short("t")
.long("to")
.takes_value(true)))
.subcommand(SubCommand::with_name(CHANGELOG)
.settings(SUBCOMMAND_SETTINGS)
.about("Display a changelog for a given commit oid range")
.arg(Arg::with_name("from")
.help("Generate the changelog from this commit or tag ref, default latest tag")
.short("f")
.long("from")
.takes_value(true)
)
.arg(Arg::with_name("to")
.help("Generate the changelog to this commit or tag ref, default HEAD")
.short("t")
.long("to")
.takes_value(true)))
.subcommands(commit_subcommands)
.get_matches();

if let Some(subcommand) = matches.subcommand_name() {
match subcommand {
PUBLISH => todo!(),
PUBLISH => {
let subcommand = matches.subcommand_matches(PUBLISH).unwrap();

if let Some(version) = subcommand.value_of("version") {
todo!()
} else if subcommand.is_present("auto") {
todo!()
} else if subcommand.is_present("major") {
todo!()
} else if subcommand.is_present("patch") {
todo!()
} else if subcommand.is_present("minor") {
todo!()
}
}
VERIFY => {
let subcommand = matches.subcommand_matches(VERIFY).unwrap();
let message = subcommand.value_of("message").unwrap();

match CocoGitto::verify(message) {
Ok(()) => exit(0),
Err(err) => {
eprintln!("{}", err);
exit(1);
}
}
}

CHECK => {
let subcommand = matches.subcommand_matches(CHECK).unwrap();
if subcommand.is_present("edit") {
Expand Down
7 changes: 5 additions & 2 deletions src/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ pub struct Changelog {
impl Changelog {
pub fn tag_diff_to_markdown(&mut self) -> String {
let mut out = String::new();

out.push_str(&Changelog::header());
let short_to = &self.to.to_string()[0..6];
let short_from = &self.from.to_string()[0..6];
out.push_str(&format!(
"## {}..{} - {}\n\n",
self.from, self.to, self.date
short_from, short_to, self.date
));

let mut add_commit_section = |commit_type: CommitType| {
let commits: Vec<Commit> = self
.commits
.drain_filter(|commit| commit.commit_type == commit_type)
.drain_filter(|commit| commit.message.commit_type == commit_type)
.collect();

if !commits.is_empty() {
Expand Down
37 changes: 26 additions & 11 deletions src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ use std::fmt;
#[derive(Debug, Eq, PartialEq)]
pub struct Commit {
pub(crate) shorthand: String,
pub(crate) message: CommitMessage,
pub(crate) author: String,
}

#[derive(Debug, Eq, PartialEq)]
pub struct CommitMessage {
pub(crate) commit_type: CommitType,
pub(crate) scope: Option<String>,
pub(crate) description: String,
pub(crate) author: String,
}

#[derive(Debug, Deserialize)]
Expand All @@ -33,6 +38,7 @@ impl Commit {
.as_str()
.unwrap()
.to_string();

let commit = commit.to_owned();
let message = commit.message();
let message = message.unwrap().to_owned();
Expand All @@ -48,10 +54,20 @@ impl Commit {
println!("Parsing commit : {} - {}", shorthand, message_display);

let author = commit.author().name().unwrap_or_else(|| "").to_string();
let message = Commit::parse_commit_message(&message)?;

Ok(Commit {
shorthand,
message,
author,
})
}

pub(crate) fn parse_commit_message(message: &str) -> Result<CommitMessage> {
let split: Vec<&str> = message.split(": ").to_owned().collect();

if split.len() <= 1 {
return Err(anyhow!("Skipping commit : invalid commit format".red()));
return Err(anyhow!("{} : invalid commit format", "Error".red()));
}

let description = split[1].to_owned().replace('\n', " ");
Expand All @@ -62,29 +78,28 @@ impl Commit {

if let CommitType::Unknown(type_str) = commit_type {
return Err(anyhow!(
"Skipping commit : unknown commit type `{}`",
type_str
"{} : unknown commit type `{}`",
"Error".red(),
type_str.red()
));
};

let scope = left_part
.get(1)
.map(|scope| scope[0..scope.len() - 1].to_owned());

Ok(Commit {
shorthand,
Ok(CommitMessage {
description,
commit_type,
scope,
description,
author,
})
}

pub fn to_markdown(&self) -> String {
format!(
"{} - {} - {}\n",
self.shorthand.yellow(),
self.description,
self.message.description,
self.author.blue()
)
}
Expand Down Expand Up @@ -172,13 +187,13 @@ impl fmt::Display for CommitType {

impl PartialOrd for Commit {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.scope.partial_cmp(&other.scope)
self.message.scope.partial_cmp(&other.message.scope)
}
}

impl Ord for Commit {
fn cmp(&self, other: &Self) -> Ordering {
self.scope.cmp(&other.scope)
self.message.scope.cmp(&other.message.scope)
}
}

Expand Down
12 changes: 8 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern crate serde_derive;
mod changelog;
pub mod commit;
pub mod repository;
mod semver;
pub mod settings;

use crate::changelog::Changelog;
Expand All @@ -17,10 +18,9 @@ use anyhow::Result;
use chrono::Utc;
use colored::*;
use commit::Commit;
use git2::ErrorClass::Odb;
use git2::{Commit as Git2Commit, ObjectType, Oid, RebaseOptions, Repository as Git2Repository};
use git2::{Commit as Git2Commit, Oid, RebaseOptions, Repository as Git2Repository};
use std::fs::File;
use std::io::{Read, Write};
use std::io::Write;
use std::process::{Command, Stdio};
use tempdir::TempDir;

Expand Down Expand Up @@ -141,6 +141,10 @@ impl CocoGitto {
Ok(())
}

pub fn verify(message: &str) -> Result<()> {
Commit::parse_commit_message(message).map(|_| ())
}

pub fn conventional_commit(
&self,
commit_type: &str,
Expand All @@ -156,7 +160,7 @@ impl CocoGitto {
self.repository.commit(message)
}

pub fn version() -> () {
pub fn publish() -> () {
todo!()
}

Expand Down
22 changes: 22 additions & 0 deletions src/semver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use anyhow::Result;

pub struct SemVer {
major: u64,
patch: u64,
minor: u64,
}

impl SemVer {
fn from_tag(tag: &str) -> Result<Self> {
let parts: Vec<&str> = tag.split('.').collect();
let major = parts[0].parse::<u64>()?;
let patch = parts[1].parse::<u64>()?;
let minor = parts[2].parse::<u64>()?;

Ok(SemVer {
major,
patch,
minor,
})
}
}
1 change: 1 addition & 0 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub struct Settings {
pub commit_types: HashMap<String, String>,
pub changelog_file: PathBuf,
pub sort_commit: SortCommit,
pub semver: bool,
}

impl Settings {
Expand Down

0 comments on commit d7508af

Please sign in to comment.