Compare commits
12 Commits
feature/re
...
main
Author | SHA1 | Date | |
---|---|---|---|
a2849226ce | |||
a6c26a9213 | |||
5ea2ff445a | |||
819e5d23bb | |||
5ac9d474f2 | |||
d9ddb7139b | |||
c933073e32 | |||
6f3625c2fe | |||
92eab2361e | |||
97e988e99e | |||
784329a703 | |||
f912217549 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -737,7 +737,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toolkit"
|
name = "toolkit"
|
||||||
version = "0.1.10"
|
version = "0.1.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"eyre",
|
"eyre",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "toolkit"
|
name = "toolkit"
|
||||||
description = "Toolkit is an opinionated toolkit complementing a personal development workflow. Many of the commands are quite verbose, and well suited for adding to your shell toolbelt"
|
description = "Toolkit is an opinionated toolkit complementing a personal development workflow. Many of the commands are quite verbose, and well suited for adding to your shell toolbelt"
|
||||||
version = "0.1.10"
|
version = "0.1.14"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license-file = "LICENSE"
|
license-file = "LICENSE"
|
||||||
authors = ["Kasper J. Hermansen contact@kjuulh.io"]
|
authors = ["Kasper J. Hermansen contact@kjuulh.io"]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::review_backend::{
|
use crate::review_backend::{
|
||||||
models::{MenuChoice, PullRequest, ReviewMenuChoice},
|
models::{MenuChoice, MergeStrategy, PullRequest, ReviewMenuChoice},
|
||||||
DefaultReviewBackend, DynReviewBackend,
|
DefaultReviewBackend, DynReviewBackend,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,7 +34,11 @@ impl Review {
|
|||||||
/// 4. Present pr and use delta to view changes
|
/// 4. Present pr and use delta to view changes
|
||||||
/// 5. Approve, open, skip or quit
|
/// 5. Approve, open, skip or quit
|
||||||
/// 6. Repeat from 4
|
/// 6. Repeat from 4
|
||||||
fn run(&self, review_requested: Option<String>) -> eyre::Result<()> {
|
fn run(
|
||||||
|
&self,
|
||||||
|
review_requested: Option<String>,
|
||||||
|
merge_strategy: &Option<MergeStrategy>,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
let prs = self.backend.get_prs(review_requested.clone())?;
|
let prs = self.backend.get_prs(review_requested.clone())?;
|
||||||
|
|
||||||
let prs_table = Self::generate_prs_table(&prs);
|
let prs_table = Self::generate_prs_table(&prs);
|
||||||
@ -42,16 +46,16 @@ impl Review {
|
|||||||
|
|
||||||
match self.backend.present_menu()? {
|
match self.backend.present_menu()? {
|
||||||
MenuChoice::Exit => eyre::bail!(ReviewErrors::UserExit),
|
MenuChoice::Exit => eyre::bail!(ReviewErrors::UserExit),
|
||||||
MenuChoice::Begin => match self.review(&prs)? {
|
MenuChoice::Begin => match self.review(&prs, &merge_strategy)? {
|
||||||
Some(choice) => match choice {
|
Some(choice) => match choice {
|
||||||
MenuChoice::Exit => eyre::bail!(ReviewErrors::UserExit),
|
MenuChoice::Exit => eyre::bail!(ReviewErrors::UserExit),
|
||||||
MenuChoice::List => return self.run(review_requested.clone()),
|
MenuChoice::List => return self.run(review_requested.clone(), merge_strategy),
|
||||||
_ => eyre::bail!("invalid choice"),
|
_ => eyre::bail!("invalid choice"),
|
||||||
},
|
},
|
||||||
None => {}
|
None => {}
|
||||||
},
|
},
|
||||||
MenuChoice::Search => todo!(),
|
MenuChoice::Search => todo!(),
|
||||||
MenuChoice::List => return self.run(review_requested.clone()),
|
MenuChoice::List => return self.run(review_requested.clone(), merge_strategy),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -79,12 +83,16 @@ impl Review {
|
|||||||
table.to_string()
|
table.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn review(&self, prs: &Vec<PullRequest>) -> eyre::Result<Option<MenuChoice>> {
|
fn review(
|
||||||
|
&self,
|
||||||
|
prs: &Vec<PullRequest>,
|
||||||
|
merge_strategy: &Option<MergeStrategy>,
|
||||||
|
) -> eyre::Result<Option<MenuChoice>> {
|
||||||
for pr in prs {
|
for pr in prs {
|
||||||
self.backend.clear()?;
|
self.backend.clear()?;
|
||||||
self.backend.present_pr(pr)?;
|
self.backend.present_pr(pr)?;
|
||||||
self.review_pr(pr)?;
|
self.review_pr(pr)?;
|
||||||
if let Some(choice) = self.present_pr_menu(pr)? {
|
if let Some(choice) = self.present_pr_menu(pr, merge_strategy)? {
|
||||||
return Ok(Some(choice));
|
return Ok(Some(choice));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,13 +111,21 @@ impl Review {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_browser(&self, pr: &PullRequest) -> eyre::Result<Option<MenuChoice>> {
|
fn open_browser(
|
||||||
|
&self,
|
||||||
|
pr: &PullRequest,
|
||||||
|
merge_strategy: &Option<MergeStrategy>,
|
||||||
|
) -> eyre::Result<Option<MenuChoice>> {
|
||||||
self.backend.pr_open_browser(pr)?;
|
self.backend.pr_open_browser(pr)?;
|
||||||
|
|
||||||
self.present_pr_menu(pr)
|
self.present_pr_menu(pr, merge_strategy)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn present_pr_menu(&self, pr: &PullRequest) -> eyre::Result<Option<MenuChoice>> {
|
fn present_pr_menu(
|
||||||
|
&self,
|
||||||
|
pr: &PullRequest,
|
||||||
|
merge_strategy: &Option<MergeStrategy>,
|
||||||
|
) -> eyre::Result<Option<MenuChoice>> {
|
||||||
self.backend.present_pr(pr)?;
|
self.backend.present_pr(pr)?;
|
||||||
|
|
||||||
match self.backend.present_review_menu(pr)? {
|
match self.backend.present_review_menu(pr)? {
|
||||||
@ -117,33 +133,58 @@ impl Review {
|
|||||||
ReviewMenuChoice::List => return Ok(Some(MenuChoice::List)),
|
ReviewMenuChoice::List => return Ok(Some(MenuChoice::List)),
|
||||||
ReviewMenuChoice::Approve => {
|
ReviewMenuChoice::Approve => {
|
||||||
self.approve(pr)?;
|
self.approve(pr)?;
|
||||||
return self.present_pr_menu(pr);
|
return self.present_pr_menu(pr, merge_strategy);
|
||||||
}
|
}
|
||||||
ReviewMenuChoice::Open => return self.open_browser(pr),
|
ReviewMenuChoice::Open => return self.open_browser(pr, merge_strategy),
|
||||||
ReviewMenuChoice::Skip => {}
|
ReviewMenuChoice::Skip => {}
|
||||||
ReviewMenuChoice::Merge => self.merge(pr)?,
|
ReviewMenuChoice::Merge => self.merge(pr, merge_strategy)?,
|
||||||
ReviewMenuChoice::ApproveAndMerge => {
|
ReviewMenuChoice::ApproveAndMerge => {
|
||||||
self.approve(pr)?;
|
self.approve(pr)?;
|
||||||
self.merge(pr)?;
|
self.merge(pr, merge_strategy)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge(&self, pr: &PullRequest) -> eyre::Result<()> {
|
fn merge(&self, pr: &PullRequest, merge_strategy: &Option<MergeStrategy>) -> eyre::Result<()> {
|
||||||
self.backend.enable_auto_merge(pr);
|
self.backend.enable_auto_merge(pr, merge_strategy)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl util::Cmd for Review {
|
impl util::Cmd for Review {
|
||||||
fn cmd() -> eyre::Result<clap::Command> {
|
fn cmd() -> eyre::Result<clap::Command> {
|
||||||
Ok(clap::Command::new("review"))
|
Ok(clap::Command::new("review")
|
||||||
|
.arg(
|
||||||
|
clap::Arg::new("review-requested")
|
||||||
|
.long("review-requested")
|
||||||
|
.default_value("@me")
|
||||||
|
.help("which user or team to pull reviews from"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
clap::Arg::new("merge-strategy")
|
||||||
|
.long("merge-strategy")
|
||||||
|
.help(
|
||||||
|
"when merging which merge strategy to use, possible values: [squash, merge]",
|
||||||
|
),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(_: &clap::ArgMatches) -> eyre::Result<()> {
|
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
|
||||||
Self::default().run(Some("lunarway/squad-aura".into()))
|
let request_requested = args
|
||||||
|
.get_one::<String>("review-requested")
|
||||||
|
.map(|r| r.clone());
|
||||||
|
|
||||||
|
let squash = args
|
||||||
|
.get_one::<String>("merge-strategy")
|
||||||
|
.and_then(|s| match s.as_str() {
|
||||||
|
"squash" => Some(MergeStrategy::Squash),
|
||||||
|
"merge" => Some(MergeStrategy::MergeCommit),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
Self::default().run(request_requested, &squash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +235,7 @@ mod tests {
|
|||||||
backend.expect_present_prs().times(1).returning(|_| Ok(()));
|
backend.expect_present_prs().times(1).returning(|_| Ok(()));
|
||||||
|
|
||||||
let review = Review::new(std::sync::Arc::new(backend));
|
let review = Review::new(std::sync::Arc::new(backend));
|
||||||
let res = review.run(Some("kjuulh".into()));
|
let res = review.run(None, &None);
|
||||||
|
|
||||||
assert_err::<ReviewErrors, _>(res)
|
assert_err::<ReviewErrors, _>(res)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ pub mod models;
|
|||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use self::models::{MenuChoice, PullRequest, ReviewMenuChoice};
|
use self::models::{MenuChoice, MergeStrategy, PullRequest, ReviewMenuChoice};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use mockall::{automock, predicate::*};
|
use mockall::{automock, predicate::*};
|
||||||
@ -16,7 +16,11 @@ pub trait ReviewBackend {
|
|||||||
fn approve(&self, pr: &PullRequest) -> eyre::Result<()>;
|
fn approve(&self, pr: &PullRequest) -> eyre::Result<()>;
|
||||||
fn pr_open_browser(&self, pr: &PullRequest) -> eyre::Result<()>;
|
fn pr_open_browser(&self, pr: &PullRequest) -> eyre::Result<()>;
|
||||||
fn clear(&self) -> eyre::Result<()>;
|
fn clear(&self) -> eyre::Result<()>;
|
||||||
fn enable_auto_merge(&self, pr: &PullRequest) -> eyre::Result<()>;
|
fn enable_auto_merge(
|
||||||
|
&self,
|
||||||
|
pr: &PullRequest,
|
||||||
|
merge_strategy: &Option<MergeStrategy>,
|
||||||
|
) -> eyre::Result<()>;
|
||||||
fn present_pr(&self, pr: &PullRequest) -> eyre::Result<()>;
|
fn present_pr(&self, pr: &PullRequest) -> eyre::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,11 +38,9 @@ impl ReviewBackend for DefaultReviewBackend {
|
|||||||
"prs",
|
"prs",
|
||||||
"--state=open",
|
"--state=open",
|
||||||
"--review-requested",
|
"--review-requested",
|
||||||
"@me",
|
review_request.unwrap_or("@me".into()).as_str(),
|
||||||
//review_request.unwrap().as_str(),
|
|
||||||
"--label",
|
"--label",
|
||||||
"dependencies",
|
"dependencies",
|
||||||
//"--checks=pending",
|
|
||||||
"--json",
|
"--json",
|
||||||
"repository,number,title",
|
"repository,number,title",
|
||||||
],
|
],
|
||||||
@ -163,19 +165,30 @@ impl ReviewBackend for DefaultReviewBackend {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_auto_merge(&self, pr: &PullRequest) -> eyre::Result<()> {
|
fn enable_auto_merge(
|
||||||
util::shell::run(
|
&self,
|
||||||
&[
|
pr: &PullRequest,
|
||||||
|
merge_strategy: &Option<MergeStrategy>,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let number = pr.number.to_string();
|
||||||
|
let mut args = vec![
|
||||||
"gh",
|
"gh",
|
||||||
"pr",
|
"pr",
|
||||||
"merge",
|
"merge",
|
||||||
pr.number.to_string().as_str(),
|
number.as_str(),
|
||||||
"--auto",
|
"--auto",
|
||||||
"--repo",
|
"--repo",
|
||||||
pr.repository.name.as_str(),
|
pr.repository.name.as_str(),
|
||||||
],
|
];
|
||||||
None,
|
|
||||||
)?;
|
if let Some(merge_strategy) = merge_strategy {
|
||||||
|
match merge_strategy {
|
||||||
|
MergeStrategy::Squash => args.push("--squash"),
|
||||||
|
MergeStrategy::MergeCommit => args.push("--merge"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
util::shell::run(args.as_slice(), None)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,12 @@ pub struct PullRequest {
|
|||||||
pub repository: Repository,
|
pub repository: Repository,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum MergeStrategy {
|
||||||
|
Squash,
|
||||||
|
MergeCommit,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum MenuChoice {
|
pub enum MenuChoice {
|
||||||
Exit,
|
Exit,
|
||||||
Begin,
|
Begin,
|
||||||
|
Reference in New Issue
Block a user