This commit is contained in:
Aria Desires 2025-07-05 09:22:55 +08:00 committed by GitHub
commit 41d7f125d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 1338 additions and 50 deletions

View file

@ -532,8 +532,11 @@ pub struct VersionArgs {
pub value: Option<String>, pub value: Option<String>,
/// Update the project version using the given semantics /// Update the project version using the given semantics
///
/// This flag can be passed multiple times to allow going to a new release and entering
/// a prerelease: `--bump patch --bump beta`
#[arg(group = "operation", long)] #[arg(group = "operation", long)]
pub bump: Option<VersionBump>, pub bump: Vec<VersionBump>,
/// Don't write a new version to the `pyproject.toml` /// Don't write a new version to the `pyproject.toml`
/// ///
@ -608,7 +611,9 @@ pub struct VersionArgs {
pub python: Option<Maybe<String>>, pub python: Option<Maybe<String>>,
} }
#[derive(Debug, Copy, Clone, PartialEq, clap::ValueEnum)] // Note that the ordering of the variants is significant, as when given a list of operations
// to perform, we sort them and apply them in order, so users don't have to think too hard about it.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
pub enum VersionBump { pub enum VersionBump {
/// Increase the major version (1.2.3 => 2.0.0) /// Increase the major version (1.2.3 => 2.0.0)
Major, Major,
@ -616,6 +621,37 @@ pub enum VersionBump {
Minor, Minor,
/// Increase the patch version (1.2.3 => 1.2.4) /// Increase the patch version (1.2.3 => 1.2.4)
Patch, Patch,
/// Make the version stable (1.2.3b4.post5.dev6 => 1.2.3)
///
/// This intentionally clears `.postN` and preserves `+local`
Stable,
/// Increase the alpha version (1.2.3a4 => 1.2.3a5)
Alpha,
/// Increase the beta version (1.2.3b4 => 1.2.3b5)
Beta,
/// Increase the rc version (1.2.3rc4 => 1.2.3rc5)
Rc,
/// Increase the post version (1.2.3.post5 => 1.2.3.post6)
Post,
/// Increase the dev version (1.2.3a4.dev6 => 1.2.3.dev7)
Dev,
}
impl std::fmt::Display for VersionBump {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let string = match self {
VersionBump::Major => "major",
VersionBump::Minor => "minor",
VersionBump::Patch => "patch",
VersionBump::Stable => "stable",
VersionBump::Alpha => "alpha",
VersionBump::Beta => "beta",
VersionBump::Rc => "rc",
VersionBump::Post => "post",
VersionBump::Dev => "dev",
};
string.fmt(f)
}
} }
#[derive(Args)] #[derive(Args)]

View file

