diff --git a/src/actions.rs b/src/actions.rs index ec518b0e9..d2735f74c 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -57,8 +57,7 @@ impl<'a> Action for Step<'a> { let mut context = Context::new(); let mut results = HashMap::new(); - for Query { repos, queries} in &self.actions { - + for Query { repos, queries } in &self.actions { for repo in repos { let repository = Repository { full_name: repo.to_string(), @@ -118,7 +117,6 @@ impl<'a> Action for Step<'a> { match count { Ok(count) => { - let result = if let Some(value) = context.get(*name) { value.as_u64().unwrap() + count as u64 } else { diff --git a/src/config.rs b/src/config.rs index a10b943cd..248ac546c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -28,6 +28,7 @@ pub(crate) struct Config { pub(crate) autolabel: Option, pub(crate) notify_zulip: Option, pub(crate) github_releases: Option, + pub(crate) review_submitted: Option, } #[derive(PartialEq, Eq, Debug, serde::Deserialize)] @@ -142,6 +143,12 @@ pub(crate) struct GlacierConfig {} #[derive(PartialEq, Eq, Debug, serde::Deserialize)] pub(crate) struct CloseConfig {} +#[derive(PartialEq, Eq, Debug, serde::Deserialize)] +pub(crate) struct ReviewSubmittedConfig { + pub(crate) review_labels: Vec, + pub(crate) reviewed_label: String, +} + pub(crate) async fn get(gh: &GithubClient, repo: &str) -> Result, ConfigurationError> { if let Some(config) = get_cached_config(repo) { log::trace!("returning config for {} from cache", repo); @@ -290,6 +297,7 @@ mod tests { autolabel: None, notify_zulip: None, github_releases: None, + review_submitted: None, } ); } diff --git a/src/github.rs b/src/github.rs index 95f7ee622..3f67cb24c 100644 --- a/src/github.rs +++ b/src/github.rs @@ -292,6 +292,18 @@ pub struct Comment { pub user: User, #[serde(alias = "submitted_at")] // for pull request reviews pub updated_at: chrono::DateTime, + #[serde(rename = "state")] + pub pr_review_state: PullRequestReviewState, +} + +#[derive(Debug, serde::Deserialize, Eq, PartialEq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum PullRequestReviewState { + Approved, + ChangesRequested, + Commented, + Dismissed, + Pending, } fn opt_string<'de, D>(deserializer: D) -> Result diff --git a/src/handlers.rs b/src/handlers.rs index 40639fff0..e1100fcd2 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -36,6 +36,7 @@ mod notify_zulip; mod ping; mod prioritize; mod relabel; +mod review_submitted; mod rustc_commits; pub async fn handle(ctx: &Context, event: &Event) -> Vec { @@ -74,6 +75,20 @@ pub async fn handle(ctx: &Context, event: &Event) -> Vec { ); } + if let Some(config) = config + .as_ref() + .ok() + .and_then(|c| c.review_submitted.as_ref()) + { + if let Err(e) = review_submitted::handle(ctx, event, config).await { + log::error!( + "failed to process event {:?} with review_submitted handler: {:?}", + event, + e + ) + } + } + if let Some(ghr_config) = config .as_ref() .ok() @@ -120,9 +135,9 @@ macro_rules! issue_handlers { } } -// Handle events that happend on issues +// Handle events that happened on issues // -// This is for events that happends only on issues (e.g. label changes). +// This is for events that happen only on issues (e.g. label changes). // Each module in the list must contain the functions `parse_input` and `handle_input`. issue_handlers! { autolabel, diff --git a/src/handlers/review_submitted.rs b/src/handlers/review_submitted.rs new file mode 100644 index 000000000..b144ae5cf --- /dev/null +++ b/src/handlers/review_submitted.rs @@ -0,0 +1,46 @@ +use crate::github::{Issue, IssueCommentAction, IssueCommentEvent, Label, PullRequestReviewState}; +use crate::{config::ReviewSubmittedConfig, github::Event, handlers::Context}; + +pub(crate) async fn handle( + ctx: &Context, + event: &Event, + config: &ReviewSubmittedConfig, +) -> anyhow::Result<()> { + if let Event::IssueComment( + event + @ + IssueCommentEvent { + action: IssueCommentAction::Created, + issue: Issue { + pull_request: Some(_), + .. + }, + .. + }, + ) = event + { + if event.comment.pr_review_state != PullRequestReviewState::ChangesRequested { + return Ok(()); + } + + if event.issue.assignees.contains(&event.comment.user) { + let labels = event + .issue + .labels() + .iter() + // Remove review related labels + .filter(|label| !config.review_labels.contains(&label.name)) + .cloned() + // Add waiting on author label + .chain(std::iter::once(Label { + name: config.reviewed_label.clone(), + })); + event + .issue + .set_labels(&ctx.github, labels.collect()) + .await?; + } + } + + Ok(()) +}