Skip to content

crate publishing workflow#755

Open
Copilot wants to merge 8 commits intomainfrom
copilot/automate-crate-publishing
Open

crate publishing workflow#755
Copilot wants to merge 8 commits intomainfrom
copilot/automate-crate-publishing

Conversation

Copy link
Contributor

Copilot AI commented Feb 10, 2026

The automated publish workflow could only be triggered by pushing version tags, making it impossible to test changes to the workflow or validate a release without actually publishing to crates.io.

Changes

Workflow trigger

  • Added workflow_dispatch with dry_run input (defaults to true)
  • Skip tag version validation when manually triggered

Publish logic

  • Pass --dry-run flag to cargo publish when enabled
  • Skip crate availability polling in dry-run mode (no actual uploads)
  • Visual indicators for mode: 🧪 DRY-RUN MODE vs 📦 LIVE MODE

Documentation

  • RELEASING.md: Testing section with dry-run vs live comparison
  • .github/TESTING_RELEASES.md: Step-by-step testing guide

Usage

Manual test without publishing:

# GitHub Actions UI → "Publish to crates.io" → "Run workflow"
# Branch: main, dry_run: true

Actual publish (unchanged):

git tag v0.46.0 && git push origin v0.46.0

Dry-run validates packaging, dependencies, and publish order across all 15 crates without uploading to the registry.

Original prompt

This section details on the original issue you should resolve

<issue_title>Automate crate publishing</issue_title>
<issue_description>## Is your feature request related to a problem? Please describe.
Automatically publish new versions to crates.io</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 4 commits February 10, 2026 16:32
Co-authored-by: harsha-simhadri <5590673+harsha-simhadri@users.noreply.github.com>
Co-authored-by: harsha-simhadri <5590673+harsha-simhadri@users.noreply.github.com>
Co-authored-by: harsha-simhadri <5590673+harsha-simhadri@users.noreply.github.com>
Co-authored-by: harsha-simhadri <5590673+harsha-simhadri@users.noreply.github.com>
Copilot AI changed the title [WIP] Automate publishing of new versions to crates.io Automate crate publishing to crates.io Feb 10, 2026
Co-authored-by: harsha-simhadri <5590673+harsha-simhadri@users.noreply.github.com>
Copilot AI changed the title Automate crate publishing to crates.io Add dry-run testing for crate publishing workflow Feb 10, 2026
@harsha-simhadri harsha-simhadri changed the title Add dry-run testing for crate publishing workflow crate publishing workflow Feb 17, 2026
@codecov-commenter
Copy link

codecov-commenter commented Feb 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.00%. Comparing base (3674a49) to head (24b706a).
⚠️ Report is 14 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##             main     #755    +/-   ##
========================================
  Coverage   88.99%   89.00%            
========================================
  Files         428      428            
  Lines       78234    78417   +183     
========================================
+ Hits        69626    69793   +167     
- Misses       8608     8624    +16     
Flag Coverage Δ
miri 89.00% <ø> (+<0.01%) ⬆️
unittests 89.00% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 61 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@harsha-simhadri harsha-simhadri marked this pull request as ready for review February 18, 2026 21:36
@harsha-simhadri harsha-simhadri requested review from a team and Copilot February 18, 2026 21:36
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an automated crate publishing workflow for releasing DiskANN crates to crates.io. The workflow can be triggered manually via workflow_dispatch with a dry-run option (default: true) for testing, or automatically when pushing version tags matching v{major}.{minor}.{patch}. The implementation aims to enable safe testing of the release process without actual publication.

Changes:

  • Added .github/workflows/publish.yml workflow with dual-trigger support (tags and manual dispatch)
  • Added .github/PUBLISH_CRATES.md documentation describing the release process and testing procedures
  • Implemented dry-run mode for testing packaging and validation without publishing

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.

File Description
.github/workflows/publish.yml New GitHub Actions workflow that validates versions, runs tests, and publishes workspace crates with optional dry-run mode
.github/PUBLISH_CRATES.md Comprehensive documentation covering prerequisites, dry-run testing, release steps, and pre-release checklist

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

