mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-13 20:12:03 +00:00
Expand the functionality of uv version --bump
to support pre-releases (#13578)
This adds `alpha`, `beta`, `rc`, `stable`, `post`, and `dev` modes to `uv version --bump`. The components that `--bump` accepts are ordered as follows: major > minor > patch > stable > alpha > beta > rc > post > dev Bumping a component "clears" all lesser component (`alpha`, `beta`, and `rc` all overwrite each other): * `--bump minor` on `1.2.3a4.post5.dev6` => `1.3.0` * `--bump alpha` on `1.2.3a4.post5.dev6` => `1.2.3a5` * `--bump dev ` on `1.2.3a4.post5.dev6` => `1.2.3a4.post5.dev7` In addition, `--bump` can now be repeated. The primary motivation of this is "bump stable version and also enter a prerelease", but it technically lets you express other things if you want them: * `--bump patch --bump alpha` on `1.2.3` => `1.2.4a1` ("bump patch version and go to alpha 1") * `--bump minor --bump patch` on `1.2.3` => `1.3.1` ("bump minor version and got to patch 1") * `--bump minor --bump minor` on `1.2.3` => `1.4.0` ("bump minor version twice") The `--bump` flags are sorted by their priority, so that you don't need to remember the priority yourself. This ordering is the only "useful" one that preserves every `--bump` you passed, so there's no concern about loss of expressiveness. For instance `--bump minor --bump major` would just be `--bump major` if we didn't sort, as the major bump clears the minor version. The ordering of `beta` after `alpha` means `--bump alpha --bump beta` will just result in beta 1; this is the one case where a bump request will effectively get overwritten. The `stable` mode "bumps to the next stable release", clearing the pre (`alpha`, `beta`, `rc`), `dev`, and `post` components from a version (`1.2.3a4.post5.dev6` => `1.2.3`). The choice to clear `post` here is a bit odd, in that `1.2.3.post4` => `1.2.3` is actually a version decrease, but I think this gives a more intuitive model (as preserving `post5` in the previous example is definitely wrong), and also post-releases are extremely obscure so probably no one will notice. In the cases where this behaviour isn't useful, you probably wanted to pass `--bump patch` or something anyway which *should* definitely clear the `post5` (putting it another way: the only cases where `--bump stable` has dubious behaviour is when you wanted it to do a noop, which, is a command you could have just not written at all). In all cases we preserve the "epoch" and "local" components of a version, so the `7!` and `+local` in `7!1.2.3+local` will never be modified by `--bump` (you can use the raw version set mode if you want to touch those). The preservation of `local` is another slightly odd choice, but it's a really obscure feature (so again it mostly won't come up) and when it's used it seems to mostly be used for referring to variant releases, in which case preserving it tends to be correct. Fixes #13223 --------- Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
parent
42fcc81b3d
commit
042df4a7de
10 changed files with 1347 additions and 56 deletions
|
@ -532,8 +532,10 @@ 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.
|
||||||
#[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,14 +610,56 @@ 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 (e.g., 1.2.3 => 2.0.0)
|
||||||
Major,
|
Major,
|
||||||
/// Increase the minor version (1.2.3 => 1.3.0)
|
/// Increase the minor version (e.g., 1.2.3 => 1.3.0)
|
||||||
Minor,
|
Minor,
|
||||||
/// Increase the patch version (1.2.3 => 1.2.4)
|
/// Increase the patch version (e.g., 1.2.3 => 1.2.4)
|
||||||
Patch,
|
Patch,
|
||||||
|
/// Move from a pre-release to stable version (e.g., 1.2.3b4.post5.dev6 => 1.2.3)
|
||||||
|
///
|
||||||
|
/// Removes all pre-release components, but will not remove "local" components.
|
||||||
|
Stable,
|
||||||
|
/// Increase the alpha version (e.g., 1.2.3a4 => 1.2.3a5)
|
||||||
|
///
|
||||||
|
/// To move from a stable to a pre-release version, combine this with a stable component, e.g.,
|
||||||
|
/// for 1.2.3 => 2.0.0a1, you'd also include [`VersionBump::Major`].
|
||||||
|
Alpha,
|
||||||
|
/// Increase the beta version (e.g., 1.2.3b4 => 1.2.3b5)
|
||||||
|
///
|
||||||
|
/// To move from a stable to a pre-release version, combine this with a stable component, e.g.,
|
||||||
|
/// for 1.2.3 => 2.0.0b1, you'd also include [`VersionBump::Major`].
|
||||||
|
Beta,
|
||||||
|
/// Increase the rc version (e.g., 1.2.3rc4 => 1.2.3rc5)
|
||||||
|
///
|
||||||
|
/// To move from a stable to a pre-release version, combine this with a stable component, e.g.,
|
||||||
|
/// for 1.2.3 => 2.0.0rc1, you'd also include [`VersionBump::Major`].]
|
||||||
|
Rc,
|
||||||
|
/// Increase the post version (e.g., 1.2.3.post5 => 1.2.3.post6)
|
||||||
|
Post,
|
||||||
|
/// Increase the dev version (e.g., 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)]
|
||||||
|
|
|
@ -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::{
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,135 @@ 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 {
|
||||||
|
let components = bump
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
return Err(anyhow!(
|
||||||
|
"`--bump stable` cannot be used with another `--bump` value, got: {components}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
let components = bump
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
return Err(anyhow!(
|
||||||
|
"`--bump post` cannot be used with another `--bump` value, got: {components}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// `--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 {
|
||||||
|
let components = release_components
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Only one release version component can be provided to `--bump`, got: {components}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// `--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 pre-releases
|
||||||
|
if prerelease_components.len() > 1 {
|
||||||
|
let components = prerelease_components
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Only one pre-release version component can be provided to `--bump`, got: {components}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 bumping to a pre-release version you also need to increase a release version component, e.g., with `--bump <major|minor|patch>`"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return Err(anyhow!(
|
||||||
|
"{old_version} => {new_version} didn't increase the version; provide the exact version to force an update"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(new_version)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -569,35 +697,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))
|
|
||||||
}
|
|
||||||
|
|
|
@ -2041,7 +2041,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(
|
||||||
|
|
|
@ -1564,7 +1564,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,
|
||||||
|
|
|
@ -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 used with another `--bump` value, got: major, patch, alpha, minor, dev, minor, post, post
|
||||||
|
");
|
||||||
|
|
||||||
|
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; provide the exact version to force an update
|
||||||
|
");
|
||||||
|
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; provide the exact version to force an update
|
||||||
|
");
|
||||||
|
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 bumping to a pre-release version you also need to increase a release version component, e.g., with `--bump <major|minor|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: Only one release version component can be provided to `--bump`, got: major, major
|
||||||
|
");
|
||||||
|
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: Only one pre-release version component can be provided to `--bump`, got: alpha, alpha
|
||||||
|
");
|
||||||
|
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` cannot be used with another `--bump` value, got: stable, 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: Only one pre-release version component can be provided to `--bump`, got: alpha, 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 used with another `--bump` value, got: major, post
|
||||||
|
");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// Set version --dry-run
|
// Set version --dry-run
|
||||||
#[test]
|
#[test]
|
||||||
fn version_set_dry() -> Result<()> {
|
fn version_set_dry() -> Result<()> {
|
||||||
|
|
|
@ -55,6 +55,70 @@ 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 update to an exact version, provide it as a positional argument:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ uv version 1.0.0
|
||||||
|
hello-world 0.7.0 => 1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
To preview the change without updating the `pyproject.toml`, 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
|
||||||
|
```
|
||||||
|
|
||||||
|
To increase the version of your package semantics, use the `--bump` option:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ uv version --bump minor
|
||||||
|
hello-world 1.2.3 => 1.3.0
|
||||||
|
```
|
||||||
|
|
||||||
|
The `--bump` option supports the following common version components: `major`, `minor`, `patch`,
|
||||||
|
`stable`, `alpha`, `beta`, `rc`, `post`, and `dev`. When provided more than once, the components
|
||||||
|
will be applied in order, from largest (`major`) to smallest (`dev`).
|
||||||
|
|
||||||
|
To move from a stable to pre-release version, bump one of the major, minor, or patch components in
|
||||||
|
addition to the pre-release component:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ uv version --bump patch --bump beta
|
||||||
|
hello-world 1.3.0 => 1.3.1b1
|
||||||
|
$ uv version --bump major --bump alpha
|
||||||
|
hello-world 1.3.0 => 2.0.0a1
|
||||||
|
```
|
||||||
|
|
||||||
|
When moving from a pre-release to a new pre-release version, just bump the relevant pre-release
|
||||||
|
component:
|
||||||
|
|
||||||
|
```console
|
||||||
|
uv version --bump beta
|
||||||
|
hello-world 1.3.0b1 => 1.3.1b2
|
||||||
|
```
|
||||||
|
|
||||||
|
When moving from a pre-release to a stable version, the `stable` option can be used to clear the
|
||||||
|
pre-release component:
|
||||||
|
|
||||||
|
```console
|
||||||
|
uv version --bump stable
|
||||||
|
hello-world 1.3.1b2 => 1.3.1
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! info
|
||||||
|
|
||||||
|
By default, when `uv version` modifies the project it will perform a lock and sync. To
|
||||||
|
prevent locking and syncing, use `--frozen`, or, to just prevent syncing, use `--no-sync`.
|
||||||
|
|
||||||
## Publishing your package
|
## Publishing your package
|
||||||
|
|
||||||
Publish your package with `uv publish`:
|
Publish your package with `uv publish`:
|
||||||
|
|
|
@ -160,6 +160,38 @@ 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.
|
||||||
|
|
||||||
|
To get the version of your package, run `uv version`:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ uv version
|
||||||
|
hello-world 0.7.0
|
||||||
|
```
|
||||||
|
|
||||||
|
To get the version without the package name, use the `--short` option:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ uv version --short
|
||||||
|
0.7.0
|
||||||
|
```
|
||||||
|
|
||||||
|
To get version information in a JSON format, use the `--output-format json` option:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ uv version --output-format json
|
||||||
|
{
|
||||||
|
"package_name": "hello-world",
|
||||||
|
"version": "0.7.0",
|
||||||
|
"commit_info": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [publishing guide](./package.md#updating-your-version) for details on updating your package
|
||||||
|
version.
|
||||||
|
|
||||||
## 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.
|
||||||
|
|
|
@ -787,11 +787,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.</p>
|
||||||
<p>Possible values:</p>
|
<p>Possible values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>major</code>: Increase the major version (1.2.3 => 2.0.0)</li>
|
<li><code>major</code>: Increase the major version (e.g., 1.2.3 => 2.0.0)</li>
|
||||||
<li><code>minor</code>: Increase the minor version (1.2.3 => 1.3.0)</li>
|
<li><code>minor</code>: Increase the minor version (e.g., 1.2.3 => 1.3.0)</li>
|
||||||
<li><code>patch</code>: Increase the patch version (1.2.3 => 1.2.4)</li>
|
<li><code>patch</code>: Increase the patch version (e.g., 1.2.3 => 1.2.4)</li>
|
||||||
|
<li><code>stable</code>: Move from a pre-release to stable version (e.g., 1.2.3b4.post5.dev6 => 1.2.3)</li>
|
||||||
|
<li><code>alpha</code>: Increase the alpha version (e.g., 1.2.3a4 => 1.2.3a5)</li>
|
||||||
|
<li><code>beta</code>: Increase the beta version (e.g., 1.2.3b4 => 1.2.3b5)</li>
|
||||||
|
<li><code>rc</code>: Increase the rc version (e.g., 1.2.3rc4 => 1.2.3rc5)</li>
|
||||||
|
<li><code>post</code>: Increase the post version (e.g., 1.2.3.post5 => 1.2.3.post6)</li>
|
||||||
|
<li><code>dev</code>: Increase the dev version (e.g., 1.2.3a4.dev6 => 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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue