Skip to content

ci(release): fix melos release automation with scoped publishing#1316

Merged
grdsdev merged 2 commits intomainfrom
grdsdev/automate-melos-release
Feb 24, 2026
Merged

ci(release): fix melos release automation with scoped publishing#1316
grdsdev merged 2 commits intomainfrom
grdsdev/automate-melos-release

Conversation

@grdsdev
Copy link
Contributor

@grdsdev grdsdev commented Feb 24, 2026

Summary

Fixed critical issues in the melos release automation workflows:

  • release-publish.yml: Now accepts package-name and package-version inputs and uses melos publish --scope to publish only the target package (instead of all unpublished packages)
  • CHANGELOG extraction: Release body now includes the actual package changelog section instead of generic text
  • Concurrency control: Added per-package concurrency group to prevent conflicting runs
  • Melos bootstrap: Added fetch-depth: 0 to checkout so melos can properly resolve tags
  • release-tag.yml: Updated to pass package name/version as workflow inputs and added 30-second delay between package triggers for pub.dev indexing

These fixes eliminate race conditions in parallel publishing and ensure only the correct package is published for each release.


🤖 Generated with Claude Code

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>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

📝 Walkthrough

Summary by CodeRabbit

  • Chores

    • Made the release/publish workflow configurable with package name and version inputs
    • Improved coordination between tagging and publishing, including a brief wait after triggering publish
  • New Features

    • Added dry-run and actual scoped publish steps with bootstrap preparation
    • Automatically extracts the changelog for the release and uses it as the release notes body, including prerelease detection and a download link

Walkthrough

The PR updates two GitHub workflows to support parameterized package publishing. The release-tag workflow now triggers the release-publish workflow passing package-name and package-version fields and pauses briefly. The release-publish workflow accepts those inputs, checks out the repo, obtains a GitHub App token, bootstraps with Melos, runs a dry-run and then publishes the specified package, extracts the CHANGELOG section for the version, and creates a GitHub Release whose tag, name, body, and prerelease flag are derived from the inputs and extracted changelog.

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
Loading

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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.

📥 Commits

Reviewing files that changed from the base of the PR and between 9923153 and 909d1a5.

📒 Files selected for processing (2)
  • .github/workflows/release-publish.yml
  • .github/workflows/release-tag.yml

@grdsdev grdsdev requested a review from a team February 24, 2026 10:45
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>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/release-publish.yml (1)

55-64: ⚠️ Potential issue | 🟠 Major

CHANGELOG heading format mismatch — extraction will produce empty content.

The index()-based awk correctly handles regex metacharacters, but HEADER is 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 909d1a5 and 9c12be6.

📒 Files selected for processing (1)
  • .github/workflows/release-publish.yml

Comment on lines +49 to +53
- 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 }}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 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 --force

Melos 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-run defaults to true). [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 -20

Repository: 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.

@grdsdev grdsdev merged commit 711e5c9 into main Feb 24, 2026
4 checks passed
@grdsdev grdsdev deleted the grdsdev/automate-melos-release branch February 24, 2026 10:55
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