diff --git a/src/github.rs b/src/github.rs index 14d7a906..0dc04fd8 100644 --- a/src/github.rs +++ b/src/github.rs @@ -16,6 +16,8 @@ use std::{ }; use tracing as log; +pub mod labels; + pub type UserId = u64; pub type PullRequestNumber = u64; @@ -565,38 +567,15 @@ impl IssueRepository { format!("{}/{}", self.organization, self.repository) } - async fn has_label(&self, client: &GithubClient, label: &str) -> anyhow::Result { - #[allow(clippy::redundant_pattern_matching)] - let url = format!("{}/labels/{}", self.url(client), label); - match client.send_req(client.get(&url)).await { - Ok(_) => Ok(true), - Err(e) => { - if e.downcast_ref::() - .map_or(false, |e| e.status() == Some(StatusCode::NOT_FOUND)) - { - Ok(false) - } else { - Err(e) - } - } - } - } -} - -#[derive(Debug)] -pub(crate) struct UnknownLabels { - labels: Vec, -} - -// NOTE: This is used to post the Github comment; make sure it's valid markdown. -impl fmt::Display for UnknownLabels { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Unknown labels: {}", &self.labels.join(", ")) + async fn labels(&self, client: &GithubClient) -> anyhow::Result> { + let url = format!("{}/labels", self.url(client)); + client + .json(client.get(&url)) + .await + .context("failed to get labels") } } -impl std::error::Error for UnknownLabels {} - impl Issue { pub fn to_zulip_github_reference(&self) -> ZulipGitHubReference { ZulipGitHubReference { @@ -730,8 +709,39 @@ impl Issue { Ok(()) } + async fn normalize_and_match_labels( + &self, + client: &GithubClient, + requested_labels: &[&str], + ) -> anyhow::Result> { + let available_labels = self + .repository() + .labels(client) + .await + .context("unable to retrieve the repository labels")?; + + labels::normalize_and_match_labels( + &available_labels + .iter() + .map(|l| l.name.as_str()) + .collect::>(), + requested_labels, + ) + } + pub async fn remove_label(&self, client: &GithubClient, label: &str) -> anyhow::Result<()> { log::info!("remove_label from {}: {:?}", self.global_id(), label); + + let normalized_labels = self.normalize_and_match_labels(client, &[label]).await?; + let label = normalized_labels + .first() + .context("failed to find label on repository")?; + log::info!( + "remove_label from {}: matched label to {:?}", + self.global_id(), + label + ); + // DELETE /repos/:owner/:repo/issues/:number/labels/{name} let url = format!( "{repo_url}/issues/{number}/labels/{name}", @@ -767,6 +777,19 @@ impl Issue { labels: Vec