Skip to content

Automate the Dart/Flutter release for livekit-uniffi - #1323

Open
hiroshihorie wants to merge 4 commits into
mainfrom
hiroshi/dart-uniffi-release
Open

Automate the Dart/Flutter release for livekit-uniffi#1323
hiroshihorie wants to merge 4 commits into
mainfrom
hiroshi/dart-uniffi-release

Conversation

@hiroshihorie

@hiroshihorie hiroshihorie commented Aug 10, 2026

Copy link
Copy Markdown
Member

Before you submit your PR

Make sure the following is true before submitting your PR:

  • I have read the contributing guidelines and validated that this PR will be accepted.
  • I have read and followed the principles regarding breaking changes, testing, and code quality.

PR description

Automates the Dart/Flutter half of the livekit-uniffi release (CLT-2872), the release-side prerequisite for livekit/client-sdk-flutter#1160. One commit per component:

  1. Pin uniffi-dart to the multi-crate codegen fixes (temporarily on ryangaus's fork; one fix is upstream as Emit runtime scaffolding once into a shared module Uniffi-Dart/uniffi-dart#150) and re-enable the Dart tests disabled since Data tracks UniFFI #1034.
  2. Make the generated package publishable: release builds omit the dev dylib and publish_to, and gain LICENSE/README/CHANGELOG and real version constraints. Fails closed for unknown profiles, and a dart-clean task keeps stale host dylibs out of release packages.
  3. Wire uniffi-cdylib.yml into uniffi-packages.yml so releases carry the build-<triple>.zip assets the Dart build hook downloads. Its tag name is now env-bound (Actions script injection, newly on the release path).
  4. Add a tag-push workflow publishing livekit_uniffi to pub.dev via OIDC (same mechanism as client-sdk-flutter's publish.yaml). It stages the package outside the work tree (packages/ is gitignored and pub archives from git's file listing) and gates on every zip having its sha256 sidecar.

Publishing stays disabled (PUBLISH_ENABLED=false, every run stops at --dry-run) until the pin moves off the personal fork, the first manual publish creates the package, and pub.dev automated publishing is configured. Runbook in the workflow header.

Follow-ups kept out: a stacked PR with two pre-existing CI cleanups, the fork-pin decision, and the non-atomic asset re-upload window.

Breaking changes

None. Dev-profile cargo make dart-package behaves as before.

MSRV

No changes.

Testing

  • Dev build: all 5 Dart FFI tests pass (same flow now re-enabled in CI).
  • Release build: dart pub publish --dry-run exits 0 with zero warnings and no dylib in the package; a release build over a previous dev tree stays clean.
  • Consumer: Integrate initial uniffi rust core client-sdk-flutter#1160's uniffi tests pass against the generated package, and the macOS example app ran a live room session on it.
  • The tag-push trigger and the asset wait can only be exercised by a real release; both are documented in the workflow header and cost nothing while publishing is disabled.

Async

No async code added; the crate surface is untouched.

🤖 Generated with Claude Code

…ests

The upstream rev pinned by #1183 predates data tracks, so the bindgen
emitted analysis errors (Bytes vs NativeType) for the multi-crate
surface and the Dart tests have been disabled since #1034. Pin the fork
rev that fixes multi-crate, custom-type and name-collision codegen; the
pin is temporary until upstream merges the fixes or a livekit fork
exists, see the Cargo.toml comment.

Verified locally: cargo make dart-package passes all 5 FFI tests across
the FFI boundary.
Split the dart-package flow by cargo-make profile: dev builds keep the
embedded host dylib and publish_to: none, release builds omit the dylib
(consumers use the hook's download mode) and clear publish_to so pub.dev
accepts the package. The publish_to guard fails closed, an unknown
profile still renders none. A dart-clean task starts every build from
scratch so a release build over a previous dev tree cannot ship the
stale host dylib, which the hook would prefer over download on every
platform.

Also add the metadata pub.dev requires or scores: LICENSE, README,
CHANGELOG, repository/homepage/issue_tracker pubspec fields, real
version constraints for code_assets/hooks (wide ranges, flutter_test
pins meta exactly so carets break older stable channels), and an
analysis_options.yaml so unused-import lints in generated code do not
fail publish validation.

Verified: both profiles build, all 5 FFI tests pass on the dev package,
dart pub publish --dry-run exits 0 on the release package, and a
release build over a dev tree contains no dylib.
@github-actions

Copy link
Copy Markdown
Contributor

Changeset ✓

This PR includes a changeset covering all affected packages:

Package Bump
livekit-uniffi patch

@hiroshihorie hiroshihorie changed the title Automate the Dart/Flutter release for livekit-uniffi (CLT-2872) Automate the Dart/Flutter release for livekit-uniffi Aug 10, 2026
Wire the existing uniffi-cdylib.yml into uniffi-packages.yml so every
livekit-uniffi release carries the build-<triple>.zip archives (and
sha256 sidecars) the Dart build hook downloads at consumer build time.
The assets attach to the already-published release, so the knope assets
marker stays off (a draft-based flow stranded releases before, #1256).

Since this activates the previously dormant uniffi-cdylib.yml on every
release, also bind its tag name through env instead of template
expanding it into the upload script: tag names may contain shell
metacharacters (Actions script injection).

The changeset cuts the release that carries the first assets.
pub.dev's automated publishing only accepts workflows triggered by a
push of a tag matching the configured pattern, so this cannot be a job
in the release-event-triggered uniffi-packages.yml. The workflow builds
the release-profile package (cached, before the asset wait), stages it
outside the work tree (pub archives from git's file listing and the
generated packages/ tree is gitignored), refuses to publish a package
containing a local native library, gates on every cdylib zip having its
sha256 sidecar, and fast-fails on mis-pointed tags or a missing release.
Tag names are env-bound, never template-expanded into scripts, since
the job holds id-token: write for pub.dev token minting.

PUBLISHING IS NOT ENABLED YET (PUBLISH_ENABLED=false): every run stops
at dart pub publish --dry-run until the uniffi-dart pin moves off the
personal fork, a livekit.io publisher admin has done the first manual
publish, and automated publishing is configured on pub.dev. See the
header for the full enablement steps.
@hiroshihorie
hiroshihorie force-pushed the hiroshi/dart-uniffi-release branch from 10fb002 to c343755 Compare August 11, 2026 04:18
@hiroshihorie
hiroshihorie marked this pull request as ready for review August 11, 2026 05:04
@hiroshihorie
hiroshihorie requested a review from ladvoc as a code owner August 11, 2026 05:04

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

Open in Devin Review

Comment thread livekit-uniffi/Cargo.toml
Comment on lines +30 to +34
# TEMPORARY: pinned to the multi-crate codegen fixes on ryangaus's fork
# (upstream is dormant; PR Uniffi-Dart/uniffi-dart#150 is one of them). Move
# the pin back to upstream once merged, or to a livekit-maintained fork if a
# release needs cutting before that (CLT-2872).
uniffi-dart = { git = "https://github.com/1egoman/uniffi-dart", rev = "ee04fd038659a9bd1438cbd297707861a55fd2f7", optional = true }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟨 Release build depends on a Rust code generator pinned to a personal GitHub fork

The Dart bindings generator is pinned to a git revision on an individual's personal fork (https://github.com/1egoman/uniffi-dart) rather than an upstream or organization-controlled repository. This code runs during the release build in CI (.github/workflows/uniffi-dart-publish.yml:135 runs cargo make --profile release dart-package, which compiles and executes uniffi-bindgen-dart) in a job that also holds id-token: write and can mint a pub.dev publishing token. A compromise or force-push of that personal repo would let attacker-controlled code execute in the publishing job. The PR text acknowledges this is temporary and publishing is gated off, and the pin is by immutable rev, which limits (but does not eliminate) exposure.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

crate with [UniFFI](https://mozilla.github.io/uniffi-rs/) and
[uniffi-dart](https://github.com/Uniffi-Dart/uniffi-dart).

This is a low-level package. It is consumed by

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice callout! We should make sure this is included in all the READMEs for the package repos (outside the scope of this PR).

# Flip to "true" once the enablement steps in the header are done. Real
# publishing additionally requires a tag-push trigger; workflow_dispatch
# runs always stop at the dry run (pub.dev rejects their OIDC tokens).
PUBLISH_ENABLED: "false"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

question: Might it make sense to turn this into a workflow input like some of the other workflows do?

- name: Setup Dart
uses: dart-lang/setup-dart@65eb853c7ba17dde3be364c3d2858773e7144260 # v1.7.2
with:
sdk: stable

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

question: Should this pin to a specific release?

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.

2 participants