hercules-ci.cargo-publish

The options in hercules-ci.cargo-publish automate publishing Rust crates to crates.io or a custom registry.

In its default configuration, this will run cargo publish --dry-run on every branch push, and perform an actual publish when a tag is pushed.

Complete Example

{
  description = "A Rust project with automated publishing";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects";
  };

  outputs = inputs@{ self, flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      imports = [
        inputs.hercules-ci-effects.flakeModule
      ];
      systems = [ "x86_64-linux" ];
      hercules-ci.cargo-publish = {
        enable = true;
        secretName = "crates-io";
        assertVersions = true;  # Check all packages match the tag version
      };
    };
}
nix

Workflow

Initial Setup

  1. Enable the module in your flake.nix with hercules-ci.cargo-publish.enable = true

  2. Set the version in Cargo.toml to a version that doesn’t exist on crates.io yet (e.g., 0.1.0)

  3. On each push, Hercules CI runs cargo publish --dry-run to verify the package is publishable

Releasing a Version

  1. Review the version — the version in Cargo.toml is probably a patch bump from the last release. Consider whether breaking changes or new features warrant a minor or major bump instead.

  2. Push a tag matching the version in Cargo.toml:

    git tag 0.1.0
    git push origin 0.1.0
    shell
  3. Hercules CI detects the tag and runs cargo publish

  4. Bump the version in Cargo.toml to the next version (e.g., 0.1.1) to allow dry-run checks to verify subsequent commits

With assertVersions = true (module) or assertVersions = "0.1.0" (function), the effect verifies that all workspace package versions match the tag name before publishing.

Rate Limits

When publishing a workspace with many crates for the first time, you may hit crates.io rate limits. The registry limits new crate registrations more strictly than updates to existing crates. At the time of writing, crates.io allows a burst of about 5 new packages, then requires a wait of approximately 10 minutes before publishing more.

If you encounter rate limit errors during an initial release:

  1. Wait for the rate limit to reset (approximately 10 minutes)

  2. Use extraPublishArgs to publish remaining crates individually:

    hercules-ci.cargo-publish = {
      enable = true;
      secretName = "crates-io";
      extraPublishArgs = [ "--package" "my-unpublished-crate" ];
    };
    nix
  3. Run locally with hci effect run to iterate through remaining crates:

    hci effect run onPush.default.effects.cargo-publish --pretend-ref refs/tags/0.1.0
    shell

After the initial release, subsequent version updates are less likely to hit rate limits.

See also