From d25129d829e0ebd70b4e60e399fe91c0d80aa1ad Mon Sep 17 00:00:00 2001 From: seth Date: Sun, 16 Jun 2024 07:15:13 -0400 Subject: use libgit2 to track PRs (#10) * nix: don't depend on registry for nixpkgs input * use libgit2 to track PRs * nix: don't use ci devShell as defaul * crates: bump serenity from `9ad74d4` to `0.12.2 * nix: fix cross compiled builds * crates: split more from client * bot-jobs: update remote refs more efficiently * git-tracker: account for HEAD commits * bot-config: use nixpkgs branches from environment * bot-commands: don't display branches prs haven't landed in * git-tracker: return false when commits aren't found this is annoying as a hard error since it turns out github will report garbage merge commit SHAs for PRs that *haven't* been merged yet. yay * bot: improve docs in some places * bot-client: display invite link on start * bot-http: add TeawieClientExt * bot-commands: add /about * docs: update readme todos * nix: enable StateDirectory in module * crates: bump to 0.2.0 --- crates/bot-commands/src/track.rs | 121 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 crates/bot-commands/src/track.rs (limited to 'crates/bot-commands/src/track.rs') diff --git a/crates/bot-commands/src/track.rs b/crates/bot-commands/src/track.rs new file mode 100644 index 0000000..1f22d0e --- /dev/null +++ b/crates/bot-commands/src/track.rs @@ -0,0 +1,121 @@ +use bot_config::Config; +use bot_consts::{NIXPKGS_REMOTE, NIXPKGS_URL}; +use bot_error::Error; +use bot_http::{self as http, GithubClientExt}; +use git_tracker::Tracker; + +use log::trace; +use serenity::all::CreateEmbed; +use serenity::builder::{CreateCommand, CreateCommandOption, CreateInteractionResponseFollowup}; +use serenity::model::application::{ + CommandInteraction, CommandOptionType, InstallationContext, ResolvedOption, ResolvedValue, +}; +use serenity::prelude::Context; + +const REPO_OWNER: &str = "NixOS"; +const REPO_NAME: &str = "nixpkgs"; + +/// Collect the status of the commit SHA [`commit_sha`] in each of the nixpkgs +/// branches in [`branches`], using the repository at path [`repository_path`] +/// +/// # Errors +/// +/// Will return [`Err`] if we can't start tracking a repository at the given path, +/// or if we can't determine if the branch has given commit +fn collect_statuses_in<'a>( + repository_path: &str, + commit_sha: &str, + branches: impl IntoIterator, +) -> Result, Error> { + // start tracking nixpkgs + let tracker = Tracker::from_path(repository_path)?; + + // check to see what branches it's in + let mut status_results = vec![]; + for branch_name in branches { + trace!("Checking for commit in {branch_name}"); + let full_branch_name = format!("{NIXPKGS_REMOTE}/{branch_name}"); + let has_pr = tracker.branch_contains_sha(&full_branch_name, commit_sha)?; + + if has_pr { + status_results.push(format!("`{branch_name}` ✅")); + } + } + + Ok(status_results) +} + +pub async fn respond( + ctx: &Context, + http: &http::Client, + config: &Config, + command: &CommandInteraction, +) -> Result<(), Error> { + // this will probably take a while + command.defer(&ctx).await?; + + let options = command.data.options(); + let Some(ResolvedOption { + value: ResolvedValue::Integer(pr), + .. + }) = options.first() + else { + let resp = CreateInteractionResponseFollowup::new() + .content("Please provide a valid pull request!"); + command.create_followup(&ctx, resp).await?; + + return Ok(()); + }; + + let Ok(pr_id) = u64::try_from(*pr) else { + let resp = + CreateInteractionResponseFollowup::new().content("PR numbers aren't negative..."); + command.create_followup(&ctx, resp).await?; + + return Ok(()); + }; + + // find out what commit our PR was merged in + let Some(commit_sha) = http.merge_commit_for(REPO_OWNER, REPO_NAME, pr_id).await? else { + let response = CreateInteractionResponseFollowup::new() + .content("It seems this pull request is very old. I can't track it"); + command.create_followup(&ctx, response).await?; + + return Ok(()); + }; + + let status_results = collect_statuses_in( + &config.nixpkgs_path, + &commit_sha, + config.nixpkgs_branches.iter(), + )?; + + // if we don't find the commit in any branches from above, we can pretty safely assume + // it's an unmerged PR + let embed_description: String = if status_results.is_empty() { + "It doesn't look like this PR has been merged yet! (or maybe I just haven't updated)" + .to_string() + } else { + status_results.join("\n") + }; + + let embed = CreateEmbed::new() + .title(format!("Nixpkgs PR #{} Status", *pr)) + .url(format!("{NIXPKGS_URL}/pull/{pr}")) + .description(embed_description); + + let resp = CreateInteractionResponseFollowup::new().embed(embed); + command.create_followup(&ctx, resp).await?; + + Ok(()) +} + +pub fn register() -> CreateCommand { + CreateCommand::new("track") + .description("Track a nixpkgs PR") + .add_integration_type(InstallationContext::User) + .add_option( + CreateCommandOption::new(CommandOptionType::Integer, "pull_request", "PR to track") + .required(true), + ) +} -- cgit v1.2.3