@ -29,8 +29,8 @@ pub use version_ranges::{
}; };
pub use { pub use {
version::{ version::{
LocalSegment, LocalVersion, LocalVersionSlice, MIN_VERSION, Operator, OperatorParseError, BumpCommand, LocalSegment, LocalVersion, LocalVersionSlice, MIN_VERSION, Operator,
Prerelease, PrereleaseKind, Version, VersionParseError, VersionPattern, OperatorParseError, Prerelease, PrereleaseKind, Version, VersionParseError, VersionPattern,
VersionPatternParseError, VersionPatternParseError,
}, },
version_specifier::{ version_specifier::{

View file

@ -643,6 +643,90 @@ impl Version {
self.with_release(release) self.with_release(release)
} }
/// Various "increment the version" operations
pub fn bump(&mut self, bump: BumpCommand) {
// This code operates on the understanding that the components of a version form
// the following hierarchy:
//
// major > minor > patch > stable > pre > post > dev
//
// Any updates to something earlier in the hierarchy should clear all values lower
// in the hierarchy. So for instance:
//
// if you bump `minor`, then clear: patch, pre, post, dev
// if you bump `pre`, then clear: post, dev
//
// ...and so on.
//
// If you bump a value that doesn't exist, it will be set to "1".
//
// The special "stable" mode has no value, bumping it clears: pre, post, dev.
let full = self.make_full();
match bump {
BumpCommand::BumpRelease { index } => {
// Clear all sub-release items
full.pre = None;
full.post = None;
full.dev = None;
// Use `max` here to try to do 0.2 => 0.3 instead of 0.2 => 0.3.0
let old_parts = &full.release;
let len = old_parts.len().max(index + 1);
let new_release_vec = (0..len)
.map(|i| match i.cmp(&index) {
// Everything before the bumped value is preserved (or is an implicit 0)
Ordering::Less => old_parts.get(i).copied().unwrap_or(0),
// This is the value to bump (could be implicit 0)
Ordering::Equal => old_parts.get(i).copied().unwrap_or(0) + 1,
// Everything after the bumped value becomes 0
Ordering::Greater => 0,
})
.collect::<Vec<u64>>();
full.release = new_release_vec;
}
BumpCommand::MakeStable => {
// Clear all sub-release items
full.pre = None;
full.post = None;
full.dev = None;
}
BumpCommand::BumpPrerelease { kind } => {
// Clear all sub-prerelease items
full.post = None;
full.dev = None;
// Either bump the matching kind or set to 1
if let Some(prerelease) = &mut full.pre {
if prerelease.kind == kind {
prerelease.number += 1;
return;
}
}
full.pre = Some(Prerelease { kind, number: 1 });
}
BumpCommand::BumpPost => {
// Clear sub-post items
full.dev = None;
// Either bump or set to 1
if let Some(post) = &mut full.post {
*post += 1;
} else {
full.post = Some(1);
}
}
BumpCommand::BumpDev => {
// Either bump or set to 1
if let Some(dev) = &mut full.dev {
*dev += 1;
} else {
full.dev = Some(1);
}
}
}
}
/// Set the min-release component and return the updated version. /// Set the min-release component and return the updated version.
/// ///
/// The "min" component is internal-only, and does not exist in PEP 440. /// The "min" component is internal-only, and does not exist in PEP 440.
@ -879,6 +963,27 @@ impl FromStr for Version {
} }
} }
/// Various ways to "bump" a version
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum BumpCommand {
/// Bump the release component
BumpRelease {
/// The release component to bump (0 is major, 1 is minor, 2 is patch)
index: usize,
},
/// Bump the prerelease component
BumpPrerelease {
/// prerelease component to bump
kind: PrereleaseKind,
},
/// Bump to the associated stable release
MakeStable,
/// Bump the post component
BumpPost,
/// Bump the dev component
BumpDev,
}
/// A small representation of a version. /// A small representation of a version.
/// ///
/// This representation is used for a (very common) subset of versions: the /// This representation is used for a (very common) subset of versions: the
@ -4043,4 +4148,351 @@ mod tests {
assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2); assert_eq!(size_of::<VersionSmall>(), size_of::<usize>() * 2);
assert_eq!(size_of::<Version>(), size_of::<usize>() * 2); assert_eq!(size_of::<Version>(), size_of::<usize>() * 2);
} }
/// Test major bumping
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn bump_major() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 0 });
assert_eq!(version.to_string().as_str(), "1");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 0 });
assert_eq!(version.to_string().as_str(), "2.0");
// three digit (zero major)
let mut version = "0.1.2".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 0 });
assert_eq!(version.to_string().as_str(), "1.0.0");
// three digit (non-zero major)
let mut version = "1.2.3".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 0 });
assert_eq!(version.to_string().as_str(), "2.0.0");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 0 });
assert_eq!(version.to_string().as_str(), "2.0.0.0");
// All the version junk
let mut version = "5!1.7.3.5b2.post345.dev456+local"
.parse::<Version>()
.unwrap();
version.bump(BumpCommand::BumpRelease { index: 0 });
assert_eq!(version.to_string().as_str(), "5!2.0.0.0+local");
version.bump(BumpCommand::BumpRelease { index: 0 });
assert_eq!(version.to_string().as_str(), "5!3.0.0.0+local");
}
/// Test minor bumping
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn bump_minor() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 1 });
assert_eq!(version.to_string().as_str(), "0.1");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 1 });
assert_eq!(version.to_string().as_str(), "1.6");
// three digit (non-zero major)
let mut version = "5.3.6".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 1 });
assert_eq!(version.to_string().as_str(), "5.4.0");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 1 });
assert_eq!(version.to_string().as_str(), "1.3.0.0");
// All the version junk
let mut version = "5!1.7.3.5b2.post345.dev456+local"
.parse::<Version>()
.unwrap();
version.bump(BumpCommand::BumpRelease { index: 1 });
assert_eq!(version.to_string().as_str(), "5!1.8.0.0+local");
version.bump(BumpCommand::BumpRelease { index: 1 });
assert_eq!(version.to_string().as_str(), "5!1.9.0.0+local");
}
/// Test patch bumping
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn bump_patch() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 2 });
assert_eq!(version.to_string().as_str(), "0.0.1");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 2 });
assert_eq!(version.to_string().as_str(), "1.5.1");
// three digit
let mut version = "5.3.6".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 2 });
assert_eq!(version.to_string().as_str(), "5.3.7");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpRelease { index: 2 });
assert_eq!(version.to_string().as_str(), "1.2.4.0");
// All the version junk
let mut version = "5!1.7.3.5b2.post345.dev456+local"
.parse::<Version>()
.unwrap();
version.bump(BumpCommand::BumpRelease { index: 2 });
assert_eq!(version.to_string().as_str(), "5!1.7.4.0+local");
version.bump(BumpCommand::BumpRelease { index: 2 });
assert_eq!(version.to_string().as_str(), "5!1.7.5.0+local");
}
/// Test alpha bumping
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn bump_alpha() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Alpha,
});
assert_eq!(version.to_string().as_str(), "0a1");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Alpha,
});
assert_eq!(version.to_string().as_str(), "1.5a1");
// three digit
let mut version = "5.3.6".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Alpha,
});
assert_eq!(version.to_string().as_str(), "5.3.6a1");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Alpha,
});
assert_eq!(version.to_string().as_str(), "1.2.3.4a1");
// All the version junk
let mut version = "5!1.7.3.5b2.post345.dev456+local"
.parse::<Version>()
.unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Alpha,
});
assert_eq!(version.to_string().as_str(), "5!1.7.3.5a1+local");
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Alpha,
});
assert_eq!(version.to_string().as_str(), "5!1.7.3.5a2+local");
}
/// Test beta bumping
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn bump_beta() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Beta,
});
assert_eq!(version.to_string().as_str(), "0b1");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Beta,
});
assert_eq!(version.to_string().as_str(), "1.5b1");
// three digit
let mut version = "5.3.6".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Beta,
});
assert_eq!(version.to_string().as_str(), "5.3.6b1");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Beta,
});
assert_eq!(version.to_string().as_str(), "1.2.3.4b1");
// All the version junk
let mut version = "5!1.7.3.5a2.post345.dev456+local"
.parse::<Version>()
.unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Beta,
});
assert_eq!(version.to_string().as_str(), "5!1.7.3.5b1+local");
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Beta,
});
assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2+local");
}
/// Test rc bumping
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn bump_rc() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Rc,
});
assert_eq!(version.to_string().as_str(), "0rc1");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Rc,
});
assert_eq!(version.to_string().as_str(), "1.5rc1");
// three digit
let mut version = "5.3.6".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Rc,
});
assert_eq!(version.to_string().as_str(), "5.3.6rc1");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Rc,
});
assert_eq!(version.to_string().as_str(), "1.2.3.4rc1");
// All the version junk
let mut version = "5!1.7.3.5b2.post345.dev456+local"
.parse::<Version>()
.unwrap();
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Rc,
});
assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc1+local");
version.bump(BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Rc,
});
assert_eq!(version.to_string().as_str(), "5!1.7.3.5rc2+local");
}
/// Test post bumping
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn bump_post() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPost);
assert_eq!(version.to_string().as_str(), "0.post1");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPost);
assert_eq!(version.to_string().as_str(), "1.5.post1");
// three digit
let mut version = "5.3.6".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPost);
assert_eq!(version.to_string().as_str(), "5.3.6.post1");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPost);
assert_eq!(version.to_string().as_str(), "1.2.3.4.post1");
// All the version junk
let mut version = "5!1.7.3.5b2.dev123+local".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpPost);
assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post1+local");
version.bump(BumpCommand::BumpPost);
assert_eq!(version.to_string().as_str(), "5!1.7.3.5b2.post2+local");
}
/// Test dev bumping
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn bump_dev() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpDev);
assert_eq!(version.to_string().as_str(), "0.dev1");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpDev);
assert_eq!(version.to_string().as_str(), "1.5.dev1");
// three digit
let mut version = "5.3.6".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpDev);
assert_eq!(version.to_string().as_str(), "5.3.6.dev1");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpDev);
assert_eq!(version.to_string().as_str(), "1.2.3.4.dev1");
// All the version junk
let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
version.bump(BumpCommand::BumpDev);
assert_eq!(
version.to_string().as_str(),
"5!1.7.3.5b2.post345.dev1+local"
);
version.bump(BumpCommand::BumpDev);
assert_eq!(
version.to_string().as_str(),
"5!1.7.3.5b2.post345.dev2+local"
);
}
/// Test stable setting
/// Explicitly using the string display because we want to preserve formatting where possible!
#[test]
fn make_stable() {
// one digit
let mut version = "0".parse::<Version>().unwrap();
version.bump(BumpCommand::MakeStable);
assert_eq!(version.to_string().as_str(), "0");
// two digit
let mut version = "1.5".parse::<Version>().unwrap();
version.bump(BumpCommand::MakeStable);
assert_eq!(version.to_string().as_str(), "1.5");
// three digit
let mut version = "5.3.6".parse::<Version>().unwrap();
version.bump(BumpCommand::MakeStable);
assert_eq!(version.to_string().as_str(), "5.3.6");
// four digit
let mut version = "1.2.3.4".parse::<Version>().unwrap();
version.bump(BumpCommand::MakeStable);
assert_eq!(version.to_string().as_str(), "1.2.3.4");
// All the version junk
let mut version = "5!1.7.3.5b2.post345+local".parse::<Version>().unwrap();
version.bump(BumpCommand::MakeStable);
assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
version.bump(BumpCommand::MakeStable);
assert_eq!(version.to_string().as_str(), "5!1.7.3.5+local");
}
} }

