|
@@ -0,0 +1,116 @@
|
|
|
+//! Purpose: Allow the use of single words shortcut to do specific actions on GitHub via comments.
|
|
|
+//!
|
|
|
+//! Parsing is done in the `parser::command::shortcut` module.
|
|
|
+
|
|
|
+use crate::{
|
|
|
+ config::ShortcutConfig,
|
|
|
+ github::{Event, Label},
|
|
|
+ handlers::Context,
|
|
|
+ interactions::ErrorComment,
|
|
|
+};
|
|
|
+use parser::command::shortcut::ShortcutCommand;
|
|
|
+
|
|
|
+pub(super) async fn handle_command(
|
|
|
+ ctx: &Context,
|
|
|
+ _config: &ShortcutConfig,
|
|
|
+ event: &Event,
|
|
|
+ input: ShortcutCommand,
|
|
|
+) -> anyhow::Result<()> {
|
|
|
+ let issue = event.issue().unwrap();
|
|
|
+ // NOTE: if shortcuts available to issues are created, they need to be allowed here
|
|
|
+ if !issue.is_pr() {
|
|
|
+ let msg = format!("The \"{:?}\" shortcut only works on pull requests.", input);
|
|
|
+ let cmnt = ErrorComment::new(&issue, msg);
|
|
|
+ cmnt.post(&ctx.github).await?;
|
|
|
+ return Ok(());
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut issue_labels = issue.labels().to_owned();
|
|
|
+ let waiting_on_review = "S-waiting-on-review";
|
|
|
+ let waiting_on_author = "S-waiting-on-author";
|
|
|
+
|
|
|
+ match input {
|
|
|
+ ShortcutCommand::Ready => {
|
|
|
+ if assign_and_remove_label(&mut issue_labels, waiting_on_review, waiting_on_author)
|
|
|
+ .is_some()
|
|
|
+ {
|
|
|
+ return Ok(());
|
|
|
+ }
|
|
|
+ issue.set_labels(&ctx.github, issue_labels).await?;
|
|
|
+ }
|
|
|
+ ShortcutCommand::Author => {
|
|
|
+ if assign_and_remove_label(&mut issue_labels, waiting_on_author, waiting_on_review)
|
|
|
+ .is_some()
|
|
|
+ {
|
|
|
+ return Ok(());
|
|
|
+ }
|
|
|
+ issue.set_labels(&ctx.github, issue_labels).await?;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+}
|
|
|
+
|
|
|
+fn assign_and_remove_label(
|
|
|
+ issue_labels: &mut Vec<Label>,
|
|
|
+ assign: &str,
|
|
|
+ remove: &str,
|
|
|
+) -> Option<()> {
|
|
|
+ if issue_labels.iter().any(|label| label.name == assign) {
|
|
|
+ return Some(());
|
|
|
+ }
|
|
|
+
|
|
|
+ if let Some(index) = issue_labels.iter().position(|label| label.name == remove) {
|
|
|
+ issue_labels.swap_remove(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ issue_labels.push(Label {
|
|
|
+ name: assign.into(),
|
|
|
+ });
|
|
|
+
|
|
|
+ None
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod tests {
|
|
|
+
|
|
|
+ use super::{assign_and_remove_label, Label};
|
|
|
+ fn create_labels(names: Vec<&str>) -> Vec<Label> {
|
|
|
+ names
|
|
|
+ .into_iter()
|
|
|
+ .map(|name| Label { name: name.into() })
|
|
|
+ .collect()
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn test_adds_without_labels() {
|
|
|
+ let expected = create_labels(vec!["assign"]);
|
|
|
+ let mut labels = vec![];
|
|
|
+ assert!(assign_and_remove_label(&mut labels, "assign", "remove").is_none());
|
|
|
+ assert_eq!(labels, expected);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn test_do_nothing_with_label_already_set() {
|
|
|
+ let expected = create_labels(vec!["assign"]);
|
|
|
+ let mut labels = create_labels(vec!["assign"]);
|
|
|
+ assert!(assign_and_remove_label(&mut labels, "assign", "remove").is_some());
|
|
|
+ assert_eq!(labels, expected);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn test_other_labels_untouched() {
|
|
|
+ let expected = create_labels(vec!["bug", "documentation", "assign"]);
|
|
|
+ let mut labels = create_labels(vec!["bug", "documentation"]);
|
|
|
+ assert!(assign_and_remove_label(&mut labels, "assign", "remove").is_none());
|
|
|
+ assert_eq!(labels, expected);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn test_correctly_remove_label() {
|
|
|
+ let expected = create_labels(vec!["bug", "documentation", "assign"]);
|
|
|
+ let mut labels = create_labels(vec!["bug", "documentation", "remove"]);
|
|
|
+ assert!(assign_and_remove_label(&mut labels, "assign", "remove").is_none());
|
|
|
+ assert_eq!(labels, expected);
|
|
|
+ }
|
|
|
+}
|