Show uv self update success and failure messages with --quiet (#18645)
With -q, suppress informational messages but still show when an update actually happens. With -qq, suppress all output. Closes #18412 ## Summary Adds `stderr_important()` to `Printer` which is only suppressed with `-qq` (silent), not `-q` (quiet). Uses this for the update success message in `uv self update` so cron users can run with `-q` and only get notified when an update actually occurs. ## Test Plan A set of new tests. --------- Co-authored-by: Tomasz (Tom) Kramkowski <tom@astral.sh>
This commit is contained in:
@@ -582,6 +582,16 @@ impl TestContext {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a (not context aware) filter for the current uv version `v<major>.<minor>.<patch>`
|
||||
#[must_use]
|
||||
pub fn with_filtered_current_version(mut self) -> Self {
|
||||
self.filters.push((
|
||||
regex::escape(&format!("v{}", env!("CARGO_PKG_VERSION"))),
|
||||
"v[CURRENT_VERSION]".to_string(),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds filters for non-deterministic `CycloneDX` data
|
||||
#[must_use]
|
||||
pub fn with_cyclonedx_filters(mut self) -> Self {
|
||||
|
||||
@@ -24,7 +24,7 @@ pub(crate) async fn self_update(
|
||||
) -> Result<ExitStatus> {
|
||||
if client_builder.is_offline() {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
printer.stderr_important(),
|
||||
"{}",
|
||||
format_args!(
|
||||
"{}{} Self-update is not possible because network connectivity is disabled (i.e., with `--offline`)",
|
||||
@@ -47,7 +47,7 @@ pub(crate) async fn self_update(
|
||||
let Ok(updater) = updater.load_receipt() else {
|
||||
debug!("No receipt found; assuming uv was installed via a package manager");
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
printer.stderr_important(),
|
||||
"{}",
|
||||
format_args!(
|
||||
concat!(
|
||||
@@ -79,7 +79,7 @@ pub(crate) async fn self_update(
|
||||
let receipt_prefix = updater.install_prefix_root()?;
|
||||
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
printer.stderr_important(),
|
||||
"{}",
|
||||
format_args!(
|
||||
concat!(
|
||||
@@ -152,7 +152,7 @@ pub(crate) async fn self_update(
|
||||
|
||||
if dry_run {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
printer.stderr_important(),
|
||||
"Would update uv from {} to {}",
|
||||
format!("v{}", env!("CARGO_PKG_VERSION")).bold().white(),
|
||||
format!("v{}", resolved.version).bold().white(),
|
||||
@@ -188,7 +188,7 @@ pub(crate) async fn self_update(
|
||||
}
|
||||
};
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
printer.stderr_important(),
|
||||
"Would update uv from {} to {}",
|
||||
format!("v{}", env!("CARGO_PKG_VERSION")).bold().white(),
|
||||
version.bold().white(),
|
||||
@@ -309,7 +309,7 @@ async fn run_updater(
|
||||
};
|
||||
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
printer.stderr_important(),
|
||||
"{}",
|
||||
format_args!(
|
||||
"{}{} {direction} uv {}! {}",
|
||||
@@ -340,7 +340,7 @@ async fn run_updater(
|
||||
return if let AxoupdateError::Reqwest(err) = err {
|
||||
if err.status() == Some(http::StatusCode::FORBIDDEN) && !has_token {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
printer.stderr_important(),
|
||||
"{}",
|
||||
format_args!(
|
||||
"{}{} GitHub API rate limit exceeded. Please provide a GitHub token via the {} option.",
|
||||
|
||||
@@ -52,6 +52,17 @@ impl Printer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the [`Stderr`] for this printer.
|
||||
pub(crate) fn stderr_important(self) -> Stderr {
|
||||
match self {
|
||||
Self::Silent => Stderr::Disabled,
|
||||
Self::Quiet => Stderr::Enabled,
|
||||
Self::Default => Stderr::Enabled,
|
||||
Self::Verbose => Stderr::Enabled,
|
||||
Self::NoProgress => Stderr::Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the [`Stderr`] for this printer.
|
||||
pub(crate) fn stderr(self) -> Stderr {
|
||||
match self {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::process::Command;
|
||||
use std::{path::PathBuf, process::Command};
|
||||
|
||||
use anyhow::Result;
|
||||
use assert_fs::prelude::*;
|
||||
@@ -6,14 +6,13 @@ use axoupdater::{
|
||||
ReleaseSourceType,
|
||||
test::helpers::{RuntestArgs, perform_runtest},
|
||||
};
|
||||
use regex::escape;
|
||||
use serde_json::json;
|
||||
use wiremock::matchers::{method, path};
|
||||
use wiremock::{Mock, MockServer, ResponseTemplate};
|
||||
|
||||
use uv_static::EnvVars;
|
||||
|
||||
use uv_test::{get_bin, uv_snapshot};
|
||||
use uv_test::{TestContext, get_bin, uv_snapshot};
|
||||
|
||||
#[test]
|
||||
fn check_self_update() {
|
||||
@@ -50,7 +49,7 @@ fn check_self_update() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_self_update_offline_error() {
|
||||
fn self_update_offline_error() {
|
||||
let context = uv_test::test_context!("3.12");
|
||||
|
||||
uv_snapshot!(context.self_update().arg("--offline"),
|
||||
@@ -64,13 +63,41 @@ fn test_self_update_offline_error() {
|
||||
");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_self_update_uses_legacy_path_with_ghe_override() -> Result<()> {
|
||||
let context = uv_test::test_context!("3.12").with_filter((
|
||||
escape(&format!("v{}", env!("CARGO_PKG_VERSION"))),
|
||||
"v[CURRENT_VERSION]",
|
||||
));
|
||||
#[test]
|
||||
fn self_update_offline_quiet() {
|
||||
let context = uv_test::test_context!("3.12");
|
||||
|
||||
uv_snapshot!(context.self_update().arg("--offline").arg("--quiet"),
|
||||
@r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Self-update is not possible because network connectivity is disabled (i.e., with `--offline`)
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn self_update_offline_extra_quiet() {
|
||||
let context = uv_test::test_context!("3.12");
|
||||
|
||||
uv_snapshot!(context.self_update().arg("--offline").arg("--quiet").arg("--quiet"),
|
||||
@r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
");
|
||||
}
|
||||
|
||||
/// Set up a fake receipt and a mock update metadata endpoint to allow
|
||||
/// simulating an update with `--dry-run`.
|
||||
async fn setup_mock_update(
|
||||
context: &TestContext,
|
||||
target_version: &str,
|
||||
) -> Result<(PathBuf, MockServer)> {
|
||||
let receipt_dir = context.temp_dir.child("receipt");
|
||||
receipt_dir.create_dir_all()?;
|
||||
|
||||
@@ -100,7 +127,6 @@ async fn test_self_update_uses_legacy_path_with_ghe_override() -> Result<()> {
|
||||
}))?)?;
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let target_version = "9.9.9";
|
||||
let installer_name = if cfg!(windows) {
|
||||
"uv-installer.ps1"
|
||||
} else {
|
||||
@@ -124,6 +150,16 @@ async fn test_self_update_uses_legacy_path_with_ghe_override() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
Ok((receipt_dir.to_path_buf(), server))
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_self_update_uses_legacy_path_with_ghe_override() -> Result<()> {
|
||||
let context = uv_test::test_context!("3.12").with_filtered_current_version();
|
||||
|
||||
let target_version = "9.9.9";
|
||||
let (receipt_dir, server) = setup_mock_update(&context, target_version).await?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.self_update()
|
||||
.arg(target_version)
|
||||
.arg("--dry-run")
|
||||
@@ -140,3 +176,101 @@ async fn test_self_update_uses_legacy_path_with_ghe_override() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn self_update_dry_run_quiet() -> Result<()> {
|
||||
let context = uv_test::test_context!("3.12").with_filtered_current_version();
|
||||
|
||||
let target_version = "9.9.9";
|
||||
let (receipt_dir, server) = setup_mock_update(&context, target_version).await?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.self_update()
|
||||
.arg(target_version)
|
||||
.arg("--dry-run")
|
||||
.arg("--quiet")
|
||||
.env("AXOUPDATER_CONFIG_PATH", receipt_dir.as_os_str())
|
||||
.env(EnvVars::UV_INSTALLER_GHE_BASE_URL, server.uri()), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Would update uv from v[CURRENT_VERSION] to v9.9.9
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn self_update_dry_run_extra_quiet() -> Result<()> {
|
||||
let context = uv_test::test_context!("3.12");
|
||||
|
||||
let receipt_dir = context.temp_dir.child("receipt");
|
||||
receipt_dir.create_dir_all()?;
|
||||
|
||||
let target_version = "9.9.9";
|
||||
let (receipt_dir, server) = setup_mock_update(&context, target_version).await?;
|
||||
|
||||
uv_snapshot!(context.self_update()
|
||||
.arg(target_version)
|
||||
.arg("--dry-run")
|
||||
.arg("--quiet")
|
||||
.arg("--quiet")
|
||||
.env("AXOUPDATER_CONFIG_PATH", receipt_dir.as_os_str())
|
||||
.env(EnvVars::UV_INSTALLER_GHE_BASE_URL, server.uri()), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn self_update_noop_dry_run() -> Result<()> {
|
||||
let context = uv_test::test_context!("3.12").with_filtered_current_version();
|
||||
|
||||
let target_version = env!("CARGO_PKG_VERSION");
|
||||
let (receipt_dir, server) = setup_mock_update(&context, target_version).await?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.self_update()
|
||||
.arg(target_version)
|
||||
.arg("--dry-run")
|
||||
.env("AXOUPDATER_CONFIG_PATH", receipt_dir.as_os_str())
|
||||
.env(EnvVars::UV_INSTALLER_GHE_BASE_URL, server.uri()), @"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
info: Checking for updates...
|
||||
You're on the latest version of uv (v[CURRENT_VERSION])
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn self_update_noop_dry_run_quiet() -> Result<()> {
|
||||
let context = uv_test::test_context!("3.12").with_filtered_current_version();
|
||||
|
||||
let target_version = env!("CARGO_PKG_VERSION");
|
||||
let (receipt_dir, server) = setup_mock_update(&context, target_version).await?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.self_update()
|
||||
.arg(target_version)
|
||||
.arg("--dry-run")
|
||||
.arg("--quiet")
|
||||
.env("AXOUPDATER_CONFIG_PATH", receipt_dir.as_os_str())
|
||||
.env(EnvVars::UV_INSTALLER_GHE_BASE_URL, server.uri()), @"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user