-
Notifications
You must be signed in to change notification settings - Fork 8
/
main.rs
130 lines (112 loc) 路 3.12 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::fs::read_to_string;
use anyhow::{Context, Result};
use clap::Parser;
use conventional_commit_parser::parse;
use git2::Repository;
use koji::answers::{get_extracted_answers, ExtractedAnswers};
use koji::commit::{commit, write_commit_msg};
use koji::config::{Config, ConfigArgs};
use koji::questions::create_prompt;
#[derive(Parser, Debug)]
#[command(
about = "馃 An interactive CLI for creating conventional commits.",
version,
author
)]
struct Args {
#[arg(
short,
long,
help = "Enables autocomplete for scope prompt via scanning commit history"
)]
autocomplete: Option<bool>,
#[arg(short, long, help = "Enables breaking change prompt")]
breaking_changes: Option<bool>,
#[arg(
short,
long,
help = "Path to a config file containing custom commit types"
)]
config: Option<String>,
#[arg(
short,
long,
help = "Prepend the commit summary with relevant emoji based on commit type"
)]
emoji: Option<bool>,
#[arg(
long,
help = "Run as a git hook, writing the commit message to COMMIT_EDITMSG instead of committing"
)]
hook: bool,
#[arg(
short,
long,
help = "Enables issue prompt, which will append a reference to an issue in the commit body"
)]
issues: Option<bool>,
#[arg(
long,
help = "Sign the commit using the user's GPG key, if one is configured"
)]
sign: Option<bool>,
}
fn main() -> Result<()> {
// Get CLI args
let Args {
autocomplete,
breaking_changes,
config,
emoji,
hook,
issues,
sign,
} = Args::parse();
// Find repo
let repo =
Repository::discover(std::env::current_dir()?).context("could not find git repository")?;
// Get existing commit message (passed in via `-m`)
let commit_editmsg = repo.path().join("COMMIT_EDITMSG");
let commit_message = match read_to_string(commit_editmsg) {
Ok(contents) => contents.lines().next().unwrap_or("").to_string(),
Err(_) => "".to_string(),
};
// If the existing message is already in the form of a conventional commit,
// just go ahead and return early
if hook && parse(&commit_message).is_ok() {
return Ok(());
}
// Load config
let config = Config::new(Some(ConfigArgs {
autocomplete,
breaking_changes,
emoji,
issues,
path: config,
sign,
}))?;
// Get answers from interactive prompt
let answers = create_prompt(&repo, commit_message, &config)?;
// Get data necessary for a conventional commit
let ExtractedAnswers {
body,
commit_type,
is_breaking_change,
scope,
summary,
} = get_extracted_answers(&answers, &config)?;
// Do the thing!
if hook {
write_commit_msg(repo, commit_type, scope, summary, body, is_breaking_change)?;
} else {
commit(
commit_type,
scope,
summary,
body,
is_breaking_change,
config.sign,
)?;
}
Ok(())
}