Skip to content

fix: use content diff for private sync state detection in release script#12181

Merged
gomesalexandre merged 8 commits intodevelopfrom
fix/release-script-no-commits-crash
Mar 17, 2026
Merged

fix: use content diff for private sync state detection in release script#12181
gomesalexandre merged 8 commits intodevelopfrom
fix/release-script-no-commits-crash

Conversation

@gomesalexandre
Copy link
Contributor

@gomesalexandre gomesalexandre commented Mar 17, 2026

SHA comparison for private branch breaks with squash merges - private's SHA will never equal main's SHA even when content is identical, so the script gets permanently stuck in tagged_private_stale and can never reach idle. New release = borked.

changes

  • deriveReleaseState / deriveHotfixState: replace privateSha param with privateContentMatchesMain boolean (computed via git diff, squash-safe)
  • doRegularRelease / doHotfixRelease: compute content diff before state derivation
  • tagged_private_stale log message: use latestTag instead of nextVersion (was showing wrong version)
  • createPr: return null on "No commits between" instead of crashing, callers handle gracefully

risk

Low - release script only, no prod code.

testing

Run GITHUB_TOKEN= pnpm release after a release where private was synced via squash - should show idle (ready for next release) instead of tagged_private_stale.

Summary by CodeRabbit

  • Bug Fixes

    • Better handling when private branches are already synchronized with main — no redundant backmerge or PRs.
    • Graceful behavior when no commits exist between branches, avoiding erroneous PR creation and improving logging/fallback messages.
  • Refactor

    • Release and hotfix decision logic simplified to use a content-match check for private vs main branches.
    • Control flow and logging streamlined for clearer, idempotent release operations.

