Skip to content

Commit

Permalink
feat(changelog): add changelog arg modes
Browse files Browse the repository at this point in the history
  • Loading branch information
oknozor committed Sep 8, 2020
1 parent 46dad5b commit 21abecf
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 103 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# cocogito

## CLI Commands
- [ ] `coco init`
- [ ] `coco check`
- [ ] `coco rename {hash}`
- [ ] `coco feat, fix, ...`
- [ ] `coco version --minor --edit`
- [ ] `coco changelog --from 0.1.0 --to 1.0.0`
- [ ] `coco changelog --from 8806av --to 8c6ca0`
- [ ] `coco changelog --from 8806av --to 1.0.0`


## Conventional commit
Expand All @@ -27,8 +29,15 @@
- [ ] BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer.


Features :
## Features :
- [ ] version hooks
- [ ] editor
- [ ] conventional commit extention (scopes, commit type)
- [ ] changelog template (header, footer)


## Misc
- [ ] bats test
- [ ] test sub repos
- [ ] CI
- [ ] fmt
21 changes: 7 additions & 14 deletions src/bin/cog.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use clap::{App, AppSettings, SubCommand, Arg};
use clap::{App, AppSettings, Arg, SubCommand};
use cocogitto::CocoGitto;

const APP_SETTINGS: &[AppSettings] = &[
Expand All @@ -15,14 +15,13 @@ const SUBCOMMAND_SETTINGS: &[AppSettings] = &[
];

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

fn main() {
let cocogitto = CocoGitto::get().unwrap_or_else(|err| panic!("{}", err));
let commit_types = cocogitto.commit_types();


let commit_subcommands = commit_types
.iter()
.map(|commit_type| {
Expand Down Expand Up @@ -85,15 +84,10 @@ fn main() {
.subcommands(commit_subcommands)
.get_matches();


if let Some(subcommand) = matches.subcommand_name() {
match subcommand {
PUBLISH => {
todo!()
}
CHECK => {
todo!()
}
PUBLISH => todo!(),
CHECK => todo!(),
CHANGELOG => {
let subcommand = matches.subcommand_matches(CHANGELOG).unwrap();
let from = subcommand.value_of("from");
Expand All @@ -106,8 +100,7 @@ fn main() {
}
}

commit_commands => {
}
commit_commands => {}
}
}
}
}
34 changes: 24 additions & 10 deletions src/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,36 @@ use crate::commit::{Commit, CommitType};
use colored::*;
use git2::Oid;

pub struct Changelog<'a> {
pub struct Changelog {
pub from: Oid,
pub to: Oid,
pub date: String,
pub commits: Vec<Commit<'a>>,
pub commits: Vec<Commit>,
}

impl Changelog<'_> {
impl Changelog {
pub fn tag_diff_to_markdown(&mut self) -> String {
let mut out = String::new();
out.push_str(&Changelog::header());
out.push_str(&format!("## {}..{} - {}\n\n", self.from, self.to, self.date));
out.push_str(&format!(
"## {}..{} - {}\n\n",
self.from, self.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).collect();
let commits: Vec<Commit> = self
.commits
.drain_filter(|commit| commit.commit_type == commit_type)
.collect();

if !commits.is_empty() {
out.push_str(&format!("\n### {}\n\n", commit_type.get_markdown_title().red()));
commits.iter().for_each(|commit| out.push_str(&commit.to_markdown()));
out.push_str(&format!(
"\n### {}\n\n",
commit_type.get_markdown_title().red()
));
commits
.iter()
.for_each(|commit| out.push_str(&commit.to_markdown()));
}
};

Expand All @@ -44,7 +55,10 @@ impl Changelog<'_> {
fn header() -> String {
let title = "# Changelog".red();
let link = "[conventional commits]".magenta();
format!("{}\nAll notable changes to this project will be documented in this file. \
See {}(https://www.conventionalcommits.org/) for commit guidelines.\n\n", title, link)
format!(
"{}\nAll notable changes to this project will be documented in this file. \
See {}(https://www.conventionalcommits.org/) for commit guidelines.\n\n",
title, link
)
}
}
}
78 changes: 53 additions & 25 deletions src/commit.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::cmp::Ordering;
use git2::Commit as Git2Commit;
use crate::commit::CommitType::*;
use anyhow::Result;
use colored::*;

use git2::Commit as Git2Commit;
use std::cmp::Ordering;

#[derive(Debug, Eq, PartialEq)]
pub struct Commit<'a> {
pub struct Commit {
pub(crate) shorthand: String,
pub(crate) commit_type: CommitType<'a>,
pub(crate) commit_type: CommitType,
pub(crate) scope: Option<String>,
pub(crate) description: String,
pub(crate) author: String,
Expand All @@ -19,43 +19,69 @@ pub enum SortCommit {
ByDate,
ByType,
ByScope,
ByTypeAndScope
ByTypeAndScope,
}

impl Commit<'_> {
pub fn from_git_commit(commit: Git2Commit) -> Self {
let shorthand = commit.as_object().short_id().unwrap().as_str().unwrap().to_string();
let message = commit.message().unwrap();
impl Commit {
pub fn from_git_commit(commit: Git2Commit) -> Result<Self> {
let shorthand = commit
.as_object()
.short_id()
.unwrap()
.as_str()
.unwrap()
.to_string();
let commit = commit.to_owned();
let message = commit.message();
let message = message.unwrap().to_owned();

print!("Parsing commit : {} - {}", shorthand, message);

let author = commit.author().name().unwrap_or_else(|| "").to_string();
let split: Vec<&str> = message.split(": ").collect();
let split: Vec<&str> = message.split(": ").to_owned().collect();

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

let description = split[1].to_owned().replace('\n', "");

let left_part: Vec<&str> = split[0]
.split("(")
.collect();
let left_part: Vec<&str> = split[0].split("(").collect();

let commit_type = CommitType::from(left_part[0]);

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

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

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

pub fn to_markdown(&self) -> String {
format!("{} - {} - {}\n", self.shorthand.yellow(), self.description, self.author.blue())
format!(
"{} - {} - {}\n",
self.shorthand.yellow(),
self.description,
self.author.blue()
)
}
}

#[derive(Eq, PartialEq, Debug)]
pub(crate) enum CommitType<'a> {
pub(crate) enum CommitType {
Feature,
BugFix,
Chore,
Expand All @@ -67,10 +93,11 @@ pub(crate) enum CommitType<'a> {
Test,
Build,
Ci,
Custom(&'a str, &'a str),
Unknown(String),
Custom(String, String),
}

impl CommitType<'_> {
impl CommitType {
pub(crate) fn get_markdown_title(&self) -> &str {
match self {
Feature => "Feature",
Expand All @@ -85,11 +112,12 @@ impl CommitType<'_> {
Build => "Build System",
Ci => "Continuous Integration",
Custom(_, value) => value,
Unknown(_) => unreachable!(),
}
}
}

impl From<&str> for CommitType<'_> {
impl From<&str> for CommitType {
fn from(commit_type: &str) -> Self {
match commit_type {
"feat" => Feature,
Expand All @@ -103,18 +131,18 @@ impl From<&str> for CommitType<'_> {
"test" => Test,
"build" => Build,
"ci" => Ci,
_ => panic!("unknown commit type {}", commit_type)
other => Unknown(other.to_string()),
}
}
}

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

impl Ord for Commit<'_> {
impl Ord for Commit {
fn cmp(&self, other: &Self) -> Ordering {
self.scope.cmp(&other.scope)
}
Expand All @@ -137,4 +165,4 @@ mod test {
assert_eq!(commit.scope, Some("database".to_owned()));
assert_eq!(commit.description, "add postgresql driver".to_owned());
}
}
}
Loading

0 comments on commit 21abecf

Please sign in to comment.