Skip to content

Commit

Permalink
feat: Allow a custom scope regex in the configuration
Browse files Browse the repository at this point in the history
Add `scopeRegex` to the `.versionrc` file. This will be used to check the validity of the conventional commit.
It can be usefull to limit the scopes to a limitied number (e.g. `changelog|check|commit|version`)

Refs: #8
  • Loading branch information
hdevalke committed Aug 21, 2020
1 parent 8c728a8 commit dc03118
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 126 deletions.
2 changes: 2 additions & 0 deletions .versionrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
template: "src/conventional/changelog"
scopeRegex: "changelog|check|commit|version"
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ exclude = [
chrono = { version = "0.4.15", features = ["serde"] }
git2 = { version = "0.13.8", default-features = false, features = [] }
handlebars = { version = "3.4.0", features = [ "dir_source" ] }
lazy_static = "1.4.0"
regex = "1.3.9"
semver = { version = "0.10.0", features = ["serde"] }
serde = { version = "1.0.115", features = ["derive"] }
Expand Down
2 changes: 2 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub struct Opt {
/// Run as if convco was started in <path> instead of the current working directory.
#[structopt(short = "C", global = true)]
pub path: Option<PathBuf>,
#[structopt(short = "c", long = "config", global = true)]
pub config: Option<PathBuf>,
#[structopt(subcommand)]
pub cmd: Command,
}
Expand Down
4 changes: 2 additions & 2 deletions src/cmd.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::Error;
use crate::{conventional::Config, Error};

mod changelog;
mod check;
mod commit;
mod version;

pub(crate) trait Command {
fn exec(&self) -> Result<(), Error>;
fn exec(&self, config: Config) -> Result<(), Error>;
}
74 changes: 12 additions & 62 deletions src/cmd/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use crate::{
cmd::Command,
conventional::{
changelog::{
ChangelogWriter, CommitContext, CommitGroup, Config, Context, ContextBase,
ContextBuilder, Note, NoteGroup, Reference,
ChangelogWriter, CommitContext, CommitGroup, Context, ContextBase, ContextBuilder,
Note, NoteGroup, Reference,
},
Footer,
config::Config,
CommitParser, Footer,
},
git::{GitHelper, VersionAndTag},
Error,
Expand All @@ -16,7 +17,6 @@ use git2::Time;
use regex::Regex;
use semver::Version;
use std::{cmp::Ordering, collections::HashMap, str::FromStr};
use url::Url;

#[derive(Debug)]
struct Rev<'a>(&'a str, Option<&'a Version>);
Expand All @@ -34,6 +34,7 @@ struct ChangeLogTransformer<'a> {
config: &'a Config,
git: &'a GitHelper,
context_builder: ContextBuilder<'a>,
commit_parser: CommitParser,
}

fn date_from_time(time: &Time) -> NaiveDate {
Expand All @@ -53,13 +54,18 @@ impl<'a> ChangeLogTransformer<'a> {
});
let re_references =
Regex::new(format!("({})([0-9]+)", config.issue_prefixes.join("|")).as_str()).unwrap();
let commit_parser = CommitParser::builder()
.scope_regex(config.scope_regex.clone())
.build();

let context_builder = ContextBuilder::new(config)?;
Ok(Self {
config,
group_types,
git,
re_references,
context_builder,
commit_parser,
})
}

