-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possibility to set the package version dynamically #6583
Comments
I think this could be created as a cargo extension using https://github.com/ordian/toml_edit. You could use https://github.com/killercup/cargo-edit as inspiration. |
Actually, I don't want to modify the But yes, you're right, there are certainly less fragile ways to edit |
I think there's a ticket for being able to modify options (I guess I'm both Cargo.toml and .cargo/config) via a command, like git config, but I don't know if it extends to temporary overrides. |
It's very common use case to specify the version from command line while releasing on a CI server that tracks and auto increments the build number. GNU/make, Maven and Gradle natively support it, manual editing of a build-spec file is not practical and error prone.
|
|
I don't think it is equivalent for my use case. This is for releasing on crates.io and modifying What I want is somewhat completely the opposite. I want to leave |
What does
mean? Is it just |
I'm not 100% sure there are no other places the version is passed into the compilation, but I guess so. I haven't tried yet (I might), but I guess cargo will set the env var unconditionally and overwrite it even if I pass it from outside. |
Maybe we could just change that: only set the environment var if unset. |
|
Looking at built, it seems to be really nice and useful thing and I'll keep this in mind. But I don't think this will help me here ‒ this doesn't help me push the right version into eg. clap or structopt. |
Can you not define the version in clap/structopt in terms of |
By default, they take the version from |
You're right, sorry. I think the solution is to not override the environment variables, then. |
Is there any progress? Also looking for the feature to externally manipulate the package version. (CI is setting the version, Cargo.toml should not be changed). An Env-Variable would be nice: This could also be done for every other part of the Cargo.toml:
The place within the code is here: This should be analogous to https://doc.rust-lang.org/cargo/reference/config.html#environment-variables I could add the implementation if we find a good name for env variables... |
Adding another +1 - we're setting the version upon release, and it'd be great to not need to edit Cargo.toml each time |
By way of another +1 and showing analogous functionality in other toolchains, the .NET SDK allows for overriding version numbers at the command line with commands like |
absolutely same for me. CI and stuff. |
This seems to be working on nightly right now: #6699 e.g. |
Will not work because --config overrides the cargo configuration, not the build definition in Cargo.toml |
Editing the Cargo.toml isn't practical in some scenarios anyway - in Nix we don't really have conventional network access during build phases, and so it's not possible rewrite toml and regenerate lock files to workaround this. I do see that there is a package macro that makes it easy to override the build version, falling back to the Cargo version, but it wouldn't be fun adding this to lots of Rust projects if Cargo could do it: https://docs.rs/git-version/latest/git_version/macro.git_version.html |
Very surprising that this is still an open issue in feb 2022. 3 years have passed! probably lost/forgotten in the 1.2k issues. Could we @ some of the active maintainers to get some visibility on this issue? +1 to adding version override in CLI like dotnet. |
Is there a way to get |
+1 here. I don't understand where the practice of statically specifying a version in a checked in manifest file comes from. I just want to release whatever is already checked in without having to commit again to change any manifests. It's very error prone unless you're using some fancy automated tools. It's so easy to overwrite a version that was already published previously if you release forgetting to change the manifest. Being able to specify the version in the command line and completely omitting the version from the manifest would be my ideal workflow! |
I suspect this is a large enough semantic change that this would need a major change proposal or an RFC and need a person to champion the proposal and implementation. It is unlikely for someone else to pick up and do all of that leg work on behalf of someone interested in this work. One challenge though is cargo is currently on a soft feature freeze and the cargo team is wanting to avoid distractions, including mentoring / shepherding, to be able to handle basic maintenance, finish currently committed work ,and to reduce technical debt so we can increase our capacity. Things off the top of my head that would need to be figured out
|
@epage This is a nice summary to figure out a considerate solution to this problem! Thanks for that! It's a pity that it's unlikely that this effort would come from the core team, but it's understandable. On the other hand, maybe an easier and good enough solution could be adding a flag (or env var) to pass the desired version to cargo so it could ignore the one specified in Cargo.toml? I'm absolutely unaware of cargo's internals, but if there's only one place where Cargo.toml is read to extract the version, then it seems like a pretty easy change to make. In my (somewhat biased) opinion: there should be no static file defining the "current" version of a package at all. This should be determined at release time by looking up the VCS info or elsewhere. |
Sorry I did not have that in mind. This issue popped up when I was searching for a solution to changing the version in the toml file using a cli tool, and simply given that I have found one I wanted to share as most likely other people would find this issue as well with the same problem at hand |
+1 here. It would be great to have a way to do this. It would be even better if it is not required to publish the crate to bump the crate version. |
It is not required to publish a crate to bump its version. All that is required to bump the version is editing the |
Hello, I've found myself here as someone doing a greenfield project at a large company where most of the current tools we build in CI use |
I was curious about this problem so I prototyped how I originally was assuming this would work, which was setting the In my prototype I added this before where the Here is what I wrote, // Determine if this compilation is for a dependency or for a workspace assembly
let rpath = self.config.registry_base_path();
let rpath = rpath.as_path_unlocked();
// If the manifest path starts with the registry path, then it is a compilation for a dependency
let version = if !pkg.manifest_path().starts_with(rpath) {
// Handle pkg_version values
let pkg_version = pkg.version();
let major = if let Ok(major) = std::env::var("CARGO_PKG_VERSION_MAJOR") {
major.parse().unwrap_or(pkg_version.major)
} else {
pkg_version.major
};
let minor = if let Ok(minor) = std::env::var("CARGO_PKG_VERSION_MINOR") {
minor.parse().unwrap_or(pkg_version.minor)
} else {
pkg_version.minor
};
let patch = if let Ok(patch) = std::env::var("CARGO_PKG_VERSION_PATCH") {
patch.parse().unwrap_or(pkg_version.patch)
} else {
pkg_version.patch
};
let pre = if let Ok(pre) = std::env::var("CARGO_PKG_VERSION_PRE") {
pre
} else {
pkg_version.pre.to_string()
};
semver::Version {
major,
minor,
patch,
pre: pre.parse().unwrap_or(pkg_version.pre.clone()),
build: pkg_version.build.clone(),
}
} else {
pkg.version().clone()
}; As a test I created a small app with this as the main.rs: fn main() {
println!("Hello, world!");
println!("{}", env!("CARGO_PKG_VERSION"));
} And I initialized with, cargo init
cargo add tokio I wanted to add a dependency because I had a suspicion that part of the complexity is that if you handle this by setting an env variable it would apply to all dependencies being compiled. I confirmed that fact and so I handle this issue by checking the manifest path, to figure out if the manifest is from the current working directory or if it was from the cargo registry. Finally, I tested the above code: ❯ CARGO_PKG_VERSION_PATCH=1004 ../cargo/target/debug/cargo build testver -> master ?
Compiling pin-project-lite v0.2.13
Compiling tokio v1.32.0
Compiling testver v0.1.0 (/home/juliusl/rs/testver)
Finished dev [unoptimized + debuginfo] target(s) in 1.02s
❯ ./target/debug/testver testver -> master ?
Hello, world!
0.1.1004 I feel like this approach is straightforward enough and is intuitive/aligned with how the rest of cargo works, especially with usage in a CI pipeline. So, I was wanted to post here and get some feedback and possibly start a PR? Maybe behind a |
Hi @kyle-rader-msft. We have solved a very similar problem in the following way:
|
Cargo does not appear to support this natively, so just roll our own behaviour: rust-lang/cargo#6583 This allows `nix run . -- --version` correctly compute the version derived from the flake git revision instead of using whatever is in `Cargo.toml`.
@faern tank you so much sharing that strategy! I need to delve into what's possible with |
FYI making the version field optional is effectively approved, see #12786. It comes with the limitation that you can't publish to a registry. I think @Faer's solution is great and was what I was getting at with my earlier comment about separating the role of your product's version from Cargo.toml. What id like to know if there are people who that solution doesn't work for. Most likely that would be people who have a reason for dynamically setting the version and publish to crates.io. |
Thanks for tackling this @epage |
feat(toml): Allow version-less manifests ### What does this PR try to resolve? Expected behavior with this PR: - `package.version` defaults to `0.0.0` - `package.publish` is defaulted to `version.is_some()` This also updates "cargo script" to rely on this new behavior. My motivation is to find ways to close the gap between "cargo script" and `Cargo.toml`. With "cargo script", we want to allow people to only write however much of a manifest is directly needed for the work they are doing (which includes having no manifest). Each difference between "cargo script" and `Cargo.toml` is a cost we have to pay in our documentation and a hurdle in a users understanding of what is happening. There has been other interest in this which I also find of interest (from #9829): - Lower boilerplate, whether for [cargo xtasks](https://github.com/matklad/cargo-xtask), nested packages (rust-lang/rfcs#3452), etc - Unmet expectations from users because this field is primarily targeted at registry operations when they want it for their marketing version (#6583). - Make "unpublished" packages stand out This then unblocks unifying `package.publish` by making the field's default based on the presence of a version as inspired by the proposal in #9829. Without this change, we were trading one form of boilerplate (`version = "0.0.0"`) for another (`publish = false`). Fixes #9829 Fixes #12690 Fixes #6153 ### How should we test and review this PR? The initial commit has test cases I thought would be relevant for this change and you can see how each commit affects those or existing test cases. Would definitely be interested in hearing of other troubling cases to test Implementation wise, I made `MaybeWorkspaceVersion` deserializer trim spaces so I could more easily handle the field being an `Option`. This is in its own commit. ### Additional information Alternatives considered - Making the default version "stand out more" with it being something like `0.0.0+HEAD`. The extra noise didn't seem worth it and people would contend over what the metadata field *should be* - Make the default version the lowest version possible (`0.0.0-0`?). Unsure if this will ever really matter especially since you can't publish - Defer defaulting `package.publish` and instead error - Further unifying more fields made this too compelling for me :) - Put this behind `-Zscript` and make it a part of rust-lang/rfcs#3502 - Having an affect outside of that RFC, I wanted to make sure this got the attention it deserved rather than getting lost in the noise of a large RFC. - Don't just default the version but make packages versionless - I extended the concept of versionless to `PackageId`'s internals and saw no observable difference - I then started to examine the idea of version being optional everywhere (via `PackageId`s API) and ... things got messy especially when starting to look at the resolver. This would have also added a lot of error checks / asserts for "the version must be set here". Overall, the gains seemed questionable and the cost high, so I held off.
#12786 is now merged. Now that In light of that, I propose to the cargo team that we close this issue and instead encourage people to look up the marketing version of their application as they best see fit (e.g. see #6583 (comment)), rather than trying to overload |
I need the package version to be dynamic (and was previously following #12144). I use git for version control, so the exact version of my package is stored there, rather than in
Ideally, if the current commit matches a git-tag, then that tag is the current version. If the current commit is 20 commit of the last tag, As prior art on this topic, in Python-world I use |
@WhyNotHugo is your version for use in the package registry or is it a marketing version? If its for marketing reasons, then my question would be "why does it need to be in If for the registry, it has the challenges of
Looking at the above, it feels like we can make something work but that it would have enough caveats and limitations that it wouldn't be up to the expected quality for a cargo feature. That leaves having some kind of plugin system. At that point, I think of the cost (implementation + maintenance + user support) compared to the benefit. The benefits seems relatively small to me especially when there is the "workaround" of release management tools which we will now be pointing people to as of #12745. |
There is no "marketing version" or anything alike. Please see #12144 for more in-depth details; what I explained above is covered there in greater detail. I'm just talking about publishing regular libraries and applications written in Rust.
Python supports multiple libraries in a single git repository too. For overly complex scenarios, setuptools_scm allow configuring the exact git command used to extract the version. It is perfectly possible to filter tags. E.g.: a package in a multi-package repository might only respect tags prefixed with its name.
If somebody is explicitly avoiding version metadata when fetching code, then it is expected that version metadata will be absent. I'm not sure that I understand the issue here.
Let's not let perfect be the enemy of good. The current approach is terrible: someone needs to remember to copy-paste the version into And builds made from intermediate versions (e.g.: N commits after the last tag) just drag the version from the last tag, rather than having a version that identifies them as distinct.
I do agree that plugins might be an overkill here. Something simpler should definitely be the aim. I looked briefly into the linked PR, but the suggested tools don't make sense to me. For example, When I tag |
I did look at that and the details I was asking for weren't there, hence why I asked.
There is a difference in expectations for a solutions to problems when contrasting python's "here are the tools, do it on your own" and cargo's "here is a first-class, native solution with a smooth workflow". We can learn from Python's experience but the Python experience is not optimized for the problems we'll have (it its janky).
I agree with the sentiment generally but taking it too far you gloss over fundamental problems which I think is happening here.. Without solving path dependencies, the problem hasn't gone away unless you restrict this to just single packages. That is a pretty dramatic restriction. Besides likely leading to more frustration when a feature is accessible sometimes but not always, it makes it unclear if a solution that gets stabilized will scale to workspaces. We are then stuck with supporting that solution for ... forever, increasing the load for the cargo team.
Let's not over-generalize. That is your workflow but I've not seen that generally applied in the Rust community. Instead, I've seen a lot of people fear release automation to the point that they don't even want to adopt a local-only tool that is dry-run by default and optionally logs everything it does to the screen. |
Maybe I'm missing something, but this, with cargo 1.78.0, doesn't seem to behave how I'd expect after reading this entire conversation:
I would expect the newly set version number to be applied as the build version. I'm also using
I would expect this to reflect the This doesn't seem like "set the package version dynamically" is working? There's a good possibility I've messed something up though. FWIW, my use case is that I need the version of my program, built in CI, to be the same as other programs built in the same pipeline (monorepo), so rather than modifying Also, I should mention that the version number (used across the monorepo) comes from elsewhere in the pipeline, it's not determinable in the Rust project context - it must be injected. If a EDIT: maybe |
@DavidAntliff See this comment: #6583 (comment)
You are not really supposed to put a product version into the Cargo version field, according to this comment. It's versioning for crates.io style registries.
It links to my previous comment about how we have solved basically the same problem you have. You will find it is much easier if you stop trying to cram the version into Cargo's |
I feel like this is a chicken and egg problem. Of course Rust community doesn't apply that workflow because it's not supported by Cargo or any other tools. Of course they fear release automation if the only way to implement it is with brittle scripts. I find it surprising that using a Version Control System as a single source of truth for managing versions of your software is a controversial topic. |
Hello
I'm building a rust application using internal teamcity CI job. I want the build number to be part of the version of the binary (so eg.
./app --version
knows from which build it came).The only way I found so far is to let the build first edit the
Cargo.toml
(sed -i -e 's/^version = .*/version = "%build.version%"/' Cargo.toml
), which seems ugly and fragile.It would be great if I could somehow override the version from
Cargo.toml
through the command line ‒ either as a parameter or an environment variable.Would something like that make sense? Are there plans to support it?
The text was updated successfully, but these errors were encountered: