1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
use crate::{config::Config, http::GitHubClientExt};
use std::sync::Arc;
use eyre::Result;
use log::debug;
use serenity::builder::{
CreateCommand, CreateCommandOption, CreateEmbed, CreateInteractionResponseFollowup,
};
use serenity::model::{
application::{
CommandInteraction, CommandOptionType, InstallationContext, ResolvedOption, ResolvedValue,
},
Timestamp,
};
use serenity::prelude::Context;
const REPO_OWNER: &str = "NixOS";
const REPO_NAME: &str = "nixpkgs";
pub async fn respond<T>(
ctx: &Context,
http: &Arc<T>,
config: &Config,
command: &CommandInteraction,
) -> Result<()>
where
T: GitHubClientExt,
{
// 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("PR numbers aren't negative or that big...");
command.create_followup(&ctx, resp).await?;
return Ok(());
};
let Ok(id) = u64::try_from(*pr) else {
let resp = CreateInteractionResponseFollowup::new()
.content("PR numbers aren't negative or that big...");
command.create_followup(&ctx, resp).await?;
return Ok(());
};
// find out what commit our PR was merged in
let pull_request = http.pull_request(REPO_OWNER, REPO_NAME, id).await?;
if !pull_request.merged {
let response = CreateInteractionResponseFollowup::new()
.content("It looks like that PR isn't merged yet! Try again when it is 😄");
command.create_followup(&ctx, response).await?;
return Ok(());
}
// seems older PRs may not have this
let Some(commit_sha) = pull_request.merge_commit_sha 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 repository = config.repository();
let branch_results = repository.branches_contain_sha(config.nixpkgs_branches(), &commit_sha)?;
let fields: Vec<_> = branch_results
.iter()
.map(|(name, has_commit)| {
let emoji = if *has_commit { "✅" } else { "❌" };
(*name, emoji, true)
})
.collect();
// if we didn't find any, bail
if fields.is_empty() {
let response = CreateInteractionResponseFollowup::new()
.content("This PR has been merged...but I can't seem to find it anywhere. I might not be tracking it's base branch");
command.create_followup(&ctx, response).await?;
return Ok(());
}
let mut embed = CreateEmbed::new()
.title(format!("Nixpkgs PR #{} Status", pull_request.number))
.url(&pull_request.html_url)
.description(&pull_request.title)
.fields(fields);
if let Some(merged_at) = pull_request.merged_at {
if let Ok(timestamp) = Timestamp::parse(&merged_at) {
embed = embed.timestamp(timestamp);
} else {
debug!("Couldn't parse timestamp from GitHub! Ignoring.");
}
} else {
debug!("Couldn't find `merged_at` information for a supposedly merged PR! Ignoring.");
}
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),
)
}
|