Compare commits

..

12 Commits

Author SHA1 Message Date
a2849226ce
chore(release) with args 2023-01-12 07:32:05 +01:00
a6c26a9213
chore(release) with bug fixes 2023-01-12 07:29:49 +01:00
5ea2ff445a
fix tests 2023-01-12 07:28:29 +01:00
819e5d23bb
with more options 2023-01-12 07:26:44 +01:00
5ac9d474f2
chore(release) with github review
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-11 22:48:59 +01:00
d9ddb7139b
hardcode to @me
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-11 22:46:20 +01:00
c933073e32 Merge pull request 'feature/review' (#6) from feature/review into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #6
2023-01-11 21:45:17 +00:00
6f3625c2fe Merge pull request 'feature/review-add-select' (#5) from feature/review-add-select into feature/review
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
Reviewed-on: #5
2023-01-11 21:40:45 +00:00
92eab2361e
with actual review functionality
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-01-11 22:39:42 +01:00
97e988e99e
fixed tests
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-01-10 22:54:18 +01:00
784329a703
limit table to 20 items
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-10 22:33:35 +01:00
f912217549
colored table
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-10 22:33:11 +01:00
5 changed files with 100 additions and 40 deletions

2
Cargo.lock generated
View File

@ -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",

View File

@ -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"]

View File

@ -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)
} }

View File

@ -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(())
} }

View File

@ -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,