View file

@ -1,6 +1,6 @@
use std::fmt::Write; use std::fmt::Write;
use std::path::Path;
use std::str::FromStr; use std::str::FromStr;
use std::{cmp::Ordering, path::Path};
use anyhow::{Context, Result, anyhow}; use anyhow::{Context, Result, anyhow};
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
@ -15,7 +15,7 @@ use uv_configuration::{
}; };
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_normalize::DefaultExtras; use uv_normalize::DefaultExtras;
use uv_pep440::Version; use uv_pep440::{BumpCommand, PrereleaseKind, Version};
use uv_pep508::PackageName; use uv_pep508::PackageName;
use uv_python::{PythonDownloads, PythonPreference, PythonRequest}; use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
use uv_settings::PythonInstallMirrors; use uv_settings::PythonInstallMirrors;
@ -55,7 +55,7 @@ pub(crate) fn self_version(
#[allow(clippy::fn_params_excessive_bools)] #[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn project_version( pub(crate) async fn project_version(
value: Option<String>, value: Option<String>,
bump: Option<VersionBump>, mut bump: Vec<VersionBump>,
short: bool, short: bool,
output_format: VersionFormat, output_format: VersionFormat,
strict: bool, strict: bool,
@ -105,7 +105,7 @@ pub(crate) async fn project_version(
}; };
// Short-circuit early for a frozen read // Short-circuit early for a frozen read
let is_read_only = value.is_none() && bump.is_none(); let is_read_only = value.is_none() && bump.is_empty();
if frozen && is_read_only { if frozen && is_read_only {
return Box::pin(print_frozen_version( return Box::pin(print_frozen_version(
project, project,
@ -158,7 +158,8 @@ pub(crate) async fn project_version(
match Version::from_str(&value) { match Version::from_str(&value) {
Ok(version) => Some(version), Ok(version) => Some(version),
Err(err) => match &*value { Err(err) => match &*value {
"major" | "minor" | "patch" => { "major" | "minor" | "patch" | "alpha" | "beta" | "rc" | "dev" | "post"
| "stable" => {
return Err(anyhow!( return Err(anyhow!(
"Invalid version `{value}`, did you mean to pass `--bump {value}`?" "Invalid version `{value}`, did you mean to pass `--bump {value}`?"
)); ));
@ -168,8 +169,120 @@ pub(crate) async fn project_version(
} }
}, },
} }
} else if let Some(bump) = bump { } else if !bump.is_empty() {
Some(bumped_version(&old_version, bump, printer)?) // While we can rationalize many of these combinations of operations together,
// we want to conservatively refuse to support any of them until users demand it.
//
// The most complex thing we *do* allow is `--bump major --bump beta --bump dev`
// because that makes perfect sense and is reasonable to do.
let release_components: Vec<_> = bump
.iter()
.filter(|bump| {
matches!(
bump,
VersionBump::Major | VersionBump::Minor | VersionBump::Patch
)
})
.collect();
let prerelease_components: Vec<_> = bump
.iter()
.filter(|bump| {
matches!(
bump,
VersionBump::Alpha | VersionBump::Beta | VersionBump::Rc | VersionBump::Dev
)
})
.collect();
let post_count = bump
.iter()
.filter(|bump| *bump == &VersionBump::Post)
.count();
let stable_count = bump
.iter()
.filter(|bump| *bump == &VersionBump::Stable)
.count();
// Very little reason to do "bump to stable" and then do other things,
// even if we can make sense of it.
if stable_count > 0 && bump.len() > 1 {
if let Some(component) = release_components.first() {
return Err(anyhow!(
"`--bump stable` isn't needed if you're already passing `--bump {component}`"
));
}
return Err(anyhow!(
"`--bump stable` cannot be combined with any other `--bump`"
));
}
// Very little reason to "bump to post" and then do other things,
// how is it a post-release otherwise?
if post_count > 0 && bump.len() > 1 {
return Err(anyhow!(
"`--bump post` cannot be combined with any other `--bump`"
));
}
// `--bump major --bump minor` makes perfect sense (1.2.3 => 2.1.0)
// ...but it's weird and probably a mistake?
// `--bump major --bump major` perfect sense (1.2.3 => 3.0.0)
// ...but it's weird and probably a mistake?
if release_components.len() > 1 {
return Err(anyhow!(
"`--bump` can only take one of `major`, `minor`, `patch`"
));
}
// `--bump alpha --bump beta` is basically completely incoherent
// `--bump beta --bump beta` makes perfect sense (1.2.3b4 => 1.2.3b6)
// ...but it's weird and probably a mistake?
// `--bump beta --bump dev` makes perfect sense (1.2.3 => 1.2.3b1.dev1)
// ...but we want to discourage mixing `dev` with prereleases
if prerelease_components.len() > 1 {
return Err(anyhow!(
"`--bump` can only take one of `alpha`, `beta`, `rc`, `dev`"
));
}
// Sort the given commands so the user doesn't have to care about
// the ordering of `--bump minor --bump beta` (only one ordering is ever useful)
bump.sort();
// Apply all the bumps
let mut new_version = old_version.clone();
for bump in &bump {
let command = match *bump {
VersionBump::Major => BumpCommand::BumpRelease { index: 0 },
VersionBump::Minor => BumpCommand::BumpRelease { index: 1 },
VersionBump::Patch => BumpCommand::BumpRelease { index: 2 },
VersionBump::Alpha => BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Alpha,
},
VersionBump::Beta => BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Beta,
},
VersionBump::Rc => BumpCommand::BumpPrerelease {
kind: PrereleaseKind::Rc,
},
VersionBump::Post => BumpCommand::BumpPost,
VersionBump::Dev => BumpCommand::BumpDev,
VersionBump::Stable => BumpCommand::MakeStable,
};
new_version.bump(command);
}
if new_version <= old_version {
if old_version.is_stable() && new_version.is_pre() {
return Err(anyhow!(
"{old_version} => {new_version} didn't increase the version; when moving to a prerelease you also need to increase the release `--bump patch`?"
));
}
return Err(anyhow!(
"{old_version} => {new_version} didn't increase the version"
));
}
Some(new_version)
} else { } else {
None None
}; };
@ -569,35 +682,3 @@ fn print_version(
} }
Ok(()) Ok(())
} }
fn bumped_version(from: &Version, bump: VersionBump, printer: Printer) -> Result<Version> {
// All prereleasey details "carry to 0" with every currently supported mode of `--bump`
// We could go out of our way to preserve epoch information but no one uses those...
if from.any_prerelease() || from.is_post() || from.is_local() || from.epoch() > 0 {
writeln!(
printer.stderr(),
"warning: prerelease information will be cleared as part of the version bump"
)?;
}
let index = match bump {
VersionBump::Major => 0,
VersionBump::Minor => 1,
VersionBump::Patch => 2,
};
// Use `max` here to try to do 0.2 => 0.3 instead of 0.2 => 0.3.0
let old_parts = from.release();
let len = old_parts.len().max(index + 1);
let new_release_vec = (0..len)
.map(|i| match i.cmp(&index) {
// Everything before the bumped value is preserved (or is an implicit 0)
Ordering::Less => old_parts.get(i).copied().unwrap_or(0),
// This is the value to bump (could be implicit 0)
Ordering::Equal => old_parts.get(i).copied().unwrap_or(0) + 1,
// Everything after the bumped value becomes 0
Ordering::Greater => 0,
})
.collect::<Vec<u64>>();
Ok(Version::new(new_release_vec))
}

View file

@ -2040,7 +2040,7 @@ async fn run_project(
let strict = project_was_explicit let strict = project_was_explicit
|| globals.preview.is_enabled() || globals.preview.is_enabled()
|| args.dry_run || args.dry_run
|| args.bump.is_some() || !args.bump.is_empty()
|| args.value.is_some() || args.value.is_some()
|| args.package.is_some(); || args.package.is_some();
Box::pin(commands::project_version( Box::pin(commands::project_version(

View file

@ -1561,7 +1561,7 @@ impl RemoveSettings {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct VersionSettings { pub(crate) struct VersionSettings {
pub(crate) value: Option<String>, pub(crate) value: Option<String>,
pub(crate) bump: Option<VersionBump>, pub(crate) bump: Vec<VersionBump>,
pub(crate) short: bool, pub(crate) short: bool,
pub(crate) output_format: VersionFormat, pub(crate) output_format: VersionFormat,
pub(crate) dry_run: bool, pub(crate) dry_run: bool,

View file

@ -512,7 +512,6 @@ requires-python = ">=3.12"
myproject 1.10.31.dev10 => 2.0.0 myproject 1.10.31.dev10 => 2.0.0
----- stderr ----- ----- stderr -----
warning: prerelease information will be cleared as part of the version bump
Resolved 1 package in [TIME] Resolved 1 package in [TIME]
Audited in [TIME] Audited in [TIME]
"); ");
@ -550,10 +549,9 @@ requires-python = ">=3.12"
success: true success: true
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
myproject 1!2a3.post4.dev5+deadbeef6 => 3 myproject 1!2a3.post4.dev5+deadbeef6 => 1!3+deadbeef6
----- stderr ----- ----- stderr -----
warning: prerelease information will be cleared as part of the version bump
Resolved 1 package in [TIME] Resolved 1 package in [TIME]
Audited in [TIME] Audited in [TIME]
"); ");
@ -564,7 +562,295 @@ requires-python = ">=3.12"
@r#" @r#"
[project] [project]
name = "myproject" name = "myproject"
version = "3" version = "1!3+deadbeef6"
requires-python = ">=3.12"
"#
);
Ok(())
}
// Pass a ton of bump flags to a complex version
// The flags are in a messy order and some are duplicated,
// Under extremely permissive semantics this could be allowed, but right
// now it fails for a dozen reasons!
#[test]
fn many_bump_complex() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev7+deadbeef6"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("major")
.arg("--bump").arg("patch")
.arg("--bump").arg("alpha")
.arg("--bump").arg("minor")
.arg("--bump").arg("dev")
.arg("--bump").arg("minor")
.arg("--bump").arg("post")
.arg("--bump").arg("post"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `--bump post` cannot be combined with any other `--bump`
");
let pyproject = fs_err::read_to_string(&pyproject_toml)?;
assert_snapshot!(
pyproject,
@r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev7+deadbeef6"
requires-python = ">=3.12"
"#
);
Ok(())
}
// --bump stable
#[test]
fn bump_stable() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev7+deadbeef6"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("stable"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 9!2.3.4a5.post6.dev7+deadbeef6 => 9!2.3.4+deadbeef6
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
let pyproject = fs_err::read_to_string(&pyproject_toml)?;
assert_snapshot!(
pyproject,
@r#"
[project]
name = "myproject"
version = "9!2.3.4+deadbeef6"
requires-python = ">=3.12"
"#
);
Ok(())
}
// --bump alpha
#[test]
fn bump_alpha() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev7+deadbeef6"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("alpha"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 9!2.3.4a5.post6.dev7+deadbeef6 => 9!2.3.4a6+deadbeef6
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
let pyproject = fs_err::read_to_string(&pyproject_toml)?;
assert_snapshot!(
pyproject,
@r#"
[project]
name = "myproject"
version = "9!2.3.4a6+deadbeef6"
requires-python = ">=3.12"
"#
);
Ok(())
}
// --bump beta
#[test]
fn bump_beta() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev7+deadbeef6"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("beta"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 9!2.3.4a5.post6.dev7+deadbeef6 => 9!2.3.4b1+deadbeef6
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
let pyproject = fs_err::read_to_string(&pyproject_toml)?;
assert_snapshot!(
pyproject,
@r#"
[project]
name = "myproject"
version = "9!2.3.4b1+deadbeef6"
requires-python = ">=3.12"
"#
);
Ok(())
}
// --bump rc
#[test]
fn bump_rc() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev7+deadbeef6"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("rc"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 9!2.3.4a5.post6.dev7+deadbeef6 => 9!2.3.4rc1+deadbeef6
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
let pyproject = fs_err::read_to_string(&pyproject_toml)?;
assert_snapshot!(
pyproject,
@r#"
[project]
name = "myproject"
version = "9!2.3.4rc1+deadbeef6"
requires-python = ">=3.12"
"#
);
Ok(())
}
// --bump post
#[test]
fn bump_post() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev7+deadbeef6"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("post"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 9!2.3.4a5.post6.dev7+deadbeef6 => 9!2.3.4a5.post7+deadbeef6
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
let pyproject = fs_err::read_to_string(&pyproject_toml)?;
assert_snapshot!(
pyproject,
@r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post7+deadbeef6"
requires-python = ">=3.12"
"#
);
Ok(())
}
// --bump dev
#[test]
fn bump_dev() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev7+deadbeef6"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("dev"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 9!2.3.4a5.post6.dev7+deadbeef6 => 9!2.3.4a5.post6.dev8+deadbeef6
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
let pyproject = fs_err::read_to_string(&pyproject_toml)?;
assert_snapshot!(
pyproject,
@r#"
[project]
name = "myproject"
version = "9!2.3.4a5.post6.dev8+deadbeef6"
requires-python = ">=3.12" requires-python = ">=3.12"
"# "#
); );
@ -594,7 +880,6 @@ requires-python = ">=3.12"
myproject 1.10.31.post10 => 2.0.0 myproject 1.10.31.post10 => 2.0.0
----- stderr ----- ----- stderr -----
warning: prerelease information will be cleared as part of the version bump
Resolved 1 package in [TIME] Resolved 1 package in [TIME]
Audited in [TIME] Audited in [TIME]
"); ");
@ -612,6 +897,317 @@ requires-python = ">=3.12"
Ok(()) Ok(())
} }
// --bump stable but it decreases the version
#[test]
fn bump_decrease_stable() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4.post6"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("stable"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: 2.3.4.post6 => 2.3.4 didn't increase the version
");
Ok(())
}
// --bump alpha but it decreases the version by reverting beta
#[test]
fn bump_decrease_alpha_beta() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4b5"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("alpha"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: 2.3.4b5 => 2.3.4a1 didn't increase the version
");
Ok(())
}
// --bump alpha but it decreases the version from a stable
#[test]
fn bump_decrease_alpha_stable() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("alpha"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: 2.3.4 => 2.3.4a1 didn't increase the version; when moving to a prerelease you also need to increase the release `--bump patch`?
");
Ok(())
}
// --bump major twice
#[test]
fn bump_double_major() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("major")
.arg("--bump").arg("major"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `--bump` can only take one of `major`, `minor`, `patch`
");
Ok(())
}
// --bump alpha twice
#[test]
fn bump_double_alpha() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("alpha")
.arg("--bump").arg("alpha"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `--bump` can only take one of `alpha`, `beta`, `rc`, `dev`
");
Ok(())
}
// --bump stable --bump major
#[test]
fn bump_stable_major() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("stable")
.arg("--bump").arg("major"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `--bump stable` isn't needed if you're already passing `--bump major`
");
Ok(())
}
// --bump major --bump alpha
#[test]
fn bump_alpha_major() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("major")
.arg("--bump").arg("alpha"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 2.3.4 => 3.0.0a1
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
Ok(())
}
// --bump major --bump minor
#[test]
fn bump_minor_major() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("major")
.arg("--bump").arg("alpha"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 2.3.4 => 3.0.0a1
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
Ok(())
}
// --bump alpha --bump dev
#[test]
fn bump_alpha_dev() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("alpha")
.arg("--bump").arg("dev"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `--bump` can only take one of `alpha`, `beta`, `rc`, `dev`
");
Ok(())
}
// --bump major --bump dev
#[test]
fn bump_dev_major() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("major")
.arg("--bump").arg("dev"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 2.3.4 => 3.0.0.dev1
----- stderr -----
Resolved 1 package in [TIME]
Audited in [TIME]
");
Ok(())
}
// --bump major --bump post
#[test]
fn bump_post_major() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "2.3.4"
requires-python = ">=3.12"
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("major")
.arg("--bump").arg("post"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `--bump post` cannot be combined with any other `--bump`
");
Ok(())
}
// Set version --dry-run // Set version --dry-run
#[test] #[test]
fn version_set_dry() -> Result<()> { fn version_set_dry() -> Result<()> {

View file

@ -160,6 +160,8 @@ Setting `tool.uv.package = false` will force a project package _not_ to be built
the project environment. uv will ignore a declared build system when interacting with the project; the project environment. uv will ignore a declared build system when interacting with the project;
however, uv will still respect explicit attempts to build the project such as invoking `uv build`. however, uv will still respect explicit attempts to build the project such as invoking `uv build`.
## Project versioning
## Project environment path ## Project environment path
The `UV_PROJECT_ENVIRONMENT` environment variable can be used to configure the project virtual The `UV_PROJECT_ENVIRONMENT` environment variable can be used to configure the project virtual

View file

@ -55,6 +55,83 @@ Alternatively, `uv build <SRC>` will build the package in the specified director
running `uv build --no-sources` to ensure that the package builds correctly when `tool.uv.sources` running `uv build --no-sources` to ensure that the package builds correctly when `tool.uv.sources`
is disabled, as is the case when using other build tools, like [`pypa/build`](https://github.com/pypa/build). is disabled, as is the case when using other build tools, like [`pypa/build`](https://github.com/pypa/build).
## Updating your version
The `uv version` command provides conveniences for updating the version of your package before you
publish it.
[See the project docs for reading your package's version](./projects.md#managing-version).
To set the the exact version of your package, just pass that version:
```console
$ uv version 1.0.0
hello-world 0.7.0 => 1.0.0
```
If you want to preview the change without actually applying it, use the `--dry-run` flag:
```console
$ uv version 2.0.0 --dry-run
hello-world 1.0.0 => 2.0.0
$ uv version
hello-world 1.0.0
```
If you want to change the version of a particular package, use the `--package` flag:
```console
$ uv version --package hello-world 1.2.3
hello-world 1.0.0 => 1.2.3
```
To increase the version of your package, use the `--bump` flag:
```console
$ uv version --bump minor
hello-world 1.2.3 => 1.3.0
```
The `--bump` flag can be passed multiple times, and uv will run them in the following order that
prevents bumps from clobbering eachother:
```text
major > minor > patch > stable > alpha > beta > rc > post > dev
```
When you're on a stable version and want to start shipping prereleases, you'll want to bump the
release and the prerelease:
```console
$ uv version --bump patch --bump beta
hello-world 1.3.0 => 1.3.1b1
```
!!! Note
If you only bump the prerelease here it will actually decrease the current version.
`uv version` will error if that ever happens. If you intended to do that, you can pass
`--allow-decreases` to disable the check.
When you're on a prerelease and want to ship another, you can just bump the prerelease:
```console
uv version --bump beta
hello-world 1.3.0b1 => 1.3.1b2
```
When you're on a prerelease and want to ship a stable version, you can bump to stable:
```console
uv version --bump stable
hello-world 1.3.1b2 => 1.3.1
```
!!! info
By default, when `uv version` modifies your package it will lock and sync your project to
ensure everything sees the change. To prevent locking and syncing, pass `--frozen`. To just
prevent syncing, pass `--no-sync`.
## Publishing your package ## Publishing your package
Publish your package with `uv publish`: Publish your package with `uv publish`:

View file

@ -160,6 +160,43 @@ version, while keeping the rest of the lockfile intact.
See the documentation on [managing dependencies](../concepts/projects/dependencies.md) for more See the documentation on [managing dependencies](../concepts/projects/dependencies.md) for more
details. details.
## Managing version
The `uv version` command can be used to read your package's version.
[See the publishing docs for updating your package's version](./package.md#updating-your-version).
To get the version of your package, run `uv version` with no other arguments:
```console
$ uv version
hello-world 0.7.0
```
To get the version of a particular package, pass `--package`:
```console
$ uv version --package myapp
myapp 1.2.3
```
To just get the version with no other output, pass `--short`:
```console
$ uv version --short
0.7.0
```
To get the version as json, pass `--output-format json`:
```console
$ uv version --output-format json
{
"package_name": "hello-world",
"version": "0.7.0",
"commit_info": null
}
```
## Running commands ## Running commands
`uv run` can be used to run arbitrary scripts or commands in your project environment. `uv run` can be used to run arbitrary scripts or commands in your project environment.

View file

@ -785,11 +785,18 @@ uv version [OPTIONS] [VALUE]
<p>Expects to receive either a hostname (e.g., <code>localhost</code>), a host-port pair (e.g., <code>localhost:8080</code>), or a URL (e.g., <code>https://localhost</code>).</p> <p>Expects to receive either a hostname (e.g., <code>localhost</code>), a host-port pair (e.g., <code>localhost:8080</code>), or a URL (e.g., <code>https://localhost</code>).</p>
<p>WARNING: Hosts included in this list will not be verified against the system's certificate store. Only use <code>--allow-insecure-host</code> in a secure network with verified sources, as it bypasses SSL verification and could expose you to MITM attacks.</p> <p>WARNING: Hosts included in this list will not be verified against the system's certificate store. Only use <code>--allow-insecure-host</code> in a secure network with verified sources, as it bypasses SSL verification and could expose you to MITM attacks.</p>
<p>May also be set with the <code>UV_INSECURE_HOST</code> environment variable.</p></dd><dt id="uv-version--bump"><a href="#uv-version--bump"><code>--bump</code></a> <i>bump</i></dt><dd><p>Update the project version using the given semantics</p> <p>May also be set with the <code>UV_INSECURE_HOST</code> environment variable.</p></dd><dt id="uv-version--bump"><a href="#uv-version--bump"><code>--bump</code></a> <i>bump</i></dt><dd><p>Update the project version using the given semantics</p>
<p>This flag can be passed multiple times to allow going to a new release and entering a prerelease: <code>--bump patch --bump beta</code></p>
<p>Possible values:</p> <p>Possible values:</p>
<ul> <ul>
<li><code>major</code>: Increase the major version (1.2.3 =&gt; 2.0.0)</li> <li><code>major</code>: Increase the major version (1.2.3 =&gt; 2.0.0)</li>
<li><code>minor</code>: Increase the minor version (1.2.3 =&gt; 1.3.0)</li> <li><code>minor</code>: Increase the minor version (1.2.3 =&gt; 1.3.0)</li>
<li><code>patch</code>: Increase the patch version (1.2.3 =&gt; 1.2.4)</li> <li><code>patch</code>: Increase the patch version (1.2.3 =&gt; 1.2.4)</li>
<li><code>stable</code>: Make the version stable (1.2.3b4.post5.dev6 =&gt; 1.2.3)</li>
<li><code>alpha</code>: Increase the alpha version (1.2.3a4 =&gt; 1.2.3a5)</li>
<li><code>beta</code>: Increase the beta version (1.2.3b4 =&gt; 1.2.3b5)</li>
<li><code>rc</code>: Increase the rc version (1.2.3rc4 =&gt; 1.2.3rc5)</li>
<li><code>post</code>: Increase the post version (1.2.3.post5 =&gt; 1.2.3.post6)</li>
<li><code>dev</code>: Increase the dev version (1.2.3a4.dev6 =&gt; 1.2.3.dev7)</li>
</ul></dd><dt id="uv-version--cache-dir"><a href="#uv-version--cache-dir"><code>--cache-dir</code></a> <i>cache-dir</i></dt><dd><p>Path to the cache directory.</p> </ul></dd><dt id="uv-version--cache-dir"><a href="#uv-version--cache-dir"><code>--cache-dir</code></a> <i>cache-dir</i></dt><dd><p>Path to the cache directory.</p>
<p>Defaults to <code>$XDG_CACHE_HOME/uv</code> or <code>$HOME/.cache/uv</code> on macOS and Linux, and <code>%LOCALAPPDATA%\uv\cache</code> on Windows.</p> <p>Defaults to <code>$XDG_CACHE_HOME/uv</code> or <code>$HOME/.cache/uv</code> on macOS and Linux, and <code>%LOCALAPPDATA%\uv\cache</code> on Windows.</p>
<p>To view the location of the cache directory, run <code>uv cache dir</code>.</p> <p>To view the location of the cache directory, run <code>uv cache dir</code>.</p>