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
123
124
125
126
127
128
129
130
131
132
133
|
use crate::{config::Config, consts::NIXPKGS_REMOTE, 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 status_results = git_tracker::collect_statuses_in(
&config.nixpkgs_path,
&commit_sha,
&config.nixpkgs_branches,
)?;
// find branches containing our PR and trim the remote ref prefix
let found_branches: Vec<String> = status_results
.iter()
.filter(|&(_, has_pr)| *has_pr)
.map(|(branch_name, _)| {
// remove the ref prefix that we add in our Config struct
let start_pos = format!("{NIXPKGS_REMOTE}/").len();
branch_name[start_pos..].to_string()
})
.collect();
// if we didn't find any, bail
if found_branches.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(
found_branches
.iter()
.map(|branch_name| (branch_name, "✅", true)),
);
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),
)
}
|