Browse Source

New way of performing set_assignee

Try to assign regardless if the user is in the repo assignee list, and
check whether it is successful. If so, remove all other assignees.

This would allow "outside contributers" to be assigned if they have
commented the issue.
Gary Guo 4 years ago
parent
commit
d412eaf08b
1 changed files with 33 additions and 39 deletions
  1. 33 39
      src/github.rs

+ 33 - 39
src/github.rs

@@ -284,9 +284,10 @@ pub enum AssignmentError {
 }
 
 #[derive(Debug)]
-pub enum Selection<'a, T> {
+pub enum Selection<'a, T: ?Sized> {
     All,
     One(&'a T),
+    Except(&'a T),
 }
 
 impl fmt::Display for AssignmentError {
@@ -462,7 +463,7 @@ impl Issue {
     pub async fn remove_assignees(
         &self,
         client: &GithubClient,
-        selection: Selection<'_, String>,
+        selection: Selection<'_, str>,
     ) -> Result<(), AssignmentError> {
         log::info!("remove {:?} assignees for {}", selection, self.global_id());
         let url = format!(
@@ -477,7 +478,13 @@ impl Issue {
                 .iter()
                 .map(|u| u.login.as_str())
                 .collect::<Vec<_>>(),
-            Selection::One(user) => vec![user.as_str()],
+            Selection::One(user) => vec![user],
+            Selection::Except(user) => self
+                .assignees
+                .iter()
+                .map(|u| u.login.as_str())
+                .filter(|&u| u != user)
+                .collect::<Vec<_>>(),
         };
 
         #[derive(serde::Serialize)]
@@ -493,60 +500,47 @@ impl Issue {
         Ok(())
     }
 
-    pub async fn set_assignee(
+    pub async fn add_assignee(
         &self,
         client: &GithubClient,
         user: &str,
     ) -> Result<(), AssignmentError> {
-        log::info!("set_assignee for {} to {}", self.global_id(), user);
+        log::info!("add_assignee {} for {}", user, self.global_id());
         let url = format!(
             "{repo_url}/issues/{number}/assignees",
             repo_url = self.repository().url(),
             number = self.number
         );
 
-        let check_url = format!(
-            "{repo_url}/assignees/{name}",
-            repo_url = self.repository().url(),
-            name = user,
-        );
-
-        match client._send_req(client.get(&check_url)).await {
-            Ok((resp, _)) => {
-                if resp.status() == reqwest::StatusCode::NO_CONTENT {
-                    // all okay
-                    log::debug!("set_assignee: assignee is valid");
-                } else {
-                    log::error!(
-                        "unknown status for assignee check, assuming all okay: {:?}",
-                        resp
-                    );
-                }
-            }
-            Err(e) => {
-                if let Some(e) = e.downcast_ref::<reqwest::Error>() {
-                    if e.status() == Some(reqwest::StatusCode::NOT_FOUND) {
-                        log::debug!("set_assignee: assignee is invalid, returning");
-                        return Err(AssignmentError::InvalidAssignee);
-                    }
-                }
-                log::debug!("set_assignee: get {} failed, {:?}", check_url, e);
-                return Err(AssignmentError::Http(e));
-            }
-        }
-
-        self.remove_assignees(client, Selection::All).await?;
-
         #[derive(serde::Serialize)]
         struct AssigneeReq<'a> {
             assignees: &'a [&'a str],
         }
 
-        client
-            ._send_req(client.post(&url).json(&AssigneeReq { assignees: &[user] }))
+        let result: Issue = client
+            .json(client.post(&url).json(&AssigneeReq { assignees: &[user] }))
             .await
             .map_err(AssignmentError::Http)?;
+        // Invalid assignees are silently ignored. We can just check if the user is now
+        // contained in the assignees list.
+        let success = result.assignees.iter().any(|u| u.login.as_str() == user);
+
+        if success {
+            Ok(())
+        } else {
+            Err(AssignmentError::InvalidAssignee)
+        }
+    }
 
+    pub async fn set_assignee(
+        &self,
+        client: &GithubClient,
+        user: &str,
+    ) -> Result<(), AssignmentError> {
+        log::info!("set_assignee for {} to {}", self.global_id(), user);
+        self.add_assignee(client, user).await?;
+        self.remove_assignees(client, Selection::Except(user))
+            .await?;
         Ok(())
     }
 }