diff --git a/Sources/TabManager.swift b/Sources/TabManager.swift index 1b7f3701..2c4cadaf 100644 --- a/Sources/TabManager.swift +++ b/Sources/TabManager.swift @@ -913,18 +913,10 @@ class TabManager: ObservableObject { let activeProbeKeys = Set(workspaceGitProbeGenerationByKey.keys) for workspace in tabs { - var candidatePanelIds = Set(workspace.panelGitBranches.keys) - candidatePanelIds.formUnion(workspace.panelPullRequests.keys) - - if candidatePanelIds.isEmpty, - let focusedPanelId = workspace.focusedPanelId, - workspace.gitBranch != nil || workspace.pullRequest != nil { - candidatePanelIds.insert(focusedPanelId) - } - - for panelId in candidatePanelIds { - let probeKey = WorkspaceGitProbeKey(workspaceId: workspace.id, panelId: panelId) - guard !activeProbeKeys.contains(probeKey) else { continue } + for panelId in trackedWorkspaceGitMetadataPollCandidatePanelIds( + in: workspace, + activeProbeKeys: activeProbeKeys + ) { scheduleWorkspaceGitMetadataRefreshIfPossible( workspaceId: workspace.id, panelId: panelId, @@ -938,6 +930,54 @@ class TabManager: ObservableObject { refreshTrackedWorkspaceGitMetadata() } + func trackedWorkspaceGitMetadataPollCandidatePanelIdsForTesting(workspaceId: UUID) -> Set { + let activeProbeKeys = Set(workspaceGitProbeGenerationByKey.keys) + guard let workspace = tabs.first(where: { $0.id == workspaceId }) else { + return [] + } + return trackedWorkspaceGitMetadataPollCandidatePanelIds( + in: workspace, + activeProbeKeys: activeProbeKeys + ) + } + + private func trackedWorkspaceGitMetadataPollCandidatePanelIds( + in workspace: Workspace, + activeProbeKeys: Set + ) -> Set { + var candidatePanelIds = Set(workspace.panelGitBranches.keys) + candidatePanelIds.formUnion(workspace.panelPullRequests.keys) + + if candidatePanelIds.isEmpty, + let focusedPanelId = workspace.focusedPanelId, + workspace.gitBranch != nil || workspace.pullRequest != nil { + candidatePanelIds.insert(focusedPanelId) + } + + return Set(candidatePanelIds.filter { panelId in + let probeKey = WorkspaceGitProbeKey(workspaceId: workspace.id, panelId: panelId) + guard !activeProbeKeys.contains(probeKey) else { return false } + return shouldPollTrackedWorkspaceGitMetadata(in: workspace, panelId: panelId) + }) + } + + private func shouldPollTrackedWorkspaceGitMetadata(in workspace: Workspace, panelId: UUID) -> Bool { + guard let branch = trackedWorkspaceGitBranch(in: workspace, panelId: panelId) else { + return true + } + return !Self.shouldSkipWorkspacePullRequestLookup(branch: branch) + } + + private func trackedWorkspaceGitBranch(in workspace: Workspace, panelId: UUID) -> String? { + if let branch = workspace.panelGitBranches[panelId]?.branch { + return branch + } + if workspace.focusedPanelId == panelId { + return workspace.gitBranch?.branch + } + return nil + } + private func sweepStaleAgentPIDs() { for tab in tabs { var keysToRemove: [String] = [] @@ -1462,6 +1502,10 @@ class TabManager: ObservableObject { directory: String, branch: String ) -> WorkspacePullRequestSnapshot { + guard !shouldSkipWorkspacePullRequestLookup(branch: branch) else { + return .notFound + } + let repoSlugs = githubRepositorySlugs(directory: directory) guard !repoSlugs.isEmpty else { return .unsupportedRepository @@ -2010,6 +2054,15 @@ class TabManager: ObservableObject { return trimmed.isEmpty ? nil : trimmed } + nonisolated static func shouldSkipWorkspacePullRequestLookup(branch: String) -> Bool { + switch normalizedBranchName(branch) { + case "main", "master": + return true + default: + return false + } + } + func requestBackgroundWorkspaceLoad(for workspaceId: UUID) { guard !pendingBackgroundWorkspaceLoadIds.contains(workspaceId) else { return } var updated = pendingBackgroundWorkspaceLoadIds diff --git a/cmuxTests/TabManagerUnitTests.swift b/cmuxTests/TabManagerUnitTests.swift index 78920716..d8ec097a 100644 --- a/cmuxTests/TabManagerUnitTests.swift +++ b/cmuxTests/TabManagerUnitTests.swift @@ -301,6 +301,72 @@ final class TabManagerPullRequestProbeTests: XCTestCase { ) } + func testShouldSkipWorkspacePullRequestLookupOnlyForExactMainAndMaster() { + XCTAssertTrue(TabManager.shouldSkipWorkspacePullRequestLookup(branch: "main")) + XCTAssertTrue(TabManager.shouldSkipWorkspacePullRequestLookup(branch: "master")) + XCTAssertTrue(TabManager.shouldSkipWorkspacePullRequestLookup(branch: " master \n")) + + XCTAssertFalse(TabManager.shouldSkipWorkspacePullRequestLookup(branch: "Main")) + XCTAssertFalse(TabManager.shouldSkipWorkspacePullRequestLookup(branch: "mainline")) + XCTAssertFalse(TabManager.shouldSkipWorkspacePullRequestLookup(branch: "feature/main")) + XCTAssertFalse(TabManager.shouldSkipWorkspacePullRequestLookup(branch: "release/master-fix")) + } + + func testTrackedWorkspaceGitMetadataPollCandidatesSkipMainAndMasterPanelsOnly() throws { + let manager = TabManager() + guard let workspace = manager.selectedWorkspace, + let mainPanelId = workspace.focusedPanelId else { + XCTFail("Expected selected workspace with focused panel") + return + } + + guard let masterPanel = workspace.newTerminalSplit(from: mainPanelId, orientation: .horizontal), + let featurePanel = workspace.newTerminalSplit(from: mainPanelId, orientation: .vertical), + let mainlinePanel = workspace.newTerminalSplit(from: mainPanelId, orientation: .horizontal) else { + XCTFail("Expected split panels to be created") + return + } + + let staleURL = try XCTUnwrap(URL(string: "https://github.com/manaflow-ai/cmux/pull/371")) + workspace.updatePanelGitBranch(panelId: mainPanelId, branch: "main", isDirty: false) + workspace.updatePanelPullRequest( + panelId: mainPanelId, + number: 371, + label: "PR", + url: staleURL, + status: .open, + branch: "main" + ) + workspace.updatePanelGitBranch(panelId: masterPanel.id, branch: "master", isDirty: false) + workspace.updatePanelGitBranch(panelId: featurePanel.id, branch: "feature/sidebar-pr", isDirty: false) + workspace.updatePanelGitBranch(panelId: mainlinePanel.id, branch: "mainline", isDirty: false) + + XCTAssertEqual( + manager.trackedWorkspaceGitMetadataPollCandidatePanelIdsForTesting(workspaceId: workspace.id), + Set([featurePanel.id, mainlinePanel.id]) + ) + } + + func testTrackedWorkspaceGitMetadataPollCandidatesSkipFocusedFallbackOnMainOnly() { + let manager = TabManager() + guard let workspace = manager.selectedWorkspace, + let panelId = workspace.focusedPanelId else { + XCTFail("Expected selected workspace with focused panel") + return + } + + workspace.gitBranch = SidebarGitBranchState(branch: "main", isDirty: false) + XCTAssertTrue( + manager.trackedWorkspaceGitMetadataPollCandidatePanelIdsForTesting(workspaceId: workspace.id).isEmpty + ) + + workspace.gitBranch = SidebarGitBranchState(branch: "feature/sidebar-pr", isDirty: false) + XCTAssertEqual( + manager.trackedWorkspaceGitMetadataPollCandidatePanelIdsForTesting(workspaceId: workspace.id), + Set([panelId]) + ) + } + func testResolvedCommandPathFallsBackOutsideAppPATH() throws { let fileManager = FileManager.default let tempDir = fileManager.temporaryDirectory.appendingPathComponent(