Skip to content
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 62 additions & 10 deletions scripts/release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,9 @@ const doRegularRelease = async () => {
// Two sub-states within idle:
// 1. Release branch ahead of main (prerelease merged) -> create release -> main PR
// 2. Release branch matches main (fresh start) -> create develop -> release PR
const prereleaseMerged = releaseSha !== mainSha
// Use content diff (not SHA) to handle squash merges where SHAs diverge but content is identical
const releaseMatchesMain = !(await git().diff(['origin/main', 'origin/release']))
const prereleaseMerged = releaseSha !== mainSha && !releaseMatchesMain

if (prereleaseMerged) {
const messages = await getCommitMessages(`${latestTag}..origin/release`)
Expand Down Expand Up @@ -610,21 +612,38 @@ const doRegularRelease = async () => {
await git().push(['origin', '--tags'])
console.log(chalk.green(`Tagged ${nextVersion}.`))

console.log(chalk.green('Creating PR to sync private to main...'))
const privatePrUrl = await createPr({
base: 'private',
head: 'main',
title: `chore: sync private to ${nextVersion}`,
body: `Sync private branch to main after release ${nextVersion}.`,
})
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
console.log(chalk.green('Merge it on GitHub to complete the release.'))
const existingPrivatePrAfterTag = await findOpenPr('main', 'private')
if (existingPrivatePrAfterTag) {
console.log(
chalk.yellow(
`Private sync PR already open: #${existingPrivatePrAfterTag.number}. Merge it on GitHub.`,
),
)
} else {
console.log(chalk.green('Creating PR to sync private to main...'))
const privatePrUrl = await createPr({
base: 'private',
head: 'main',
title: `chore: sync private to ${nextVersion}`,
body: `Sync private branch to main after release ${nextVersion}.`,
})
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
console.log(chalk.green('Merge it on GitHub to complete the release.'))
}
break
}

case 'tagged_private_stale': {
console.log(chalk.yellow(`${nextVersion} is tagged but private is behind main.`))

const privateDiff = await git().diff(['origin/main', 'origin/private'])
if (!privateDiff) {
console.log(
chalk.green('Private is already in sync with main content-wise. Nothing to do.'),
)
break
}

const existingPrivatePr = await findOpenPr('main', 'private')
if (existingPrivatePr) {
console.log(
Expand All @@ -642,6 +661,26 @@ const doRegularRelease = async () => {
})
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
}

const existingBackmerge = await findOpenPr('main', 'develop')
if (!existingBackmerge) {
const mainDevelopCommits = await getCommitMessages('origin/develop..origin/main')
if (mainDevelopCommits.length > 0) {
console.log(chalk.green('Creating backmerge PR (main -> develop)...'))
const backmergeUrl = await createPr({
base: 'develop',
head: 'main',
title: `chore: backmerge ${nextVersion} into develop`,
body: `Backmerge main into develop after release ${nextVersion}.`,
})
console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`))
console.log(chalk.green('Setting auto-merge with merge commit strategy...'))
await pify(exec)(`gh pr merge --auto --merge ${backmergeUrl}`)
console.log(
chalk.green('Auto-merge set. Backmerge will merge automatically when CI passes.'),
)
}
}
Comment on lines +671 to 689
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

Auto-merge is skipped when backmerge PR already exists.

Right now, gh pr merge --auto --merge ... runs only in the “new PR created” branch. On reruns where a backmerge PR is already open, auto-merge is never set, so automation can stall.

🔧 Minimal fix (apply in both regular + hotfix backmerge blocks)
-      const existingBackmerge = await findOpenPr('main', 'develop')
-      if (!existingBackmerge) {
+      const existingBackmerge = await findOpenPr('main', 'develop')
+      if (existingBackmerge) {
+        console.log(chalk.yellow(`Backmerge PR already open: #${existingBackmerge.number}.`))
+        console.log(chalk.green('Setting auto-merge with merge commit strategy...'))
+        await pify(exec)(`gh pr merge --auto --merge ${existingBackmerge.number}`)
+        console.log(
+          chalk.green('Auto-merge set. Backmerge will merge automatically when CI passes.'),
+        )
+      } else {
         const mainDevelopCommits = await getCommitMessages('origin/develop..origin/main')
         if (mainDevelopCommits.length > 0) {
           console.log(chalk.green('Creating backmerge PR (main -> develop)...'))
           const backmergeUrl = await createPr({
             base: 'develop',
             head: 'main',
             title: `chore: backmerge ${nextVersion} into develop`,
             body: `Backmerge main into develop after release ${nextVersion}.`,
           })
           console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`))
           console.log(chalk.green('Setting auto-merge with merge commit strategy...'))
           await pify(exec)(`gh pr merge --auto --merge ${backmergeUrl}`)
           console.log(
             chalk.green('Auto-merge set. Backmerge will merge automatically when CI passes.'),
           )
         }
       }

Also applies to: 860-877

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

In `@scripts/release.ts` around lines 669 - 687, The backmerge branch creates
auto-merge only when a new PR is created, so reruns where findOpenPr('main',
'develop') returns an existingBackmerge never enable auto-merge; update the
logic so after detecting an existingBackmerge you extract its identifier/URL
(from the existingBackmerge object returned by findOpenPr) and run the same
pify(exec)(`gh pr merge --auto --merge ${prIdentifierOrUrl}`) call to enable
auto-merge, and apply the identical change to the hotfix backmerge block (the
other block that uses createPr/getCommitMessages and gh pr merge).

break
}

Expand Down Expand Up @@ -787,6 +826,14 @@ const doHotfixRelease = async () => {
case 'tagged_private_stale': {
console.log(chalk.yellow(`${nextVersion} is tagged but private is behind main.`))

const privateDiffHotfix = await git().diff(['origin/main', 'origin/private'])
if (!privateDiffHotfix) {
console.log(
chalk.green('Private is already in sync with main content-wise. Nothing to do.'),
)
break
}

const existingPrivatePr = await findOpenPr('main', 'private')
if (existingPrivatePr) {
console.log(
Expand Down Expand Up @@ -817,6 +864,11 @@ const doHotfixRelease = async () => {
body: `Backmerge main into develop after hotfix ${nextVersion}.`,
})
console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`))
console.log(chalk.green('Setting auto-merge with merge commit strategy...'))
await pify(exec)(`gh pr merge --auto --merge ${backmergeUrl}`)
console.log(
chalk.green('Auto-merge set. Backmerge will merge automatically when CI passes.'),
)
}
}
break
Expand Down
Loading