0xApotheosis and others added 2 commits March 16, 2026 13:09
The native QR scanner handler ships in mobile app v3.7.2 (mobile-app
PR #156), but the version gate was set to 3.4.0. This caused mobile
apps v3.4.0–3.7.1 to incorrectly attempt native scanning, resulting
in a 60-second spinner timeout with no way to scan.

Co-authored-by: Claude Opus 4.6 <[email protected]>
@gomesalexandre gomesalexandre requested a review from a team as a code owner March 17, 2026 01:06
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 17, 2026

📝 Walkthrough

Walkthrough

The release script replaces SHA-based private/main comparisons with a boolean privateContentMatchesMain, updates deriveReleaseState and deriveHotfixState signatures, and makes createPr return Promise<string | null> to handle "No commits between" cases and conditional logging when no PR is produced.

Changes

Cohort / File(s) Summary
Release State Derivation & Control Flow
scripts/release.ts
Replaced privateSha with privateContentMatchesMain across deriveReleaseState and deriveHotfixState. Adjusted branching (e.g., tagged_private_stale) to use the boolean and updated logging to reference latestTag.
PR Creation & Backmerge Handling
scripts/release.ts
Changed createPr return type to `Promise<string
Hotfix & Regular Release Flows
scripts/release.ts
doRegularRelease and doHotfixRelease now compute privateContentMatchesMain via diff against origin/private and pass it to state derivation. Guard clauses updated to use the boolean instead of SHA equality checks. Minor error handling adjustments for idempotency.

Sequence Diagram(s)

sequenceDiagram
    participant Script as Release Script
    participant Git as Git (origin/private, main)
    participant GH as GitHub API
    participant State as State Deriver

    Script->>Git: fetch SHAs & diff origin/private vs main
    Git-->>Script: returns privateContentMatchesMain (boolean) and SHAs
    Script->>State: deriveReleaseState(privateContentMatchesMain, SHAs, openPRs...)
    State-->>Script: returns ReleaseState
    Script->>GH: createPr/backmerge if needed
    GH-->>Script: returns PR URL or error ("No commits between") -> null
    Script->>Script: conditional logging / exit based on PR URL and ReleaseState
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through diffs at break of day,
SHA ghosts cleared, a boolean lights the way,
If no PR rises, I'll nap instead—
Private and main in step, well-led! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: replacing SHA comparison with content diff for detecting private branch sync state in the release script.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-script-no-commits-crash
📝 Coding Plan
  • Generate coding plan for human review comments

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.

SHA comparison for private branch breaks with squash merges - private's
SHA will never equal main's SHA even when content is identical, leaving
the script permanently stuck in tagged_private_stale and unable to
reach idle/done. Fixes the "can't cut a new release" situation.

changes:
- deriveReleaseState/deriveHotfixState: replace privateSha param with
  privateContentMatchesMain boolean (git diff based, squash-safe)
- doRegularRelease/doHotfixRelease: compute content diff before state
  derivation
- tagged_private_stale log message: use latestTag (not nextVersion)
- createPr: return null on "No commits between" instead of crashing

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@gomesalexandre gomesalexandre force-pushed the fix/release-script-no-commits-crash branch from ef505bb to acb8d81 Compare March 17, 2026 01:17
@gomesalexandre gomesalexandre changed the title fix: gracefully handle no-commits-between error in release script fix: use content diff for private sync state detection in release script Mar 17, 2026
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
scripts/release.ts (3)

548-554: ⚠️ Potential issue | 🟡 Minor

Inconsistent null handling for createPr return value.

Since createPr can now return null when there are no commits between branches, this call site should handle that case to avoid printing "Release PR created: null". Other call sites in this file (lines 625-630, 652-656, 790-794, etc.) properly check for null before logging.

While unlikely in the idle state flow (commits are checked beforehand), the branches could theoretically be in sync due to race conditions or edge cases.

Proposed fix
       const releasePrUrl = await createPr({
         base: 'main',
         head: 'release',
         title: `chore: release ${nextVersion}`,
         body: releaseBody,
       })
-      console.log(chalk.green(`Release PR created: ${releasePrUrl}`))
+      if (releasePrUrl) {
+        console.log(chalk.green(`Release PR created: ${releasePrUrl}`))
+      } else {
+        console.log(chalk.green('release branch already in sync with main - nothing to do.'))
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/release.ts` around lines 548 - 554, Handle the case where createPr
returns null before logging: after calling createPr (the releasePrUrl variable)
check for null and only call console.log(chalk.green(...)) if releasePrUrl is
non-null; otherwise skip the success log (or log an appropriate message). Update
the block that assigns releasePrUrl from createPr({ base: 'main', head:
'release', title: `chore: release ${nextVersion}`, body: releaseBody }) to
perform a null-check and guard the console.log accordingly so the code mirrors
other call sites that avoid printing "Release PR created: null".

753-761: ⚠️ Potential issue | 🟡 Minor

Same inconsistent null handling.

For consistency with other call sites, this should also handle the null case, even though it's less likely to occur in the hotfix flow (commits are explicitly cherry-picked).

Proposed fix
       const prUrl = await createPr({
         base: 'main',
         head: hotfixBranch,
         title: `chore: hotfix ${nextVersion}`,
         body: `## Hotfix ${nextVersion}\n\n${commitList}`,
       })

-      console.log(chalk.green(`Hotfix PR created: ${prUrl}`))
+      if (prUrl) {
+        console.log(chalk.green(`Hotfix PR created: ${prUrl}`))
+      } else {
+        console.log(chalk.green('hotfix branch already in sync with main - nothing to do.'))
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/release.ts` around lines 753 - 761, The call to createPr in the
hotfix flow does not handle a null return like other call sites; after invoking
createPr({ base: 'main', head: hotfixBranch, title: `chore: hotfix
${nextVersion}`, body: ... }), add a null-check for prUrl and handle it the same
way as elsewhere (e.g., log an error with context including
hotfixBranch/nextVersion and exit with a non-zero status) before proceeding to
the success console.log lines so the script fails cleanly when createPr returns
null.

571-577: ⚠️ Potential issue | 🟡 Minor

Same inconsistent null handling.

Similar to the release PR creation above, this should handle the null case for consistency.

Proposed fix
       const prereleasePrUrl = await createPr({
         base: 'release',
         head: 'develop',
         title: `chore: prerelease ${nextVersion}`,
         body: `## Prerelease ${nextVersion}\n\n${commitList}`,
       })
