ci(release): fix melos release automation with scoped publishing#1316
ci(release): fix melos release automation with scoped publishing#1316
Conversation
Fix critical issues in release automation: release-publish.yml now accepts package-name and package-version as inputs and publishes only the scoped package instead of all unpublished packages. Added CHANGELOG extraction to release body, concurrency control per-package, and fetch-depth: 0 for melos bootstrap. release-tag.yml passes inputs to publish workflow and adds 30s delay between triggers for pub.dev propagation. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe PR updates two GitHub workflows to support parameterized package publishing. The release-tag workflow now triggers the release-publish workflow passing Sequence Diagram(s)sequenceDiagram
participant TriggerWF as release-tag workflow
participant PublishWF as release-publish workflow
participant GitHubAPI as GitHub API
participant Melos as Melos / pub.dev
participant Repo as Repository
TriggerWF->>GitHubAPI: gh workflow run release-publish (--field package-name, --field package-version)
Note right of GitHubAPI: sleep 30
GitHubAPI->>PublishWF: start workflow (with inputs)
PublishWF->>Repo: checkout (ref from inputs)
PublishWF->>GitHubAPI: request App token
GitHubAPI-->>PublishWF: return GITHUB_TOKEN
PublishWF->>Melos: bootstrap workspace
PublishWF->>Melos: dry-run publish for scoped package
Melos-->>PublishWF: dry-run result
PublishWF->>Melos: publish scoped package to pub.dev
Melos-->>PublishWF: publish result / URL
PublishWF->>Repo: extract CHANGELOG section for version
PublishWF->>GitHubAPI: create GitHub Release (tag: package-name-vversion, body: changelog, prerelease if semver contains '-')
GitHubAPI-->>PublishWF: release created
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/release-publish.yml:
- Around line 55-63: The awk extraction treats VERSION as a regex so versions
with metacharacters (e.g., "0.3.1+1") fail and it also misses the bracketed
headings used in CHANGELOG.md; update the extraction in the release-publish.yml
step that sets VERSION, PACKAGE and CHANGELOG_CONTENT so awk (or an equivalent)
searches for the literal header string "## [${VERSION}]" (not a regex) and stops
at the next header starting with "## [" — i.e., perform fixed-string matching
for "## [VERSION]" (or use index($0, pattern)>0) and use the same bracketed
header pattern to terminate extraction.
ℹ️ Review info
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
.github/workflows/release-publish.yml.github/workflows/release-tag.yml
Replace regex-based awk pattern with index()-based fixed-string matching to correctly handle version strings containing regex metacharacters (e.g. dots, plus signs in build metadata like 0.3.1+1). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
.github/workflows/release-publish.yml (1)
55-64:⚠️ Potential issue | 🟠 MajorCHANGELOG heading format mismatch — extraction will produce empty content.
The
index()-based awk correctly handles regex metacharacters, butHEADERis still set to## ${VERSION}(e.g.,## 0.3.1+1) while the actual CHANGELOG headings in this repository use bracket-wrapped format (## [0.3.1+1]). The section will never match, producing an empty release body.Additionally, there is no guard against empty extraction — a silent empty body is easy to miss.
Suggested fix
- name: Extract CHANGELOG section id: changelog - run: | - VERSION="${{ inputs.package-version }}" - PACKAGE="${{ inputs.package-name }}" - HEADER="## ${VERSION}" - CHANGELOG_CONTENT=$(awk -v header="$HEADER" 'index($0,header)==1{flag=1;next} /^## /{flag=0} flag' "packages/${PACKAGE}/CHANGELOG.md") - echo "changelog<<EOF" >> $GITHUB_OUTPUT - echo "${CHANGELOG_CONTENT}" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT + env: + VERSION: ${{ inputs.package-version }} + PACKAGE: ${{ inputs.package-name }} + run: | + HEADER="## [${VERSION}]" + CHANGELOG_CONTENT=$(awk -v header="$HEADER" 'index($0,header)==1{flag=1;next} /^## \[/{flag=0} flag' "packages/${PACKAGE}/CHANGELOG.md") + if [ -z "$CHANGELOG_CONTENT" ]; then + echo "::warning::No CHANGELOG section found for ${PACKAGE} ${VERSION}" + fi + echo "changelog<<EOF" >> "$GITHUB_OUTPUT" + echo "${CHANGELOG_CONTENT}" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/release-publish.yml around lines 55 - 64, The workflow step "Extract CHANGELOG section" builds HEADER as "## ${VERSION}" but changelog headings use bracketed format like "## [0.3.1+1]", so the awk match (used to populate CHANGELOG_CONTENT) never finds the section; update HEADER to include brackets (e.g., HEADER="## [${VERSION}]") and keep using the awk that relies on index; after extraction, add a guard that checks if CHANGELOG_CONTENT is empty and either fail the job with a clear error or populate a sensible fallback message so releases never proceed with a silent empty body.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/release-publish.yml:
- Around line 49-53: In the "Publish to pub.dev" GitHub Actions step, melos
publish currently runs as a dry-run because it lacks the explicit --no-dry-run
flag and also injects ${{ inputs.package-name }} directly into the run line;
update the step named "Publish to pub.dev" to add the --no-dry-run flag to the
melos publish invocation (melos publish --scope <pkg> --no-dry-run) and avoid
shell injection by passing the input via an environment variable (e.g., set
PACKAGE_NAME: ${{ inputs.package-name }} in env and reference that env var in
the run command) so melos actually publishes and the input is safely provided.
---
Duplicate comments:
In @.github/workflows/release-publish.yml:
- Around line 55-64: The workflow step "Extract CHANGELOG section" builds HEADER
as "## ${VERSION}" but changelog headings use bracketed format like "##
[0.3.1+1]", so the awk match (used to populate CHANGELOG_CONTENT) never finds
the section; update HEADER to include brackets (e.g., HEADER="## [${VERSION}]")
and keep using the awk that relies on index; after extraction, add a guard that
checks if CHANGELOG_CONTENT is empty and either fail the job with a clear error
or populate a sensible fallback message so releases never proceed with a silent
empty body.
ℹ️ Review info
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
.github/workflows/release-publish.yml
| - name: Publish dry run | ||
| run: melos publish --scope ${{ inputs.package-name }} --dry-run | ||
|
|
||
| - name: Publish to pub.dev | ||
| run: melos publish --scope ${{ inputs.package-name }} |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
melos publish --no-dry-run flag CI interactive mode
💡 Result:
melos publish --no-dry-run only disables Melos’s default dry-run; it doesn’t add a “yes / non-interactive” mode, so it can still block in CI on the underlying publish confirmation prompt. [1]
Melos publishes by running pub publish internally. [2] For CI/non-interactive publishing, use dart pub publish --force (skips the confirmation prompt) [3] and run it per-package via melos exec, for example:
# Publish only packages whose current version is NOT on pub.dev
melos exec --no-published -- dart pub publish --forceMelos supports --published/--no-published as package filters. [4]
Sources: [1] [2] [3] [4]
🌐 Web query:
melos publish default behavior dry run CLI documentation
💡 Result:
melos publish defaults to a dry run: it validates what would be published but does not publish anything unless you explicitly disable dry-run. [1]
From the CLI docs:
melos publish→ dry-run enabled by default (--dry-rundefaults totrue). [2]- To actually publish:
melos publish --no-dry-run. [1][2] - You can also spell it explicitly as
melos publish --dry-run(same as the default). [2]
Docs locations: the publish command reference and the Automated Releases guide. [2][1]
🏁 Script executed:
# Search for melos usage patterns in the repository
fd -type f -name "*.yml" -o -name "*.yaml" | head -20Repository: supabase/supabase-flutter
Length of output: 239
The "Publish to pub.dev" step will not actually publish without --no-dry-run.
melos publish defaults to dry-run mode and will not publish anything without the explicit --no-dry-run flag. Line 53 will execute a dry-run instead of publishing to pub.dev, defeating the purpose of the workflow.
Additionally, passing ${{ inputs.package-name }} directly into run: is a shell-injection surface. The GitHub Actions hardening pattern is to pass inputs via environment variables.
Suggested fix
- name: Publish dry run
- run: melos publish --scope ${{ inputs.package-name }} --dry-run
+ env:
+ PACKAGE_NAME: ${{ inputs.package-name }}
+ run: melos publish --scope "$PACKAGE_NAME" --dry-run
- name: Publish to pub.dev
- run: melos publish --scope ${{ inputs.package-name }}
+ env:
+ PACKAGE_NAME: ${{ inputs.package-name }}
+ run: melos publish --scope "$PACKAGE_NAME" --no-dry-run🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/release-publish.yml around lines 49 - 53, In the "Publish
to pub.dev" GitHub Actions step, melos publish currently runs as a dry-run
because it lacks the explicit --no-dry-run flag and also injects ${{
inputs.package-name }} directly into the run line; update the step named
"Publish to pub.dev" to add the --no-dry-run flag to the melos publish
invocation (melos publish --scope <pkg> --no-dry-run) and avoid shell injection
by passing the input via an environment variable (e.g., set PACKAGE_NAME: ${{
inputs.package-name }} in env and reference that env var in the run command) so
melos actually publishes and the input is safely provided.
Summary
Fixed critical issues in the melos release automation workflows:
package-nameandpackage-versioninputs and usesmelos publish --scopeto publish only the target package (instead of all unpublished packages)fetch-depth: 0to checkout so melos can properly resolve tagsThese fixes eliminate race conditions in parallel publishing and ensure only the correct package is published for each release.
🤖 Generated with Claude Code