From a7104b50ef0ebc275a15d471e31e3d9db101150c Mon Sep 17 00:00:00 2001 From: Erik Doernenburg Date: Mon, 22 Apr 2024 22:42:49 +0200 Subject: [PATCH] Added handling of rate limit problems when adding workflows. --- .../GitHub Sheets/GitHubRepositoryList.swift | 10 +++++++ CCMenuUITests/GitHubTests.swift | 27 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/CCMenu/Source/Pipeline Window/GitHub Sheets/GitHubRepositoryList.swift b/CCMenu/Source/Pipeline Window/GitHub Sheets/GitHubRepositoryList.swift index 95589a0..84a8e12 100644 --- a/CCMenu/Source/Pipeline Window/GitHub Sheets/GitHubRepositoryList.swift +++ b/CCMenu/Source/Pipeline Window/GitHub Sheets/GitHubRepositoryList.swift @@ -6,6 +6,7 @@ import Foundation +// TODO: Refactor the list classes (repo, workflow, branch) to use some common code @MainActor class GitHubRepositoryList: ObservableObject { @Published private(set) var items = [GitHubRepository()] { didSet { selected = items[0] }} @@ -45,6 +46,15 @@ class GitHubRepositoryList: ObservableObject { do { let (data, response) = try await URLSession.feedSession.data(for: request) guard let response = response as? HTTPURLResponse else { throw URLError(.unsupportedURL) } + // TODO: Somehow refactor this to use the same code as feed reader + if response.statusCode == 403 || response.statusCode == 429 { + if let v = response.value(forHTTPHeaderField: "x-ratelimit-remaining"), Int(v) == 0 { + // HTTPURLResponse doesn't have a specific message for code 429 + return [GitHubRepository(message: "too many requests")] + } else { + return [GitHubRepository(message: HTTPURLResponse.localizedString(forStatusCode: response.statusCode))] + } + } if response.statusCode != 200 { return [GitHubRepository(message: HTTPURLResponse.localizedString(forStatusCode: response.statusCode))] } diff --git a/CCMenuUITests/GitHubTests.swift b/CCMenuUITests/GitHubTests.swift index c52f899..544ccfd 100644 --- a/CCMenuUITests/GitHubTests.swift +++ b/CCMenuUITests/GitHubTests.swift @@ -216,6 +216,33 @@ class GitHubTests: XCTestCase { XCTAssertTrue(repositoryPicker.menuItems["jekyll-site-test"].exists) } + func testShowsRateLimitExceededForRepositories() throws { + webapp.router.get("/users/erikdoe/repos", options: .editResponse) { r -> String in + r.response.status = .forbidden + r.response.headers.replaceOrAdd(name: "x-ratelimit-remaining", value: "0") + return "{ \"message\": \"API rate limit exceeded for ...\" } " + } + + let app = TestHelper.launchApp(pipelines: "EmptyPipelines.json", pauseMonitor: false) + let window = app.windows["Pipelines"] + let sheet = window.sheets.firstMatch + + // Navigate to add workflow sheet + window.toolbars.popUpButtons["Add pipeline menu"].click() + window.toolbars.menuItems["Add GitHub Actions workflow..."].click() + + // Enter owner + sheet.textFields["Owner field"].click() + sheet.typeText("erikdoe" + "\n") + + // Make sure that the repository list shows rate limit exceeded message + let repositoryPicker = sheet.popUpButtons["Repository picker"] + expectation(for: NSPredicate(format: "value == '(too many requests)'"), evaluatedWith: repositoryPicker) + waitForExpectations(timeout: 2) + + // TODO: The other pickers should also show the error + } + func testDoesntDoubleFetchRepositories() throws { var fetchCount = 0 webapp.router.get("/users/erikdoe/repos") { _ in