-      console.log(chalk.green(`Prerelease PR created: ${prereleasePrUrl}`))
+      if (prereleasePrUrl) {
+        console.log(chalk.green(`Prerelease PR created: ${prereleasePrUrl}`))
+      } else {
+        console.log(chalk.green('develop already in sync with release - nothing to do.'))
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/release.ts` around lines 571 - 577, createPr can return null so the
prerelease PR branch must handle that case consistently: after calling createPr
for prerelease, check if prereleasePrUrl is null and if so call
processLogger.error (or console.error) with a descriptive message and exit
non-zero (mirroring the release PR handling); only call
console.log(chalk.green(...)) when prereleasePrUrl is non-null. Refer to
createPr, prereleasePrUrl, and the console.log(chalk.green(...)) call to locate
where to add the null-check and error handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@scripts/release.ts`:
- Around line 548-554: Handle the case where createPr returns null before
logging: after calling createPr (the releasePrUrl variable) check for null and
only call console.log(chalk.green(...)) if releasePrUrl is non-null; otherwise
skip the success log (or log an appropriate message). Update the block that
assigns releasePrUrl from createPr({ base: 'main', head: 'release', title:
`chore: release ${nextVersion}`, body: releaseBody }) to perform a null-check
and guard the console.log accordingly so the code mirrors other call sites that
avoid printing "Release PR created: null".
- Around line 753-761: The call to createPr in the hotfix flow does not handle a
null return like other call sites; after invoking createPr({ base: 'main', head:
hotfixBranch, title: `chore: hotfix ${nextVersion}`, body: ... }), add a
null-check for prUrl and handle it the same way as elsewhere (e.g., log an error
with context including hotfixBranch/nextVersion and exit with a non-zero status)
before proceeding to the success console.log lines so the script fails cleanly
when createPr returns null.
- Around line 571-577: createPr can return null so the prerelease PR branch must
handle that case consistently: after calling createPr for prerelease, check if
prereleasePrUrl is null and if so call processLogger.error (or console.error)
with a descriptive message and exit non-zero (mirroring the release PR
handling); only call console.log(chalk.green(...)) when prereleasePrUrl is
non-null. Refer to createPr, prereleasePrUrl, and the
console.log(chalk.green(...)) call to locate where to add the null-check and
error handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3bff3940-c3af-4497-bcca-2cd9a6945180

📥 Commits

Reviewing files that changed from the base of the PR and between ef505bb and acb8d81.

📒 Files selected for processing (1)
  • scripts/release.ts

@gomesalexandre
Copy link
Contributor Author

@coderabbitai the title is intentional - the content diff approach is the primary fix (replaces SHA comparison, unblocks new releases after squash-synced private). The no-commits-between null handling is a secondary defensive change bundled in the same PR. Both are captured in the commit message body.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 17, 2026

Tip

For best results, initiate chat on the files or code changes.

@gomesalexandre Thanks for the clarification! That context is helpful — the content-diff approach (privateContentMatchesMain replacing the SHA equality check) is indeed the more impactful fix since SHA comparison breaks after squash-merges, while the null-return from createPr is just a defensive improvement bundled alongside. The title under-sells the primary change.

Would you like me to regenerate the PR summary to better highlight the content-diff approach as the primary fix?


✏️ Learnings added
Learnt from: gomesalexandre
URL: https://github.com/shapeshift/web/pull/12181

Timestamp: 2026-03-17T01:29:21.605Z
Learning: In shapeshift/web PR `#12181`, the primary fix is replacing SHA-based comparison (`privateSha`) with a content diff approach (`privateContentMatchesMain` boolean) in `deriveReleaseState`/`deriveHotfixState` in `scripts/release.ts`. This unblocks new releases when `private` has been squash-synced with `main` (SHA differs even though content is identical). The secondary fix — `createPr` returning `null` on "No commits between" GitHub error — is a defensive improvement bundled in the same PR. The PR title only references the secondary change; the commit message body captures both.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/Routes/RoutesCommon.tsx:231-267
Timestamp: 2025-09-03T21:17:27.699Z
Learning: gomesalexandre prefers to keep PR diffs focused and reasonable in size, deferring tangential improvements (like Mixpanel privacy enhancements) to separate efforts rather than expanding the scope of feature PRs.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/TransactionContent.tsx:40-140
Timestamp: 2025-09-12T12:04:24.562Z
Learning: gomesalexandre prefers to defer error handling improvements in new/preparatory code until real-world error cases are encountered, rather than implementing speculative error handling without concrete failure scenarios to test against. This aligns with keeping PR scope focused and evidence-based development practices.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:0-0
Timestamp: 2025-09-12T11:56:19.437Z
Learning: gomesalexandre rejected verbose try/catch error handling for address validation in Tenderly integration (PR `#10461`), calling the approach "ugly" but still implemented safety measures in commit ad7e424b89, preferring cleaner safety implementations over defensive programming patterns.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11536
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:252-265
Timestamp: 2025-12-27T16:02:59.817Z
Learning: When fixing critical bugs in shapeshift/web, gomesalexandre prefers to keep changes minimal and focused on correctness rather than combining bug fixes with code quality improvements like extracting duplicated logic, even when duplication is present.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10136
File: src/lib/asset-service/service/encodedRelatedAssetIndex.json:1-1
Timestamp: 2025-07-29T10:22:27.037Z
Learning: PRs with titles starting with "feat: regenerate asset data" are routine daily asset updates that don't need detailed code analysis. Users prefer to skip automated reviews for these maintenance PRs using coderabbitai ignore.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10376
File: packages/contracts/src/viemClient.ts:39-40
Timestamp: 2025-08-27T09:51:36.901Z
Learning: NeOMakinG confirmed that issues flagged by CodeRabbit that predate the PR changes and are unrelated to the PR's core objective should be addressed separately, not within the current PR scope.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10232
File: packages/unchained-client/openapitools.json:61-61
Timestamp: 2025-08-08T10:23:16.843Z
Learning: In shapeshift/web, for temporary “monkey patch” PRs (e.g., packages/unchained-client/openapitools.json using jsDelivr CDN refs like cosmos/mayachain), gomesalexandre is fine with branch-based URLs and does not want SHA pinning. Treat this as a scoped exception to their general preference for pinned dependencies/refs.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10569
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/WalletConnectModalSigningFooter.tsx:121-129
Timestamp: 2025-09-17T22:40:30.149Z
Learning: gomesalexandre maintains strict scope discipline even for style/UI PRs in shapeshift/web, declining functionally correct UX improvements (like keeping Cancel button enabled during gas simulation loading) when they fall outside the PR's stated styling objectives, demonstrating his consistent pattern of deferring valid but tangential improvements to separate efforts.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:21-24
Timestamp: 2025-09-12T13:16:27.004Z
Learning: gomesalexandre declined to add error boundaries to WalletConnect modals in PR `#10461`, stating "no error boundaries in this pr ser", consistent with his preference to keep PR scope focused and defer tangential improvements to separate efforts.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11170
File: patches/@shapeshiftoss+bitcoinjs-lib+7.0.0-shapeshift.0.patch:9-19
Timestamp: 2025-11-25T21:43:10.838Z
Learning: In shapeshift/web, gomesalexandre will not expand PR scope to fix latent bugs in unused API surface (like bitcoinjs-lib patch validation methods) when comprehensive testing proves the actual used code paths work correctly, preferring to avoid costly hdwallet/web verdaccio publish cycles and full regression testing for conceptual issues with zero runtime impact.

Learnt from: firebomb1
Repo: shapeshift/web PR: 0
File: :0-0
Timestamp: 2025-07-24T13:49:39.586Z
Learning: Translation-only PRs that sync localization files (like biweekly translation updates) typically don't benefit from detailed code analysis suggestions, and users may prefer to use coderabbitai ignore for such routine maintenance PRs.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10154
File: src/assets/translations/en/main.json:1004-1006
Timestamp: 2025-08-04T13:33:22.878Z
Learning: When reviewing JSON diffs in translation files, distinguish between syntax-required changes (like adding commas to existing lines to accommodate new entries) versus actual content modifications. A comma addition to an existing line is often just JSON syntax infrastructure, not an intentional change to that line's content.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/components/Stake/components/StakeSummary.tsx:112-114
Timestamp: 2025-08-22T13:00:44.879Z
Learning: NeOMakinG prefers to keep PR changes minimal and focused on the core objectives, avoiding cosmetic or defensive code improvements that aren't directly related to the PR scope, even when they would improve robustness.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SendTransactionContent.tsx:0-0
Timestamp: 2025-09-12T10:44:46.723Z
Learning: gomesalexandre dismissed a clipboard error handling suggestion in PR `#10461` for SendTransactionContent.tsx, demonstrating that the current navigator.clipboard.writeText implementation works as expected and preferring to keep it simple without additional try/catch error handling.

Learnt from: gomes-bot
Repo: shapeshift/web PR: 12049
File: .npmrc:1-4
Timestamp: 2026-03-01T22:00:52.269Z
Learning: In shapeshift/web migration PRs (e.g., package manager migrations), intentionally match the previous tool's default behavior rather than introducing stricter enforcement or improvements. For example, during the yarn→pnpm migration, strict-peer-dependencies=false and auto-install-peers=true were intentionally set to mirror yarn's defaults. Hardening steps like enabling strict peer enforcement should be tracked as separate follow-up PRs after the migration lands and stabilizes, not included in the migration PR scope.

@gomesalexandre
Copy link
Contributor Author

@coderabbitai no need to regenerate, title and existing summary are fine as-is ser

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 17, 2026

Tip

For best results, initiate chat on the files or code changes.

@gomesalexandre Understood, no changes to the summary — keeping it as-is! 👍


🧠 Learnings used
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 0
File: :0-0
Timestamp: 2026-03-17T01:29:21.605Z
Learning: In shapeshift/web PR `#12181`, the primary fix is replacing SHA-based comparison (`privateSha`) with a content diff approach (`privateContentMatchesMain` boolean) in `deriveReleaseState`/`deriveHotfixState` in `scripts/release.ts`. This unblocks new releases when `private` has been squash-synced with `main` (SHA differs even though content is identical). The secondary fix — `createPr` returning `null` on "No commits between" GitHub error — is a defensive improvement bundled in the same PR. The PR title only references the secondary change; the commit message body captures both.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/Routes/RoutesCommon.tsx:231-267
Timestamp: 2025-09-03T21:17:27.699Z
Learning: gomesalexandre prefers to keep PR diffs focused and reasonable in size, deferring tangential improvements (like Mixpanel privacy enhancements) to separate efforts rather than expanding the scope of feature PRs.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11170
File: patches/@shapeshiftoss+bitcoinjs-lib+7.0.0-shapeshift.0.patch:9-19
Timestamp: 2025-11-25T21:43:10.838Z
Learning: In shapeshift/web, gomesalexandre will not expand PR scope to fix latent bugs in unused API surface (like bitcoinjs-lib patch validation methods) when comprehensive testing proves the actual used code paths work correctly, preferring to avoid costly hdwallet/web verdaccio publish cycles and full regression testing for conceptual issues with zero runtime impact.

Learnt from: gomes-bot
Repo: shapeshift/web PR: 12049
File: .npmrc:1-4
Timestamp: 2026-03-01T22:00:52.269Z
Learning: In shapeshift/web migration PRs (e.g., package manager migrations), intentionally match the previous tool's default behavior rather than introducing stricter enforcement or improvements. For example, during the yarn→pnpm migration, strict-peer-dependencies=false and auto-install-peers=true were intentionally set to mirror yarn's defaults. Hardening steps like enabling strict peer enforcement should be tracked as separate follow-up PRs after the migration lands and stabilizes, not included in the migration PR scope.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10569
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/WalletConnectModalSigningFooter.tsx:121-129
Timestamp: 2025-09-17T22:40:30.149Z
Learning: gomesalexandre maintains strict scope discipline even for style/UI PRs in shapeshift/web, declining functionally correct UX improvements (like keeping Cancel button enabled during gas simulation loading) when they fall outside the PR's stated styling objectives, demonstrating his consistent pattern of deferring valid but tangential improvements to separate efforts.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10232
File: packages/unchained-client/openapitools.json:61-61
Timestamp: 2025-08-08T10:23:16.843Z
Learning: In shapeshift/web, for temporary “monkey patch” PRs (e.g., packages/unchained-client/openapitools.json using jsDelivr CDN refs like cosmos/mayachain), gomesalexandre is fine with branch-based URLs and does not want SHA pinning. Treat this as a scoped exception to their general preference for pinned dependencies/refs.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11536
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:252-265
Timestamp: 2025-12-27T16:02:59.817Z
Learning: When fixing critical bugs in shapeshift/web, gomesalexandre prefers to keep changes minimal and focused on correctness rather than combining bug fixes with code quality improvements like extracting duplicated logic, even when duplication is present.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10566
File: src/hooks/useLedgerAccountGuard/useLedgerAccountGuard.tsx:4-4
Timestamp: 2025-09-23T10:36:13.916Z
Learning: gomesalexandre dismisses suggestions to expand PR scope beyond the current migration when the PR is already systematically implementing the desired pattern (like KeyManager.Ledger migration) within focused boundaries, preferring to keep scope contained rather than doing comprehensive codebase-wide cleanups.

Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10136
File: src/lib/asset-service/service/encodedRelatedAssetIndex.json:1-1
Timestamp: 2025-07-29T10:22:27.037Z
Learning: PRs with titles starting with "feat: regenerate asset data" are routine daily asset updates that don't need detailed code analysis. Users prefer to skip automated reviews for these maintenance PRs using coderabbitai ignore.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:21-24
Timestamp: 2025-09-12T13:16:27.004Z
Learning: gomesalexandre declined to add error boundaries to WalletConnect modals in PR `#10461`, stating "no error boundaries in this pr ser", consistent with his preference to keep PR scope focused and defer tangential improvements to separate efforts.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:0-0
Timestamp: 2025-09-12T11:56:19.437Z
Learning: gomesalexandre rejected verbose try/catch error handling for address validation in Tenderly integration (PR `#10461`), calling the approach "ugly" but still implemented safety measures in commit ad7e424b89, preferring cleaner safety implementations over defensive programming patterns.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/TransactionContent.tsx:40-140
Timestamp: 2025-09-12T12:04:24.562Z
Learning: gomesalexandre prefers to defer error handling improvements in new/preparatory code until real-world error cases are encountered, rather than implementing speculative error handling without concrete failure scenarios to test against. This aligns with keeping PR scope focused and evidence-based development practices.

Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SendTransactionContent.tsx:0-0
Timestamp: 2025-09-12T10:44:46.723Z
Learning: gomesalexandre dismissed a clipboard error handling suggestion in PR `#10461` for SendTransactionContent.tsx, demonstrating that the current navigator.clipboard.writeText implementation works as expected and preferring to keep it simple without additional try/catch error handling.

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.

🧹 Nitpick comments (3)
scripts/release.ts (3)

553-559: Minor: Missing null check for release PR URL.

While this code path is only reached when commits exist (validated at line 532), if createPr returns null unexpectedly, the log would show "Release PR created: null". The same applies to prerelease PR (line 576) and hotfix PR (line 798).

Since the "No commits between" error should only occur when branches are identical (which shouldn't happen here given prior validation), this is very low risk. Consider adding a defensive check for consistency with other call sites.

💡 Optional: Defensive null check
         const releasePrUrl = await createPr({
           base: 'main',
           head: 'release',
           title: `chore: release ${nextVersion}`,
           body: releaseBody,
         })
-        console.log(chalk.green(`Release PR created: ${releasePrUrl}`))
+        if (releasePrUrl) {
+          console.log(chalk.green(`Release PR created: ${releasePrUrl}`))
+        } else {
+          exit(chalk.red('Failed to create release PR - no commits between branches.'))
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/release.ts` around lines 553 - 559, Add a defensive null check after
calling createPr so we never log "Release PR created: null": after the createPr
call that sets releasePrUrl, verify releasePrUrl is non-null and only call
console.log(chalk.green(...)) when it is; if null, log an error or throw
(consistent with other call sites). Apply the same pattern for the prerelease
and hotfix createPr calls (the variables used there) so all PR creation sites
consistently guard against a null return from createPr.

860-861: Minor: Redundant diff computation.

privateContentMatchesMain was already computed at the start of doHotfixRelease (lines 732-734). This additional diff check (privateDiffHotfix) is defensive but redundant—if we're in tagged_private_stale, we already know privateContentMatchesMain is false. Additionally, createPr now returns null when there are no commits between branches, providing another safety net.

This isn't a bug, but it's slightly inconsistent with the regular release flow which doesn't have this double-check. Consider removing for consistency, or keep as belt-and-suspenders.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/release.ts` around lines 860 - 861, The extra diff check computing
privateDiffHotfix and shouldSyncPrivateHotfix inside doHotfixRelease is
redundant because privateContentMatchesMain was already determined earlier and
the createPr call now returns null when there are no commits; remove the
redundant computation (privateDiffHotfix and shouldSyncPrivateHotfix) and any
logic that relies on it, and instead use the previously computed
privateContentMatchesMain (and rely on createPr's null result) to decide whether
to sync/create the private PR; update any references to shouldSyncPrivateHotfix
to use the existing privateContentMatchesMain or the createPr return value, and
remove the unnecessary git().diff call.

427-429: Defensive error handling looks correct.

The String(err).includes('No commits between') check handles the GitHub API response gracefully. However, consider using a more specific check if GitHub provides a structured error code, as string matching can be fragile if GitHub changes their error message wording.

💡 Optional: More robust error detection

If the error object has a structured format (e.g., err.stderr or err.code), matching on that would be more reliable than string matching on the full error. However, since this is a CLI tool and the current approach works, this is a low-priority refinement.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/release.ts` around lines 427 - 429, The catch block that currently
does if (String(err).includes('No commits between')) return null should be made
more robust by checking structured error properties first (e.g., err.code,
err.message, err.stderr) and only falling back to the string include if those
properties are absent; update the catch handling around that try/catch to test
err.code or err.message for a known GitHub/CLI code or phrase, then return null
when matched, otherwise rethrow the error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/release.ts`:
- Around line 553-559: Add a defensive null check after calling createPr so we
never log "Release PR created: null": after the createPr call that sets
releasePrUrl, verify releasePrUrl is non-null and only call
console.log(chalk.green(...)) when it is; if null, log an error or throw
(consistent with other call sites). Apply the same pattern for the prerelease
and hotfix createPr calls (the variables used there) so all PR creation sites
consistently guard against a null return from createPr.
- Around line 860-861: The extra diff check computing privateDiffHotfix and
shouldSyncPrivateHotfix inside doHotfixRelease is redundant because
privateContentMatchesMain was already determined earlier and the createPr call
now returns null when there are no commits; remove the redundant computation
(privateDiffHotfix and shouldSyncPrivateHotfix) and any logic that relies on it,
and instead use the previously computed privateContentMatchesMain (and rely on
createPr's null result) to decide whether to sync/create the private PR; update
any references to shouldSyncPrivateHotfix to use the existing
privateContentMatchesMain or the createPr return value, and remove the
unnecessary git().diff call.
- Around line 427-429: The catch block that currently does if
(String(err).includes('No commits between')) return null should be made more
robust by checking structured error properties first (e.g., err.code,
err.message, err.stderr) and only falling back to the string include if those
properties are absent; update the catch handling around that try/catch to test
err.code or err.message for a known GitHub/CLI code or phrase, then return null
when matched, otherwise rethrow the error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 27174c94-9d12-4774-a4fb-2e96eadcf2e1

📥 Commits

Reviewing files that changed from the base of the PR and between acb8d81 and 8d621bb.

📒 Files selected for processing (1)
  • scripts/release.ts

Copy link
Member

@0xApotheosis 0xApotheosis left a comment

Choose a reason for hiding this comment

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

PR Review

Root cause fix is correct. Replacing privateSha !== mainSha with a git diff-based boolean is squash-merge safe — the right approach.

What's good

  • createPr returning null on "No commits between" is a nice defensive improvement
  • All callers handle null correctly
  • Log message fix (latestTag instead of nextVersion in tagged_private_stale) is correct

Minor issues

1. Inconsistency in hotfix tagged_private_stale handler

The regular release tagged_private_stale handler was cleanly refactored — removed the redundant git diff check and relies on createPr returning null. But the hotfix tagged_private_stale handler (~line 846) still uses the old pattern:

const privateDiffHotfix = await git().diff(['origin/main', 'origin/private'])
const shouldSyncPrivateHotfix = Boolean(privateDiffHotfix)

This is redundant because tagged_private_stale already means !privateContentMatchesMain. Could be simplified to match the regular release path. Not a bug, just inconsistent and a wasted diff call.

2. Nit: String(err).includes('No commits between') is a bit fragile if GH CLI ever changes that message, but the fallback is just throw err so low risk.

LGTM 👍

…tale

- add exit() on null releasePrUrl/prereleasePrUrl/prUrl (hotfix) - these
  are unexpected nulls since commits are validated beforehand, so fail loud
- remove privateDiffHotfix/shouldSyncPrivateHotfix from hotfix
  tagged_private_stale - redundant since that state only fires when
  !privateContentMatchesMain. matches regular release path now.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@gomesalexandre
Copy link
Contributor Author

done @0xApotheosis - removed the redundant privateDiffHotfix/shouldSyncPrivateHotfix from hotfix tagged_private_stale (ef3bb14), now mirrors the regular release path. also added exit() on unexpected null for releasePrUrl/prereleasePrUrl/prUrl as suggested by the rabbit.

@gomesalexandre gomesalexandre enabled auto-merge (squash) March 17, 2026 08:47
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/release.ts (1)

68-84: ⚠️ Potential issue | 🟠 Major

Update test fixtures/callers to the renamed state input (privateContentMatchesMain).

deriveReleaseState and deriveHotfixState now require privateContentMatchesMain: boolean, but related tests still appear to pass privateSha: string. This will break type-checking (or invalidate test intent) until those fixtures are migrated.

Suggested test updates
- privateSha: 'aaa',
+ privateContentMatchesMain: true,

- privateSha: 'zzz',
+ privateContentMatchesMain: false,

Also applies to: 98-108

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/release.ts` around lines 68 - 84, The tests and any callers still
pass the old privateSha string to deriveReleaseState/deriveHotfixState; update
those fixtures and call sites to provide the renamed boolean parameter
privateContentMatchesMain (true/false) instead of privateSha, and adjust any
test assertions/fixtures to reflect the boolean semantics; search for
deriveReleaseState and deriveHotfixState usages and replace the former
privateSha argument with a computed boolean (e.g., privateContentMatchesMain) so
TypeScript types and test intent match the new signature.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/release.ts`:
- Around line 664-669: The PR metadata for the "tagged_private_stale" PRs uses
nextVersion but should reference the already-tagged release latestTag; update
the createPr calls that build the private branch PR (the call that assigns
privatePrUrl and the analogous call around lines 874-879) to use latestTag in
the title and body instead of nextVersion so the title/body read e.g. `chore:
sync private to ${latestTag}` and `Sync private branch to main after release
${latestTag}`; keep the same createPr invocation and variables (createPr,
privatePrUrl) but replace nextVersion with latestTag.

---

Outside diff comments:
In `@scripts/release.ts`:
- Around line 68-84: The tests and any callers still pass the old privateSha
string to deriveReleaseState/deriveHotfixState; update those fixtures and call
sites to provide the renamed boolean parameter privateContentMatchesMain
(true/false) instead of privateSha, and adjust any test assertions/fixtures to
reflect the boolean semantics; search for deriveReleaseState and
deriveHotfixState usages and replace the former privateSha argument with a
computed boolean (e.g., privateContentMatchesMain) so TypeScript types and test
intent match the new signature.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1fc09235-2e5a-4d5d-bfb8-3dd40332273d

📥 Commits

Reviewing files that changed from the base of the PR and between 8d621bb and ef3bb14.

📒 Files selected for processing (1)
  • scripts/release.ts

@gomesalexandre gomesalexandre merged commit 865d7d0 into develop Mar 17, 2026
3 checks passed
@gomesalexandre gomesalexandre deleted the fix/release-script-no-commits-crash branch March 17, 2026 09:02
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