Skip to content

Commit

Permalink
Show full error chain on tool upgrade failures (astral-sh#8753)
Browse files Browse the repository at this point in the history
As reported in astral-sh#8555
  • Loading branch information
zanieb authored Nov 2, 2024
1 parent d3e50a2 commit 2ed9474
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 28 deletions.
38 changes: 23 additions & 15 deletions crates/uv/src/commands/tool/upgrade.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{collections::BTreeSet, fmt::Write};

use anyhow::Result;
use itertools::Itertools;
use owo_colors::OwoColorize;
use tracing::debug;

Expand Down Expand Up @@ -95,9 +96,7 @@ pub(crate) async fn upgrade(
// Determine whether we applied any upgrades.
let mut did_upgrade_environment = vec![];

// Determine whether any tool upgrade failed.
let mut failed_upgrade = false;

let mut errors = Vec::new();
for name in &names {
debug!("Upgrading tool: `{name}`");
let result = upgrade_tool(
Expand Down Expand Up @@ -125,22 +124,31 @@ pub(crate) async fn upgrade(
debug!("Upgrading `{name}` was a no-op");
}
Err(err) => {
// If we have a single tool, return the error directly.
if names.len() > 1 {
writeln!(
printer.stderr(),
"Failed to upgrade `{}`: {err}",
name.cyan(),
)?;
} else {
writeln!(printer.stderr(), "{err}")?;
}
failed_upgrade = true;
errors.push((name, err));
}
}
}

if failed_upgrade {
if !errors.is_empty() {
for (name, err) in errors
.into_iter()
.sorted_unstable_by(|(name_a, _), (name_b, _)| name_a.cmp(name_b))
{
writeln!(
printer.stderr(),
"{}: Failed to upgrade {}",
"error".red().bold(),
name.green()
)?;
for err in err.chain() {
writeln!(
printer.stderr(),
" {}: {}",
"Caused by".red().bold(),
err.to_string().trim()
)?;
}
}
return Ok(ExitStatus::Failure);
}

Expand Down
28 changes: 15 additions & 13 deletions crates/uv/tests/it/tool_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use uv_static::EnvVars;
use crate::common::{uv_snapshot, TestContext};

#[test]
fn test_tool_upgrade_name() {
fn tool_upgrade_name() {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -56,7 +56,7 @@ fn test_tool_upgrade_name() {
}

#[test]
fn test_tool_upgrade_multiple_names() {
fn tool_upgrade_multiple_names() {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -131,7 +131,7 @@ fn test_tool_upgrade_multiple_names() {
}

#[test]
fn test_tool_upgrade_all() {
fn tool_upgrade_all() {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -205,7 +205,7 @@ fn test_tool_upgrade_all() {
}

#[test]
fn test_tool_upgrade_non_existing_package() {
fn tool_upgrade_non_existing_package() {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand All @@ -223,7 +223,8 @@ fn test_tool_upgrade_non_existing_package() {
----- stdout -----
----- stderr -----
`black` is not installed; run `uv tool install black` to install
error: Failed to upgrade black
Caused by: `black` is not installed; run `uv tool install black` to install
"###);

// Attempt to upgrade all.
Expand All @@ -242,7 +243,7 @@ fn test_tool_upgrade_non_existing_package() {
}

#[test]
fn test_tool_upgrade_not_stop_if_upgrade_fails() -> anyhow::Result<()> {
fn tool_upgrade_not_stop_if_upgrade_fails() -> anyhow::Result<()> {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -314,14 +315,15 @@ fn test_tool_upgrade_not_stop_if_upgrade_fails() -> anyhow::Result<()> {
+ babel==2.14.0
- pytz==2018.5
Installed 1 executable: pybabel
Failed to upgrade `python-dotenv`: `python-dotenv` is missing a valid receipt; run `uv tool install --force python-dotenv` to reinstall
error: Failed to upgrade python-dotenv
Caused by: `python-dotenv` is missing a valid receipt; run `uv tool install --force python-dotenv` to reinstall
"###);

Ok(())
}

#[test]
fn test_tool_upgrade_settings() {
fn tool_upgrade_settings() {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -386,7 +388,7 @@ fn test_tool_upgrade_settings() {
}

#[test]
fn test_tool_upgrade_respect_constraints() {
fn tool_upgrade_respect_constraints() {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -437,7 +439,7 @@ fn test_tool_upgrade_respect_constraints() {
}

#[test]
fn test_tool_upgrade_constraint() {
fn tool_upgrade_constraint() {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -530,7 +532,7 @@ fn test_tool_upgrade_constraint() {
/// Upgrade a tool, but only by upgrading one of it's `--with` dependencies, and not the tool
/// itself.
#[test]
fn test_tool_upgrade_with() {
fn tool_upgrade_with() {
let context = TestContext::new("3.12")
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -578,7 +580,7 @@ fn test_tool_upgrade_with() {
}

#[test]
fn test_tool_upgrade_python() {
fn tool_upgrade_python() {
let context = TestContext::new_with_versions(&["3.11", "3.12"])
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down Expand Up @@ -639,7 +641,7 @@ fn test_tool_upgrade_python() {
}

#[test]
fn test_tool_upgrade_python_with_all() {
fn tool_upgrade_python_with_all() {
let context = TestContext::new_with_versions(&["3.11", "3.12"])
.with_filtered_counts()
.with_filtered_exe_suffix();
Expand Down

0 comments on commit 2ed9474

Please sign in to comment.