Skip to content

Commit

Permalink
Add github-action PR open/closer
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark-Simulacrum committed Dec 8, 2024
1 parent b8d10a2 commit e8d017a
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub(crate) struct Config {
pub(crate) pr_tracking: Option<ReviewPrefsConfig>,
pub(crate) transfer: Option<TransferConfig>,
pub(crate) merge_conflicts: Option<MergeConflictConfig>,
pub(crate) bot_pull_requests: Option<BotPullRequests>,
}

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

#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
pub(crate) struct BotPullRequests {}

fn get_cached_config(repo: &str) -> Option<Result<Arc<Config>, ConfigurationError>> {
let cache = CONFIG_CACHE.read().unwrap();
cache.get(repo).and_then(|(config, fetch_time)| {
Expand Down Expand Up @@ -580,6 +586,7 @@ mod tests {
pr_tracking: None,
transfer: None,
merge_conflicts: None,
bot_pull_requests: None,
}
);
}
Expand Down Expand Up @@ -641,6 +648,7 @@ mod tests {
pr_tracking: None,
transfer: None,
merge_conflicts: None,
bot_pull_requests: None,
}
);
}
Expand Down
25 changes: 25 additions & 0 deletions src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,31 @@ impl GithubClient {
.await
.context("failed to create issue")
}

pub(crate) async fn set_pr_state(
&self,
repo: &IssueRepository,
number: u64,
state: PrState,
) -> anyhow::Result<()> {
#[derive(serde::Serialize)]
struct Update {
state: PrState,
}
let url = format!("{}/pulls/{number}", repo.url(&self));
self.send_req(self.patch(&url).json(&Update { state }))
.await
.context("failed to update pr state")?;
Ok(())
}
}

#[derive(Debug, serde::Serialize)]
pub(crate) enum PrState {
#[serde(rename = "open")]
Open,
#[serde(rename = "closed")]
Closed,
}

#[derive(Debug, serde::Deserialize)]
Expand Down
11 changes: 11 additions & 0 deletions src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ impl fmt::Display for HandlerError {

mod assign;
mod autolabel;
mod bot_pull_requests;
mod close;
pub mod docs_update;
mod github_releases;
Expand Down Expand Up @@ -117,6 +118,16 @@ pub async fn handle(ctx: &Context, event: &Event) -> Vec<HandlerError> {
);
}

if config.as_ref().is_ok_and(|c| c.bot_pull_requests.is_some()) {
if let Err(e) = bot_pull_requests::handle(ctx, event).await {
log::error!(
"failed to process event {:?} with bot_pull_requests handler: {:?}",
event,
e
)
}
}

if let Some(config) = config
.as_ref()
.ok()
Expand Down
40 changes: 40 additions & 0 deletions src/handlers/bot_pull_requests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use crate::github::{IssuesAction, PrState};
use crate::{github::Event, handlers::Context};

pub(crate) async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
let Event::Issue(event) = event else {
return Ok(());
};
// Note that this filters out reopened too, which is what we'd expect when we set the state
// back to opened after closing.
if event.action != IssuesAction::Opened {
return Ok(());
}
if !event.issue.is_pr() {
return Ok(());
}

// avoid acting on our own open events, otherwise we'll infinitely loop
if event.sender.login == ctx.username {
return Ok(());
}

// If it's not the github-actions bot, we don't expect this handler to be needed. Skip the
// event.
if event.sender.login != "app/github-actions" {
return Ok(());
}

ctx.github
.set_pr_state(
event.issue.repository(),
event.issue.number,
PrState::Closed,
)
.await?;
ctx.github
.set_pr_state(event.issue.repository(), event.issue.number, PrState::Open)
.await?;

Ok(())
}

0 comments on commit e8d017a

Please sign in to comment.