native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #195 from supabitapp/fix-gh-cli-version-check

Handle outdated GitHub CLI

authored by

khoi and committed by
GitHub
c5ed2a52 26c53cc7

+49 -1
+14
supacode/Clients/Github/GithubCLIClient.swift
··· 249 249 .replacing("\t", with: "\\t") 250 250 } 251 251 252 + nonisolated private func isOutdatedGitHubCLI(_ error: ShellClientError) -> Bool { 253 + let combined = "\(error.stdout)\n\(error.stderr)".lowercased() 254 + if combined.contains("unknown flag: --json") { 255 + return true 256 + } 257 + if combined.contains("unknown shorthand flag") && combined.contains("json") { 258 + return true 259 + } 260 + return false 261 + } 262 + 252 263 nonisolated private func runGh( 253 264 shell: ShellClient, 254 265 arguments: [String], ··· 261 272 return try await shell.runLogin(env, ["gh"] + arguments, repoRoot, log: shouldLog).stdout 262 273 } catch { 263 274 if let shellError = error as? ShellClientError { 275 + if isOutdatedGitHubCLI(shellError) { 276 + throw GithubCLIError.outdated 277 + } 264 278 let message = shellError.errorDescription ?? "Command failed: \(command)" 265 279 throw GithubCLIError.commandFailed(message) 266 280 }
+3
supacode/Clients/Github/GithubCLIError.swift
··· 2 2 3 3 nonisolated enum GithubCLIError: LocalizedError, Equatable { 4 4 case unavailable 5 + case outdated 5 6 case commandFailed(String) 6 7 7 8 var errorDescription: String? { 8 9 switch self { 9 10 case .unavailable: 10 11 return "GitHub CLI is unavailable" 12 + case .outdated: 13 + return "GitHub CLI is outdated. Update to the latest version." 11 14 case .commandFailed(let message): 12 15 return message 13 16 }
+32 -1
supacode/Features/Settings/Views/GithubSettingsView.swift
··· 6 6 enum State: Equatable { 7 7 case loading 8 8 case unavailable 9 + case outdated 9 10 case notAuthenticated 10 11 case authenticated(username: String, host: String) 11 12 case error(String) ··· 32 33 state = .authenticated(username: status.username, host: status.host) 33 34 } else { 34 35 state = .notAuthenticated 36 + } 37 + } catch let error as GithubCLIError { 38 + switch error { 39 + case .outdated: 40 + state = .outdated 41 + case .unavailable: 42 + state = .unavailable 43 + case .commandFailed(let message): 44 + state = .error(message) 35 45 } 36 46 } catch { 37 47 state = .error(error.localizedDescription) ··· 81 91 .font(.callout) 82 92 } 83 93 94 + case .outdated: 95 + VStack(alignment: .leading, spacing: 8) { 96 + Label("GitHub CLI outdated", systemImage: "exclamationmark.triangle") 97 + .foregroundStyle(.orange) 98 + Text("Update GitHub CLI to the latest version to use GitHub integration.") 99 + .foregroundStyle(.secondary) 100 + .font(.callout) 101 + } 102 + 84 103 case .authenticated(let username, let host): 85 104 LabeledContent("Signed in as") { 86 105 Text(username) ··· 104 123 } 105 124 .formStyle(.grouped) 106 125 107 - if case .unavailable = viewModel.state { 126 + switch viewModel.state { 127 + case .unavailable: 108 128 HStack { 109 129 Button("Get GitHub CLI") { 110 130 NSWorkspace.shared.open(URL(string: "https://cli.github.com")!) ··· 113 133 Spacer() 114 134 } 115 135 .padding(.top) 136 + case .outdated: 137 + HStack { 138 + Button("Update GitHub CLI") { 139 + NSWorkspace.shared.open(URL(string: "https://cli.github.com")!) 140 + } 141 + .help("Open GitHub CLI website") 142 + Spacer() 143 + } 144 + .padding(.top) 145 + default: 146 + EmptyView() 116 147 } 117 148 } 118 149 .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)