| 1 | use { |
| 2 | crate::{cli::PrCommand, context::Ctx, git, ui}, |
| 3 | anyhow::{anyhow, Result}, |
| 4 | sigit_si_api::State, |
| 5 | }; |
| 6 | |
| 7 | pub async fn run(ctx: &Ctx, command: PrCommand) -> Result<()> { |
| 8 | ctx.require_token()?; |
| 9 | |
| 10 | match command { |
| 11 | PrCommand::List { repo, state } => list(ctx, repo, state).await, |
| 12 | PrCommand::View { number, repo } => view(ctx, number, repo).await, |
| 13 | PrCommand::Diff { number, repo } => diff(ctx, number, repo).await, |
| 14 | PrCommand::Create { |
| 15 | title, |
| 16 | head, |
| 17 | base, |
| 18 | body, |
| 19 | repo, |
| 20 | } => create(ctx, title, head, base, body, repo).await, |
| 21 | PrCommand::Comment { number, body, repo } => comment(ctx, number, body, repo).await, |
| 22 | } |
| 23 | } |
| 24 | |
| 25 | async fn list(ctx: &Ctx, repo: Option<String>, state: String) -> Result<()> { |
| 26 | let slug = ctx.resolve_repo(repo)?; |
| 27 | let state = parse_state(&state)?; |
| 28 | let pulls = ctx.client.pulls(&slug.to_string(), state).await?; |
| 29 | ui::emit(ctx.json, &pulls, |pulls| ui::render::pulls(pulls)) |
| 30 | } |
| 31 | |
| 32 | async fn view(ctx: &Ctx, number: i64, repo: Option<String>) -> Result<()> { |
| 33 | let slug = ctx.resolve_repo(repo)?; |
| 34 | let pr = ctx.client.pull(&slug.to_string(), number).await?; |
| 35 | ui::emit(ctx.json, &pr, ui::render::pull_detail) |
| 36 | } |
| 37 | |
| 38 | async fn diff(ctx: &Ctx, number: i64, repo: Option<String>) -> Result<()> { |
| 39 | let slug = ctx.resolve_repo(repo)?; |
| 40 | let pr = ctx.client.pull(&slug.to_string(), number).await?; |
| 41 | |
| 42 | match pr.diff { |
| 43 | Some(diff) => { |
| 44 | print!("{diff}"); |
| 45 | if let Some(note) = pr.diff_note { |
| 46 | ui::note(note); |
| 47 | } |
| 48 | } |
| 49 | None => { |
| 50 | ui::note( |
| 51 | pr.diff_note |
| 52 | .unwrap_or_else(|| "No diff available.".to_string()), |
| 53 | ); |
| 54 | } |
| 55 | } |
| 56 | Ok(()) |
| 57 | } |
| 58 | |
| 59 | async fn create( |
| 60 | ctx: &Ctx, |
| 61 | title: String, |
| 62 | head: Option<String>, |
| 63 | base: String, |
| 64 | body: Option<String>, |
| 65 | repo: Option<String>, |
| 66 | ) -> Result<()> { |
| 67 | let slug = ctx.resolve_repo(repo)?; |
| 68 | let head = match head { |
| 69 | Some(head) => head, |
| 70 | None => git::current_branch(&std::env::current_dir()?) |
| 71 | .ok_or_else(|| anyhow!("Could not determine the current branch. Pass --head."))?, |
| 72 | }; |
| 73 | |
| 74 | let created = ctx |
| 75 | .client |
| 76 | .create_pull(&slug.to_string(), &title, &head, &base, body.as_deref()) |
| 77 | .await?; |
| 78 | |
| 79 | ui::emit(ctx.json, &created, |created| { |
| 80 | ui::success(format!("Opened pull request #{}.", created.number)); |
| 81 | println!(" {}", created.url); |
| 82 | }) |
| 83 | } |
| 84 | |
| 85 | async fn comment(ctx: &Ctx, number: i64, body: String, repo: Option<String>) -> Result<()> { |
| 86 | let slug = ctx.resolve_repo(repo)?; |
| 87 | let comment = ctx |
| 88 | .client |
| 89 | .add_comment(&slug.to_string(), number, &body) |
| 90 | .await?; |
| 91 | ui::emit(ctx.json, &comment, |comment| { |
| 92 | ui::success(format!("Commented on #{number}.")); |
| 93 | println!(" {}", comment.url); |
| 94 | }) |
| 95 | } |
| 96 | |
| 97 | fn parse_state(input: &str) -> Result<State> { |
| 98 | match input.to_ascii_lowercase().as_str() { |
| 99 | "open" => Ok(State::Open), |
| 100 | "closed" => Ok(State::Closed), |
| 101 | "merged" => Ok(State::Merged), |
| 102 | "all" => Ok(State::All), |
| 103 | other => Err(anyhow!( |
| 104 | "Unknown state {other:?}. Expected one of: open, closed, merged, all." |
| 105 | )), |
| 106 | } |
| 107 | } |