DRY_RUN_FLAG="--dry-run"
echo "🧪 DRY-RUN MODE"
fi
cargo publish --locked --workspace $DRY_RUN_FLAG
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cargo publish command does not support a --workspace flag. As of Rust 1.92 (and as of January 2025), cargo publish only publishes a single crate at a time. To publish multiple workspace crates, you need to either:

  1. Use a loop to publish each crate individually in dependency order
  2. Use a tool like cargo-workspaces or cargo-release
  3. Manually specify the publish order

The current command will fail with an error. You'll need to implement a solution that publishes crates one at a time, ensuring dependencies are published and indexed before their dependents.

Suggested change
cargo publish --locked --workspace $DRY_RUN_FLAG
echo "Resolving workspace crates to publish..."
PKGS=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.source == null) | .name')
if [ -z "$PKGS" ]; then
echo "::error::No workspace crates found to publish"
exit 1
fi
for pkg in $PKGS; do
echo "📦 Publishing crate: $pkg (DRY_RUN_FLAG='$DRY_RUN_FLAG')"
cargo publish --locked -p "$pkg" $DRY_RUN_FLAG
# When actually publishing, wait a bit for crates.io index to update
if [ -z "$DRY_RUN_FLAG" ]; then
echo "Waiting for crates.io index to update before publishing the next crate..."
sleep 30
fi
done

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not accurate. There is a cargo publish --workspace and it does work. It doesn't necessarily handle partial failures gracefully, but hopefully those are relatively rare.


## Overview

All workspace crates are published together with synchronized version numbers using `cargo publish --workspace`, which automatically resolves dependency order and waits for each crate to be indexed before publishing its dependents. The release is triggered by pushing a version tag. The Rust toolchain version is read from [`rust-toolchain.toml`](../../rust-toolchain.toml).
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states that cargo publish --workspace "automatically resolves dependency order and waits for each crate to be indexed before publishing its dependents," but this is not accurate. The cargo publish command does not have a --workspace flag and does not automatically handle dependency ordering or index polling. This documentation needs to be updated to reflect the actual implementation approach.

Copilot uses AI. Check for mistakes.
DRY_RUN_FLAG=""
if [ "${{ github.event.inputs.dry_run || 'false' }}" = "true" ]; then
DRY_RUN_FLAG="--dry-run"
echo "🧪 DRY-RUN MODE"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When not in dry-run mode (live publishing), there's no visual indicator in the logs. Consider adding an else clause to echo a message like "📦 LIVE MODE - Publishing to crates.io" to make it clear when actual publishing is happening. This helps prevent accidental publishes and makes logs easier to understand.

Suggested change
echo "🧪 DRY-RUN MODE"
echo "🧪 DRY-RUN MODE"
else
echo "📦 LIVE MODE - Publishing to crates.io"

Copilot uses AI. Check for mistakes.
if: github.event_name == 'push'
run: |
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -n1 | sed 's/.*"\(.*\)".*/\1/')
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version extraction uses grep '^version = ' Cargo.toml | head -n1 which assumes the workspace version is the first version field in the file. However, looking at the root Cargo.toml structure, the version is under [workspace.package] section. A more robust approach would be to use grep -A 5 '^\[workspace\.package\]' Cargo.toml | grep 'version = ' or use a proper TOML parser to avoid potential mismatches if the file structure changes.

Suggested change
CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -n1 | sed 's/.*"\(.*\)".*/\1/')
CARGO_VERSION=$(grep -A 5 '^\[workspace\.package\]' Cargo.toml | grep 'version = ' | head -n1 | sed 's/.*"\(.*\)".*/\1/')

Copilot uses AI. Check for mistakes.
### Option 2: Local

```bash
cargo publish --locked --workspace --dry-run
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command example shows cargo publish --locked --workspace --dry-run, but as noted, cargo publish does not support --workspace. This example needs to be updated to reflect the actual implementation.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +30
3. Watch the workflow — look for successful `cargo publish --workspace --dry-run`

### Option 2: Local

```bash
cargo publish --locked --workspace --dry-run
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation mentions "look for successful cargo publish --workspace --dry-run" but this command format is invalid. Update this to reflect the actual command that will be used.

