Skip to content

Commit c85f8cf

Browse files
committed
feat: add --use-gh-cli option
1 parent cb9f0e9 commit c85f8cf

File tree

9 files changed

+123
-99
lines changed

9 files changed

+123
-99
lines changed

src/cli.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ pub enum Command {
8888

8989
impl Command {
9090
/// Execute the command
91-
pub async fn execute(self) -> anyhow::Result<()> {
91+
pub async fn execute(self, use_gh_cli: bool) -> anyhow::Result<()> {
9292
match self {
9393
Self::Init => commands::init()?,
94-
Self::Run { yes } => commands::run(yes).await?,
94+
Self::Run { yes } => commands::run(yes, use_gh_cli).await?,
9595
Self::GenPatch { commit, filename } => {
9696
commands::gen_patch(commit, filename)?;
9797
}
@@ -101,12 +101,12 @@ impl Command {
101101
branch,
102102
commit,
103103
checkout,
104-
} => commands::pr_fetch(pr, remote, branch, commit, checkout).await?,
104+
} => commands::pr_fetch(pr, remote, branch, commit, checkout, use_gh_cli).await?,
105105
Self::BranchFetch {
106106
remote,
107107
commit,
108108
checkout,
109-
} => commands::branch_fetch(remote, commit, checkout).await?,
109+
} => commands::branch_fetch(remote, commit, checkout, use_gh_cli).await?,
110110
Self::Completions { shell } => {
111111
shell.generate(&mut Cli::command(), &mut std::io::stdout());
112112
}

src/commands/branch_fetch.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ use colored::Colorize as _;
44

55
use crate::config::{CommitId, Remote};
66
use crate::git;
7-
use crate::github_api;
7+
use crate::github;
88
use anyhow::anyhow;
99

1010
/// Fetch the given branch
1111
pub async fn branch_fetch(
1212
remote: Remote,
1313
commit: Option<CommitId>,
1414
checkout: bool,
15+
use_gh_cli: bool,
1516
) -> anyhow::Result<()> {
16-
let (_, info) = github_api::fetch_branch(&remote).await?;
17+
let (_, info) = github::fetch_branch(&remote, use_gh_cli).await?;
1718

1819
log::info!(
1920
"Fetched branch {}/{}/{} available at branch {}{}",

src/commands/pr_fetch.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use anyhow::{Context as _, anyhow};
44
use colored::Colorize as _;
55

66
use crate::config::{BranchName, CommitId, PrNumber, Remote, RepoName, RepoOwner};
7-
use crate::git;
8-
use crate::github_api::fetch_pull_request;
7+
use crate::{git, github};
98

109
/// Fetch the given `pr` of `remote` at `commit` and store it in local `branch`
1110
///
@@ -16,6 +15,7 @@ pub async fn pr_fetch(
1615
branch: Option<BranchName>,
1716
commit: Option<CommitId>,
1817
checkout: bool,
18+
use_gh_cli: bool,
1919
) -> anyhow::Result<()> {
2020
pub const GITHUB_REMOTE_PREFIX: &str = "[email protected]:";
2121
pub const GITHUB_REMOTE_SUFFIX: &str = ".git";
@@ -46,11 +46,12 @@ pub async fn pr_fetch(
4646
Ok,
4747
)?;
4848

49-
let Ok((response, info)) = fetch_pull_request(
49+
let Ok((response, info)) = github::fetch_pull_request(
5050
&format!("{}/{}", remote.owner, remote.repo),
5151
pr,
5252
branch,
5353
commit.as_ref(),
54+
use_gh_cli,
5455
)
5556
.await
5657
.inspect_err(|err| {
@@ -61,16 +62,7 @@ pub async fn pr_fetch(
6162

6263
log::info!(
6364
"Fetched pull request {} available at branch {}{}",
64-
crate::utils::display_link(
65-
&format!(
66-
"{}{}{}{}",
67-
"#".bright_blue(),
68-
pr.to_string().bright_blue(),
69-
" ".bright_blue(),
70-
response.title.bright_blue().italic()
71-
),
72-
&response.html_url
73-
),
65+
crate::utils::format_pr(pr, &response.title, &response.html_url),
7466
info.branch.local_branch_name.as_ref().bright_cyan(),
7567
commit
7668
.clone()

src/commands/run.rs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use anyhow::{anyhow, bail};
1010
use colored::Colorize as _;
1111

1212
use crate::git_high_level;
13-
use crate::github_api::{self, Branch, Remote, RemoteBranch};
14-
use crate::utils::{display_link, with_uuid};
13+
use crate::github::{self, Branch, Remote, RemoteBranch};
14+
use crate::utils::{format_pr, format_url, with_uuid};
1515
use crate::{commands, confirm_prompt, git};
1616

1717
/// Backup for a file
@@ -23,7 +23,7 @@ struct FileBackup {
2323
}
2424

2525
/// Run patchy, if `yes` then there will be no prompt
26-
pub async fn run(yes: bool) -> anyhow::Result<()> {
26+
pub async fn run(yes: bool, use_gh_cli: bool) -> anyhow::Result<()> {
2727
let root = config::ROOT.as_str();
2828

2929
let Ok(config_string) = fs::read_to_string(&*config::FILE_PATH) else {
@@ -140,7 +140,7 @@ pub async fn run(yes: bool) -> anyhow::Result<()> {
140140
if config.pull_requests.is_empty() && config.branches.is_empty() {
141141
log::warn!(
142142
"You haven't specified any pull requests or branches to fetch in your config, {}",
143-
display_link(
143+
format_url(
144144
"see the instructions on how to configure patchy.",
145145
"https://github.com/nik-rev/patchy?tab=readme-ov-file#config"
146146
)
@@ -157,13 +157,17 @@ pub async fn run(yes: bool) -> anyhow::Result<()> {
157157
} in &config.pull_requests
158158
{
159159
// TODO: refactor this to not use such deep nesting
160-
let Ok((response, info)) =
161-
github_api::fetch_pull_request(&config.repo, *pull_request, None, commit.as_ref())
162-
.await
163-
.inspect_err(|err| {
164-
log::error!("failed to fetch branch from remote:\n{err}");
165-
})
166-
else {
160+
let Ok((response, info)) = github::fetch_pull_request(
161+
&config.repo,
162+
*pull_request,
163+
None,
164+
commit.as_ref(),
165+
use_gh_cli,
166+
)
167+
.await
168+
.inspect_err(|err| {
169+
log::error!("failed to fetch branch from remote:\n{err}");
170+
}) else {
167171
continue;
168172
};
169173

@@ -179,16 +183,7 @@ pub async fn run(yes: bool) -> anyhow::Result<()> {
179183

180184
log::info!(
181185
"Merged pull request {}",
182-
display_link(
183-
&format!(
184-
"{}{}{}{}",
185-
"#".bright_blue(),
186-
pull_request.to_string().bright_blue(),
187-
" ".bright_blue(),
188-
&response.title.bright_blue().italic()
189-
),
190-
&response.html_url
191-
),
186+
format_pr(*pull_request, &response.title, &response.html_url),
192187
);
193188
}
194189

@@ -197,9 +192,12 @@ pub async fn run(yes: bool) -> anyhow::Result<()> {
197192
let owner = &remote.owner;
198193
let repo = &remote.repo;
199194
let branch = &remote.branch;
200-
let Ok((_, info)) = github_api::fetch_branch(remote).await.inspect_err(|err| {
201-
log::error!("failed to fetch branch {owner}/{repo}/{branch}: {err}");
202-
}) else {
195+
let Ok((_, info)) = github::fetch_branch(remote, use_gh_cli)
196+
.await
197+
.inspect_err(|err| {
198+
log::error!("failed to fetch branch {owner}/{repo}/{branch}: {err}");
199+
})
200+
else {
203201
continue;
204202
};
205203

src/git_high_level.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use crate::git;
1010
use anyhow::{Result, anyhow, bail};
1111
use colored::Colorize as _;
1212

13-
use crate::github_api::RemoteBranch;
14-
use crate::utils::display_link;
13+
use crate::github::RemoteBranch;
14+
use crate::utils::{format_pr, format_url};
1515

1616
/// Fetches a branch of a remote into local. Optionally accepts a commit hash
1717
/// for versioning.
@@ -79,18 +79,9 @@ pub fn merge_pull_request(
7979
&info.branch.upstream_branch_name,
8080
)
8181
.map_err(|err| {
82-
let pr = display_link(
83-
&format!(
84-
"{}{}{}{}",
85-
"#".bright_blue(),
86-
pull_request.to_string().bright_blue(),
87-
" ".bright_blue(),
88-
pr_title.bright_blue().italic()
89-
),
90-
pr_url,
91-
);
82+
let pr = format_pr(pull_request, pr_title, pr_url);
9283

93-
let support_url = display_link(
84+
let support_url = format_url(
9485
"Merge conflicts (github)",
9586
"https://github.com/nik-rev/patchy?tab=readme-ov-file#merge-conflicts",
9687
)

src/github_api.rs renamed to src/github.rs

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
reason = "GitHub API is self-explanatory"
55
)]
66

7+
use std::process;
8+
79
use serde::{Deserialize, Serialize};
10+
use tap::Pipe as _;
811

912
use crate::{
1013
config::{BranchName, CommitId, PrNumber},
@@ -50,23 +53,38 @@ pub struct RemoteBranch {
5053
pub branch: Branch,
5154
}
5255

53-
/// Fetch the branch of `remote` at the given `commit`
54-
pub async fn fetch_branch(remote: &crate::config::Remote) -> Result<(Repo, RemoteBranch)> {
55-
let url = format!(
56-
"https://api.github.com/repos/{}/{}",
57-
remote.owner, remote.repo
58-
);
56+
/// Make a request to GitHub's API.
57+
///
58+
/// Either manually fetch the URL or use `gh` CLI
59+
async fn gh_api(url: &str, use_gh_cli: bool) -> Result<String> {
60+
if use_gh_cli {
61+
process::Command::new("gh")
62+
.arg("api")
63+
.arg(url)
64+
.output()?
65+
.stdout
66+
.pipe(String::from_utf8)?
67+
.pipe(Ok)
68+
} else {
69+
make_request(url).await
70+
}
71+
}
5972

60-
let response = make_request(&url).await.map_err(|err| {
61-
anyhow!(
62-
"Could not fetch branch: {}/{}\n{err}\n",
63-
remote.owner,
64-
remote.repo
65-
)
66-
})?;
73+
/// Fetch the branch of `remote` at the given `commit`
74+
pub async fn fetch_branch(
75+
remote: &crate::config::Remote,
76+
use_gh_cli: bool,
77+
) -> Result<(Repo, RemoteBranch)> {
78+
let owner = &remote.owner;
79+
let repo = &remote.repo;
80+
let url = format!("https://api.github.com/repos/{owner}/{repo}",);
81+
82+
let response = gh_api(&url, use_gh_cli)
83+
.await
84+
.map_err(|err| anyhow!("failed to fetch branch `{owner}/{repo}`:\n{err}\n"))?;
6785

6886
let response: Repo = serde_json::from_str(&response).map_err(|err| {
69-
anyhow!("Could not parse response.\n{response}. Could not parse because: \n{err}")
87+
anyhow!("failed to parse response.\n{response}. failed to parse because: \n{err}")
7088
})?;
7189

7290
let info = RemoteBranch {
@@ -98,15 +116,25 @@ pub async fn fetch_pull_request(
98116
pull_request: PrNumber,
99117
custom_branch_name: Option<BranchName>,
100118
commit_hash: Option<&CommitId>,
119+
use_gh_cli: bool,
101120
) -> Result<(GitHubResponse, RemoteBranch)> {
102121
let url = format!("https://api.github.com/repos/{repo}/pulls/{pull_request}");
103122

104-
let response = make_request(&url)
105-
.await
106-
.map_err(|err| anyhow!("failed to fetch pull request #{pull_request}\n{err}\n"))?;
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+
};
107135

108-
let response: GitHubResponse = serde_json::from_str(&response).map_err(|err| {
109-
anyhow!("failed to parse GitHub response.\n{response}. Could not parse because: \n{err}")
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}")
110138
})?;
111139

112140
let remote_branch = RemoteBranch {

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ mod commands;
77
mod config;
88
mod git;
99
mod git_high_level;
10-
mod github_api;
10+
mod github;
1111
mod utils;
1212

1313
pub use cli::Cli;

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ async fn main() -> ExitCode {
1111
.filter_level(args.verbosity.into())
1212
.init();
1313

14-
if let Err(err) = args.command.execute().await {
14+
if let Err(err) = args.command.execute(args.use_gh_cli).await {
1515
log::error!("{err}");
1616
ExitCode::FAILURE
1717
} else {

0 commit comments

Comments
 (0)