|
@@ -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(())
|
|
|
}
|
|
|
}
|