Skip to content

Commit e23ea9b

Browse files
committed
refactor: make a generic get_gh_api function
1 parent c85f8cf commit e23ea9b

File tree

1 file changed

+40
-30
lines changed

1 file changed

+40
-30
lines changed

src/github.rs

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
use std::process;
88

9-
use serde::{Deserialize, Serialize};
9+
use serde::{Deserialize, Serialize, de::DeserializeOwned};
1010
use tap::Pipe as _;
1111

1212
use crate::{
13-
config::{BranchName, CommitId, PrNumber},
13+
config::{BranchName, CommitId, PrNumber, RepoName, RepoOwner},
1414
git_high_level::{AvailableBranch, add_remote_branch, find_first_available_branch},
1515
utils::{make_request, normalize_commit_msg, with_uuid},
1616
};
@@ -30,11 +30,27 @@ pub struct Head {
3030
pub r#ref: BranchName,
3131
}
3232

33+
impl GitHubResponse {
34+
/// The endpoint which returns the structure [`GitHubResponse`]
35+
fn endpoint(repo: &str, pull_request: PrNumber) -> String {
36+
format!("https://api.github.com/repos/{repo}/pulls/{pull_request}")
37+
}
38+
}
39+
40+
/// Data returned by endpoint
3341
#[derive(Serialize, Deserialize, Debug)]
3442
pub struct Repo {
43+
/// e.g. `https://github.com/helix-editor/helix.git`
3544
pub clone_url: String,
3645
}
3746

47+
impl Repo {
48+
/// the endpoint that returns the structure [`Repo`]
49+
pub fn endpoint(owner: &RepoOwner, repo: &RepoName) -> String {
50+
format!("https://api.github.com/repos/{owner}/{repo}",)
51+
}
52+
}
53+
3854
#[derive(Debug)]
3955
pub struct Branch {
4056
pub upstream_branch_name: BranchName,
@@ -53,10 +69,16 @@ pub struct RemoteBranch {
5369
pub branch: Branch,
5470
}
5571

72+
/////////////////////////////////////////////////////////
73+
5674
/// Make a request to GitHub's API.
5775
///
5876
/// Either manually fetch the URL or use `gh` CLI
59-
async fn gh_api(url: &str, use_gh_cli: bool) -> Result<String> {
77+
///
78+
/// - Outer `Result`: Failed to fetch the URL
79+
/// - Inner `Result`: Failed to deserialize text received by the URL
80+
async fn get_gh_api<T: DeserializeOwned>(url: &str, use_gh_cli: bool) -> Result<Result<T>> {
81+
log::trace!("making a request to {url}");
6082
if use_gh_cli {
6183
process::Command::new("gh")
6284
.arg("api")
@@ -68,6 +90,11 @@ async fn gh_api(url: &str, use_gh_cli: bool) -> Result<String> {
6890
} else {
6991
make_request(url).await
7092
}
93+
.map(|response| {
94+
serde_json::from_str::<T>(&response).map_err(|err| {
95+
anyhow!("failed to parse response.\n{response}. failed to parse because: \n{err}")
96+
})
97+
})
7198
}
7299

73100
/// Fetch the branch of `remote` at the given `commit`
@@ -77,20 +104,16 @@ pub async fn fetch_branch(
77104
) -> Result<(Repo, RemoteBranch)> {
78105
let owner = &remote.owner;
79106
let repo = &remote.repo;
80-
let url = format!("https://api.github.com/repos/{owner}/{repo}",);
107+
let url = Repo::endpoint(owner, repo);
81108

82-
let response = gh_api(&url, use_gh_cli)
109+
let response = get_gh_api::<Repo>(&url, use_gh_cli)
83110
.await
84-
.map_err(|err| anyhow!("failed to fetch branch `{owner}/{repo}`:\n{err}\n"))?;
85-
86-
let response: Repo = serde_json::from_str(&response).map_err(|err| {
87-
anyhow!("failed to parse response.\n{response}. failed to parse because: \n{err}")
88-
})?;
111+
.map_err(|err| anyhow!("failed to fetch branch `{owner}/{repo}`:\n{err}\n"))??;
89112

90113
let info = RemoteBranch {
91114
remote: Remote {
92115
repository_url: response.clone_url.clone(),
93-
local_remote_alias: with_uuid(&format!("{}/{}", &remote.owner, remote.repo)),
116+
local_remote_alias: with_uuid(&format!("{}/{}", &owner, repo)),
94117
},
95118
branch: Branch {
96119
local_branch_name: remote.branch.clone(),
@@ -101,8 +124,8 @@ pub async fn fetch_branch(
101124
add_remote_branch(&info, remote.commit.as_ref()).map_err(|err| {
102125
anyhow!(
103126
"Could not add remote branch {}/{}, skipping.\n{err}",
104-
remote.owner,
105-
remote.repo
127+
owner,
128+
repo
106129
)
107130
})?;
108131

@@ -118,24 +141,11 @@ pub async fn fetch_pull_request(
118141
commit_hash: Option<&CommitId>,
119142
use_gh_cli: bool,
120143
) -> Result<(GitHubResponse, RemoteBranch)> {
121-
let url = format!("https://api.github.com/repos/{repo}/pulls/{pull_request}");
144+
let url = GitHubResponse::endpoint(repo, pull_request);
122145

123-
let gh_response = if use_gh_cli {
124-
process::Command::new("gh")
125-
.arg("api")
126-
.arg(url)
127-
.output()?
128-
.stdout
129-
.pipe(String::from_utf8)?
130-
} else {
131-
make_request(&url)
132-
.await
133-
.map_err(|err| anyhow!("failed to fetch pull request #{pull_request}\n{err}\n"))?
134-
};
135-
136-
let response: GitHubResponse = serde_json::from_str(&gh_response).map_err(|err| {
137-
anyhow!("failed to parse GitHub response.\n{gh_response}. Could not parse because: \n{err}")
138-
})?;
146+
let response = get_gh_api::<GitHubResponse>(&url, use_gh_cli)
147+
.await
148+
.map_err(|err| anyhow!("failed to fetch pull request #{pull_request}\n{err}\n"))??;
139149

140150
let remote_branch = RemoteBranch {
141151
remote: Remote {

0 commit comments

Comments
 (0)