feat!: configurable title prefixes (#14)

This commit adds the `--prefix` CLI option. Providing this option allows
users to tell `gh-stack` their title prefixes begin and/or end with
something other than `[]`. Title prefixes can only be 2 characters
long. The starting prefix is the first character and the end prefix
is the second character.
This commit is contained in:
Luis H. Ball Jr 2021-11-24 10:17:32 -08:00 committed by GitHub
parent cabd354ec9
commit 037b33f66d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 19 deletions

12
Cargo.lock generated
View File

@ -319,7 +319,7 @@ dependencies = [
[[package]]
name = "gh-stack"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"clap",
"console",
@ -698,9 +698,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.4.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "openssl"
@ -1111,11 +1111,11 @@ dependencies = [
[[package]]
name = "thread_local"
version = "1.0.1"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"lazy_static",
"once_cell",
]
[[package]]

View File

@ -1,6 +1,6 @@
[package]
name = "gh-stack"
version = "0.2.0"
version = "0.3.0"
authors = ["Timothy Andrew <mail@timothyandrew.net>, Luis Ball <luqven@gmail.com>"]
license = "MIT"
repository = "https://github.com/luqven/gh-stack"

View File

@ -1,6 +1,7 @@
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use console::style;
use git2::Repository;
use regex::Regex;
use std::env;
use std::error::Error;
use std::rc::Rc;
@ -35,6 +36,11 @@ fn clap<'a, 'b>() -> App<'a, 'b> {
.takes_value(false)
.help("Skip waiting for confirmation");
let prefix = Arg::with_name("prefix")
.long("prefix")
.takes_value(true)
.help("PR title prefix identifier to remove from the title");
let annotate = SubCommand::with_name("annotate")
.about("Annotate the descriptions of all PRs in a stack with metadata about all PRs in the stack")
.setting(AppSettings::ArgRequiredElseHelp)
@ -42,6 +48,7 @@ fn clap<'a, 'b>() -> App<'a, 'b> {
.arg(exclude.clone())
.arg(repository.clone())
.arg(ci.clone())
.arg(prefix.clone())
.arg(Arg::with_name("prelude")
.long("prelude")
.short("p")
@ -148,6 +155,12 @@ fn get_excluded(m: &ArgMatches) -> Vec<String> {
}
}
fn remove_title_prefixes(title: String, prefix: &str) -> String {
let regex = Regex::new(&format!("[{}]", prefix).to_string()).unwrap();
let result = regex.replace_all(&title, "").into_owned();
return result;
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
dotenv::from_filename(".gh-stack.env").ok();
@ -161,6 +174,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
match matches.subcommand() {
("annotate", Some(m)) => {
let identifier = m.value_of("identifier").unwrap();
let prefix = m.value_of("prefix").unwrap_or("[]");
let prefix = regex::escape(prefix);
// if ci flag is set, set ci to true
let ci = m.is_present("ci");
// replace it with the -r argument value if set
@ -173,18 +188,20 @@ async fn main() -> Result<(), Box<dyn Error>> {
panic!("{}", error);
}
let identifier = remove_title_prefixes(identifier.to_string(), &prefix);
println!(
"Searching for {} identifier in {} repo",
style(identifier).bold(),
style(&identifier).bold(),
style(repository).bold()
);
let stack =
build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m))
build_pr_stack_for_repo(&identifier, repository, &credentials, get_excluded(m))
.await?;
let table =
markdown::build_table(&stack, identifier, m.value_of("prelude"), repository);
markdown::build_table(&stack, &identifier, m.value_of("prelude"), repository);
for (pr, _) in stack.iter() {
println!("{}: {}", pr.number(), pr.title());
@ -195,7 +212,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
loop_until_confirm("Going to update these PRs ☝️ ");
}
persist::persist(&stack, &table, &credentials).await?;
persist::persist(&stack, &table, &credentials, &prefix).await?;
println!("Done!");
}
@ -283,7 +300,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
&project,
remote.name().unwrap(),
m.value_of("boundary"),
ci
ci,
)
.await?;
println!("All done!");

View File

@ -27,17 +27,24 @@ fn safe_replace(body: &str, table: &str) -> String {
}
}
fn remove_title_prefixes(row: String) -> String {
// TODO: Make this configurable
let regex = Regex::new(r"\[[^\]]+\]\s*").unwrap();
regex.replace_all(&row, "").into_owned()
fn remove_title_prefixes(row: String, prefix: &str) -> String {
let prefix = String::from(prefix);
let prefix_1 = &prefix[0..2];
let prefix_2 = &prefix[2..4];
let regex_str = format!(r"{}[^\]]+{}\s*", prefix_1, prefix_2);
let regex = Regex::new(&regex_str).unwrap();
return regex.replace_all(&row, "").into_owned();
}
pub async fn persist(prs: &FlatDep, table: &str, c: &Credentials) -> Result<(), Box<dyn Error>> {
pub async fn persist(
prs: &FlatDep,
table: &str,
c: &Credentials,
prefix: &str,
) -> Result<(), Box<dyn Error>> {
let futures = prs.iter().map(|(pr, _)| {
let body = table.replace(&pr.title()[..], &format!("👉 {}", pr.title())[..]);
let body = remove_title_prefixes(body);
let body = remove_title_prefixes(body, prefix);
let description = safe_replace(pr.body(), body.as_ref());
pull_request::update_description(description, pr.clone(), c)
});