mirror of
https://github.com/stablyai/orca.git
synced 2026-11-04 11:07:42 +00:00
* fix(ssh): relinking a stopped server keeps the groups it holds, and later moves reference them Relinking found server-held groups only through the rows in them, so an empty group renamed on the server was re-imported and refused. Delta moves re-exported a linked group whenever a new row sat in it, so a group renamed on the server refused the next Move. Both now leave the server's group as is. * fix(ssh): delta moves keep the server's record of groups the first move imported * test(ssh): cover a deleted moved group and tidy the relink group fixtures * fix(ssh): resume an older build's delta with the groups its manifest exported * fix(ssh): take no group-ownership evidence from server rows on another host * fix(ssh): a relink records only the groups the server's own list holds, with their host stamps
82 lines
3.0 KiB
TypeScript
82 lines
3.0 KiB
TypeScript
/** The folder workspaces a managed server already holds, so a move links them (#27285). */
|
|
import { z } from 'zod'
|
|
import { normalizeRuntimePathForComparison } from '../../shared/cross-platform-path'
|
|
import {
|
|
resolveFolderWorkspaceHost,
|
|
type FolderHostCatalog
|
|
} from '../../shared/folder-workspace-execution-host'
|
|
import type { FolderWorkspace } from '../../shared/folder-workspace-types'
|
|
import { listServerRows, type CatalogRequestOptions } from './orcad-migration-catalog-client'
|
|
import type { OrcadServerRepository } from './orcad-migration-repository-link'
|
|
|
|
/** The server's folder rows and the groups that decide which host each folder is on. */
|
|
export type OrcadServerFolderCatalog = Omit<FolderHostCatalog, 'repos'>
|
|
|
|
const HostFields = { connectionId: z.string().nullish(), executionHostId: z.string().nullish() }
|
|
|
|
const ServerFolderWorkspacesSchema = z.object({
|
|
folderWorkspaces: z.array(
|
|
z.object({
|
|
id: z.string().min(1),
|
|
folderPath: z.string().min(1),
|
|
projectGroupId: z.string().min(1),
|
|
...HostFields
|
|
})
|
|
)
|
|
})
|
|
|
|
const ServerProjectGroupsSchema = z.object({
|
|
groups: z.array(
|
|
z.object({
|
|
id: z.string().min(1),
|
|
parentGroupId: z.string().nullish(),
|
|
...HostFields
|
|
})
|
|
)
|
|
})
|
|
|
|
/** The folder workspaces and groups the destination already holds, as the server stores them. */
|
|
export async function listRemoteOrcadFolderCatalog(
|
|
pairingCode: string,
|
|
options: CatalogRequestOptions = {}
|
|
): Promise<OrcadServerFolderCatalog> {
|
|
const [folders, groups] = await Promise.all([
|
|
listServerRows(pairingCode, 'folderWorkspace.list', 'folder_workspaces', options),
|
|
listServerRows(pairingCode, 'projectGroup.list', 'project_groups', options)
|
|
])
|
|
return {
|
|
folderWorkspaces: ServerFolderWorkspacesSchema.parse(folders).folderWorkspaces,
|
|
projectGroups: ServerProjectGroupsSchema.parse(groups).groups.map((group) => ({
|
|
...group,
|
|
parentGroupId: group.parentGroupId ?? null
|
|
}))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Incoming folder workspaces the server holds under the same id and folder, on its own machine:
|
|
* its copy from an earlier move. Any other same-id row still imports, so the server refuses it.
|
|
*/
|
|
export function folderWorkspacesHeldByServer(
|
|
incoming: readonly Pick<FolderWorkspace, 'id' | 'folderPath'>[],
|
|
server: OrcadServerFolderCatalog,
|
|
serverRepositories: readonly OrcadServerRepository[]
|
|
): string[] {
|
|
const catalog = { ...server, repos: serverRepositories }
|
|
const serverFolderById = new Map(
|
|
server.folderWorkspaces.map((workspace) => [workspace.id, workspace.folderPath])
|
|
)
|
|
return incoming
|
|
.filter((workspace) => {
|
|
const serverFolder = serverFolderById.get(workspace.id)
|
|
return (
|
|
serverFolder !== undefined &&
|
|
normalizeRuntimePathForComparison(serverFolder) ===
|
|
normalizeRuntimePathForComparison(workspace.folderPath) &&
|
|
// A row its group places on another host is a different folder, though stored bare.
|
|
resolveFolderWorkspaceHost(catalog, workspace.id).kind === 'local'
|
|
)
|
|
})
|
|
.map((workspace) => workspace.id)
|
|
}
|