Suggested change
3. Watch the workflow — look for successful `cargo publish --workspace --dry-run`
### Option 2: Local
```bash
cargo publish --locked --workspace --dry-run
3. Watch the workflow — look for successful `cargo publish --locked --dry-run`
### Option 2: Local
```bash
cargo publish --locked --dry-run

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +67
- name: Verify version matches tag
if: github.event_name == 'push'
run: |
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -n1 | sed 's/.*"\(.*\)".*/\1/')
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
echo "::error::Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
exit 1
fi
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a validation step to ensure that all workspace crates use version.workspace = true and don't have hardcoded versions. This would catch configuration errors before attempting to publish. A simple check like grep -r '^version = "' */Cargo.toml | grep -v workspace could identify crates with hardcoded versions.

Copilot uses AI. Check for mistakes.
exit 1
fi

- name: Run tests
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running the full test suite on every publish attempt (including dry-run) adds significant time to the workflow. Consider making the test step conditional with if: github.event.inputs.dry_run != 'true' || github.event_name == 'push' to skip tests during dry-run testing, since tests are already validated in PR CI checks before merging. However, keeping tests for actual releases (tag pushes) is valuable as a final safety check.

Suggested change
- name: Run tests
- name: Run tests
if: github.event.inputs.dry_run != 'true' || github.event_name == 'push'

Copilot uses AI. Check for mistakes.
### What Dry-Run Tests

- Crate metadata and packaging validation
- Dependency resolution and publish ordering
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The claim that dry-run tests "Dependency resolution and publish ordering" is misleading. Since workspace-wide publishing isn't supported by cargo publish, the actual implementation will need to determine publish order separately. A dry-run of a single crate publish won't validate that all crates will be published in the correct dependency order.

Copilot uses AI. Check for mistakes.
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
run: |
DRY_RUN_FLAG=""
if [ "${{ github.event.inputs.dry_run || 'false' }}" = "true" ]; then
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dry-run default expression github.event.inputs.dry_run || 'false' will evaluate to 'false' when the workflow is triggered by a tag push (since github.event.inputs.dry_run will be empty/null). This is correct behavior for tag-triggered publishes. However, consider making this more explicit with a comment or using a more readable approach like setting a workflow-level environment variable that checks both the trigger type and input.

Suggested change
if [ "${{ github.event.inputs.dry_run || 'false' }}" = "true" ]; then
# For tag-push events, github.event.inputs.dry_run is empty, so this evaluates to a real (non-dry-run) publish.
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then

Copilot uses AI. Check for mistakes.

- name: Publish workspace crates
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vermy minor - this can be slightly safer with

   env:
      DRY_RUN: ${{ github.event.inputs.dry_run || 'false ' }}

And then using DRY_RUN to set the DRY_RUN_FLAG internally rather than expanding the entire github.event directly in the shell script. Evaluating it in env should force it to be a boolean as an extra safety measure.

- name: Read Rust version from rust-toolchain.toml
id: rust-version
run: |
RUST_VERSION=$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading from rust-toolchain.toml is a nice trick - we should update ci.yml to do the same thing (though probably in a different PR).

cargo search diskann --limit 20
```

### Example Pre-Release Flow
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This recommends pushing directly to main, which we can't do due to branch protection rules.

Instead, we should use this workflow:

  1. Checkout main, bump the version and push.
  2. Make a pull-request out of the version bumped commit.
  3. Use the dry-run as a pre-merge check.
  4. Merge the PR and use the github UI to tag the release along with change notes.


- name: Verify version matches tag
if: github.event_name == 'push'
run: |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I noticed while adding another comment is that since manual running takes dry-run as a parameter - it's currently possible to publish without a dry run from branches that aren't main.

Copilot suggest putting something like this early in the workflow

   - name: Prevent publish from non-main branch
     if: >-
       github.event_name == 'workflow_dispatch'
       && github.event.inputs.dry_run != 'true'
       && github.ref != 'refs/heads/main'
     run: |
       echo "Live publishing is only allowed from main. Use dry-run for other branches."
       exit 1

which I think is reasonable. It will fail the triggered manually on a branch that is not main and dry-run is not provided.


### What It Does NOT Test

- Actual publishing, registry token auth, upload reliability
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to mention what to do if the publish step fails. Basically, we either need to manually fix and publish the remaining crates, or fix the publish issue, bump the version number, and bump again (or if the fix doesn't change the versions that succeeded, then the remaining ones can be updated and pushed potentially in the same release).

If the publishing fails part way through for networking issues, then we'll need to handle the remaining ones manually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Automate crate publishing

4 participants

Comments