Skip to content

Decide and document crate versioning policy + release runbook #10

Open

Description

@iainmcgin

v0.2.1 shipped with connectrpc at 0.2.1 while connectrpc-codegen
and connectrpc-build stayed at 0.2.0 (nothing changed in them). Then
the v0.2.1 tag triggered a binary release - but those binaries come
from connectrpc-codegen, which didn't change, so they're functionally
identical to v0.2.0's.

Neither of these is wrong, but there's no written policy and the
interaction is a little awkward. This issue is for deciding and writing
it down before the next release.

The versioning question

Lockstep (bump all crates together): simpler user mental model
("use 0.2.1 everywhere"), trivially answers "which codegen works with
which runtime." prost does this. Every release is one version.

Independent (only bump what changed): semver-accurate, no zero-diff
publishes cluttering the crates.io index. tonic does this for patches,
lockstep for minor/major.

Relevant constraint: codegen emits calls to connectrpc APIs, so
there's a real coupling - a codegen bump that emits a new helper call
needs a matching runtime bump. Lockstep makes this trivially
discoverable; independent means documenting "codegen X requires
runtime >= Y" somewhere.

Relevant observation: if we want a GitHub release for every
version (discoverability, changelog visibility), and the release
workflow builds protoc-gen-connect-rust binaries from whatever's on
the tag, then a runtime-only patch under independent versioning
produces a release with redundant binaries. Lockstep sidesteps this:
every tag corresponds to a real codegen build.

The runbook question

Separately, there's no written doc for "how to cut a release" - the
sequence is publish workflow dispatch -> tag push, and the publish
workflow is idempotent so order doesn't strictly matter, but none of
that is written down outside the workflow comments themselves.

Deliverable

Probably a RELEASING.md covering both: the policy, and the steps.

Activity

  1. rvcas commented on Mar 26, 2026

    @rvcas

    I recommend using sampo to granularly/independently bump crate versions as needed. For a while I used to just use cargo release and bump versions for all crates in a monorepo in lock step but that feels dirty for some reason. Sampo brings the changeset workflow to rust monorepos. Changesets provide much better changelogs per crate instead of scraping conventional commits which are technical details not necessarily user facing change documentation. Also Claude is very good at generating change set files. It's truly a fantastic workflow that I've been using on my projects. Happy to help set it up.

    https://github.com/bruits/sampo

    Sampo would handle

    • crate version bumping
    • maintaining a rebased release PR at all times if changesets are present on main
    • uploading to crates.io on release PR merge
    • pushing tags and GitHub releases
    • merging a release PR deletes the consumed changeset files

    Example GitHub action handles it all:

    name: Sampo
    
    on:
      push:
        branches: [main]
      workflow_dispatch: {}
    
    permissions:
      contents: write
      pull-requests: write
    
    jobs:
      sampo:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
            with:
              fetch-depth: 0
              token: ${{ secrets.TAG_TOKEN }}
          - name: Configure git identity
            run: |
              git config user.name "rvcas"
              git config user.email "x@rvcas.dev"
          - name: Sampo
            id: sampo
            uses: bruits/sampo/crates/sampo-github-action@main
            with:
              cargo-token: ${{ secrets.CARGO_TOKEN }}
            env:
              GITHUB_TOKEN: ${{ secrets.TAG_TOKEN }}
  2. iainmcgin commented on Apr 1, 2026

    @iainmcgin
    CollaboratorAuthor

    This looks very interesting, I'll invest some time into this post v0.3.0!

  3. rvcas commented on Apr 12, 2026

    @rvcas

    No worries, just wanted to point to something useful

  4. zackberaznik commented on May 5, 2026

    @zackberaznik

    Hi @iainmcgin — happy to take a swing at this if it's still up for grabs. Two scope questions before I start:

    1. Documentation only, or also migrate to Sampo? Reading your "looks interesting, post v0.3.0" comment, I'm not sure if you've made a call. If documentation-only, I'd write a RELEASING.md matching the existing flow: lockstep version bumps across the three publishable crates (which is what 0.3.0–0.3.3 actually did), the [Unreleased] → numbered-section CHANGELOG ritual, manual workflow_dispatch for publish-crates.yml with a dry-run pass, then tag push to fire release.yml.
    2. On versioning policy specifically: the v0.2.1 patch where only connectrpc bumped (and connectrpc-codegen/connectrpc-build stayed at 0.2.0) reads as the awkwardness you're flagging. Is the intent going forward to always lockstep, or keep that as an option for runtime-only patches?

    Happy to defer if you'd rather write it yourself or are already mid-Sampo evaluation.

  5. iainmcgin commented on May 15, 2026

    @iainmcgin
    CollaboratorAuthor

    @zackberaznik I haven't given this much more thought yet, and have been getting by with the current agent-managed approach to updating the CHANGELOG. Happy for you to take a stab at this and send us a PR that shows how to use sampo to manage the process.

    I'd like to keep all the connectrpc related crates in version lockstep, as I think that's easier to reason about. Buffa and connectrpc can diverge, as I expect they'll start changing at different rates over time.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions