mirror of
https://github.com/stablyai/orca.git
synced 2026-10-16 08:03:09 +00:00
Harden worktree identity migration coverage
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -133,6 +133,7 @@ function createTestStore() {
|
||||
expandedDirs: {},
|
||||
gitStatusByWorktree: {},
|
||||
gitStatusHeadByWorktree: {},
|
||||
gitStatusHugeByWorktree: {},
|
||||
gitIgnoredPathsByWorktree: {},
|
||||
gitConflictOperationByWorktree: {},
|
||||
trackedConflictPathsByWorktree: {},
|
||||
@@ -144,6 +145,8 @@ function createTestStore() {
|
||||
activeBrowserTabIdByWorktree: {},
|
||||
browserTabsByWorktree: {},
|
||||
recentlyClosedBrowserTabsByWorktree: {},
|
||||
recentlyClosedEditorTabsByWorktree: {},
|
||||
remoteStatusesByWorktree: {},
|
||||
activeTabTypeByWorktree: {},
|
||||
rightSidebarTab: 'explorer' as const,
|
||||
rightSidebarTabByWorktree: {},
|
||||
@@ -5003,6 +5006,11 @@ describe('migrateWorktreeIdentity', () => {
|
||||
const OLD = 'repo1::/ws/cunner'
|
||||
const NEW = 'repo1::/ws/worktree-creation-spinner'
|
||||
const CANONICAL = makeWorktreeKey({ hostId: 'local', repoId: 'repo1', path: '/ws/cunner' })
|
||||
const WORKTREE_ID_VALUE_MIGRATED_KEYS = new Set([
|
||||
'browserPagesByWorkspace',
|
||||
'recentlyClosedBrowserPagesByWorkspace',
|
||||
'sleepingAgentSessionsByPaneKey'
|
||||
])
|
||||
|
||||
function makeMigrationMapValue(
|
||||
key: (typeof WORKTREE_ID_KEYED_MAP_KEYS)[number],
|
||||
@@ -5026,11 +5034,24 @@ describe('migrateWorktreeIdentity', () => {
|
||||
return [{ id: 'unified1', worktreeId }]
|
||||
case 'groupsByWorktree':
|
||||
return [{ id: 'group1', worktreeId }]
|
||||
case 'recentlyClosedEditorTabsByWorktree':
|
||||
return [{ id: 'file1', worktreeId }]
|
||||
default:
|
||||
return { marker: key }
|
||||
}
|
||||
}
|
||||
|
||||
it('keeps the worktree-id keyed map list in sync with store fields', () => {
|
||||
const declared = new Set<keyof AppState>(WORKTREE_ID_KEYED_MAP_KEYS)
|
||||
const state = createTestStore().getState()
|
||||
const uncovered = Object.keys(state)
|
||||
.filter((key) => key.includes('ByWorktree'))
|
||||
.filter((key) => !declared.has(key as keyof AppState))
|
||||
.filter((key) => !WORKTREE_ID_VALUE_MIGRATED_KEYS.has(key))
|
||||
|
||||
expect(uncovered).toEqual([])
|
||||
})
|
||||
|
||||
it('re-keys worktree-scoped maps, pointers, the Set, and openFiles old->new', () => {
|
||||
const store = createTestStore()
|
||||
store.setState({
|
||||
@@ -5052,6 +5073,7 @@ describe('migrateWorktreeIdentity', () => {
|
||||
groupsByWorktree: { [OLD]: [{ id: 'group1', worktreeId: OLD }] },
|
||||
gitStatusByWorktree: { [OLD]: [{ path: 'a.ts' }] },
|
||||
gitStatusHeadByWorktree: { [OLD]: 'head-old' },
|
||||
gitStatusHugeByWorktree: { [OLD]: { limit: 10_000 } },
|
||||
gitBranchCompareRequestStatusHeadByWorktree: { [OLD]: 'head-old' },
|
||||
lastVisitedAtByWorktreeId: { [OLD]: 123 },
|
||||
defaultTerminalTabsAppliedByWorktreeId: { [OLD]: true },
|
||||
@@ -5095,12 +5117,12 @@ describe('migrateWorktreeIdentity', () => {
|
||||
expect(s.groupsByWorktree[NEW]?.[0]?.worktreeId).toBe(NEW)
|
||||
expect(s.gitStatusByWorktree[NEW]).toEqual([{ path: 'a.ts' }])
|
||||
expect(s.gitStatusHeadByWorktree[NEW]).toBe('head-old')
|
||||
expect(s.gitStatusHugeByWorktree[NEW]).toEqual({ limit: 10_000 })
|
||||
expect(s.gitBranchCompareRequestStatusHeadByWorktree[NEW]).toBe('head-old')
|
||||
expect(s.rightSidebarExplorerViewByWorktree[OLD]).toBeUndefined()
|
||||
expect(s.rightSidebarExplorerViewByWorktree[NEW]).toBe('search')
|
||||
expect(s.lastVisitedAtByWorktreeId[NEW]).toBe(123)
|
||||
expect(s.defaultTerminalTabsAppliedByWorktreeId[NEW]).toBe(true)
|
||||
// The two maps absent from the purge list are still re-keyed.
|
||||
expect(s.recentlyClosedEditorTabsByWorktree[NEW]).toEqual([{ id: 'f1', worktreeId: NEW }])
|
||||
expect(s.remoteStatusesByWorktree[NEW]).toEqual({ ahead: 1 })
|
||||
expect(s.everActivatedWorktreeIds.has(NEW)).toBe(true)
|
||||
|
||||
@@ -1272,6 +1272,7 @@ export const WORKTREE_ID_KEYED_MAP_KEYS = [
|
||||
'activeGroupIdByWorktree',
|
||||
'gitStatusByWorktree',
|
||||
'gitStatusHeadByWorktree',
|
||||
'gitStatusHugeByWorktree',
|
||||
'gitIgnoredPathsByWorktree',
|
||||
'gitConflictOperationByWorktree',
|
||||
'trackedConflictPathsByWorktree',
|
||||
@@ -1279,6 +1280,8 @@ export const WORKTREE_ID_KEYED_MAP_KEYS = [
|
||||
'gitBranchCompareSummaryByWorktree',
|
||||
'gitBranchCompareRequestKeyByWorktree',
|
||||
'gitBranchCompareRequestStatusHeadByWorktree',
|
||||
'recentlyClosedEditorTabsByWorktree',
|
||||
'remoteStatusesByWorktree',
|
||||
'showDotfilesByWorktree',
|
||||
'expandedDirs',
|
||||
'lastVisitedAtByWorktreeId',
|
||||
@@ -1371,7 +1374,9 @@ function buildWorktreeRenameState(
|
||||
pages: snapshot.pages.map(withNewWorktreeId)
|
||||
})),
|
||||
unifiedTabsByWorktree: (tabs: { worktreeId: string }[]) => tabs.map(withNewWorktreeId),
|
||||
groupsByWorktree: (groups: { worktreeId: string }[]) => groups.map(withNewWorktreeId)
|
||||
groupsByWorktree: (groups: { worktreeId: string }[]) => groups.map(withNewWorktreeId),
|
||||
recentlyClosedEditorTabsByWorktree: (files: { worktreeId: string }[]) =>
|
||||
files.map(withNewWorktreeId)
|
||||
}
|
||||
for (const key of WORKTREE_ID_KEYED_MAP_KEYS) {
|
||||
renameKey(key, renameValueByKey[key] as ((value: unknown) => unknown) | undefined)
|
||||
@@ -1398,14 +1403,6 @@ function buildWorktreeRenameState(
|
||||
oldWorkspaceKey,
|
||||
newWorkspaceKey
|
||||
)
|
||||
// Re-key these on rename so a renamed worktree keeps its editor-undo + push/pull
|
||||
// state. (Both removal paths — buildWorktreePurgeState and the single
|
||||
// removeWorktree reducer — now also purge them on removal.)
|
||||
renameKey('recentlyClosedEditorTabsByWorktree', (files: { worktreeId: string }[]) =>
|
||||
files.map(withNewWorktreeId)
|
||||
)
|
||||
renameKey('remoteStatusesByWorktree')
|
||||
|
||||
const openFiles = s.openFiles?.some((f) => f.worktreeId === oldWorktreeId)
|
||||
? s.openFiles.map((f) =>
|
||||
f.worktreeId === oldWorktreeId ? { ...f, worktreeId: newWorktreeId } : f
|
||||
|
||||
Reference in New Issue
Block a user