aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/repository/vcs/github_driver.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-18 07:18:07 +0900
committernsfisis <nsfisis@gmail.com>2026-08-18 07:18:07 +0900
commit6a7e64d04a8b0ad932169df43e2d93efe8ceedf8 (patch)
treef74bca82b226fde11c820ba3988e094a49073940 /crates/shirabe/src/repository/vcs/github_driver.rs
parentbed0cd33ca32b95aed9d65891f97649a6f9d0069 (diff)
downloadphp-shirabe-6a7e64d04a8b0ad932169df43e2d93efe8ceedf8.tar.gz
php-shirabe-6a7e64d04a8b0ad932169df43e2d93efe8ceedf8.tar.zst
php-shirabe-6a7e64d04a8b0ad932169df43e2d93efe8ceedf8.zip
fix: propagate ported exceptions instead of flattening them
`ProcessExecutor::execute_args` existed only to turn `execute`'s `anyhow::Result` into an exit code of 1, so every one of its ~87 call sites silently took the "command failed" branch on an error PHP would have thrown. It is gone; callers use `execute` and propagate with `?`. Where the enclosing function had no `Result` to propagate into, its signature grew one, up to and including `Git::get_version`, `Svn::binary_version`, `GitHub`/`GitLab`/`Bitbucket::authorize_oauth`, `InitCommand::get_git_config` and `DiagnoseCommand::check_git`. The VCS drivers had the same problem in the other direction: their `get_contents` returned `Result<Response, Box<TransportException>>`, a type too narrow for the PHP method, which lets any Throwable out of the `catch (TransportException $e)` block. Every non-transport error was therefore rewritten into a `TransportException` with code 0, which the callers switch on. They now return `anyhow::Result<Result<Response, Box<TransportException>>>`: the outer `Result` carries what PHP does not catch, the inner one the exception the drivers handle. That signature also restores `GitLabDriver::getContents`: the 400/401 `TransportException`s it raises to force authentication are thrown inside its own `try` block and handled by its own `catch`, but the port returned them straight to the caller, so the authentication flow behind them never ran. `impl_php_exception!` gains `From<Box<$ty>> for anyhow::Error` so a caught exception can be re-propagated with `?`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/repository/vcs/github_driver.rs')
-rw-r--r--crates/shirabe/src/repository/vcs/github_driver.rs64
1 files changed, 24 insertions, 40 deletions
diff --git a/crates/shirabe/src/repository/vcs/github_driver.rs b/crates/shirabe/src/repository/vcs/github_driver.rs
index c41cc2d0..f2b2d458 100644
--- a/crates/shirabe/src/repository/vcs/github_driver.rs
+++ b/crates/shirabe/src/repository/vcs/github_driver.rs
@@ -696,10 +696,7 @@ impl GitHubDriver {
file,
urlencode(identifier)
);
- let mut resource = self
- .get_contents(&resource_url, false)
- .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?
- .decode_json()?;
+ let mut resource = self.get_contents(&resource_url, false)??.decode_json()?;
// The GitHub contents API only returns files up to 1MB as base64 encoded files
// larger files either need be fetched with a raw accept header or by using the git blob endpoint
@@ -724,10 +721,7 @@ impl GitHubDriver {
.and_then(|v| v.as_string())
.unwrap_or("")
.to_string();
- resource = self
- .get_contents(&git_url, false)
- .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?
- .decode_json()?;
+ resource = self.get_contents(&git_url, false)??.decode_json()?;
}
let resource_map = match resource {
@@ -776,10 +770,7 @@ impl GitHubDriver {
self.repository,
urlencode(identifier)
);
- let commit = self
- .get_contents(&resource, false)
- .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?
- .decode_json()?;
+ let commit = self.get_contents(&resource, false)??.decode_json()?;
let date_str = match commit {
PhpMixed::Array(m) => m
@@ -812,9 +803,7 @@ impl GitHubDriver {
));
loop {
- let response = self
- .get_contents(resource.as_deref().unwrap_or(""), false)
- .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?;
+ let response = self.get_contents(resource.as_deref().unwrap_or(""), false)??;
let tags_data = response.decode_json()?;
if let PhpMixed::List(ref list) = tags_data {
for tag in list {
@@ -862,9 +851,7 @@ impl GitHubDriver {
));
loop {
- let response = self
- .get_contents(resource.as_deref().unwrap_or(""), false)
- .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?;
+ let response = self.get_contents(resource.as_deref().unwrap_or(""), false)??;
let branch_data = response.decode_json()?;
if let PhpMixed::List(ref list) = branch_data {
for branch in list {
@@ -969,40 +956,38 @@ impl GitHubDriver {
&mut self,
url: &str,
fetching_repo_data: bool,
- ) -> anyhow::Result<Response, Box<TransportException>> {
- let response_result = self.inner.get_contents(url);
+ ) -> anyhow::Result<Result<Response, Box<TransportException>>> {
+ let response_result = self.inner.get_contents(url)?;
match response_result {
- Ok(r) => Ok(r),
+ Ok(r) => Ok(Ok(r)),
Err(e) => {
let mut git_hub_util = GitHub::new(
self.inner.io.clone(),
self.inner.config.clone(),
Some(self.inner.process.clone()),
Some(self.inner.http_downloader.clone()),
- )
- .map_err(|err| TransportException::new(err.to_string(), 0))?;
+ )?;
match e.get_code() {
401 | 404 => {
// try to authorize only if we are fetching the main /repos/foo/bar data, otherwise it must be a real 404
if !fetching_repo_data {
- return Err(e);
+ return Ok(Err(e));
}
- if git_hub_util.authorize_oauth(&self.inner.origin_url) {
+ if git_hub_util.authorize_oauth(&self.inner.origin_url)? {
return self.inner.get_contents(url);
}
if !self.inner.io.is_interactive() {
- self.attempt_clone_fallback(Some(std::sync::Arc::new((*e).into())))
- .map_err(|err| TransportException::new(err.to_string(), 0))?;
+ self.attempt_clone_fallback(Some(std::sync::Arc::new((*e).into())))?;
- return Ok(Response::new(
+ return Ok(Ok(Response::new(
"dummy".to_string(),
Some(200),
vec![],
Some("null".to_string()),
- ));
+ )));
}
let mut scopes_issued: Vec<String> = vec![];
@@ -1033,28 +1018,27 @@ impl GitHubDriver {
"Your GitHub credentials are required to fetch private repository metadata (<info>{}</info>)",
self.inner.url
)),
- );
+ )?;
}
self.inner.get_contents(url)
}
403 => {
if !self.inner.io.has_authentication(&self.inner.origin_url)
- && git_hub_util.authorize_oauth(&self.inner.origin_url)
+ && git_hub_util.authorize_oauth(&self.inner.origin_url)?
{
return self.inner.get_contents(url);
}
if !self.inner.io.is_interactive() && fetching_repo_data {
- self.attempt_clone_fallback(Some(std::sync::Arc::new((*e).into())))
- .map_err(|err| TransportException::new(err.to_string(), 0))?;
+ self.attempt_clone_fallback(Some(std::sync::Arc::new((*e).into())))?;
- return Ok(Response::new(
+ return Ok(Ok(Response::new(
"dummy".to_string(),
Some(200),
vec![],
Some("null".to_string()),
- ));
+ )));
}
let rate_limited = git_hub_util
@@ -1070,7 +1054,7 @@ impl GitHubDriver {
true,
io_interface::NORMAL,
);
- return Err(e);
+ return Ok(Err(e));
}
git_hub_util.authorize_oauth_interactively(
@@ -1079,7 +1063,7 @@ impl GitHubDriver {
"API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>{}</info>)",
self.inner.url
)),
- );
+ )?;
return self.inner.get_contents(url);
}
@@ -1099,9 +1083,9 @@ impl GitHubDriver {
);
}
- Err(e)
+ Ok(Err(e))
}
- _ => Err(e),
+ _ => Ok(Err(e)),
}
}
}
@@ -1122,7 +1106,7 @@ impl GitHubDriver {
self.repository
);
- let repo_data_result = self.get_contents(&repo_data_url, true);
+ let repo_data_result = self.get_contents(&repo_data_url, true)?;
match repo_data_result {
Ok(response) => {
let data = response.decode_json()?;