summaryrefslogtreecommitdiff
path: root/src/command/track.rs
diff options
context:
space:
mode:
authorseth <[email protected]>2024-05-27 04:55:45 -0400
committerseth <[email protected]>2024-05-27 04:56:48 -0400
commitc69eea2f4823da476628742fbbec600ee95ac049 (patch)
tree7cf3d87f5f202e6049ba44a06ac6fe9d3558826b /src/command/track.rs
initial commit
Diffstat (limited to 'src/command/track.rs')
-rw-r--r--src/command/track.rs133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/command/track.rs b/src/command/track.rs
new file mode 100644
index 0000000..6217043
--- /dev/null
+++ b/src/command/track.rs
@@ -0,0 +1,133 @@
+use crate::http::{Client, GithubClientExt};
+
+use eyre::Result;
+use futures::future::try_join_all;
+use serenity::builder::{CreateCommand, CreateCommandOption, CreateInteractionResponseFollowup};
+use serenity::model::application::{
+ CommandInteraction, CommandOptionType, InstallationContext, ResolvedOption, ResolvedValue,
+};
+use serenity::prelude::Context;
+use tracing::{instrument, trace};
+
+/// All of our tracked branches in nixpkgs
+const BRANCHES: [&str; 8] = [
+ "master",
+ "staging",
+ "nixos-unstable",
+ "nixos-unstable-small",
+ "nixos-24.05-small",
+ "release-24.05",
+ "nixos-23.11-small",
+ "release-23.11",
+];
+
+#[derive(Clone, Debug, Default)]
+struct BranchStatus {
+ repo_owner: String,
+ repo_name: String,
+ name: String,
+}
+
+impl BranchStatus {
+ fn new(repo_owner: String, repo_name: String, name: String) -> Self {
+ Self {
+ repo_owner,
+ repo_name,
+ name,
+ }
+ }
+
+ /// Make a nice friendly string displaying if this branch has a PR merged into it
+ fn to_status_string(&self, has_pr: bool) -> String {
+ let emoji = if has_pr { "✅" } else { "❌" };
+ format!("`{}` {emoji}", &self.name)
+ }
+
+ /// Check if this branch has the specified pull request merged into it
+ #[instrument(skip(http))]
+ async fn has_pr(&self, http: &Client, pr: u64) -> Result<bool> {
+ let commit = http
+ .merge_commit_for(
+ &self.repo_owner,
+ &self.repo_name,
+ u64::try_from(pr).unwrap(),
+ )
+ .await?;
+
+ let has_pr = http
+ .is_commit_in_branch(&self.repo_owner, &self.repo_name, &self.name, &commit)
+ .await?;
+
+ Ok(has_pr)
+ }
+}
+
+/// async wrapper for [BranchStatus::to_status_string()]
+#[instrument(skip(http))]
+async fn collect_status(
+ http: &Client,
+ repo_owner: String,
+ repo_name: String,
+ branch: String,
+ pr: u64,
+) -> Result<String> {
+ let status = BranchStatus::new(repo_owner, repo_name, branch);
+ let has_pr = status.has_pr(http, pr).await?;
+ let res = status.to_status_string(has_pr);
+
+ Ok(res)
+}
+
+#[instrument(skip_all)]
+pub async fn respond(ctx: &Context, http: &Client, command: &CommandInteraction) -> Result<()> {
+ trace!("Responding to track command");
+
+ // this will probably take a while
+ command.defer(&ctx).await?;
+
+ // TODO: make these configurable for nixpkgs forks...or other github repos ig
+ const REPO_OWNER: &str = "NixOS";
+ const REPO_NAME: &str = "nixpkgs";
+
+ let options = command.data.options();
+
+ let response = if let Some(ResolvedOption {
+ value: ResolvedValue::Integer(pr),
+ ..
+ }) = options.first()
+ {
+ if *pr < 0 {
+ CreateInteractionResponseFollowup::new().content("PR numbers aren't negative...")
+ } else {
+ // TODO: this is gross
+ let statuses = try_join_all(BRANCHES.iter().map(|&branch| {
+ collect_status(
+ http,
+ REPO_OWNER.to_string(),
+ REPO_NAME.to_string(),
+ branch.to_string(),
+ u64::try_from(*pr).unwrap(),
+ )
+ }))
+ .await?;
+
+ CreateInteractionResponseFollowup::new().content(statuses.join("\n"))
+ }
+ } else {
+ CreateInteractionResponseFollowup::new().content("Please provide a valid commit!")
+ };
+
+ command.create_followup(&ctx, response).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),
+ )
+}