Expand Down Expand Up @@ -113,8 +119,7 @@ impl<'a> ChangeLogTransformer<'a> {
.flat_map(|oid| self.git.find_commit(oid).ok())
.filter(|commit| commit.parent_count() <= 1)
{
if let Some(Ok(conv_commit)) =
commit.message().map(crate::conventional::Commit::from_str)
if let Some(Ok(conv_commit)) = commit.message().map(|msg| self.commit_parser.parse(msg))
{
self.make_notes(&conv_commit.footers, conv_commit.scope.clone())
.into_iter()
Expand Down Expand Up @@ -220,62 +225,9 @@ impl<'a> ChangeLogTransformer<'a> {
}
}

fn make_cl_config(git: &GitHelper) -> Config {
let mut config: Config = std::fs::read(".versionrc")
.ok()
.and_then(|versionrc| serde_yaml::from_reader(versionrc.as_slice()).ok())
.unwrap_or_default();
if let Config {
host: None,
owner: None,
repository: None,
..
} = config
{
if let Ok((host, owner, repository)) = host_info(git) {
config.host = host;
config.owner = owner;
config.repository = repository;
}
}
config
}

type HostOwnerRepo = (Option<String>, Option<String>, Option<String>);

/// Get host, owner and repository based on the git remote origin url.
pub(crate) fn host_info(git: &GitHelper) -> Result<HostOwnerRepo, Error> {
if let Some(mut url) = git.url()? {
if !url.contains("://") {
// check if it contains a port
if let Some(colon) = url.find(':') {
match url.as_bytes()[colon + 1] {
b'0'..=b'9' => url = format!("scheme://{}", url),
_ => url = format!("scheme://{}/{}", &url[..colon], &url[colon + 1..]),
}
}
}
let url = Url::parse(url.as_str())?;
let host = url.host().map(|h| format!("https://{}", h));
let mut owner = None;
let mut repository = None;
if let Some(mut segments) = url.path_segments() {
owner = segments.next().map(|s| s.to_string());
repository = segments
.next()
.map(|s: &str| s.trim_end_matches(".git").to_string());
}

Ok((host, owner, repository))
} else {
Ok((None, None, None))
}
}

impl Command for ChangelogCommand {
fn exec(&self) -> Result<(), Error> {
fn exec(&self, config: Config) -> Result<(), Error> {
let helper = GitHelper::new(self.prefix.as_str())?;

let rev = self.rev.as_str();
let (rev, rev_stop) = if rev.contains("..") {
let mut split = rev.split("..");
Expand All @@ -290,15 +242,13 @@ impl Command for ChangelogCommand {
(rev, "")
};

let config = make_cl_config(&helper);
let stdout = std::io::stdout();
let stdout = stdout.lock();
let template = config.template.as_deref();
let mut writer = ChangelogWriter::new(template, stdout)?;
writer.write_header(config.header.as_str())?;

let transformer = ChangeLogTransformer::new(&config, &helper)?;

match helper.find_last_version(rev)? {
Some(last_version) => {
let semver = Version::from_str(rev.trim_start_matches(&self.prefix));
Expand Down
13 changes: 9 additions & 4 deletions src/cmd/check.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::{cli::CheckCommand, cmd::Command, conventional, Error};
use conventional::Config;
use git2::{Commit, Repository};

fn print_check(commit: &Commit<'_>) -> bool {
fn print_check(commit: &Commit<'_>, parser: &conventional::CommitParser) -> bool {
let msg = std::str::from_utf8(commit.message_bytes()).expect("valid utf-8 message");
let short_id = commit.as_object().short_id().unwrap();
let short_id = short_id.as_str().expect("short id");
let msg_parsed: Result<conventional::Commit, &str> = msg.parse();
let msg_parsed = parser.parse(msg);
match msg_parsed {
Err(e) => {
let first_line = msg.lines().next().unwrap_or("");
Expand All @@ -22,7 +23,7 @@ fn print_check(commit: &Commit<'_>) -> bool {
}

impl Command for CheckCommand {
fn exec(&self) -> Result<(), Error> {
fn exec(&self, config: Config) -> Result<(), Error> {
let repo = Repository::open_from_env()?;
let mut revwalk = repo.revwalk()?;
if self.rev.contains("..") {
Expand All @@ -34,13 +35,17 @@ impl Command for CheckCommand {
let mut total = 0;
let mut fail = 0;

let parser = conventional::CommitParser::builder()
.scope_regex(config.scope_regex)
.build();

for commit in revwalk
.flatten()
.flat_map(|oid| repo.find_commit(oid).ok())
.filter(|commit| commit.parent_count() <= 1)
{
total += 1;
fail += u32::from(!print_check(&commit));
fail += u32::from(!print_check(&commit, &parser));
}
if fail == 0 {
match total {
Expand Down
4 changes: 2 additions & 2 deletions src/cmd/commit.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{cli::CommitCommand, Command, Error};
use crate::{cli::CommitCommand, conventional::Config, Command, Error};
use std::{
io,
io::{Read, Write},
Expand Down Expand Up @@ -97,7 +97,7 @@ impl CommitCommand {
}

impl Command for CommitCommand {
fn exec(&self) -> Result<(), Error> {
fn exec(&self, _: Config) -> Result<(), Error> {
let scope = read_single_line("optional scope: ")?;
let description = read_single_line("description: ")?;
let body = read_multi_line("optional body:")?;
Expand Down
14 changes: 9 additions & 5 deletions src/cmd/version.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::{
cli::VersionCommand,
cmd::Command,
conventional::{Commit, Type},
conventional::{CommitParser, Config, Type},
git::{GitHelper, VersionAndTag},
Error,
};
use semver::Version;
use std::{fmt, str::FromStr};
use std::fmt;

enum Label {
/// Bump minor version (0.1.0 -> 1.0.0)
Expand Down Expand Up @@ -52,6 +52,7 @@ impl VersionCommand {
&self,
last_v_tag: &str,
mut last_version: Version,
parser: &CommitParser,
) -> Result<(Version, Label), Error> {
let prefix = self.prefix.as_str();
let git = GitHelper::new(prefix)?;
Expand All @@ -60,7 +61,7 @@ impl VersionCommand {
let i = revwalk
.flatten()
.filter_map(|oid| git.find_commit(oid).ok())
.filter_map(|commit| commit.message().and_then(|msg| Commit::from_str(msg).ok()));
.filter_map(|commit| commit.message().and_then(|msg| parser.parse(msg).ok()));

let mut major = false;
let mut minor = false;
Expand Down Expand Up @@ -105,7 +106,7 @@ impl VersionCommand {
}

impl Command for VersionCommand {
fn exec(&self) -> Result<(), Error> {
fn exec(&self, config: Config) -> Result<(), Error> {
if let Some(VersionAndTag { tag, mut version }) = self.find_last_version()? {
let v = if self.major {
version.increment_major();
Expand All @@ -122,7 +123,10 @@ impl Command for VersionCommand {
version.build.clear();
(version, Label::Release)
} else {
self.find_bump_version(tag.as_str(), version)?
let parser = CommitParser::builder()
.scope_regex(config.scope_regex)
.build();
self.find_bump_version(tag.as_str(), version, &parser)?
}
} else {
(version, Label::Release)
Expand Down
4 changes: 3 additions & 1 deletion src/conventional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@

pub(crate) mod changelog;
mod commits;
pub(crate) mod config;

pub(crate) use commits::{Commit, Footer, Type};
pub(crate) use commits::{CommitParser, Footer, Type};
pub(crate) use config::Config;
3 changes: 1 addition & 2 deletions src/conventional/changelog.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
mod config;
use super::config::Config;
use crate::Error;
use chrono::NaiveDate;
pub(crate) use config::Config;
use handlebars::{no_escape, Handlebars};
use serde::Serialize;
use std::{io, path::Path};
Expand Down

0 comments on commit dc03118

Please sign in to comment.