diff --git a/supacode/Commands/WorktreeCommands.swift b/supacode/Commands/WorktreeCommands.swift index 52680963..bfef7f4a 100644 --- a/supacode/Commands/WorktreeCommands.swift +++ b/supacode/Commands/WorktreeCommands.swift @@ -134,7 +134,7 @@ struct WorktreeCommands: Commands { guard let selectedWorktreeID = repositories.selectedWorktreeID else { return nil } guard let repositoryID = repositories.repositoryID(containing: selectedWorktreeID), - repositories.repositories[id: repositoryID]?.capabilities.supportsPullRequests == true + repositories.repositories[id: repositoryID]?.capabilities.supportsCodeHost == true else { return nil } diff --git a/supacode/Domain/Repository.swift b/supacode/Domain/Repository.swift index 0df9e26b..5292cb98 100644 --- a/supacode/Domain/Repository.swift +++ b/supacode/Domain/Repository.swift @@ -11,6 +11,7 @@ nonisolated struct Repository: Identifiable, Hashable, Sendable { let supportsWorktrees: Bool let supportsBranchOperations: Bool let supportsPullRequests: Bool + let supportsCodeHost: Bool let supportsDiff: Bool let supportsGitStatus: Bool let supportsRunnableFolderActions: Bool @@ -20,6 +21,7 @@ nonisolated struct Repository: Identifiable, Hashable, Sendable { supportsWorktrees: true, supportsBranchOperations: true, supportsPullRequests: true, + supportsCodeHost: true, supportsDiff: true, supportsGitStatus: true, supportsRunnableFolderActions: true, @@ -30,6 +32,7 @@ nonisolated struct Repository: Identifiable, Hashable, Sendable { supportsWorktrees: false, supportsBranchOperations: false, supportsPullRequests: false, + supportsCodeHost: false, supportsDiff: false, supportsGitStatus: false, supportsRunnableFolderActions: true, diff --git a/supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift b/supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift index b2bfff9e..f5a6621a 100644 --- a/supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift +++ b/supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift @@ -277,14 +277,17 @@ private func selectedCodeHostItems( guard let selectedWorktreeID = repositories.selectedWorktreeID, let repositoryID = repositories.repositoryID(containing: selectedWorktreeID), - let repository = repositories.repositories[id: repositoryID], - repository.capabilities.supportsPullRequests + let repository = repositories.repositories[id: repositoryID] else { return [] } let pullRequest = repositories.worktreeInfo(for: selectedWorktreeID)?.pullRequest - if let pullRequest, pullRequest.number > 0, pullRequest.state.uppercased() != "CLOSED" { + if repository.capabilities.supportsPullRequests, + let pullRequest, + pullRequest.number > 0, + pullRequest.state.uppercased() != "CLOSED" + { return pullRequestItems( pullRequest: pullRequest, worktreeID: selectedWorktreeID, @@ -292,6 +295,10 @@ private func selectedCodeHostItems( ) } + guard repository.capabilities.supportsCodeHost else { + return [] + } + return [ CommandPaletteItem( id: CommandPaletteItemID.pullRequestOpen(repositoryID), diff --git a/supacode/Features/CommandPalette/Views/CommandPaletteOverlayView.swift b/supacode/Features/CommandPalette/Views/CommandPaletteOverlayView.swift index 298e775d..7c33d820 100644 --- a/supacode/Features/CommandPalette/Views/CommandPaletteOverlayView.swift +++ b/supacode/Features/CommandPalette/Views/CommandPaletteOverlayView.swift @@ -520,7 +520,7 @@ private struct CommandPaletteRowView: View { case .archiveWorktree: base = "Archive \(row.title)" case .openPullRequest: - base = "Open on code host" + base = "Open on Code Host" case .markPullRequestReady: base = "Mark pull request ready for review" case .mergePullRequest: diff --git a/supacode/Features/Repositories/Reducer/RepositoriesFeature+GithubIntegration.swift b/supacode/Features/Repositories/Reducer/RepositoriesFeature+GithubIntegration.swift index 64965a79..0c9d88f8 100644 --- a/supacode/Features/Repositories/Reducer/RepositoriesFeature+GithubIntegration.swift +++ b/supacode/Features/Repositories/Reducer/RepositoriesFeature+GithubIntegration.swift @@ -237,28 +237,11 @@ extension RepositoriesFeature { } let repoRoot = worktree.repositoryRootURL let worktreeRoot = worktree.workingDirectory - let pullRequest = state.worktreeInfo(for: worktreeID)?.pullRequest - if action != .openOnCodeHost, pullRequest == nil { - return .send( - .presentAlert( - title: "Pull request not available", - message: "Prowl could not find a pull request for this worktree." - ) - ) - } - let pullRequestRefresh = WorktreeInfoWatcherClient.Event.repositoryPullRequestRefresh( - repositoryRootURL: repoRoot, - worktreeIDs: repository.worktrees.map(\.id) - ) - let branchName = pullRequest?.headRefName ?? worktree.name - let failingCheckDetailsURL = (pullRequest?.statusCheckRollup?.checks ?? []).first { - $0.checkState == .failure && $0.detailsUrl != nil - }?.detailsUrl - switch action { - case .openOnCodeHost: + let optionalPullRequest = state.worktreeInfo(for: worktreeID)?.pullRequest + if case .openOnCodeHost = action { let gitClient = gitClient let openURLClient = openURLClient - let pullRequestURL = pullRequest.flatMap { Self.validWebURL($0.url) } + let pullRequestURL = optionalPullRequest.flatMap { Self.validWebURL($0.url) } return .run { send in if let pullRequestURL { await openURLClient.open(pullRequestURL) @@ -275,6 +258,26 @@ extension RepositoriesFeature { } await openURLClient.open(repositoryURL) } + } + guard let pullRequest = optionalPullRequest else { + return .send( + .presentAlert( + title: "Pull request not available", + message: "Prowl could not find a pull request for this worktree." + ) + ) + } + let pullRequestRefresh = WorktreeInfoWatcherClient.Event.repositoryPullRequestRefresh( + repositoryRootURL: repoRoot, + worktreeIDs: repository.worktrees.map(\.id) + ) + let branchName = pullRequest.headRefName ?? worktree.name + let failingCheckDetailsURL = (pullRequest.statusCheckRollup?.checks ?? []).first { + $0.checkState == .failure && $0.detailsUrl != nil + }?.detailsUrl + switch action { + case .openOnCodeHost: + return .none case .copyFailingJobURL: guard let failingCheckDetailsURL, !failingCheckDetailsURL.isEmpty else { @@ -310,7 +313,6 @@ extension RepositoriesFeature { let githubCLI = githubCLI let githubIntegration = githubIntegration return .run { send in - guard let pullRequest else { return } guard await githubIntegration.isAvailable() else { await send( .presentAlert( @@ -340,7 +342,6 @@ extension RepositoriesFeature { let githubCLI = githubCLI let githubIntegration = githubIntegration return .run { send in - guard let pullRequest else { return } guard await githubIntegration.isAvailable() else { await send( .presentAlert( @@ -374,7 +375,6 @@ extension RepositoriesFeature { let githubCLI = githubCLI let githubIntegration = githubIntegration return .run { send in - guard let pullRequest else { return } guard await githubIntegration.isAvailable() else { await send( .presentAlert( @@ -405,7 +405,6 @@ extension RepositoriesFeature { let githubCLI = githubCLI let githubIntegration = githubIntegration return .run { send in - guard pullRequest != nil else { return } guard await githubIntegration.isAvailable() else { await send( .presentAlert( @@ -483,7 +482,6 @@ extension RepositoriesFeature { let githubCLI = githubCLI let githubIntegration = githubIntegration return .run { send in - guard pullRequest != nil else { return } guard await githubIntegration.isAvailable() else { await send( .presentAlert(