ci(repo): add automated per-package pub.dev publishing - #142
Conversation
Replace StreamReactions.onPressed (a bare VoidCallback shared by every chip) with onReactionPressed, which reports the pressed StreamReactionsItem — or null for the cluster/overflow chip, which represents no single reaction. Add an optional StreamReactionsItem.key so callers can identify the pressed item. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ction-pressed # Conflicts: # packages/stream_core_flutter/CHANGELOG.md # packages/stream_core_flutter/test/components/reaction/stream_reactions_test.dart
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nPressed in gallery Extract the callback type into OnReactionItemPressed (mirrors OnReactionItemPicked). Migrate the design system gallery to onReactionPressed and demonstrate it by showing a snackbar with the tapped emoji. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ssed Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ng it Keep onPressed (VoidCallback) as a deprecated fallback alongside the new onReactionPressed, so the change is non-breaking (mirrors the chat onReactionsTap deprecation). onReactionPressed wins when both are set; onPressed is folded in via the chip callback. Requires a few deprecated_member_use ignores since core runs --fatal-infos + deprecated_consistency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deprecate only the public StreamReactions constructor onPressed params (which is what warns callers) and leave the internal StreamReactionsProps field un-annotated, mirroring the chat StreamMessageItem pattern. Referencing the deprecated ctor param in its own initializer isn't flagged, and internal props access is clean — so no // ignore comments are needed in lib. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ction-pressed # Conflicts: # packages/stream_core_flutter/CHANGELOG.md
Add tag + publish workflows for the repo's independent per-package versioning, so merging a release PR publishes each bumped package to pub.dev via OIDC (no stored credentials) and cuts a GitHub Release. - release_tag.yml: on a `chore(...): release` merge to main, tag every package whose current version is not yet on pub.dev (`<pkg>-vX.Y.Z`, derived from package state — robust to multi-package release PRs and title typos) and push the tags dependency-first. - release_publish.yml: on a `<pkg>-vX.Y.Z` tag push (+ workflow_dispatch for re-runs), verify the tag against the pubspec, publish that one package (OIDC), and create a per-package GitHub Release from its CHANGELOG section. A dependency gate waits until each in-workspace dependency is live on pub.dev before publishing, guaranteeing dependent order without a manual re-run. Releases are never marked "latest" since packages version independently. - STYLE_GUIDE.md: document the release flow. Manual setup (bot token + pub.dev config) done in FLU-638. Closes FLU-636. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds release preparation guidance and a ChangesRelease automation
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant PackageTag
participant release_publish
participant PubDev
participant Melos
participant GitHubRelease
PackageTag->>release_publish: package and version tag
release_publish->>Melos: bootstrap and lint package
release_publish->>PubDev: poll dependency versions
PubDev-->>release_publish: required versions available
release_publish->>Melos: publish scoped package
release_publish->>PubDev: verify package publication
release_publish->>GitHubRelease: create release with changelog notes
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #142 +/- ##
=======================================
Coverage 54.70% 54.70%
=======================================
Files 185 185
Lines 7575 7575
=======================================
Hits 4144 4144
Misses 3431 3431 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
.github/workflows/release_publish.yml (1)
172-184: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider
gh release createinstead of a third-party action.The GitHub-hosted runner already ships
gh, sogh release create --title ... --notes-file ... ${{ github.ref_name }}would drop the third-party action dependency. Purely optional —action-gh-releaseis a widely-trusted, well-maintained action, so the practical benefit here is marginal.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release_publish.yml around lines 172 - 184, Optionally replace the softprops/action-gh-release step with a native gh release create command, passing the parsed package/version as the title, the notes output path as the notes file, and github.ref_name as the tag. Preserve prerelease handling, make_latest: false behavior, and authentication through the existing token.Source: Linters/SAST tools
.github/workflows/release_tag.yml (1)
23-29: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winReduce bot-PAT credential exposure window in both release workflows.
Both workflows check out with the bot PAT and the default
persist-credentials: true, so the write-scoped token sits in git config through every later step — includingflutter pub global activate melos/melos bootstrap, which execute third-party pub.dev code. The fix differs per file because only one of them actually needs the persisted credential:
.github/workflows/release_tag.yml#L23-L29: still needs togit pushtags later, so keep the credential but scope it — e.g.persist-credentials: falseplus an explicitgit remote set-url origin https://x-access-token:${TOKEN}@github.com/...immediately before the push step, so the token isn't sitting in git config during the Flutter/melos install steps..github/workflows/release_publish.yml#L23-L27: never pushes to git (the GitHub Release step already passestoken:explicitly at line 184), sopersist-credentials: falsecan be set here with no functional change.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release_tag.yml around lines 23 - 29, Reduce bot PAT exposure in both checkout steps: in .github/workflows/release_tag.yml at lines 23-29, disable persisted credentials and configure the authenticated origin immediately before the later tag push using the bot token; in .github/workflows/release_publish.yml at lines 23-27, disable persisted credentials since no git push occurs and the release action supplies its token explicitly.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release_publish.yml:
- Around line 39-45: Harden the tag parsing around the release workflow’s parse
step by replacing the unbounded version capture in the tag regex with the
repository’s expected semver-shaped pattern. For every affected run step, expose
the parsed package and version through step-level env variables and reference
those shell variables instead of directly interpolating
steps.parse.outputs.package/version in the script; preserve the existing release
behavior.
In
`@packages/stream_core_flutter/lib/src/components/reaction/stream_reactions.dart`:
- Around line 197-202: Add `@Deprecated` annotations to the legacy onPressed
constructor parameter and corresponding final field in StreamReactionsProps,
preserving the existing deprecation guidance used by the widget-level API and
leaving onReactionPressed unchanged.
---
Nitpick comments:
In @.github/workflows/release_publish.yml:
- Around line 172-184: Optionally replace the softprops/action-gh-release step
with a native gh release create command, passing the parsed package/version as
the title, the notes output path as the notes file, and github.ref_name as the
tag. Preserve prerelease handling, make_latest: false behavior, and
authentication through the existing token.
In @.github/workflows/release_tag.yml:
- Around line 23-29: Reduce bot PAT exposure in both checkout steps: in
.github/workflows/release_tag.yml at lines 23-29, disable persisted credentials
and configure the authenticated origin immediately before the later tag push
using the bot token; in .github/workflows/release_publish.yml at lines 23-27,
disable persisted credentials since no git push occurs and the release action
supplies its token explicitly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 99f85e54-97a9-4d71-8be2-2985a2051c5b
📒 Files selected for processing (8)
.github/workflows/release_publish.yml.github/workflows/release_tag.ymlSTYLE_GUIDE.mdapps/design_system_gallery/lib/components/message/stream_message_content.dartapps/design_system_gallery/lib/components/reaction/stream_reactions.dartpackages/stream_core_flutter/CHANGELOG.mdpackages/stream_core_flutter/lib/src/components/reaction/stream_reactions.dartpackages/stream_core_flutter/test/components/reaction/stream_reactions_test.dart
Extract the tag/publish commands from the workflows into `release:tag`, `release:pub:dry`, and `release:pub` melos scripts (matching the existing `lint:pub` convention) so they're documented in one place and runnable locally. Workflows now call `melos run …`. All three scripts publish/tag in dependency order (`--order-dependents`), so a dependency is always tagged/published before anything that depends on it — correct even when `release:pub` is run unscoped. The publish workflow scopes each run to one package via the MELOS_PACKAGES env var (melos's `--scope` flag can't read an env var from a script). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ed-package-publishing-for-core
Port of stream-chat-flutter release-pr skill, adapted for per-package independent versioning and hand-curated changelogs (no melos version). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Repurpose the existing lint:pub to chat's exact pre-publish dry-run command and make release:pub byte-identical (`-f`); drop the redundant release:pub:dry. release_publish now runs `melos run lint:pub` for the dry run. release:tag stays (no chat equivalent — per-package tagging). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… in skill Multi-package release PRs use a generic `chore(repo): release packages` title (short regardless of package count) instead of enumerating each pkg+version. The release-pr skill now derives packages from `packages/*` and scopes from pr_title.yml instead of a hard-coded table. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dependency gate now polls `melos list --published --scope=$dep` (melos's own published detection, same as --no-published) instead of curling the pub.dev API. Drops the hardcoded URL and the pubspec version parsing; melos checks the workspace version directly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses CodeRabbit/zizmor findings:
- Bound the tag version capture to a semver shape (was an open-ended `.+`).
- Pass parsed package/version to the gate and changelog steps via step-level
env vars instead of interpolating ${{ }} into the run: scripts (avoids
template injection; dry-run/publish already used env).
- persist-credentials: false on checkout — this job never pushes, so the bot
token no longer sits in git config through the melos/pub steps.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The checkout is read-only (only the Release step pushes, with its own token), so drop the bot PAT from it entirely — the default GITHUB_TOKEN clones fine. Combined with persist-credentials: false, the bot PAT never enters this job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep the bot PAT and default persist-credentials on the checkout to
match stream-chat-flutter, reverting the persist-credentials/token
change. The regex tightening and env-var scoping (no ${{ }} in run:)
stay.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Before publishing, check the per-version pub.dev endpoint (/api/packages/$PKG/versions/$VERSION) and skip the publish step if the version is already live. melos --no-published (which release:pub uses) reads the package listing, which lags for minutes after a publish, so re-running a finished publish could wrongly retry and fail "already exists". The version endpoint stays fresh, so re-runs are now a clean no-op while the CHANGELOG/GitHub Release steps still run. Validated end-to-end on a real per-package test repo: a fresh publish proceeds; re-running a published tag skips publish and exits 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re-runs of an already-published tag rely on melos --no-published (like stream-chat-flutter and the melos-action ecosystem). The guard only helped when manually re-running an already-succeeded publish — an uncommon, self-inflicted case where the failure is safe (pub.dev rejects the duplicate; nothing double-publishes). Keeping the workflow minimal and matching the reference repos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ation Replace the bespoke "wait until in-workspace deps are on pub.dev" gate step with `flutter pub publish --skip-validation` on the publish command — Dart's recommended approach for publishing interdependent packages. A package no longer blocks on its dependency being indexed; the dependent resolves once the dependency's own run lands moments later. Removes the melos --graph/awk/jq parsing and the melos --published poll, whose CI listing-lag made coordinated releases slow (~75s+/level) and brittle. Validated end-to-end on a per-package test repo: chain and fan-out releases publish immediately with no failures. Tradeoff: if a dependency's own publish fails, the dependent is momentarily unresolvable until the dependency is re-published (safe, idempotent re-run). Documented in STYLE_GUIDE. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Align the release-notes step with bluefireteam/melos-action: - resolve the package dir via `melos list --json` instead of assuming `packages/<name>` (drops the dir==name assumption). - match the `## <version>` heading by version token ($2==ver), so a dated heading like `## 0.4.0 (2026-07-31)` is still found. - append a "Published to pub.dev: <link>" footer to the release body. Verified on the test repo: a dated-header release extracts correctly and links to the published version. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Publishing interdependent packages with --skip-validation would let a dependent publish before its dependency is live on pub.dev, leaving it momentarily unresolvable if the dependency's own run fails. Restore the "Wait for in-workspace dependencies" step: it polls pub.dev's fresh per-version endpoint until each dependency is live before publishing, so a dependent never publishes against a missing dependency. release:pub drops --skip-validation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
.github/workflows/release_publish.yml (1)
111-111: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueSplit the overlong shell statements.
Lines 111 and 146 exceed 120 characters. Split the timeout error branch and construct the changelog URL in a separate variable.
As per coding guidelines,
**/*.{dart,yaml}files must use a maximum line width of 120 characters.Also applies to: 146-146
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release_publish.yml at line 111, Split the overlong timeout error branch near the dependency wait logic into separate shell statements while preserving its error message and exit behavior. At the changelog-generation logic near the corresponding URL construction, assign the URL to a separate variable before using it, keeping every YAML/Dart line within 120 characters.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/skills/release-pr/SKILL.md:
- Line 65: Update the release workflow instructions around the branch update and
staging checks to use git status --short, not git status --short -uno. Check for
any tracked or untracked changes before checkout and again immediately before
git add -A, and stop the release process when either check is non-empty.
In @.github/workflows/release_publish.yml:
- Line 110: Update the pub.dev probe in the until loop to pass curl connection
and total-transfer time limits using --connect-timeout and --max-time, ensuring
each request returns within a bounded duration so the existing 15-minute expiry
check can execute.
- Around line 6-7: Update the release tag patterns in the workflow to recognize
Dart build-metadata versions with a literal “+” suffix, escaping the plus for
GitHub Actions glob syntax. Add the corresponding +<build> parse-regex branch
and matching trigger pattern in release_tag.yml, alongside the existing stable
and prerelease patterns.
In `@melos.yaml`:
- Around line 121-124: Update the tag creation command in the melos exec release
flow to check whether an existing $MELOS_PACKAGE_NAME-v$MELOS_PACKAGE_VERSION
tag resolves to HEAD; allow the command to succeed only when it already points
to HEAD or can be created for HEAD, and fail otherwise. Remove the unconditional
`|| true` suppression while preserving the subsequent push behavior.
---
Nitpick comments:
In @.github/workflows/release_publish.yml:
- Line 111: Split the overlong timeout error branch near the dependency wait
logic into separate shell statements while preserving its error message and exit
behavior. At the changelog-generation logic near the corresponding URL
construction, assign the URL to a separate variable before using it, keeping
every YAML/Dart line within 120 characters.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 88aece31-8308-45ee-aa41-4d99e6226d8a
📒 Files selected for processing (5)
.claude/skills/release-pr/SKILL.md.github/workflows/release_publish.yml.github/workflows/release_tag.ymlSTYLE_GUIDE.mdmelos.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
- STYLE_GUIDE.md
…se skill Address CodeRabbit review on #142: - release_publish.yml: align the tag trigger with pub.dev's suggested OIDC pattern (`<pkg>-vX.Y.Z*`) and extend the parse regex to accept build metadata (`+…`) alongside pre-release suffixes. A `+build` release now fires the workflow and validates, rather than being silently skipped. Make pre-release detection ignore the build-metadata part. - release-pr skill: pre-flight now requires `git status --short` clean *including untracked files*, so a stray local file can't enter the release commit via `git add -A`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address CodeRabbit review on #142: - release_publish.yml: add --connect-timeout/--max-time to the dependency wait probe so a stalled transfer can't hang past the 15-minute deadline. - release:tag: replace `git tag … || true` with tag_package.sh, which creates the tag at HEAD, no-ops if it already points at HEAD, and fails loudly if an existing tag points at a different commit (a stale/failed release) instead of silently re-pushing the wrong tree or skipping the publish. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse release:tag's two exec passes into one that tags (via tag_package.sh) then pushes each package in dependency order — matching chat's tag-then-push shape. The stale-tag guard still runs first, and `&&` skips the push if it fails, so a bad tag never gets pushed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move `git push` into the script so release:tag is a single script call per package. The push is idempotent (no-op if origin already has the tag) and is skipped when the stale-tag guard fails. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace tag_package.sh with melos-action's proven pattern: create tags with `git tag … || true`, then push only tags that point at HEAD, one at a time. Pushing only HEAD tags means a stale tag on an old commit (e.g. a prior release that was tagged but never published) is simply ignored rather than failing the whole run — no stop-the-line, while still emitting one tag event per package. The publish-side dependency wait already handles ordering, so pushes need no special order. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9115c3d to
015a791
Compare
Address review feedback: - release:tag pushed via `git tag --points-at HEAD`, which git sorts lexicographically — so "dependency order" held only by the accident that `-` sorts before `_`. Push inside the ordered `melos exec` instead, so a dependency's tag is genuinely pushed (and published) before its dependent's. The docs' "tags push in dependency order" claim is now true. - Document that tagging is state-derived: it tags every unpublished package, not just the ones a PR bumped — so keep version bumps to release PRs, and publish a brand-new package before releasing anything that depends on it (else the dependent's wait polls for a version that never lands). - Make that wait's timeout message name the new-package cause instead of a bare "re-run once it's published". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5f5ba3a to
bc02c18
Compare
renefloor
left a comment
There was a problem hiding this comment.
Reviewed this with the load-bearing melos assumptions verified locally against the melos source and this workspace. Overall a well-reasoned design — the per-package tag + dependency-wait approach is the right answer to "more independent than chat", and most of the tricky details hold up. Findings below, ranked.
Should fix
1. lint:pub is now a no-op — verified
Adding --no-published means it matches zero packages once versions are released, which is the steady state. All three current versions are live on pub.dev (stream_core 0.4.0, stream_core_flutter 0.4.1, stream_thumbnail 0.1.0):
$ melos exec -c 1 --no-published --no-private --order-dependents -- "echo HIT"
└> RUNNING (in 0 packages) # was 3 packages with the old filter
└> SUCCESSSo the "melos run lint:pub passes for all three packages" line in the description is vacuously true, and the script loses its old role as a local "are these actually publishable?" check.
Suggestion: leave lint:pub unfiltered (all non-private packages) and let MELOS_PACKAGES do the scoping in the workflow. That's strictly better — the 🌵 Dry Run step then actually runs even on a re-run of an already-published tag, and pub publish -n doesn't check version collisions, so idempotency is unaffected.
2. The dependency wait includes dev-dependencies and private packages
melos list --graph emits allDependenciesInWorkspace, which is dependencies + devDependencies + dependencyOverrides (melos/lib/src/package.dart:874). Today the graph is stream_core_flutter: ["stream_core"], so it's fine — but the first time a publishable package takes a workspace dev-dependency on a private package (a test-utils package, or stream_thumbnail_example), the release blocks for 15 minutes polling a pub.dev URL that will never 200, then fails — for a dependency that publishing never needed in the first place.
melos list --json already carries "private": true|false; filtering the dep list on it (and ideally down to real dependencies only) closes this.
3. Nothing verifies the publish actually landed
Between 📢 Publish to pub.dev and 🚀 Create GitHub Release there's no check that the version is live. If the scoped release:pub filter matches zero packages for any reason, the step reports SUCCESS and you get a GitHub Release announcing a version that isn't on pub.dev.
The curl poll from the wait step is already written — reusing it once after publish makes that state unreachable.
Worth fixing
4. Silent skip on an existing tag
if git tag $MELOS_PACKAGE_NAME-v$MELOS_PACKAGE_VERSION 2>/dev/null; then git push ...; fiswallows the failure, so a stale tag on an old commit drops a package from the release with a green run. An else echo "::warning ::..." costs nothing.
Related: there are currently no stream_core-v* tags at all in this repo — only stream_core_flutter-v*, stream_thumbnail-v0.1.0, and the legacy v0.x tags. So the "an existing tag fails git tag and is skipped" safety net that the release:tag description leans on doesn't exist for stream_core.
5. release_tag.yml has no workflow_dispatch
It's gated on a commit-message prefix that the skill itself calls "load-bearing". If a squash title gets edited on the way in, there's no supported recovery path — you'd tag by hand. release_publish.yml has that escape hatch; the tag job should have one too.
6. Skill doc bug
grep -A6 'semantic_changelog_update' .github/workflows/pr_title.ymlstops exactly at scopes: | and never prints the scope→path map the skill tells you to read. Needs -A12.
7. Skill title inconsistency
The header says chore(repo): release <...> for multi-package; step 5 and STYLE_GUIDE.md say chore(repo): release packages.
Nits
- The parse step hardcodes
packages/$pkg/pubspec.yamland greps^version:, while the notes and wait steps deliberately resolve location/version viamelos list --json("dir name may differ"). Both fail safe — just inconsistent. - 📚 Checkout branch in
release_publish.ymluses the bot PAT it doesn't need: nothing is pushed, and the release step passes the token explicitly. Dropping it reduces PAT exposure in a job that also holdsid-token: write. actions/checkout@v6here vs@v4in every other workflow in this repo.- Unpinned
flutter pub global activate melosis the repo-wide pattern, but the release path is the worst place for a surprise major — local dev resolves melos 6.3.3, CI would get 8.2.2 today. STYLE_GUIDE.md: extra blank line before## Where to look when you're stuck.
Verified correct
Checked these so they don't get re-litigated:
MELOS_PACKAGEScomposes with--no-publishedrather than replacing it —createWorkspacedoespackageFilters.copyWith(scope: ...). The scoping and idempotency claims hold, andMELOS_PACKAGES=stream_coredoes not matchstream_core_flutter(exact glob).--order-dependentsis dependencies-first.sortPackagesForExecutionbuilds layers from in-degree 0 and then.reversed; empiricallystream_thumbnail → stream_core → stream_core_flutter. The "tags push in dependency order" claim is accurate.\$MELOS_PACKAGE_NAMEescaping inrelease:tagis correct on Linux —resolveEnvironmentVariableReferencesreturns the input unchanged off Windows and letsshexpand.[[ -z "$deps" ]] && { ...; exit 0; }does not tripset -ewhen deps are present.melos list --graph/--jsonwrite the update notice to stderr, so theawkguard is harmless either way.- Examples and the gallery are
publish_to: 'none', so dropping--ignore="*example*"is safe;pubspec_overrides.yamlis gitignored so bootstrap's path overrides don't ship. - Dart-before-Flutter ordering for the OIDC token is right, and
actionlintis clean on both workflows. - The skill's claims about
pr_title.yml'srelease/-branch gate matchcheck-changelog-placement.sh.
…rify, dispatch From renefloor's review: - lint:pub: drop `--no-published` so the dry run isn't a no-op in steady state; MELOS_PACKAGES scopes it in CI and `pub publish -n` doesn't check collisions. - Wait step: skip private in-workspace deps (they never publish, so waiting on one would hang until timeout); url-encode a build-metadata '+'. - Add a post-publish "Verify published" step so a no-op publish can't cut a GitHub Release for a version that isn't on pub.dev. - release:tag: warn (`::warning`) when a stale tag causes a package to be skipped, instead of silently dropping it from the release. - release_tag.yml: add workflow_dispatch recovery + widen the gate for it. - Skill: `grep -A6` -> `-A12` (was cutting off the scope map); fix multi-package title to match STYLE_GUIDE (`chore(repo): release packages`). - STYLE_GUIDE: drop a stray blank line. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release_tag.yml:
- Around line 14-18: Prevent release publishing from non-default-branch commits
by adding a guard before the publish steps in
.github/workflows/release_publish.yml at lines 23-27 that resolves GITHUB_REF
and verifies the target commit is an ancestor of origin/main, refusing the
release otherwise; update .github/workflows/release_tag.yml at lines 14-18 only
as needed to ensure manually created tags are subject to this validation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 671446c4-fdee-419b-9f70-9870e5afaad5
📒 Files selected for processing (5)
.claude/skills/release-pr/SKILL.md.github/workflows/release_publish.yml.github/workflows/release_tag.ymlSTYLE_GUIDE.mdmelos.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
- .claude/skills/release-pr/SKILL.md
- STYLE_GUIDE.md
- melos.yaml
…ublished Re-running release_publish for an already-published tag hit `flutter pub publish` "version already exists" because `melos --no-published` doesn't reliably exclude published versions in CI. Collapse publish + verify into one step that checks the live per-version endpoint first: skip if the version is already there (a true no-op), otherwise publish and confirm it landed before the release is cut. This makes workflow_dispatch recovery safe whether the prior run failed or succeeded. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
One tag = one package, and idempotency is now the pub.dev per-version check — so the melos exec fan-out (--order-dependents / --no-private / --no-published) added nothing. Publish the tagged package directly with `flutter pub publish --force` in its directory, and drop the now-unused release:pub script. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This reverts commit 007c966.
Mirror stream-chat-flutter: the tagging logic lives in the workflow, not a melos script. Move the `melos exec … git tag/push` command straight into release_tag.yml's run step and remove the now-single-use release:tag from melos.yaml. Behaviour is unchanged (same command, same dependency-ordered push + stale-tag ::warning); release:pub stays a melos script as in chat. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Trim the verbose comments (tag step, dependency wait, dep resolution, gate) to one or two terse lines each, and fix the release:pub / lint:pub descriptions — release:pub no longer relies on --no-published for idempotency (the publish step's live-check does), so the description no longer claims it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ame, docs - release_publish checkout: use the default GITHUB_TOKEN (the job never pushes; the release step passes its own token), so no write-scoped PAT sits in git config across the melos install/bootstrap steps. - Parse step: resolve the package's pubspec by grepping for its `name:` instead of assuming packages/<name>/ — robust to a dir that differs from the package name (melos isn't installed yet at this step). - release_tag: drop the dead `git config user.*` — the tags are lightweight (`git tag <name>`), which record no tagger. - Document that release PRs must be squash-merged (the tag gate reads the tip commit's message; a merge commit would silently bypass it). Validated on the test repo: checkout with the default token, parse-by-name, and tag-without-identity all pass; the manual workflow_dispatch recovery path runs green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Automated pub.dev publishing for this repo, matching its independent per-package versioning (each package releases on its own
<pkg>-vX.Y.Ztag). Ports the proven design used by stream-chat-flutter / flame / supabase-flutter /bluefireteam/melos-action, wired through the repo's bot PAT.Closes FLU-636. Manual setup (bot token + pub.dev automated-publishing config) was completed in FLU-638.
How it works
release_tag.yml— on achore(...): releasemerge tomain:melos exec --no-published), so tags are derived from package state, not the commit message — robust to multi-package release PRs and title typos.--order-dependents) with the bot PAT (aGITHUB_TOKENtag push would not trigger the publish workflow).release_publish.yml— on a<pkg>-vX.Y.Ztag push (+workflow_dispatchfor re-runs):packages/<pkg>/pubspec.yaml.id-token: write, no stored credentials).## X.Y.ZCHANGELOG section.release-prskill (.claude/skills/release-pr/) — opens the release PR: detects each package's## Upcomingchangelog, bumps versions, promotes the changelog heading, and opens a single PR from arelease/…branch. Never versions/tags/publishes/merges itself — that's the workflows' job.STYLE_GUIDE.md— documents the release flow (release from arelease/…branch, single PR may bump many packages, dependent order is automatic).Notable design decisions
--order-dependentson the trigger only orders firing, not completion. flame/supabase live with best-effort + manual re-run; the wait makes ours self-healing (no re-run for thestream_core→stream_core_fluttercase). It polls the per-version pub.dev endpoint, which stays fresh in CI — the package listingmelos --publishedreads lags for minutes.--skip-validation— would let a dependent publish before its dependency is live, leaving it unresolvable if the dependency's run fails. The wait keeps a dependent from ever publishing against a missing dependency.make_latest: false— with independent versioning no single release is the repo's "latest"; astream_thumbnailpatch must not outrank astream_core_flutterrelease for the badge.cancel-in-progress: falseon both — never cancel a run mid tag-push / mid-publish.generate_release_notes— it would list every repo commit since the previous tag of any package; we extract the package's own CHANGELOG section (matched by version token, so a dated## X.Y.Z (date)heading still resolves).Verification
Validated end-to-end with real pub.dev publishes on a dedicated test monorepo (automated publishing enabled), covering the full matrix:
-beta.x→prerelease: true), tag-parse guard (malformed tag fails fast), non-release commit correctly skipsrelease_tag, and idempotent re-runs of an already-published tag are a no-op.release-prskill authored the release PR; the merged PR then drove the workflows above.Repo-side checks:
actionlintclean on both workflows;melos run lint:pub(publish dry-run) passes for all three packages.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Chores