Arco ships as one product snapshot with one shared semantic version.
Every release version is shared across:
Cargo.tomlworkspace versionbindings/python/pyproject.tomlproject versionbindings/python/uv.lockpackage entry forarco- GitHub tag (
vX.Y.Z) - GitHub Release
- Keep release identity simple, one product version everywhere.
- Build once, publish the exact built artifacts.
- Keep release automation retryable and safe when failures happen.
- Ship everything together or nothing: GitHub Release and PyPI publish atomically.
release-pleaseowns changelog generation, version bump PRs (acrossCargo.toml,pyproject.toml, anduv.lock), tag creation, and draft GitHub Release creation (bookkeeping only — invisible to users).cargo-distowns cross-platform CLI binaries, installers, checksums, dist manifests, and publishing the GitHub Release (uploads artifacts to the draft and undrafts it).ci.yamlowns pre-merge validation: version consistency checks, code quality, and tests. cargo-dist also validates artifact builds on PRs viapr-run-mode.
| Workflow | Trigger | Purpose |
|---|---|---|
release-please.yaml |
push to main |
Maintains release PRs, creates tag + draft release, dispatches cargo-dist-release.yml, then builds and publishes Python package to PyPI |
cargo-dist-release.yml |
workflow_dispatch from release-please.yaml (with tag) or pull_request (dry-run) |
Builds CLI artifacts via cargo-dist, uploads them to the draft release, and publishes it |
release-please.yaml calls cargo-dist-release.yml as a reusable workflow
(workflow_call) because tags created with GITHUB_TOKEN do not trigger tag
workflows. The call passes the release tag as an input and GitHub Actions
natively waits for the called workflow to complete.
cargo-dist-release.yml is generated by cargo-dist. When called with a tag
(publishing mode), it runs these jobs in order:
plan
-> build-local-artifacts (matrix across target platforms)
-> build-global-artifacts (installers, checksums)
-> host (upload artifacts to draft + undraft with gh release edit)
-> announce
On pull_request triggers the workflow runs in dry-run mode: it plans and
builds artifacts but does not upload or create a release.
The py-build and publish-pypi jobs in release-please.yaml depend on the
cargo-dist job. This ensures the Python package is only published to
PyPI after cargo-dist has successfully published the GitHub Release. If
cargo-dist fails, nothing is published.
release-please is the source of truth for release notes and changelog content.
Changelog sections are configured in .release-please-config.json.
On any failure in cargo-dist-release.yml:
- The GitHub Release stays as a draft (invisible to users).
- Workflow artifacts are preserved for inspection and retries.
- No downstream jobs run after the failed step.
- Python package is not published to PyPI.
Retries rerun the workflow dispatch with the same tag. gh release upload --clobber ensures artifact uploads are idempotent.
cargo-dist-release.yml is auto-generated by cargo dist init. After
regeneration, manually re-apply:
- The
workflow_calltrigger withinputs.tag(required for reusable workflow call fromrelease-please.yaml). - The
timeout-minutesvalues on all jobs. - The
pathsfilter on thepull_requesttrigger. - The host job patch: replace
gh release createwithgh release upload+gh release edit --draft=false. Look for the# MODIFIED:comment.
New first-party bindings should join the shared product version stream unless explicitly declared as a separate product line.
If they join the stream, their build and publish steps should be added to the release workflow before the release is made public.
- Use Conventional Commits (
feat:,fix:,perf:,refactor:,docs:,build:,ci:). - Non-conventional commits may be omitted or misclassified in release notes.
Use Release-As only when an explicit one-off version override is necessary:
chore(release): force 0.3.0
Release-As: 0.3.0
Close stale release PRs and remove stale draft releases for old forced tags before rerunning automation.