From 2dcb67fbc54087a0887d0b85022d28d64b05f3f3 Mon Sep 17 00:00:00 2001 From: Ben Date: Sat, 23 Nov 2024 10:14:17 +0100 Subject: [PATCH] improvements to pr workflow --- Cargo.lock | 66 ++++++++++++++++++++++++------------ Cargo.toml | 2 +- src/main.rs | 77 +++++++++++++++++++++++++++++++----------- src/repo_extensions.rs | 21 +++++++++++- 4 files changed, 122 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9530dc3..0e0cf5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -554,9 +554,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.26.0" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http", @@ -599,7 +599,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", + "tower 0.4.13", "tower-service", "tracing", ] @@ -831,9 +831,9 @@ dependencies = [ [[package]] name = "octocrab" -version = "0.38.0" +version = "0.41.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a8a3df00728324ad654ecd1ed449a60157c55b7ff8c109af3a35989687c367" +checksum = "e2dfd11f6efbd39491d71a3864496f0b6f45e2d01b73b26c55d631c4e0dafaef" dependencies = [ "arc-swap", "async-trait", @@ -862,7 +862,7 @@ dependencies = [ "serde_urlencoded", "snafu", "tokio", - "tower", + "tower 0.5.1", "tower-http", "tracing", "url", @@ -1067,11 +1067,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "ebbbdb961df0ad3f2652da8f3fdc4b36122f568f968f45ad3316f26c025c677b" dependencies = [ "log", + "once_cell", "ring", "rustls-pki-types", "rustls-webpki", @@ -1081,9 +1082,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -1152,9 +1153,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "secrecy" -version = "0.8.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" dependencies = [ "zeroize", ] @@ -1346,6 +1347,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "tempfile" version = "3.10.1" @@ -1456,9 +1463,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ "rustls", "rustls-pki-types", @@ -1523,6 +1530,22 @@ dependencies = [ "pin-project", "pin-project-lite", "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", "tokio-util", "tower-layer", "tower-service", @@ -1531,19 +1554,18 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" dependencies = [ "bitflags 2.5.0", "bytes", "futures-util", "http", "http-body", - "http-body-util", "iri-string", "pin-project-lite", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -1551,15 +1573,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" diff --git a/Cargo.toml b/Cargo.toml index fdad3c1..3635b86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ clap = { version = "4.5.11", features = ["derive"] } console = "0.15.8" dialoguer = "0.11.0" indicatif = "0.17.8" -octocrab = "0.38.0" +octocrab = "0.41.2" ron = "0.8.1" toml = "0.8.16" rustygit = "0.5.0" diff --git a/src/main.rs b/src/main.rs index 90dc592..d2d2d40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,9 @@ use std::{path::PathBuf, str::FromStr, sync::Arc}; use clap::Parser; use console::{pad_str, style}; use dialoguer::{theme::ColorfulTheme, Input, Select}; -use octocrab::{models::pulls::PullRequest, Octocrab, Page}; +use octocrab::{ + models::pulls::PullRequest, params::pulls::Sort, pulls::PullRequestHandler, Octocrab, Page, +}; use rustygit::types::BranchName; use crate::{ @@ -48,7 +50,7 @@ async fn main() -> Result<()> { Some(Commands::Add { name }) => ctx.add_to_stack(name)?, Some(Commands::List {}) => ctx.list()?, Some(Commands::Change {}) => ctx.change()?, - Some(Commands::Sync {}) => ctx.sync()?, + Some(Commands::Sync {}) => ctx.sync().await?, Some(Commands::Up {}) => ctx.checkout_above()?, Some(Commands::Down {}) => ctx.checkout_below()?, Some(Commands::Base {}) => ctx.checkout_base()?, @@ -59,7 +61,7 @@ async fn main() -> Result<()> { Some(Commands::Reset {}) => ctx.reset()?, None => println!( "Welcome to {}! Run {} to see available commands.", - style("G-Stack").bold().cyan(), + style("G-Stack v0.0.3").bold().cyan(), style("gs help").italic().green(), ), } @@ -282,7 +284,7 @@ impl GsContext { Ok(()) } - fn sync(&self) -> Result<()> { + async fn sync(&self) -> Result<()> { let current_branch = self.repo.current_branch()?; let branches = &self.current_stack().unwrap().branches; self.repo.pull_all(branches).ok(); @@ -296,8 +298,13 @@ impl GsContext { BranchName::from_str(rebase_on)?, )?; self.repo - .push_to_upstream("origin", &BranchName::from_str(branch)?)?; + .force_push_to_upstream("origin", &BranchName::from_str(branch)?)?; } + let open_pulls = self.get_pull_requests().await?; + let remote = self.repo.remote_repo_info()?; + let pulls = self.github.pulls(remote.owner, remote.name); + self.update_pr_descriptions(&pulls, open_pulls).await?; + self.repo.switch_branch(¤t_branch)?; Ok(()) } @@ -322,25 +329,43 @@ impl GsContext { ); println!("base: {}, title: {}", base, title); - let pr = pulls - .create(title, branch, base) - .body("Created by [gstack](https://github.com/Bendzae/gstack)") - .send() - .await?; + let pr = pulls.create(title, branch, base).body("---").send().await?; println!("#{}: {}", pr.number, pr.html_url.clone().unwrap()); created_pulls.push(pr); } - for pr in &created_pulls { - let mut body = "".to_string(); - created_pulls - .iter() - .for_each(|p| body = body.clone() + format!("#{} \n", p.number).as_str()); - body = body.clone() + "\nCreated by [gstack](https://github.com/Bendzae/gstack)"; + self.update_pr_descriptions(&pulls, created_pulls).await?; + Ok(()) + } + async fn update_pr_descriptions( + &self, + pulls: &PullRequestHandler<'_>, + prs: Vec, + ) -> Result<()> { + for pr in &prs { + let mut body = pr + .body + .clone() + .unwrap_or("".to_string()) + .lines() + .take_while(|line| !line.contains("---")) + .collect::>() + .join("\n"); + + body.push_str("\n---\n"); + prs.iter().for_each(|p| { + body.push_str(format!("- #{}", p.number).as_str()); + if pr.number == p.number { + body.push_str(" (This PR)"); + } + body.push('\n'); + }); + body = body.clone() + "\n**Created by [gstack](https://github.com/Bendzae/gstack)**"; + + // println!("Updating: {:?}", body); pulls.update(pr.number).body(body).send().await?; } - Ok(()) } @@ -349,7 +374,6 @@ impl GsContext { println!( "{:?}", open_pulls - .items .iter() .map(|pr| pr.title.clone().unwrap()) .collect::>() @@ -357,15 +381,28 @@ impl GsContext { Ok(()) } - async fn get_pull_requests(&self) -> Result> { + async fn get_pull_requests(&self) -> Result> { let remote = self.repo.remote_repo_info()?; let pulls = self.github.pulls(remote.owner, remote.name); let open_pulls = pulls .list() .state(octocrab::params::State::Open) + .sort(Sort::Created) .send() .await?; - Ok(open_pulls) + let stack = &self.current_stack().unwrap(); + let branches = &stack.branches; + let stack_pulls = branches + .iter() + .filter_map(|branch| { + open_pulls + .items + .iter() + .find(|&pr| pr.head.sha == self.repo.head_sha(branch).unwrap_or("".to_string())) + }) + .cloned() + .collect::>(); + Ok(stack_pulls) } fn reset(&mut self) -> Result<()> { diff --git a/src/repo_extensions.rs b/src/repo_extensions.rs index 7f0a959..4675ca0 100644 --- a/src/repo_extensions.rs +++ b/src/repo_extensions.rs @@ -1,6 +1,7 @@ use anyhow::Result; use anyhow::{bail, Ok}; use regex::Regex; +use std::fmt::Debug; use std::{ops::Rem, str::FromStr}; use rustygit::{types::BranchName, Repository}; @@ -16,6 +17,8 @@ pub trait RepoExtenstions { fn pull_all(&self, branches: &Vec) -> Result<()>; fn remote_repo_url(&self) -> Result; fn remote_repo_info(&self) -> Result; + fn force_push_to_upstream(&self, upstream: &str, upstream_branch: &BranchName) -> Result<()>; + fn head_sha(&self, branch_name: &String) -> Result; } impl RepoExtenstions for Repository { @@ -28,7 +31,6 @@ impl RepoExtenstions for Repository { self.switch_branch(&branch)?; let output = self.cmd_out(&["rebase", "--update-refs", on.to_string().as_str()])?; println!("{:?}", output); - println!("{:?}", output); Ok(()) } @@ -63,4 +65,21 @@ impl RepoExtenstions for Repository { bail!("Malformed remote url") } } + + ///Force push the curent branch to its associated remote, specifying the upstream branch + fn force_push_to_upstream(&self, upstream: &str, upstream_branch: &BranchName) -> Result<()> { + self.cmd_out(&[ + "push", + "-u", + upstream, + upstream_branch.to_string().as_str(), + "--force", + ]); + Ok(()) + } + + fn head_sha(&self, branch_name: &String) -> Result { + let output = self.cmd_out(&["rev-parse", branch_name])?; + Ok(output.first().unwrap().clone()) + } }