Skip to content

Commit

Permalink
feat(cli): add --token option to self update command (#7279)
Browse files Browse the repository at this point in the history
<!--
Thank you for contributing to uv! To help us out with reviewing, please
consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

It often reaches the GitHub API rate limit and shows error like `error:
HTTP status client error (403 Forbidden) for url
(https://api.github.com/repos/astral-sh/uv/releases)` when running `uv
self update`.

To bypass this rate limit issue, allow user to pass a GitHub token via
`--token` or `UV_GITHUB_TOKEN` env.

## Test Plan

<!-- How was it tested? -->

---------

Signed-off-by: Frost Ming <me@frostming.com>
  • Loading branch information
frostming committed Sep 12, 2024
1 parent 3d2b94f commit e1e85ab
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 7 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,11 @@ pub enum SelfCommand {
pub struct SelfUpdateArgs {
/// Update to the specified version. If not provided, uv will update to the latest version.
pub target_version: Option<String>,

/// A GitHub token for authentication.
/// A token is not required but can be used to reduce the chance of encountering rate limits.
#[arg(long, env = "UV_GITHUB_TOKEN")]
pub token: Option<String>,
}

#[derive(Args)]
Expand Down
1 change: 1 addition & 0 deletions crates/uv/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ ctrlc = { workspace = true }
flate2 = { workspace = true, default-features = false }
fs-err = { workspace = true, features = ["tokio"] }
futures = { workspace = true }
http = { workspace = true }
indexmap = { workspace = true }
indicatif = { workspace = true }
indoc = { workspace = true }
Expand Down
32 changes: 27 additions & 5 deletions crates/uv/src/commands/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ use crate::commands::ExitStatus;
use crate::printer::Printer;

/// Attempt to update the uv binary.
pub(crate) async fn self_update(version: Option<String>, printer: Printer) -> Result<ExitStatus> {
pub(crate) async fn self_update(
version: Option<String>,
token: Option<String>,
printer: Printer,
) -> Result<ExitStatus> {
let mut updater = AxoUpdater::new_for("uv");
updater.disable_installer_output();

if let Some(ref token) = token {
updater.set_github_token(token);
}

// Load the "install receipt" for the current binary. If the receipt is not found, then
// uv was likely installed via a package manager.
let Ok(updater) = updater.load_receipt() else {
Expand Down Expand Up @@ -121,11 +129,25 @@ pub(crate) async fn self_update(version: Option<String>, printer: Printer) -> Re
)?;
}
Err(err) => {
return Err(if let AxoupdateError::Reqwest(err) = err {
WrappedReqwestError::from(err).into()
return if let AxoupdateError::Reqwest(err) = err {
if err.status() == Some(http::StatusCode::FORBIDDEN) && token.is_none() {
writeln!(
printer.stderr(),
"{}",
format_args!(
"{}{} GitHub API rate limit exceeded. Please provide a GitHub token via the {} option.",
"error".red().bold(),
":".bold(),
"`--token`".green().bold()
)
)?;
Ok(ExitStatus::Error)
} else {
Err(WrappedReqwestError::from(err).into())
}
} else {
err.into()
});
Err(err.into())
};
}
}

Expand Down
8 changes: 6 additions & 2 deletions crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,8 +766,12 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
}
#[cfg(feature = "self-update")]
Commands::Self_(SelfNamespace {
command: SelfCommand::Update(SelfUpdateArgs { target_version }),
}) => commands::self_update(target_version, printer).await,
command:
SelfCommand::Update(SelfUpdateArgs {
target_version,
token,
}),
}) => commands::self_update(target_version, token, printer).await,
Commands::Version { output_format } => {
commands::version(output_format, &mut stdout())?;
Ok(ExitStatus::Success)
Expand Down

0 comments on commit e1e85ab

Please sign in to comment.