Skip to content

chore: Self healing release - #533

Open
brunomenezes wants to merge 3 commits into
prerelease/v2-alphafrom
ci/self-healing-release
Open

brunomenezes wants to merge 3 commits into
prerelease/v2-alphafrom
ci/self-healing-release

Conversation

@brunomenezes

@brunomenezes brunomenezes commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Summary

The current state is a blocker to me as per description I am adding below. Therefore I will continue aligning my PRs using the temporary commits some of the branches have to be able to continue development with the latest SDK. However, I need the published SDK on docker hub to be able to get those PRs merged and the current mechanism does not allow that after a partial failure. Also, I am adding foundry to that new reusable workflow because is needed to what is in prerelease/v2-alpha, but it will be removed on #529 which already contains changes from #520 that remove the use of cartesi/devnet from the apps/cli

What happened on 2026-10-03

The 2.0.0-alpha.36 release failed partway through. changeset publish broke under npm 12 (fixed in #532) after it had already:

  • published @cartesi/cli@2.0.0-alpha.36 and @cartesi/devnet@2.0.0-alpha.15 to npm
  • pushed the git tags, including @cartesi/sdk@0.12.0-alpha.42
  • created the GitHub pre-releases

Because the step failed, changesets/action never set its published / publishedPackages outputs. Those outputs are the only thing that triggers the SDK image build and the CLI binary upload, so both were skipped:

  • cartesi/{sdk,rollups-runtime,rollups-database}:0.12.0-alpha.42 were never pushed to Docker Hub or GHCR
  • the @cartesi/cli@2.0.0-alpha.36 pre-release has no binaries

Re-running doesn't help. Every later run finds nothing new to publish, so the outputs stay false, and nothing in Actions can rebuild a release that's already tagged.

What this PR changes

Publishing artifacts is now decided by what exists, not by what this run just published.

  • New artifacts job in release.yaml. It runs after release, even if release failed, and checks the current SDK and CLI versions:
    • SDK: if the @cartesi/sdk@<version> tag exists and any of the 3 images is missing from Docker Hub or GHCR, the images are rebuilt.
    • CLI: if the @cartesi/cli@<version> GitHub release exists and has fewer than 4 cartesi-*.tar.gz binaries, they're rebuilt. Only those tarballs are counted, so other files on the release can't hide a missing binary.
  • Builds always come from the version tag, never from the pushed commit, so artifacts match the released source:
    • sdk.yaml takes an optional ref input. When it's empty, checkout behaves as before, so PR builds are unchanged.
    • The new reusable cli-binaries.yaml checks out the tag and cross-compiles all 4 targets (darwin and linux, arm64 and x64) with Bun on one runner. It then uploads them to the existing release with gh release upload --clobber. --clobber replaces only assets with the same name, such as tarballs left by a partial upload, so a retry doesn't fail with "asset already exists". Other files on the release are kept.
  • build_sdk and cli_binaries run only when artifacts finds something missing. The old checks based on changesets/action outputs are removed.

Why

  • Recovery is just re-running the Release workflow (or any push). No manual builds, no one-off workflows.
  • Fixes the current gap on merge: this PR's own Release run publishes the alpha.42 images and attaches the alpha.36 binaries to the existing pre-release.
  • Safe to run repeatedly: when everything exists, build_sdk and cli_binaries are skipped.

Just a note not a limitation: this only covers the current version of each package, not versions that were missed and have since been superseded.

@brunomenezes brunomenezes self-assigned this Oct 5, 2026
@brunomenezes brunomenezes added cli sdk github_actions Pull requests that update GitHub Actions code labels Oct 5, 2026
@changeset-bot

changeset-bot Bot commented Oct 5, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: e557ecd

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@tuler

tuler commented Oct 5, 2026

Copy link
Copy Markdown
Member

I think this adds even more complexity because of a bug in npm that is already fixed

@endersonmaia endersonmaia left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I found the workflow confusing, but sent my 2 cents on review.

Comment on lines +8 to +11
description: "Git ref to build the images from, e.g. refs/tags/@cartesi/sdk@0.12.0-alpha.42 (default: triggering commit)"
type: string
required: false
default: ""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

default: "" and the comment says it's the triggering commit

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

empty will be the commit that triggered the action.

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@908c540300062bd5a7e473851cdb4282204cee09 # v1.9.1
with:
version: v1.4.3

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

shouldn't it be 1.5.1 already? to match what's used on cartesi/rollups-contracts

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I mentioned in the PR description why it is here. It will be removed afterwards.

@brunomenezes

brunomenezes commented Oct 5, 2026 •

Copy link
Copy Markdown
Member Author

I found the workflow confusing, but sent my 2 cents on review.

What is confusing, could you explain? We have a bunch of automation, but it is not considering situations as the problem that happen this Saturday demonstrated. The SDK release and tags exist, but the publishing of the SDK images don't unless @tuler or whoever has authorisation on docker hub published it manually from that point onwards. That is not a good solution in my opinion. Let me know what in the PR description is confusing

@endersonmaia

Copy link
Copy Markdown
Member

What is confusing, could you explain?

I'm a little away from this code for some time, and I may have lost some context, but I think I'm spoiled by the changesets tool.

Instead of this PR, can't we just bump packages versions that are failing and move on? Would that work?

tuler commented Oct 5, 2026

Copy link
Copy Markdown
Member

I think this is more machinery than the problem needs. What happened on Saturday was a one-off: a tooling bug, already fixed in #532, failed the publish step after the tags were pushed. A rare partial failure calls for a simple manual recovery, not checks that run on every push.

This approach adds ongoing cost and risk:

  • Every push to a release branch probes the registries and GitHub releases. That's 6 image lookups plus a release query, forever, to cover something that has happened once.
  • It fails in the unsafe direction. Any imagetools inspect error, such as a Docker Hub rate limit, a network error or an auth problem, counts as "missing". That rebuilds and re-pushes all 3 images to both registries, overwriting already-released tags with images that aren't byte-identical.
  • It doesn't cover the case it's built for. build_sdk and cli_binaries have no status function in their if, so the implicit success() is false whenever release failed, even though artifacts ran with !cancelled(). The jobs get skipped exactly when release fails.
  • It hardcodes assumptions about every past tag. The image list and the Foundry pin get applied to whatever tag is being rebuilt. On main, for example, @cartesi/sdk@0.11.1 has no rollups-* images or bake targets, so a branch on that version would trigger a failing rebuild on every push.

A simpler fix: add a manual trigger to sdk.yaml.

on:
    workflow_dispatch:
        inputs:
            ref:
                description: Tag to build, e.g. refs/tags/@cartesi/sdk@0.12.0-alpha.42
                required: true

Keep the ref input and the with: ref: ${{ inputs.ref }} on checkout from this PR. Change the version-tag condition from github.event_name == 'push' to github.event_name != 'pull_request'. Then anyone with Actions access can rebuild a missed release from the tag using the repo's secrets, without needing Docker Hub credentials. That's about 10 lines and leaves release.yaml untouched.

For CLI binaries, a matching workflow_dispatch on a small upload workflow (your cli-binaries.yaml, with the trigger changed) covers the same case.

The recovery becomes: something failed → run the workflow once with the tag. It's explicit, easy to see, and adds nothing to the normal release path.


Generated by Claude Code

@tuler

tuler commented Oct 5, 2026

Copy link
Copy Markdown
Member

can't we just bump packages versions that are failing and move on? Would that work?

That would work. I approved the changes anyway.

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

Labels

cli github_actions Pull requests that update GitHub Actions code sdk

Projects

Status: In progress
Status: 📝 Changes Requested

Development

Successfully merging this pull request may close these issues.

3 participants