Skip to content

Latest commit

 

History

History
257 lines (214 loc) · 12.5 KB

releasing.md

File metadata and controls

257 lines (214 loc) · 12.5 KB

Releasing RustiQ

RustiQ uses dist to build and publish binary archives to GitHub Releases. crates.io publication runs in a separate workflow, so a registry outage does not block a binary release. Neither workflow creates a release from a GitHub Release event; both are triggered directly by a version tag, and crates.io publication can also be started manually for an existing tag.

Binary releases

The repository-root dist-workspace.toml pins dist 0.33.0, selects only the rustiq-chem CLI package, and lists the six supported targets. Pull requests run dist plan; this checks the release plan without building or publishing artifacts. The generated workflow also runs on non-main pull requests because dist 0.33.0 does not expose a pull-request base-branch filter. A pull request cannot enter the publishing jobs.

All six target builds use native GitHub-hosted runners: Linux x64 on ubuntu-22.04, Linux ARM64 on ubuntu-24.04-arm, macOS Intel on macos-15-intel, Apple Silicon on macos-14, Windows x64 on windows-2025, and Windows ARM64 on windows-11-arm. The configuration explicitly selects the ARM runners and preserves the native Windows runners.

The rustiq-chem-core library remains a build dependency and is not packaged as an application. The generated workflow is .github/workflows/release.yml. It pins actions/upload-artifact to an exact version. Because cargo-dist emits a major version reference for that action, dist-workspace.toml sets allow-dirty = ["ci"] so dist plan does not reject the exact pin as an out-of-date generated workflow. Keep the pin synchronized with the intended upload-artifact release when updating the workflow or cargo-dist.

Release rehearsal

Run Actions → Release artifact smoke test → Run workflow and select the commit, branch, or tag to rehearse. The manually triggered workflow builds the configured target archive with the pinned dist version on each target's native GitHub-hosted runner. It extracts that archive, verifies its dist-generated SHA-256 checksum, starts the packaged rustiq executable, checks --help, and runs the checked-in H2/STO-3G regression with a copied local basis fixture and JSON output. Per-target results appear in the job summary; archives, dist manifests, and command logs are uploaded as workflow artifacts.

This checks archive integrity and basic executable operation for the six configured targets. The H2 energy comparison reuses the regression reference and is a packaging smoke test, not broad scientific validation, independent platform validation, or proof of compatibility with every supported operating system. The runs use GitHub-hosted runners, which are not pristine operating system installations. A sha256.sum release manifest may only be created in the tagged release's combined build; when unavailable, the rehearsal verifies the per-archive checksum emitted by dist and fails if neither checksum is available. A checksum made during a rehearsal does not independently validate a published release.

The rehearsal has read-only repository permissions and only a workflow_dispatch trigger. It does not run dist's host command, upload release assets, create a GitHub Release, create tags, or publish crates. It complements .github/workflows/release.yml, whose tagged-release path builds and publishes the release assets; ordinary pull requests continue to use the generated plan-only check.

Each executable archive includes rustiq (named rustiq.exe on Windows), the README, LICENSE-MIT, LICENSE-APACHE, COPYING, DISTRIBUTION.md, and THIRD-PARTY-NOTICES.txt. RustiQ-authored source retains MIT OR Apache-2.0; Malachite and ansi_colours retain their LGPL terms. COPYING supplies the GPLv3 text referenced by LGPLv3, rather than imposing GPLv3 on all RustiQ code. Unix archives use .tar.gz and Windows archives use .zip. Dist adds a .sha256 file for each archive and a sha256.sum manifest. Installers are disabled. Archives do not include calculation samples or basis data.

Each release also includes rustiq-corresponding-source.tar.gz, generated by the dist extra-artifact command python3 tools/distribution.py source before publication. This supplies the committed repository tree and all locked dependency sources. The generated Cargo configuration allows registry-free rebuilding. Dist's repository-only source tarball is disabled because it would omit the dependency sources. Dist treats this file as an extra artifact; it does not emit a separate checksum for it in the release plan. Before publishing, verify that the source archive is actually present in the release assets and corresponds to the tagged commit. Its checksum can be calculated separately when verifying distribution integrity. See licenses and redistribution for rebuild instructions and the requirements for package maintainers. The Nix package installs the same notice documents into share/doc/rustiq; its metadata describes RustiQ's MIT/Apache terms and the bundled LGPL/MPL components.

To verify the assets listed in sha256.sum on Linux, download it and all listed assets into one directory, then run:

sha256sum --check sha256.sum

On macOS, use the built-in shasum command:

shasum -a 256 --check sha256.sum

On Windows PowerShell, use the explicit manifest comparison in the installation guide, replacing its example archive filename with the archive for your target.

The archive target identifies the operating system and CPU architecture; it does not guarantee compatibility with every Linux distribution or older system library. The Linux GNU archives require a compatible glibc runtime.

Preparing a release

From the repository root, update the version in both package manifests and update the CLI's rustiq-chem-core dependency requirement to that same version:

  • Cargo.toml (rustiq-chem)
  • crates/rustiq-core/Cargo.toml (rustiq-chem-core)
  • Cargo.toml's rustiq-core dependency

After editing the manifests, regenerate Cargo.lock and the corresponding notices. The distribution script needs Python with tarfile extraction filters: Python 3.12 or later, or the backported filters in Python 3.10.12+/3.11.4+. This is independent of the optional PySCF environment. Enter the Nix rust or full shell for the pinned notice generator, or install cargo-about 0.9.2 outside Nix, then run:

cargo check --workspace
cargo install cargo-about --version 0.9.2 --locked
python3 tools/distribution.py notices
python3 tools/distribution.py check
cargo deny --locked --workspace --all-features check
git add Cargo.toml crates/rustiq-core/Cargo.toml Cargo.lock THIRD-PARTY-NOTICES.txt THIRD-PARTY-NOTICES.sha256
git commit -m "Prepare release X.Y.Z"

The publishing workflow checks both package versions and the CLI dependency requirement against the tag using Cargo metadata. After committing the version change, build the workspace:

cargo check --workspace --locked

A binary release does not require registry publication readiness. There is currently no local Nickel patch or corresponding crates.io publication block. Before publishing crates, review the acknowledged upstream advisories described in crates.io publication and run cargo publish --dry-run --workspace --locked.

Regenerate and commit notices after changing dependencies, license configuration, the notice template or generator. Review supplemental upstream notices when updating crates whose published packages omit their licenses. CI checks their package inventory, input hashes and generated-file integrity. This catches stale or accidentally edited output; it does not independently verify every license clause or certify legal compliance. Review generated notices and supplemental attribution when changing dependencies. To rehearse the complete source delivery from a clean committed checkout:

python3 tools/distribution.py source

The command rejects source changes and untracked files, except the dist workflow's generated JSON manifests. It verifies offline Cargo resolution from the archive staging tree. Before a release, also extract the source artifact and run the reconstruction command documented in licensing.

Review the dist release plan and regenerate the workflow after changing the dist configuration or updating dist. The allow-dirty = ["ci"] setting means the generator does not check whether the checked-in release workflow matches its current template. Preserve the exact upload-artifact pin if you regenerate the workflow:

dist plan
dist generate --mode ci
dist generate --mode ci --check

The Rust development shell includes the Nixpkgs cargo-dist package. The generated workflow installs the exact dist version recorded in dist-workspace.toml. Before regenerating locally, install that same version if the Nixpkgs package differs:

cargo install cargo-dist --version 0.33.0 --locked

Commit and push the version changes, then create and push the matching tag:

git tag vX.Y.Z
git push origin HEAD
git push origin vX.Y.Z

Release tags must match vX.Y.Z or vX.Y.Z-prerelease, such as v1.2.3 or v0.1.0-beta.1. For a prerelease, include the same suffix in both package versions and the tag. Dist recognizes the suffix and marks the GitHub Release as a prerelease. Do not reuse an existing tag or a crates.io package version.

The tag starts dist's generated workflow, which builds the configured platform archives, creates their checksums, and publishes the assets to GitHub Releases. A dist plan-jobs reusable workflow validates the tag format and requires its commit to be an ancestor of main before artifact builds can proceed. This accepts prerelease suffixes such as -alpha.1. A failed validation blocks the build and therefore the publishing jobs.

crates.io publication

Nickel 0.19's published dependency graph currently includes imbl-sized-chunks 0.1.3, affected by the unfixed security advisory RUSTSEC-2026-0292, and the unmaintained bitmaps 3.2.1 (RUSTSEC-2026-0247). RustiQ intentionally uses Nickel's published releases: it does not fork Nickel or backport its transitive dependencies. deny.toml records explicit exceptions for these advisories. Passing cargo deny check does not indicate that the vulnerability is fixed. Review these exceptions and upstream fixes before each release; see dependency review.

The crates.io workflow is not blocked by these exceptions. A version tag can trigger publication of both crates while the upstream vulnerability remains present. Decide whether to publish that version with the documented risk or hold the tag until Nickel publishes a compatible fix.

.github/workflows/publish-crates.yml publishes both workspace crates when a v* tag on main is pushed. Cargo publishes workspace members in dependency order, so rustiq-chem-core is available before rustiq-chem. Before publishing, the workflow uses the crates.io API to exclude package versions that already exist. If a run publishes the core crate and then fails while publishing the CLI, rerunning the same tag skips the existing core version and retries the CLI. For a retry, open Actions → Publish crates.io packages → Run workflow, enter the existing v… tag, and start the workflow. This workflow remains separate from the dist binary release workflow and can also be run manually for an existing tag.

The workflow currently authenticates with the Actions secret CARGO_REGISTRY_TOKEN. Create it from a crates.io API token with only package publishing permissions, then add it under the repository's Actions secrets before the first release. Keep the token out of repository files and do not grant permissions to yank crates.

Crates.io Trusted Publishing uses GitHub OIDC and avoids a long-lived token, but crates.io requires each crate to have an initial token-authenticated publication before a Trusted Publisher can be configured. For RustiQ's first publication, use CARGO_REGISTRY_TOKEN to publish both packages through the tag workflow or its manual execution for an existing tag. After both crates exist, configure a Trusted Publisher for each crate in crates.io to trust this repository and the publishing workflow. A follow-up change can then replace the token authentication with OIDC; the binary release workflow does not use or depend on the crates.io token.

Cargo may time out while waiting for a published version to appear in the registry index even when the upload succeeded. Check the version on crates.io before retrying; the workflow's existence check will skip a version already published.