Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add triage command #1492

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions parser/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod prioritize;
pub mod relabel;
pub mod second;
pub mod shortcut;
pub mod triage;

pub fn find_command_start(input: &str, bot: &str) -> Option<usize> {
input.to_ascii_lowercase().find(&format!("@{}", bot))
Expand All @@ -27,6 +28,7 @@ pub enum Command<'a> {
Glacier(Result<glacier::GlacierCommand, Error<'a>>),
Shortcut(Result<shortcut::ShortcutCommand, Error<'a>>),
Close(Result<close::CloseCommand, Error<'a>>),
Triage(Result<triage::TriageCommand, Error<'a>>),
}

#[derive(Debug)]
Expand Down Expand Up @@ -131,6 +133,11 @@ impl<'a> Input<'a> {
Command::Close,
&original_tokenizer,
));
success.extend(parse_single_command(
triage::TriageCommand::parse,
Command::Triage,
&original_tokenizer,
));

if success.len() > 1 {
panic!(
Expand Down Expand Up @@ -191,6 +198,7 @@ impl<'a> Command<'a> {
Command::Glacier(r) => r.is_ok(),
Command::Shortcut(r) => r.is_ok(),
Command::Close(r) => r.is_ok(),
Command::Triage(r) => r.is_ok(),
}
}

Expand Down
82 changes: 82 additions & 0 deletions parser/src/command/triage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//! The triage command parser.
//!
//! Gives the priority to be changed to.
//!
//! The grammar is as follows:
//!
//! ```text
//! Command: `@bot triage {high,medium,low,P-high,P-medium,P-low}`
//! ```

use crate::error::Error;
use crate::token::{Token, Tokenizer};
use std::fmt;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Priority {
Critical,
High,
Medium,
Low,
}

#[derive(PartialEq, Eq, Debug)]
pub struct TriageCommand {
pub priority: Priority,
}

#[derive(PartialEq, Eq, Debug)]
pub enum ParseError {
ExpectedPriority,
ExpectedEnd,
}

impl std::error::Error for ParseError {}

impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ParseError::ExpectedPriority => write!(f, "expected priority (critical, high, medium, low)"),
ParseError::ExpectedEnd => write!(f, "expected end of command"),
}
}
}

impl TriageCommand {
pub fn parse<'a>(input: &mut Tokenizer<'a>) -> Result<Option<Self>, Error<'a>> {
let mut toks = input.clone();
if let Some(Token::Word("triage")) = toks.peek_token()? {
toks.next_token()?;
let priority = match toks.peek_token()? {
Some(Token::Word("critical")) | Some(Token::Word("P-critical")) => {
toks.next_token()?;
Priority::Critical
}
Some(Token::Word("high")) | Some(Token::Word("P-high")) => {
toks.next_token()?;
Priority::High
}
Some(Token::Word("medium")) | Some(Token::Word("P-medium")) => {
toks.next_token()?;
Priority::Medium
}
Some(Token::Word("low")) | Some(Token::Word("P-low")) => {
toks.next_token()?;
Priority::Low
}
_ => {
return Err(toks.error(ParseError::ExpectedPriority));
}
};
if let Some(Token::Dot) | Some(Token::EndOfLine) = toks.peek_token()? {
toks.next_token()?;
*input = toks;
return Ok(Some(TriageCommand { priority: priority }));
} else {
return Err(toks.error(ParseError::ExpectedEnd));
}
} else {
return Ok(None);
}
}
}
11 changes: 11 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub(crate) struct Config {
pub(crate) github_releases: Option<GitHubReleasesConfig>,
pub(crate) review_submitted: Option<ReviewSubmittedConfig>,
pub(crate) shortcut: Option<ShortcutConfig>,
pub(crate) triage: Option<TriageConfig>,
}

#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
Expand Down Expand Up @@ -158,6 +159,15 @@ pub(crate) struct ReviewSubmittedConfig {
pub(crate) reviewed_label: String,
}

#[derive(PartialEq, Eq, Debug, serde::Deserialize)]
pub(crate) struct TriageConfig {
pub(crate) remove: Vec<String>,
pub(crate) critical: String,
pub(crate) high: String,
pub(crate) medium: String,
pub(crate) low: String,
}

pub(crate) async fn get(gh: &GithubClient, repo: &str) -> Result<Arc<Config>, ConfigurationError> {
if let Some(config) = get_cached_config(repo) {
log::trace!("returning config for {} from cache", repo);
Expand Down Expand Up @@ -310,6 +320,7 @@ mod tests {
notify_zulip: None,
github_releases: None,
review_submitted: None,
triage: None,
}
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod relabel;
mod review_submitted;
mod rustc_commits;
mod shortcut;
mod triage;

pub async fn handle(ctx: &Context, event: &Event) -> Vec<HandlerError> {
let config = config::get(&ctx.github, &event.repo_name()).await;
Expand Down Expand Up @@ -242,6 +243,7 @@ command_handlers! {
major_change: Second,
shortcut: Shortcut,
close: Close,
triage: Triage,
}

pub struct Context {
Expand Down
49 changes: 49 additions & 0 deletions src/handlers/triage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Triage command
//!
//! Removes I-nominated tag and adds priority label.

use crate::{
config::TriageConfig,
github::{self, Event},
handlers::Context,
};
use parser::command::triage::{Priority, TriageCommand};

pub(super) async fn handle_command(
ctx: &Context,
config: &TriageConfig,
event: &Event,
cmd: TriageCommand,
) -> anyhow::Result<()> {
let event = if let Event::IssueComment(e) = event {
e
} else {
// not interested in other events
return Ok(());
};

let is_team_member =
if let Err(_) | Ok(false) = event.comment.user.is_team_member(&ctx.github).await {
false
} else {
true
};
if !is_team_member {
anyhow::bail!("Cannot use triage command as non-team-member");
}

let mut labels = event.issue.labels().to_owned();
let add = match cmd.priority {
Priority::Critical => &config.critical,
Priority::High => &config.high,
Priority::Medium => &config.medium,
Priority::Low => &config.low,
};
labels.push(github::Label { name: add.clone() });
labels.retain(|label| !config.remove.contains(&label.name));
if &labels[..] != event.issue.labels() {
event.issue.set_labels(&ctx.github, labels).await?;
}

Ok(())
}