Skip to content

Commit 9d28d7b

Browse files
Merge pull request #1693 from ehuss/more-errors
Add better error message for GitHub client errors.
2 parents 0184c17 + cf63b53 commit 9d28d7b

File tree

4 files changed

+43
-60
lines changed

4 files changed

+43
-60
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ rand = "0.8.5"
4444
ignore = "0.4.18"
4545
postgres-types = { version = "0.2.4", features = ["derive"] }
4646
cron = { version = "0.12.0" }
47+
bytes = "1.1.0"
4748

4849
[dependencies.serde]
4950
version = "1"

src/github.rs

Lines changed: 40 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use anyhow::{anyhow, Context};
22
use async_trait::async_trait;
3+
use bytes::Bytes;
34
use chrono::{DateTime, FixedOffset, Utc};
45
use futures::{future::BoxFuture, FutureExt};
56
use hyper::header::HeaderValue;
@@ -21,9 +22,9 @@ pub struct User {
2122
}
2223

2324
impl GithubClient {
24-
async fn _send_req(&self, req: RequestBuilder) -> anyhow::Result<(Response, String)> {
25+
async fn send_req(&self, req: RequestBuilder) -> anyhow::Result<(Bytes, String)> {
2526
const MAX_ATTEMPTS: usize = 2;
26-
log::debug!("_send_req with {:?}", req);
27+
log::debug!("send_req with {:?}", req);
2728
let req_dbg = format!("{:?}", req);
2829
let req = req
2930
.build()
@@ -33,10 +34,17 @@ impl GithubClient {
3334
if let Some(sleep) = Self::needs_retry(&resp).await {
3435
resp = self.retry(req, sleep, MAX_ATTEMPTS).await?;
3536
}
37+
let maybe_err = resp.error_for_status_ref().err();
38+
let body = resp
39+
.bytes()
40+
.await
41+
.with_context(|| format!("failed to read response body {req_dbg}"))?;
42+
if let Some(e) = maybe_err {
43+
return Err(anyhow::Error::new(e))
44+
.with_context(|| format!("response: {}", String::from_utf8_lossy(&body)));
45+
}
3646

37-
resp.error_for_status_ref()?;
38-
39-
Ok((resp, req_dbg))
47+
Ok((body, req_dbg))
4048
}
4149

4250
async fn needs_retry(resp: &Response) -> Option<Duration> {
@@ -151,27 +159,12 @@ impl GithubClient {
151159
.boxed()
152160
}
153161

154-
async fn send_req(&self, req: RequestBuilder) -> anyhow::Result<Vec<u8>> {
155-
let (mut resp, req_dbg) = self._send_req(req).await?;
156-
157-
let mut body = Vec::new();
158-
while let Some(chunk) = resp.chunk().await.transpose() {
159-
let chunk = chunk
160-
.context("reading stream failed")
161-
.map_err(anyhow::Error::from)
162-
.context(req_dbg.clone())?;
163-
body.extend_from_slice(&chunk);
164-
}
165-
166-
Ok(body)
167-
}
168-
169162
pub async fn json<T>(&self, req: RequestBuilder) -> anyhow::Result<T>
170163
where
171164
T: serde::de::DeserializeOwned,
172165
{
173-
let (resp, req_dbg) = self._send_req(req).await?;
174-
Ok(resp.json().await.context(req_dbg)?)
166+
let (body, _req_dbg) = self.send_req(req).await?;
167+
Ok(serde_json::from_slice(&body)?)
175168
}
176169
}
177170

@@ -412,8 +405,8 @@ impl IssueRepository {
412405
async fn has_label(&self, client: &GithubClient, label: &str) -> anyhow::Result<bool> {
413406
#[allow(clippy::redundant_pattern_matching)]
414407
let url = format!("{}/labels/{}", self.url(), label);
415-
match client._send_req(client.get(&url)).await {
416-
Ok((_, _)) => Ok(true),
408+
match client.send_req(client.get(&url)).await {
409+
Ok(_) => Ok(true),
417410
Err(e) => {
418411
if e.downcast_ref::<reqwest::Error>()
419412
.map_or(false, |e| e.status() == Some(StatusCode::NOT_FOUND))
@@ -493,7 +486,7 @@ impl Issue {
493486
body: &'a str,
494487
}
495488
client
496-
._send_req(client.patch(&edit_url).json(&ChangedIssue { body }))
489+
.send_req(client.patch(&edit_url).json(&ChangedIssue { body }))
497490
.await
498491
.context("failed to edit issue body")?;
499492
Ok(())
@@ -511,7 +504,7 @@ impl Issue {
511504
body: &'a str,
512505
}
513506
client
514-
._send_req(
507+
.send_req(
515508
client
516509
.patch(&comment_url)
517510
.json(&NewComment { body: new_body }),
@@ -527,7 +520,7 @@ impl Issue {
527520
body: &'a str,
528521
}
529522
client
530-
._send_req(client.post(&self.comments_url).json(&PostComment { body }))
523+
.send_req(client.post(&self.comments_url).json(&PostComment { body }))
531524
.await
532525
.context("failed to post comment")?;
533526
Ok(())
@@ -553,7 +546,7 @@ impl Issue {
553546
}
554547

555548
client
556-
._send_req(client.delete(&url))
549+
.send_req(client.delete(&url))
557550
.await
558551
.context("failed to delete label")?;
559552

@@ -610,7 +603,7 @@ impl Issue {
610603
}
611604

612605
client
613-
._send_req(client.post(&url).json(&LabelsReq {
606+
.send_req(client.post(&url).json(&LabelsReq {
614607
labels: known_labels,
615608
}))
616609
.await
@@ -661,7 +654,7 @@ impl Issue {
661654
assignees: &'a [&'a str],
662655
}
663656
client
664-
._send_req(client.delete(&url).json(&AssigneeReq {
657+
.send_req(client.delete(&url).json(&AssigneeReq {
665658
assignees: &assignees[..],
666659
}))
667660
.await
@@ -754,7 +747,7 @@ impl Issue {
754747
}
755748
let url = format!("{}/issues/{}", self.repository().url(), self.number);
756749
client
757-
._send_req(client.patch(&url).json(&SetMilestone {
750+
.send_req(client.patch(&url).json(&SetMilestone {
758751
milestone: milestone_no,
759752
}))
760753
.await
@@ -769,7 +762,7 @@ impl Issue {
769762
state: &'a str,
770763
}
771764
client
772-
._send_req(
765+
.send_req(
773766
client
774767
.patch(&edit_url)
775768
.json(&CloseIssue { state: "closed" }),
@@ -794,8 +787,9 @@ impl Issue {
794787
after
795788
));
796789
req = req.header("Accept", "application/vnd.github.v3.diff");
797-
let diff = client.send_req(req).await?;
798-
Ok(Some(String::from(String::from_utf8_lossy(&diff))))
790+
let (diff, _) = client.send_req(req).await?;
791+
let body = String::from_utf8_lossy(&diff).to_string();
792+
Ok(Some(body))
799793
}
800794

801795
/// Returns the commits from this pull request (no commits are returned if this `Issue` is not
@@ -1235,7 +1229,7 @@ impl Repository {
12351229
) -> anyhow::Result<()> {
12361230
let url = format!("{}/git/refs/{}", self.url(), refname);
12371231
client
1238-
._send_req(client.patch(&url).json(&serde_json::json!({
1232+
.json(client.patch(&url).json(&serde_json::json!({
12391233
"sha": sha,
12401234
"force": true,
12411235
})))
@@ -1494,7 +1488,7 @@ impl Repository {
14941488
pub async fn merge_upstream(&self, client: &GithubClient, branch: &str) -> anyhow::Result<()> {
14951489
let url = format!("{}/merge-upstream", self.url());
14961490
client
1497-
._send_req(client.post(&url).json(&serde_json::json!({
1491+
.send_req(client.post(&url).json(&serde_json::json!({
14981492
"branch": branch,
14991493
})))
15001494
.await
@@ -1783,7 +1777,7 @@ impl GithubClient {
17831777
repo: &str,
17841778
branch: &str,
17851779
path: &str,
1786-
) -> anyhow::Result<Option<Vec<u8>>> {
1780+
) -> anyhow::Result<Option<Bytes>> {
17871781
let url = format!(
17881782
"https://raw.githubusercontent.com/{}/{}/{}",
17891783
repo, branch, path
@@ -1793,20 +1787,14 @@ impl GithubClient {
17931787
let req = req
17941788
.build()
17951789
.with_context(|| format!("failed to build request {:?}", req_dbg))?;
1796-
let mut resp = self.client.execute(req).await.context(req_dbg.clone())?;
1790+
let resp = self.client.execute(req).await.context(req_dbg.clone())?;
17971791
let status = resp.status();
1792+
let body = resp
1793+
.bytes()
1794+
.await
1795+
.with_context(|| format!("failed to read response body {req_dbg}"))?;
17981796
match status {
1799-
StatusCode::OK => {
1800-
let mut buf = Vec::with_capacity(resp.content_length().unwrap_or(4) as usize);
1801-
while let Some(chunk) = resp.chunk().await.transpose() {
1802-
let chunk = chunk
1803-
.context("reading stream failed")
1804-
.map_err(anyhow::Error::from)
1805-
.context(req_dbg.clone())?;
1806-
buf.extend_from_slice(&chunk);
1807-
}
1808-
Ok(Some(buf))
1809-
}
1797+
StatusCode::OK => Ok(Some(body)),
18101798
StatusCode::NOT_FOUND => Ok(None),
18111799
status => anyhow::bail!("failed to GET {}: {}", url, status),
18121800
}
@@ -2010,11 +1998,8 @@ impl IssuesQuery for LeastRecentlyReviewedPullRequests {
20101998
let req = client.post(Repository::GITHUB_GRAPHQL_API_URL);
20111999
let req = req.json(&query);
20122000

2013-
let (resp, req_dbg) = client._send_req(req).await?;
2014-
let data = resp
2015-
.json::<cynic::GraphQlResponse<queries::LeastRecentlyReviewedPullRequests>>()
2016-
.await
2017-
.context(req_dbg)?;
2001+
let data: cynic::GraphQlResponse<queries::LeastRecentlyReviewedPullRequests> =
2002+
client.json(req).await?;
20182003
if let Some(errors) = data.errors {
20192004
anyhow::bail!("There were graphql errors. {:?}", errors);
20202005
}
@@ -2147,11 +2132,7 @@ async fn project_items_by_status(
21472132
let req = client.post(Repository::GITHUB_GRAPHQL_API_URL);
21482133
let req = req.json(&query);
21492134

2150-
let (resp, req_dbg) = client._send_req(req).await?;
2151-
let data = resp
2152-
.json::<cynic::GraphQlResponse<project_items_by_status::Query>>()
2153-
.await
2154-
.context(req_dbg)?;
2135+
let data: cynic::GraphQlResponse<project_items_by_status::Query> = client.json(req).await?;
21552136
if let Some(errors) = data.errors {
21562137
anyhow::bail!("There were graphql errors. {:?}", errors);
21572138
}

src/handlers/github_releases.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ async fn load_changelog(
132132
.await?
133133
.ok_or_else(|| anyhow::Error::msg("missing file"))?;
134134

135-
Ok(String::from_utf8(resp)?)
135+
Ok(String::from_utf8(resp.to_vec())?)
136136
}
137137

138138
async fn load_paginated<T, R, F>(ctx: &Context, url: &str, key: F) -> anyhow::Result<HashMap<R, T>>

0 commit comments

Comments
 (0)