Skip to content

Commit 4e83f7a

Browse files
authored
Merge pull request #1866 from Mark-Simulacrum/github-pr-openclose
Add github-action PR open/closer
2 parents b8d10a2 + e8d017a commit 4e83f7a

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

src/config.rs

+8
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub(crate) struct Config {
4646
pub(crate) pr_tracking: Option<ReviewPrefsConfig>,
4747
pub(crate) transfer: Option<TransferConfig>,
4848
pub(crate) merge_conflicts: Option<MergeConflictConfig>,
49+
pub(crate) bot_pull_requests: Option<BotPullRequests>,
4950
}
5051

5152
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
@@ -402,6 +403,11 @@ pub(crate) struct MergeConflictConfig {
402403
pub unless: HashSet<String>,
403404
}
404405

406+
#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
407+
#[serde(rename_all = "kebab-case")]
408+
#[serde(deny_unknown_fields)]
409+
pub(crate) struct BotPullRequests {}
410+
405411
fn get_cached_config(repo: &str) -> Option<Result<Arc<Config>, ConfigurationError>> {
406412
let cache = CONFIG_CACHE.read().unwrap();
407413
cache.get(repo).and_then(|(config, fetch_time)| {
@@ -580,6 +586,7 @@ mod tests {
580586
pr_tracking: None,
581587
transfer: None,
582588
merge_conflicts: None,
589+
bot_pull_requests: None,
583590
}
584591
);
585592
}
@@ -641,6 +648,7 @@ mod tests {
641648
pr_tracking: None,
642649
transfer: None,
643650
merge_conflicts: None,
651+
bot_pull_requests: None,
644652
}
645653
);
646654
}

src/github.rs

+25
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,31 @@ impl GithubClient {
189189
.await
190190
.context("failed to create issue")
191191
}
192+
193+
pub(crate) async fn set_pr_state(
194+
&self,
195+
repo: &IssueRepository,
196+
number: u64,
197+
state: PrState,
198+
) -> anyhow::Result<()> {
199+
#[derive(serde::Serialize)]
200+
struct Update {
201+
state: PrState,
202+
}
203+
let url = format!("{}/pulls/{number}", repo.url(&self));
204+
self.send_req(self.patch(&url).json(&Update { state }))
205+
.await
206+
.context("failed to update pr state")?;
207+
Ok(())
208+
}
209+
}
210+
211+
#[derive(Debug, serde::Serialize)]
212+
pub(crate) enum PrState {
213+
#[serde(rename = "open")]
214+
Open,
215+
#[serde(rename = "closed")]
216+
Closed,
192217
}
193218

194219
#[derive(Debug, serde::Deserialize)]

src/handlers.rs

+11
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ impl fmt::Display for HandlerError {
2525

2626
mod assign;
2727
mod autolabel;
28+
mod bot_pull_requests;
2829
mod close;
2930
pub mod docs_update;
3031
mod github_releases;
@@ -117,6 +118,16 @@ pub async fn handle(ctx: &Context, event: &Event) -> Vec<HandlerError> {
117118
);
118119
}
119120

121+
if config.as_ref().is_ok_and(|c| c.bot_pull_requests.is_some()) {
122+
if let Err(e) = bot_pull_requests::handle(ctx, event).await {
123+
log::error!(
124+
"failed to process event {:?} with bot_pull_requests handler: {:?}",
125+
event,
126+
e
127+
)
128+
}
129+
}
130+
120131
if let Some(config) = config
121132
.as_ref()
122133
.ok()

src/handlers/bot_pull_requests.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use crate::github::{IssuesAction, PrState};
2+
use crate::{github::Event, handlers::Context};
3+
4+
pub(crate) async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
5+
let Event::Issue(event) = event else {
6+
return Ok(());
7+
};
8+
// Note that this filters out reopened too, which is what we'd expect when we set the state
9+
// back to opened after closing.
10+
if event.action != IssuesAction::Opened {
11+
return Ok(());
12+
}
13+
if !event.issue.is_pr() {
14+
return Ok(());
15+
}
16+
17+
// avoid acting on our own open events, otherwise we'll infinitely loop
18+
if event.sender.login == ctx.username {
19+
return Ok(());
20+
}
21+
22+
// If it's not the github-actions bot, we don't expect this handler to be needed. Skip the
23+
// event.
24+
if event.sender.login != "app/github-actions" {
25+
return Ok(());
26+
}
27+
28+
ctx.github
29+
.set_pr_state(
30+
event.issue.repository(),
31+
event.issue.number,
32+
PrState::Closed,
33+
)
34+
.await?;
35+
ctx.github
36+
.set_pr_state(event.issue.repository(), event.issue.number, PrState::Open)
37+
.await?;
38+
39+
Ok(())
40+
}

0 commit comments

Comments
 (0)