mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 10:37:35 +00:00
* fix(mobile): gate PR merge and linking on desktop's shared rules Merge state moves to src/shared so the phone stops offering Merge on drafts, conflicts and blocked PRs, and stops letting branch PRs override explicit links. * fix(mobile): keep stack merges and stale-link recovery in the PR panel Mobile now applies desktop's stack override and drops a linked PR the branch has moved past, and only offers Ready for review when a relaying desktop also forwards it. * fix(mobile): persist stale PR link clears and add a merge recheck The phone now writes desktop's link clear instead of rereading the stale link, and a blocked Merge can be rechecked since nothing on mobile polls PR state. * fix(mobile): guard stale PR link clears like desktop Re-reads the worktree before clearing so a link chosen after the lookup survives, and localizes the merge-state strings the lift exposed to the coverage gate. * test(mobile): drop identity test for worktree link params * refactor(mobile): share one stack-merge decision and trim PR panel wiring * fix(mobile): default worktree bare/archived flags for the stale-link guard * fix(mobile): label the PR merge button from its default merge method
84 lines
3.2 KiB
TypeScript
84 lines
3.2 KiB
TypeScript
import type { PRInfo } from './pull-request-types'
|
|
import type { Worktree } from '../worktree/types'
|
|
|
|
export function shouldClearDivergedLinkedMergedPR(args: {
|
|
pr: PRInfo | null
|
|
linkedPRNumber: number | null
|
|
requestHeadOid: string | null
|
|
}): boolean {
|
|
const { pr, linkedPRNumber, requestHeadOid } = args
|
|
return (
|
|
linkedPRNumber != null &&
|
|
requestHeadOid !== null &&
|
|
pr?.number === linkedPRNumber &&
|
|
pr.state === 'merged' &&
|
|
// Head-scoped: clear only the worktree whose head diverged, so a PR-number-coalesced broadcast can't clear a sibling still on the PR's line of work.
|
|
pr.headDivergedFromMergedPRAtOid === requestHeadOid &&
|
|
pr.headSha !== requestHeadOid &&
|
|
pr.confirmedContainedHeadOid !== requestHeadOid
|
|
)
|
|
}
|
|
|
|
// Clear linked PR after branch switch only when neither push target nor HEAD matches its head; otherwise Checks remains pinned to old work.
|
|
export function shouldClearBranchMismatchedLinkedOpenPR(args: {
|
|
pr: PRInfo | null
|
|
linkedPRNumber: number | null
|
|
branch: string
|
|
requestHeadOid: string | null
|
|
pushTargetBranch: string | null
|
|
}): boolean {
|
|
const { pr, linkedPRNumber, branch, requestHeadOid, pushTargetBranch } = args
|
|
const headRefName = pr?.headRefName?.trim() ?? ''
|
|
const currentBranch = branch.replace(/^refs\/heads\//, '').trim()
|
|
return (
|
|
linkedPRNumber != null &&
|
|
pr?.number === linkedPRNumber &&
|
|
// Draft reviews are open PRs too; don't let their distinct renderer state leave a stale durable link wedged after a branch switch.
|
|
(pr.state === 'open' || pr.state === 'draft') &&
|
|
requestHeadOid !== null &&
|
|
headRefName !== '' &&
|
|
currentBranch !== '' &&
|
|
headRefName !== currentBranch &&
|
|
(pushTargetBranch === null || pushTargetBranch !== headRefName) &&
|
|
// A worktree parked on the PR's head commit is the same line of work (e.g. renamed local branch); keep the link.
|
|
!(pr.headSha != null && pr.headSha === requestHeadOid)
|
|
)
|
|
}
|
|
|
|
export function shouldApplyDivergedLinkedPRClear(args: {
|
|
worktree: Pick<Worktree, 'linkedPR' | 'branch' | 'head' | 'isBare' | 'isArchived'> | undefined
|
|
linkedPRNumber: number
|
|
branch: string
|
|
requestHeadOid: string | null
|
|
}): boolean {
|
|
const { worktree, linkedPRNumber, branch, requestHeadOid } = args
|
|
return (
|
|
Boolean(worktree) &&
|
|
requestHeadOid !== null &&
|
|
worktree?.linkedPR === linkedPRNumber &&
|
|
worktree.branch.replace(/^refs\/heads\//, '') === branch &&
|
|
worktree.head === requestHeadOid &&
|
|
worktree.isBare !== true &&
|
|
worktree.isArchived !== true
|
|
)
|
|
}
|
|
|
|
export function shouldApplyBranchMismatchedLinkedPRClear(args: {
|
|
worktree: Pick<Worktree, 'linkedPR' | 'branch' | 'head' | 'isBare' | 'isArchived'> | undefined
|
|
linkedPRNumber: number
|
|
branch: string
|
|
requestHeadOid: string | null
|
|
}): boolean {
|
|
const { worktree, linkedPRNumber, branch, requestHeadOid } = args
|
|
return (
|
|
Boolean(worktree) &&
|
|
requestHeadOid !== null &&
|
|
worktree?.linkedPR === linkedPRNumber &&
|
|
// Branch-scoped: clear only while still on the branch the mismatch was computed against; a newer switch re-validates.
|
|
worktree.branch.replace(/^refs\/heads\//, '') === branch.replace(/^refs\/heads\//, '') &&
|
|
worktree.head === requestHeadOid &&
|
|
worktree.isBare !== true &&
|
|
worktree.isArchived !== true
|
|
)
|
|
}
|