Skip to content

fix(ci): include commits in all relevant workspace changelogs#7570

Merged
paulbalaji merged 3 commits intomainfrom
fix/changelog-multi-workspace
Dec 9, 2025
Merged

fix(ci): include commits in all relevant workspace changelogs#7570
paulbalaji merged 3 commits intomainfrom
fix/changelog-multi-workspace

Conversation

@paulbalaji
Copy link
Collaborator

@paulbalaji paulbalaji commented Dec 9, 2025

Summary

Fixes a bug where commits touching multiple Rust workspaces were only included in one changelog.

Problem

When a commit touched files in multiple workspaces (e.g., both agents/relayer/ and agents/validator/), it would only appear in whichever workspace was checked first due to break 2 exiting both loops in the changelog generation script.

For example, PR #7464 (feat: crash loop even in the event reorg_flag.json is unparsable) touches both relayer and validator, but was only appearing in the relayer changelog in release PR #7505.

Solution

  1. Track ALL matched workspaces per commit using an associative array
  2. Add each commit to every workspace changelog it touches
  3. Support explicit scope override via conventional commit format (e.g., feat(relayer): will only add to the relayer changelog, regardless of files touched)

Before vs After

Before: git log -- rust/main/agents/validator shows 5 commits, but validator changelog only had 2

After:

### agents/validator
* feat: aleo fallback provider (#7407)
* feat: Aleo HyperlaneProvider (#7344)
* feat: aleo validator announce (#7445)
* feat: crash loop even in the event `reorg_flag.json` is unparsable (#7464)
* refactor: Remove duplication and move tests into separate files (#7357)

All 5 commits now appear correctly.

Test Plan

# Compare git log with script output
git log agents-v1.7.0..HEAD --oneline -- rust/main/agents/validator
./rust/scripts/ci/generate-workspace-changelog.sh "agents-v1.7.0..HEAD" "agents/validator"

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Improved changelog generation for multi-workspace projects: commits can be mapped by scope or changed files, and may belong to multiple workspaces with an "other" category for unmatched changes.
    • Per-workspace sections can include headers and be written into workspace-specific CHANGELOGs for a given version via a write flag.
    • Preserves workspace manifest ordering and appends a generated marker.

✏️ Tip: You can customize this high-level summary in your review settings.

Previously, when a commit touched files in multiple workspaces (e.g., both
agents/relayer and agents/validator), it would only appear in whichever
workspace was checked first due to `break 2` exiting both loops.

This fix:
1. Tracks ALL matched workspaces per commit using an associative array
2. Adds each commit to every workspace changelog it touches
3. Supports explicit scope override via conventional commit format
   (e.g., `feat(relayer):` will only add to relayer changelog)

Example: A commit touching both `agents/relayer/` and `agents/validator/`
will now correctly appear in both changelogs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Dec 9, 2025

⚠️ No Changeset found

Latest commit: 9ec884c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@paulbalaji paulbalaji marked this pull request as ready for review December 9, 2025 12:32
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

📝 Walkthrough

Walkthrough

The script now maps commit scopes to workspace paths, prefers explicit scope parsing, supports assigning a single commit to multiple workspaces, writes per-workspace changelog buckets, and can prepend generated sections into workspace CHANGELOG.md when run with --write-to-workspace.

Changes

Cohort / File(s) Summary
Scope & multi-workspace detection
rust/scripts/ci/generate-workspace-changelog.sh
Added SCOPE_TO_WORKSPACE mapping and explicit scope parsing; changed commit processing to collect matched_workspaces so a commit can belong to multiple workspaces; falls back to an other category when no matches.
Changelog rendering & workspace updates
rust/scripts/ci/generate-workspace-changelog.sh
Added generate_workspace_changelog() (signature: generate_workspace_changelog() { local workspace="$1"; local include_header="${2:-true}" ... }) to render per-workspace sections; updated logic to write each commit into all matched workspace buckets; added --write-to-workspace handling with VERSION validation and prepending to workspace CHANGELOG.md.
Processing & output behavior
rust/scripts/ci/generate-workspace-changelog.sh
Switched commit loop to avoid subshells (preserves associative arrays), preserves workspace order from Cargo.toml, includes other category, supports optional workspace filtering, and appends a generated-marker to final output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to focus on:
    • Scope regex parsing and completeness of SCOPE_TO_WORKSPACE entries
    • Multi-workspace matching logic (file-based vs scope-based precedence, duplicates)
    • --write-to-workspace VERSION validation, file prepend correctness, and atomicity
    • Bash associative arrays, loop changes to avoid subshells, and quoting/IO edge cases

Possibly related PRs

Suggested reviewers

  • kamiyaa
  • yjamin

Poem

In a swamp of commits, scopes now lead the way,
Filesfind and match, no more stray display.
Workspaces gather, each note in its place,
CHANGELOGs wake up with tidy new grace. 🐴

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main fix: ensuring commits touching multiple workspaces are included in all relevant changelogs rather than just one.
Description check ✅ Passed The description covers the required template sections with clear problem statement, solution approach, and test plan. All major sections are present and adequately filled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/changelog-multi-workspace

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.

❤️ Share

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: 0

🧹 Nitpick comments (1)
rust/scripts/ci/generate-workspace-changelog.sh (1)

171-178: Perfect. This is where each commit lands in every workspace that needs it.

Sanitizing the workspace name to use as a filename (/ -> _) is necessary and clean. No issues here.

That said, you're sanitizing workspace names a few more times down the script (lines 214, 274). If this ever needs tweaking, you might want to extract it to a tiny helper function. But honestly, for a script this size, it's not a big deal.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 036e035 and 89bf03e.

📒 Files selected for processing (1)
  • rust/scripts/ci/generate-workspace-changelog.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6943
File: rust/main/config/mainnet_config.json:965-965
Timestamp: 2025-08-26T13:46:37.695Z
Learning: In the repository hyperlane-xyz/hyperlane-monorepo, skip reviewing the file rust/main/config/testnet_config.json in future code reviews as requested by paulbalaji.
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6943
File: rust/main/config/mainnet_config.json:965-965
Timestamp: 2025-08-26T13:46:37.695Z
Learning: In the repository hyperlane-xyz/hyperlane-monorepo, skip reviewing the file rust/main/config/mainnet_config.json in future code reviews as requested by paulbalaji.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: build-and-push-to-gcr
  • GitHub Check: e2e-matrix (radix)
  • GitHub Check: e2e-matrix (starknet)
  • GitHub Check: e2e-matrix (sealevel)
  • GitHub Check: e2e-matrix (cosmwasm)
  • GitHub Check: e2e-matrix (evm)
  • GitHub Check: e2e-matrix (cosmosnative)
  • GitHub Check: lint-rs
  • GitHub Check: test-rs
  • GitHub Check: lander-coverage
🔇 Additional comments (7)
rust/scripts/ci/generate-workspace-changelog.sh (7)

107-119: Scope mapping looks solid.

Covers all the important workspaces and chains. Good convention to have this centralized.


121-122: Variable scoping inside the subshell works, but the design is a touch fragile.

The matched_workspaces array declared here sits outside the while read loop, which creates a subshell (line 125). Inside that subshell, the array at line 145 becomes a fresh local one—which is fine because you're really just tracking which TEMP_DIR files to write. Files survive the subshell boundary fine. That said, the comment at line 144 suggests some uncertainty about array behavior. The design works, but using process substitution instead of piping would keep everything in one scope and make the intent clearer.


129-137: Explicit scope detection is sound.

Regex correctly pulls the scope from conventional format (e.g., feat(relayer):), and the safe lookup via ${SCOPE_TO_WORKSPACE[$scope]:-} is the right defensive move. Good that explicit scopes win over file-based detection.


143-164: This is where the fix lives, and it's done right.

The old code had a break 2 that would bail out after the first workspace match. Now you're properly iterating through all files and collecting all matching workspaces before storing the commit (lines 171-178). The regex at line 158 with (/|$) is sensible—it prevents partial name matches. This should mean commits that touch agents/relayer/ and agents/validator/ get added to both changelogs, which is the whole point of this PR.


166-169: Good fallback for the odd commit that doesn't fit the workspace mold.

Assigning to "other" ensures nothing gets lost. Smart design.


181-196: Solid abstraction for rendering workspace sections.

Sorting and deduplicating with sort -u keeps things clean. Using it in two different contexts (lines 222 and 283) is a nice touch—DRY without being overly clever.


198-258: The file-update logic is well thought out.

You validate the VERSION upfront, respect workspace filters, skip workspaces with no changes, and properly preserve existing changelogs by prepending. Date handling is automatic. Nice touches all around.

One small thing: line 257 exits with 0 regardless of whether anything was updated. It works fine (no changes = success), but if a caller ever needs to distinguish between "nothing to do" and "updated 5 workspaces," they can't. Not a blocker—just something to keep in mind.

@paulbalaji paulbalaji enabled auto-merge December 9, 2025 12:42
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

🧹 Nitpick comments (1)
rust/scripts/ci/generate-workspace-changelog.sh (1)

129-137: Optional: Consider scope pattern robustness.

The regex at line 132 only matches lowercase scopes (^[a-z]+\(([a-z]+)\):). While consistent with the SCOPE_TO_WORKSPACE map, you might want to handle variations gracefully—for instance, converting uppercase to lowercase or supporting hyphens in scope names if developers use them. Not a blocker, but worth thinking about for future-proofing.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89bf03e and 8fb6f67.

📒 Files selected for processing (1)
  • rust/scripts/ci/generate-workspace-changelog.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6943
File: rust/main/config/mainnet_config.json:965-965
Timestamp: 2025-08-26T13:46:37.695Z
Learning: In the repository hyperlane-xyz/hyperlane-monorepo, skip reviewing the file rust/main/config/testnet_config.json in future code reviews as requested by paulbalaji.
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6943
File: rust/main/config/mainnet_config.json:965-965
Timestamp: 2025-08-26T13:46:37.695Z
Learning: In the repository hyperlane-xyz/hyperlane-monorepo, skip reviewing the file rust/main/config/mainnet_config.json in future code reviews as requested by paulbalaji.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: infra-test
  • GitHub Check: e2e-matrix (starknet)
  • GitHub Check: e2e-matrix (cosmwasm)
  • GitHub Check: e2e-matrix (radix)
  • GitHub Check: e2e-matrix (evm)
  • GitHub Check: e2e-matrix (cosmosnative)
  • GitHub Check: e2e-matrix (sealevel)
  • GitHub Check: agent-configs (mainnet3)
  • GitHub Check: agent-configs (testnet4)
  • GitHub Check: yarn-install
  • GitHub Check: build-and-push-to-gcr
  • GitHub Check: test-rs
  • GitHub Check: lint-rs
  • GitHub Check: lander-coverage
🔇 Additional comments (4)
rust/scripts/ci/generate-workspace-changelog.sh (4)

107-122: LGTM on the scope mapping and declarations.

The SCOPE_TO_WORKSPACE mapping covers all the main workspaces nicely, and the structure is clear and maintainable.


182-196: Nice helper function design.

The generate_workspace_changelog() function is clean, reusable, and properly handles the include_header flag. Using sort -u to deduplicate commits is sensible for changelog consistency.


199-258: --write-to-workspace implementation looks solid.

The logic properly validates VERSION, iterates through filtered workspaces, generates content, and prepends it to each workspace's CHANGELOG.md with a version header and date. The directory creation and existing changelog preservation are handled correctly.


260-290: Output generation logic is well-structured.

Processing workspaces in Cargo.toml order plus "other" is the right approach. The filter check is applied consistently, and the separator logic between workspaces keeps output readable.

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: 0

🧹 Nitpick comments (1)
rust/scripts/ci/generate-workspace-changelog.sh (1)

130-138: Mind your scope regex—it's lowercase-only.

The pattern ^[a-z]+\(([a-z]+)\): at line 133 only matches lowercase scopes like feat(relayer):. If someone writes feat(Relayer): or feat(RELAYER):, the explicit scope detection skips it and falls back to file-based detection. Conventional commits usually stick to lowercase, but you might want to make the regex case-insensitive to catch variations:

-if [[ "$commit_msg" =~ ^[a-z]+\(([a-z]+)\): ]]; then
+if [[ "$commit_msg" =~ ^[a-z]+\(([a-z0-9_-]+)\): ]]; then

(Also added common scope separators like hyphens and underscores.)

That said, the file-based fallback means nothing breaks—commits still get categorized. So this is more of a robustness thing than a blocker.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8fb6f67 and 9ec884c.

📒 Files selected for processing (1)
  • rust/scripts/ci/generate-workspace-changelog.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6943
File: rust/main/config/mainnet_config.json:965-965
Timestamp: 2025-08-26T13:46:37.695Z
Learning: In the repository hyperlane-xyz/hyperlane-monorepo, skip reviewing the file rust/main/config/mainnet_config.json in future code reviews as requested by paulbalaji.
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6943
File: rust/main/config/mainnet_config.json:965-965
Timestamp: 2025-08-26T13:46:37.695Z
Learning: In the repository hyperlane-xyz/hyperlane-monorepo, skip reviewing the file rust/main/config/testnet_config.json in future code reviews as requested by paulbalaji.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: infra-test
  • GitHub Check: build-and-push-to-gcr
  • GitHub Check: e2e-matrix (starknet)
  • GitHub Check: e2e-matrix (cosmosnative)
  • GitHub Check: e2e-matrix (evm)
  • GitHub Check: e2e-matrix (radix)
  • GitHub Check: e2e-matrix (sealevel)
  • GitHub Check: e2e-matrix (cosmwasm)
  • GitHub Check: lander-coverage
  • GitHub Check: test-rs
  • GitHub Check: lint-rs
🔇 Additional comments (3)
rust/scripts/ci/generate-workspace-changelog.sh (3)

122-178: Nice work fixing that subshell issue—the layers are properly preserved now.

Your process substitution at line 178 (done < <(...) instead of pipe) keeps everything in the current shell context, so the associative array modifications actually stick around. That's the core fix from the past review, and it's implemented correctly. The way you're resetting matched_workspaces on each iteration (line 126) and writing all matched workspace names to separate files (lines 171-177) means commits now get categorized into every workspace they touch, not just the first one.

The multi-workspace tracking pattern here is solid—no more break 2 silently dropping commits.


181-195: Function structure looks good; just note the sorting subshell.

The generate_workspace_changelog() function is clean and reusable. Line 191 does spin up a subshell (sort -u | while read), but since you're just reading and echoing output—not modifying any shell state—it's a harmless pattern. If you ever need to squeeze more performance, you could switch to sort -u | sed 's/^/* /' to avoid the subshell, but this is perfectly fine as-is.


198-257: Verify that --write-to-workspace overwrites are safe in your CI flow.

The feature looks well-structured: it validates VERSION, respects workspace filters, and prepends new changelog entries while preserving old content. However, line 249 directly overwrites CHANGELOG.md files. A couple of things to check:

  1. Is the overwrite reversible or idempotent if the script runs twice with the same VERSION?
  2. Are these files tracked in git, and if so, how does the CI handle the modifications?

The logic itself is correct—new version goes at the top, old content shifts down. Just want to make sure this doesn't surprise the workflow.

@hyper-gonk
Copy link
Contributor

hyper-gonk bot commented Dec 9, 2025

🦀 Rust Agent Docker Image Built Successfully

Image Tags:

gcr.io/abacus-labs-dev/hyperlane-agent:pr-7570
gcr.io/abacus-labs-dev/hyperlane-agent:9ec884c-20251209-130813

@paulbalaji paulbalaji added this pull request to the merge queue Dec 9, 2025
Merged via the queue into main with commit f89a680 Dec 9, 2025
44 checks passed
@paulbalaji paulbalaji deleted the fix/changelog-multi-workspace branch December 9, 2025 13:43
@github-project-automation github-project-automation bot moved this from In Review to Done in Hyperlane Tasks Dec 9, 2025
@codecov
Copy link

codecov bot commented Dec 9, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (036e035) to head (9ec884c).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@     Coverage Diff      @@
##   main   #7570   +/-   ##
============================
============================
Components Coverage Δ
core ∅ <ø> (∅)
hooks ∅ <ø> (∅)
isms ∅ <ø> (∅)
token ∅ <ø> (∅)
middlewares ∅ <ø> (∅)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants