Repository navigation
0.32.0 - 2026-10-16
-
Use native input protocol 5 for the compiler driver.
The driver now reports the libraries that rustc selects from each native search directory.
Cargo-Rail rejects independent compiler adapter packs from 0.30 and 0.31, which use protocol 4.
Publish these packs again for this release. -
Replace the release subcommands with one stateless command,
cargo rail release.
This release breaks release commands,[release]configuration, and release workflows.
After you upgrade, runcargo rail config migrateand replace the release workflow.cargo rail release [CRATE...] [--bump B] [--pr] [--yes] [--dry-run]shows one preview and asks for confirmation once.
Then it writes the release commit and tags it.
It pushes the branch and every tag in one atomic push.
It uploads to the registry in dependency order and creates GitHub releases.
The push succeeds only iforiginstill has the starting branch tip and has none of the tags.
--dry-runruns every precondition check and changes nothing.- When you run the command again after an interruption, it finishes the release.
It reads progress from the remote tags, the registry, and GitHub.
It counts a published version as done only when the.cargo_vcs_info.jsonof that version names the release commit. - This release removes
release run,check,resume,status,abort,record, andinit.
Each removed subcommand prints its replacement.
This release also removes hosted execution,--local,--executor,--retain-remote,--prepare, release plan files,--allow-non-default-branch, GitLab releases,
and the MSRV check. - Releases keep no records.
This release removes release record refs, local release journals,clean --release-journal, and therelease-record-v11schema.
Iforiginstill holdsrefs/notes/cargo-rail/*refs from 0.31 or earlier, the result shows a warning.
The warning names these refs and gives the command that deletes them. - A release requires that every check run and commit status on its source commit passes
(release.checks = "all", the default on a GitHuborigin).
Pending checks stop the command with exit code 1 before any effect. - For GitHub access, Cargo-Rail uses the REST API with
GH_TOKEN,GITHUB_TOKEN, orgh auth token.
The GitHub CLI is not required, except to verify asset attestations. [release]addscrates,publish,github_release,checks,assets, andasset_attestations.
It retiresremote_effects,registry_publication,hosted_workflow,validation,artifacts,tag_prefix,require_change_files,release_notes_dir,require_release_notes, and the{prefix}tag placeholder.
config migratereplaces the retired fields and keeps their behavior.
It writes successors only to a file that contains a retired field or the{prefix}placeholder.
For example, such a file withoutregistry_publication = "crates-io"getspublish = "none".
Aliases accept{major}and{minor}.- A configuration without retired fields gets the new release defaults.
By default, 0.31 published to no registry and created no GitHub releases.
By default, 0.32 publishes to crates.io.
On a GitHuborigin, it also creates GitHub releases and useschecks = "all".
To keep publication and GitHub releases off, setpublish = "none",github_release = false, andchecks = "none".
Publication still needs a registry credential, and the release checks for it before any effect. release.publishnamescrates-io,none, or any Cargo registry with a sparse index.
The registry credential check reads Cargo configuration.
Packaging and semver checks run without registry or forge tokens.release.crateslimits the crates that a release manages.
change checkrequires change files only for these crates.--propens the release commit as a pull request.
When a squash merge drops the release trailer,
the next run finds the merged pull request through GitHub and tags the merged commit.
If the branch moved before the merge, the run shows a warning.- Before Cargo-Rail publishes a draft release,
it downloads eachrelease.assetsfile and compares the file with the SHA-256 that GitHub recorded.
Then it runsgh attestation verifyfor this repository and the release commit or its parent.
release.asset_attestations = "off"skips the attestation check. - The command finishes a release commit that Cargo-Rail 0.31 created.
- If a literal
vNalias would name a different major version, the release stops before any effect.
-
Bind each native search directory by the libraries that rustc selects from it, not by its content.
A directory such as/usr/lib/x86_64-linux-gnucan contain symbolic links, unrelated files, and subdirectories.
These entries no longer block or invalidate reuse of the crates that a-sysbuild script reaches.
The compiler driver reports each native-library search that rustc performs itself.
The action binds every candidate through the spelling, canonical target,
and bytes of the selected library.
Reuse-l NAMEand-l dylib=NAMEactions.
A crate such aspq-sysno longer bypasses.Name the cause of a capture bypass, such as a linked source entry or a capture bound.
Add one example for each of the first recorded bypass reasons tocargo rail cache report --finish.
Count a failed cold admission under its own reason.
Before, Cargo-Rail joined it to the miss reason and did not count it. -
Remove unused public library items.
No command used them, and the command-line interface is unchanged.
The removed items are:- 38 functions with no production caller, including the
SystemGitremote helpers
(add_remote,push_to_remote,fetch_from_remote,ls_remote_has_content),
unusedWorkspaceGraphtraversals of dependents, and unusedtomleditor methods; - the
workspace::WorkspaceViewandCrateInfofacade; UnifyOutputFormat, replaced byTextJsonOutputFormatwith the same values;toml::WorkspaceDepsBuilderandtoml::editor::TomlBatchEditor;WorkspaceContext::build_with_source_capture.
Surface backups no longer embed the configuration in
metadata.json.
Nothing read this configuration.
Also, when the embedded configuration held a key that a later release retired,
Cargo-Rail could not list or restore the backup. - 38 functions with no production caller, including the
-
Select remote cache storage for compilation only through
cache setup.
Cargo gives repository[env]values and build-scriptrustc-envoutput to the compiler wrapper.
Before this change, a repository could use these values to setCARGO_RAIL_CACHE_REMOTE,CARGO_RAIL_CACHE_MODE, orCARGO_RAIL_CACHE_REMOTE_ENVIRONMENT.
It could then select a different bucket, change a read-only setup to read-write,
or add environment names to the remote cache identity.
The compiler wrapper andcache statusnow ignore all three variables.
They use the remote that setup saved.
Cargo does not set the environment of a Cargo-Rail command that you start directly.
For this reason,cache probeand the compiler analysis ofunifyandsurfacestill read these variables. -
Read build-script rerun declarations as Cargo reads them: trim each output line first.
Before, Cargo-Rail ignored an indentedcargo:rerun-if-changed=PATHline.
Compiler evidence could then stay reusable after that file changed.Unify no longer treats
cfg(target_feature = "...")orcfg(panic = "...")code as unreachable when barerustc --print cfgomits the value.
Rustflags and the profile can enable both values.Separate remote-cache coordinators by Azure credential selection, such as
AZURE_CLIENT_IDorAZURE_FEDERATED_TOKEN_FILE.
AWS credentials already separated coordinators in the same way.Planning-evidence identities must use lowercase hexadecimal digits, as the
planning-evidence-v2schema requires. -
Reject
--checkand otherunifyorconfig migrateoptions that come before theapplysubcommand.
Before,cargo rail unify --check applyignored--checkand wrote manifests.Keep machine output to one JSON value.
--json unify undono longer printsbackup restoredbefore the JSON result.
When a--diagnostics-filewrite fails after a successful command, Cargo-Rail reports the failure on stderr.
A missing working directory or a failed standard-output write now causes exit code 2, not 1.
Exit code 1 means a pending mutation.config migrate applyno longer deletes a default-only file that--configselected explicitly.
A default-only file contains only default values.
initrefuses to write below the Cargo workspace root,
because configuration discovery never reads a file there.
init --forceno longer overwrites a file that another discovery location shadows.config explain --alllistsrelease.auxiliary_cargo_manifestsandunify.transitive_pinning.hostwhen they are unset.
config explainalso accepts these fields by name.
Theplanhelp examples save and verify the plan undertarget/.
An untracked plan file inside the checkout is itself drift.Without
--since,planandchange checkselect a default ref: the first oforigin/HEAD,origin/main,origin/master,main, ormasterthat exists.
They fail when none of these refs exists.
plancompares against the merge base of the default ref andHEAD.
change checkcompares against the default ref itself, or against that merge base with--merge-base.
Before, when neitherorigin/HEADnororigin/mainexisted, both commands compared againstHEAD~1.
That comparison left out earlier commits on the branch. -
Bind whether each package has a default README in reused Clippy results.
cargo metadatareportsREADME.md,README.txt, orREADMEas the README of a package without areadmekey.
clippy::cargo_common_metadatareads that name.
Before this change, a new or removed README did not change the Clippy action.
With-D clippy::cargo, a hit could then replay a pass after the README was removed.
The contents of a README are still not bound, so an edit to a README still hits. -
Cargo-Rail captures some inputs after the compiler exits.
Store no cold result when one of these inputs changed while the compiler ran.
This rule covers linker inputs, failed linker lookups, native-library candidates,
procedural-macro reads, and selected repository inputs.
Otherwise, a cold result could bind a state that the compiler never read.
For example, a file could change and then return to its earlier content during compilation.
A candidate could also appear and then disappear during compilation.
The action bypasses withcold_input_changed_during_execution. -
Keep one compiler session for each compiler environment in a build, up to eight sessions.
Cargo runs build-script probes with different library search paths from its ordinary units.
A build no longer recaptures the session each time it switches between these environments.
Each recapture ran tworustcqueries. -
Reuse a cached action when another compiler wrapper replaces the shared compiler session
while this wrapper reads it.
The read now tries again under the session lock.
Before, it bypassed withnative_cache_session_unavailable.
Add the error that causes a session, installation, or local cache bypass to thecargo rail cache reportdetails. -
Avoid unnecessary ELF linker search probes for directly named archives and object files.
Linker scripts and binary metadata retain candidates for actual or uncertain searches,
and every selected file keeps its content binding.
Separate limits for found files
and absent search candidates prevent their combined count from causing unnecessaryelf_linker_witness_unavailablebypasses on
large workspaces. -
Reuse crates whose build scripts emit a bare
rustc-link-searchor-L all=directory outside the repository.
An example is non-bundledlibsqlite3-syswith a system library directory.
Rustc also searches that directory for Rust crates.
That search now binds by absolute host path.
Before, it bypassed withcompiler_native_input_evidence_unavailable. -
On macOS, stage the compiler-observation wrappers as clones instead of hard links.
The first launch of a new executable waits for a Gatekeeper scan.
When the scan resolved a hard link to the deleted copy of another command, it terminated the launch. -
Name every condition that stops a procedural macro unit in the cache report.
Before this change, the example named only the first condition.
For example, a macro that startscargo metadataand reads.envfiles outside the repository showed only the process.
The example now names each effect, secret-named variable, process, and read.
The unit still has one reason, so the reason counts still add up to the bypassed units.
A process appears as its program and subcommand, such ascargo metadata, without its other arguments. -
Reuse units whose procedural macros search upward past the workspace root for a missing file.
For example,sqlx0.9 looks for a.envfile in each directory up to the file-system root.
Before this change, each check outside the repository made the unit bypass withprocedural_macro_read_outside_repository.
The action now binds the absence of that name in every directory above the root.
If a file with that name exists above the root, the unit still runs on the ordinary compiler path.
Remote storage neither publishes nor restores these results,
because directories outside the repository decide them. -
Reuse crates that load a procedural macro that links an asynchronous runtime but never starts it.
Classify the event-queue, fork-handler, socket, and descriptor functions that the standard library,
tokio, and mio import.
These functions include glibc's__register_atforkand macOSkqueueandkevent.
A function with an effect records that effect only when the macro calls the function.
Treat every socket operation and every change of user, group, or session as an effect.
Require that the import table and the Linux system-call table classify each operation in the same
way. -
Plan changes outside a nested workspace.
A changed Cargo configuration file
or toolchain file in a parent directory of the workspace root now requires every built-in Cargo item
for the whole workspace.
A changedrustfmt.toml,clippy.toml, ordeny.tomlfile in that location requirescargo.fmt,cargo.clippy, ordependency-policy, respectively.
Any other changed file outside the workspace widens built-in Cargo work
until planning evidence shows that no compiler read it.
Before, the planner dropped these changes and skipped the work as if the evidence were complete. -
Reuse a library that Cargo compiles before the rlib of a dependency is complete.
Cargo starts a dependent from the rmeta of the dependency.
A compilation that reads only crate metadata never reads the rlib that has the same filename hash.
That rlib is no longer an input.
Its appearance during compilation no longer causes a bypass withcompiler_native_input_evidence_unavailable.
As a result, cold and warm builds bind the same search. -
Plan every built-in Cargo item for the whole workspace when
rust-toolchain.toml,rust-toolchain, or the root.cargo/config.tomlchanges.
Plancargo.clippyfor the whole workspace when a Clippy configuration file changes.
These files have an effect on every package.
Before, a change to these files together with a change to the source of one member selected only
that member and its dependents.Emit exact test targets for a package only when its own target files are the sole reason
for its selection.
A package whose dependency also changed now keeps all of its targets.
For example,bdepends ona, and bothcrates/a/src/lib.rsandcrates/b/tests/it.rschange.
Packagebnow keeps all of its targets. -
Apply a mutation plan that was saved inside the worktree.
Before,config migrate -f json > migrate.jsonfollowed byconfig migrate apply --plan migrate.jsonfailed with "mutation drift detected".
This failure occurred because the shell createdmigrate.jsonbefore the preview captured the worktree.
The same failure occurred after a secondunify --check -o plan.jsonrun and with every other--planconsumer.
The preview now ignores the file that its standard output or-owrites.
Apply now ignores the file that--plannames.
A relative--planor-opath is relative to the current directory. -
Make Git operations safer:
- When Cargo-Rail stages or cleans planned paths, it treats
*,?,
and[in file names as literal characters. - A split
remotemust not start with-.
Git receives every configured remote after--, so a value such as--upload-pack=<command>cannot run a command. - The post-apply check for unplanned changes now sees files that appeared
after Cargo-Rail captured the plan.
- When Cargo-Rail stages or cleans planned paths, it treats
-
Refuse a release when the changelog path, the change directory, or a change file is a symbolic link.
Before, the release followed the link and wrote its target, which configuration does not name.
For example,CHANGELOG.md -> target/CHANGELOG.mdcommitted the ignoredtarget/CHANGELOG.md.
A link to a file outside the repository was already refused, but for a different reason.
change statusandchange checkalso refuse a linked change file or change directory.
change addrefuses to write through a linked change directory. -
List change entries in release notes and changelogs by bump level.
majorentries come first, thenminorentries, thenpatchentries.
Before, entries followed the change-file names.
Thus, a breaking change and its upgrade steps could come last.
Entries with the same level keep the order of their file names. -
Keep the release push credential away from build scripts and procedural macros.
Release runners pass the push token as process-scoped Git configuration (GIT_CONFIG_*variables).
The companion Action and this repository's release workflow do this.
cargo rail releasenow removes these variables fromcargo packageandcargo semver-checks.
It already removed the registry and forge tokens there.
Before, code that these commands compiled and ran could read the push token. -
On Linux and macOS, hash each unchanged input file once for each compiler wrapper.
Before, Cargo-Rail hashed a static library in theOUT_DIRof a-syscrate again when rustc selected it.
It hashed that library again before it restored a hit. -
Build Cargo-Rail release archives and their bundled compiler driver with Rust 1.99.0.
The bundled driver serves only the exact compiler that built it.
For a workspace on another compiler, such as Rust 1.98.1,
Cargo-Rail builds the driver from its authenticated source with that compiler.
That build needs therustc-devcomponent of the workspace toolchain. -
With
release.semver_check = "deny", a crate that has no baseline tag is checked against the registry that receives it.
The release asks that registry whether the crate has an earlier version.
Before, it always asked crates.io.
Thus, an unrelated crates.io crate with the same name could block a release to another registry. -
When
cargo semver-checkscannot produce a verdict, the release warning names its error.
Before, the warning showed the first line of output, such asCloning <commit>.
The error came later, for example a baseline dependency that crates.io yanked. -
Compile one fewer view for a package that declares features but no
defaultfeature.
For that package,--no-default-featurescompiles the same configuration as the default selection.
Surface and the compiler evidence ofunifycompiled that configuration twice. -
An rlib or staticlib that rustc writes can hold a native-library member.
Compile without reuse when the compilation did not generate that member
and no reported native-library search selected it.
A future rustc might bundle a library that the compiler driver does not report.
With this rule, the archive then cannot be bound without the search that chose the library. -
Store no linked result when rustc passes a library by path from a native search directory
and no reported native-library search selected it, unless the compiler arguments name that path.
The action bypasses withnative_library_search_unreportedbecause the search that chose the library is unbound.Startup objects and runtime files added by GCC
or Clang do not require a rustc native-library search report.
Their contents and driver-selected paths remain bound by the linker witness. -
On Windows, accept a
file:///C:/...origin for releases.
Cargo-Rail read the URL path as/C:/..., which is not an absolute Windows path,
so it refused the origin as relative.