Skip to content

Commit 5355d18

Browse files
marcoieniKobzol
authored andcommitted
fix: don't fail when reading a repo that doesn't exist
1 parent d45a410 commit 5355d18

File tree

3 files changed

+79
-21
lines changed

3 files changed

+79
-21
lines changed

sync-team/src/github/api/mod.rs

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,46 @@ impl HttpClient {
9292
}
9393
}
9494

95+
/// Send a request to the GitHub API and return the response.
9596
fn graphql<R, V>(&self, query: &str, variables: V, org: &str) -> anyhow::Result<R>
97+
where
98+
R: serde::de::DeserializeOwned,
99+
V: serde::Serialize,
100+
{
101+
let res = self.send_graphql_req(query, variables, org)?;
102+
103+
if let Some(error) = res.errors.first() {
104+
bail!("graphql error: {}", error.message);
105+
}
106+
107+
read_graphql_data(res)
108+
}
109+
110+
/// Send a request to the GitHub API and return the response.
111+
/// If the request contains the error type `NOT_FOUND`, this method returns `Ok(None)`.
112+
fn graphql_opt<R, V>(&self, query: &str, variables: V, org: &str) -> anyhow::Result<Option<R>>
113+
where
114+
R: serde::de::DeserializeOwned,
115+
V: serde::Serialize,
116+
{
117+
let res = self.send_graphql_req(query, variables, org)?;
118+
119+
if let Some(error) = res.errors.first() {
120+
if error.type_ == Some(GraphErrorType::NotFound) {
121+
return Ok(None);
122+
}
123+
bail!("graphql error: {}", error.message);
124+
}
125+
126+
read_graphql_data(res)
127+
}
128+
129+
fn send_graphql_req<R, V>(
130+
&self,
131+
query: &str,
132+
variables: V,
133+
org: &str,
134+
) -> anyhow::Result<GraphResult<R>>
96135
where
97136
R: serde::de::DeserializeOwned,
98137
V: serde::Serialize,
@@ -105,19 +144,13 @@ impl HttpClient {
105144
let resp = self
106145
.req(Method::POST, &GitHubUrl::new("graphql", org))?
107146
.json(&Request { query, variables })
108-
.send()?
147+
.send()
148+
.context("failed to send graphql request")?
109149
.custom_error_for_status()?;
110150

111-
let res: GraphResult<R> = resp.json_annotated().with_context(|| {
151+
resp.json_annotated().with_context(|| {
112152
format!("Failed to decode response body on graphql request with query '{query}'")
113-
})?;
114-
if let Some(error) = res.errors.first() {
115-
bail!("graphql error: {}", error.message);
116-
} else if let Some(data) = res.data {
117-
Ok(data)
118-
} else {
119-
bail!("missing graphql data");
120-
}
153+
})
121154
}
122155

123156
fn rest_paginated<F, T>(&self, method: &Method, url: &GitHubUrl, mut f: F) -> anyhow::Result<()>
@@ -159,6 +192,17 @@ impl HttpClient {
159192
}
160193
}
161194

195+
fn read_graphql_data<R>(res: GraphResult<R>) -> anyhow::Result<R>
196+
where
197+
R: serde::de::DeserializeOwned,
198+
{
199+
if let Some(data) = res.data {
200+
Ok(data)
201+
} else {
202+
bail!("missing graphql data");
203+
}
204+
}
205+
162206
fn allow_not_found(resp: Response, method: Method, url: &str) -> Result<(), anyhow::Error> {
163207
match resp.status() {
164208
StatusCode::NOT_FOUND => {
@@ -180,9 +224,19 @@ struct GraphResult<T> {
180224

181225
#[derive(Debug, serde::Deserialize)]
182226
struct GraphError {
227+
#[serde(rename = "type")]
228+
type_: Option<GraphErrorType>,
183229
message: String,
184230
}
185231

232+
#[derive(Debug, serde::Deserialize, PartialEq, Eq)]
233+
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
234+
enum GraphErrorType {
235+
NotFound,
236+
#[serde(other)]
237+
Other,
238+
}
239+
186240
#[derive(serde::Deserialize)]
187241
struct GraphNodes<T> {
188242
nodes: Vec<Option<T>>,

sync-team/src/github/api/read.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::github::api::{
22
BranchProtection, GraphNode, GraphNodes, GraphPageInfo, HttpClient, Login, Repo, RepoTeam,
33
RepoUser, Team, TeamMember, TeamRole, team_node_id, url::GitHubUrl, user_node_id,
44
};
5+
use anyhow::Context as _;
56
use reqwest::Method;
67
use std::collections::{HashMap, HashSet};
78

@@ -271,16 +272,19 @@ impl GithubRead for GitHubApiRead {
271272
is_archived: bool,
272273
}
273274

274-
let result: Wrapper = self.client.graphql(
275-
QUERY,
276-
Params {
277-
owner: org,
278-
name: repo,
279-
},
280-
org,
281-
)?;
275+
let result: Option<Wrapper> = self
276+
.client
277+
.graphql_opt(
278+
QUERY,
279+
Params {
280+
owner: org,
281+
name: repo,
282+
},
283+
org,
284+
)
285+
.with_context(|| format!("failed to retrieve repo `{org}/{repo}`"))?;
282286

283-
let repo = result.repository.map(|repo_response| Repo {
287+
let repo = result.and_then(|r| r.repository).map(|repo_response| Repo {
284288
node_id: repo_response.id,
285289
name: repo.to_string(),
286290
description: repo_response.description.unwrap_or_default(),

sync-team/src/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ impl ResponseExt for Response {
1313
match self.error_for_status_ref() {
1414
Ok(_) => Ok(self),
1515
Err(err) => {
16-
let body = self.text()?;
17-
Err(err).context(format!("Body: {:?}", body))
16+
let body = self.text().context("failed to read response body")?;
17+
Err(err).context(format!("Body: {body:?}"))
1818
}
1919
}
2020
}

0 commit comments

Comments
 (0)