From 803ab30598e473631068cf89784ea96ba19e98be Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 10 Oct 2026 02:01:40 -0700 Subject: [PATCH] Await Git checks while discovering and importing nested projects (#26790) * Keep repository detection off the main IPC thread Share repository discovery decisions across synchronous compatibility callers and the existing asynchronous Git runner. Await discovery in project registration, nested imports, and folder upgrades, and recheck folder ownership after discovery completes. * Make repository detection fixtures work on native Windows * Await asynchronous Git checks in folder upgrade fixtures * Prevent duplicate project registration after async discovery * Check authoritative registration identity before renderer convergence * Narrow repository responsiveness to detection and registration * Keep one local project identity after concurrent registration * Run registration SSH coverage in the existing Docker lane * Await Git discovery when scanning and importing nested projects * test(git): cover classifier failure stages and literal path identity * test(git): use the current process host package * test(repos): use current process host in registration fixture --- src/main/ipc/repos/nested-repo-import-handler.ts | 6 +++--- src/main/project-groups/nested-repo-discovery.ts | 5 +++-- src/main/runtime/runtime-nested-repo-import.ts | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/ipc/repos/nested-repo-import-handler.ts b/src/main/ipc/repos/nested-repo-import-handler.ts index cd7b2a14d2c..6d1fceb9391 100644 --- a/src/main/ipc/repos/nested-repo-import-handler.ts +++ b/src/main/ipc/repos/nested-repo-import-handler.ts @@ -7,7 +7,7 @@ import type { ProjectGroupImportResult } from '../../../shared/project-group-typ import { DEFAULT_REPO_BADGE_COLOR } from '../../../shared/constants' import { normalizeRuntimePathForComparison } from '../../../shared/cross-platform-path' import { awaitWindowsHostGitEnvironmentReady } from '../../git/runner' -import { isGitRepo, getRepoName } from '../../git/repo' +import { isGitRepoAsync, getRepoName } from '../../git/repo' import { createNestedProjectGroupResolver, resolveNestedRepoSelection @@ -83,7 +83,7 @@ export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store importRepoPath = await importTargetResolver.resolveSsh(repoPath, gitProvider) } else { await awaitWindowsHostGitEnvironmentReady({ cwd: repoPath }) - if (!isGitRepo(repoPath)) { + if (!(await isGitRepoAsync(repoPath))) { results.push({ path: repoPath, status: 'failed', @@ -152,7 +152,7 @@ export function registerNestedRepoImportHandler(mainWindow: BrowserWindow, store } importedProjectIdsByRepoPath.set(normalizedImportRepoPath, repo.id) results.push({ path: repoPath, projectId: repo.id, status: 'imported' }) - // Why: reaches here only after the isGitRepo guard above confirmed a git repo, so always true. + // Why: reaches here only after the isGitRepoAsync guard above confirmed a git repo, so always true. emitRepoAdded('folder_picker', false, true) } catch (error) { results.push({ diff --git a/src/main/project-groups/nested-repo-discovery.ts b/src/main/project-groups/nested-repo-discovery.ts index 1f25a85a26f..84abbf74ae6 100644 --- a/src/main/project-groups/nested-repo-discovery.ts +++ b/src/main/project-groups/nested-repo-discovery.ts @@ -1,7 +1,7 @@ import { readFile, readdir, stat } from 'node:fs/promises' import { basename, join } from 'node:path' import type { NestedRepoCandidate, NestedRepoScanResult } from '../../shared/project-group-types' -import { isGitRepo } from '../git/repo' +import { isGitRepoAsync } from '../git/repo' import { isIgnoredNestedRepoDirectory, normalizeNestedRepoScanOptions, @@ -58,7 +58,8 @@ export async function scanNestedRepos(args: { joinPath: join, basename, hasGitMarker, - isSelectedPathGitRepo: async (path: string) => isGitRepo(path) || (await hasGitMarker(path)) + isSelectedPathGitRepo: async (path: string) => + (await isGitRepoAsync(path)) || (await hasGitMarker(path)) } const buildResult = (selectedPathKind: NestedRepoScanResult['selectedPathKind']) => ({ selectedPath: args.path, diff --git a/src/main/runtime/runtime-nested-repo-import.ts b/src/main/runtime/runtime-nested-repo-import.ts index ba2df920b51..81ab6d99f00 100644 --- a/src/main/runtime/runtime-nested-repo-import.ts +++ b/src/main/runtime/runtime-nested-repo-import.ts @@ -9,7 +9,7 @@ import type { } from '../../shared/project-group-types' import type { Repo } from '../../shared/repo-types' import { awaitWindowsHostGitEnvironmentReady } from '../git/runner' -import { getRepoName, isGitRepo } from '../git/repo' +import { getRepoName, isGitRepoAsync } from '../git/repo' import { scanNestedRepos } from '../project-groups/nested-repo-discovery' import { createNestedProjectGroupResolver, @@ -77,7 +77,7 @@ export class RuntimeNestedRepoImport { for (const [projectGroupOrder, repoPath] of selection.selectedPaths.entries()) { try { await awaitWindowsHostGitEnvironmentReady({ cwd: repoPath }) - if (!isGitRepo(repoPath)) { + if (!(await isGitRepoAsync(repoPath))) { results.push({ path: repoPath, status: 'failed', error: 'Not a valid git repository' }) continue }