Ignore URLError.cancelled so pull-to-refresh doesn't show a spurious error; bump to 3.5
Build iOS App / Build .ipa and publish source (push) Successful in 1m44s
Build iOS App / Build .ipa and publish source (push) Successful in 1m44s
Pull-to-refresh cancels the still-in-flight request (URLError.cancelled, localizedDescription 'cancelled') to run the refresh, which surfaced as an error dialog. Add an isCancellation helper and skip cancellations in the PR load and CI-runs paths. Bump to 3.5.
This commit is contained in:
@@ -187,7 +187,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
CURRENT_PROJECT_VERSION = 26;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "GiteaPR";
|
||||
@@ -197,7 +197,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.4;
|
||||
MARKETING_VERSION = 3.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.bueso.giteapr;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -211,7 +211,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 25;
|
||||
CURRENT_PROJECT_VERSION = 26;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "GiteaPR";
|
||||
@@ -221,7 +221,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.4;
|
||||
MARKETING_VERSION = 3.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.bueso.giteapr;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
||||
@@ -36,6 +36,18 @@ final class PRDetailViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// A task cancellation is not a real failure — it happens when a refresh
|
||||
/// (pull-to-refresh / .task / .onAppear) supersedes an in-flight request,
|
||||
/// and surfaces as URLError.cancelled ("cancelled"). These must not be
|
||||
/// shown as errors.
|
||||
private func isCancellation(_ error: Error) -> Bool {
|
||||
if let urlError = error as? URLError {
|
||||
return urlError.code == .cancelled
|
||||
}
|
||||
let ns = error as NSError
|
||||
return ns.domain == NSURLErrorDomain && ns.code == NSURLErrorCancelled
|
||||
}
|
||||
|
||||
func load() async {
|
||||
guard let client = SettingsStore.shared.client() else { return }
|
||||
isLoading = true
|
||||
@@ -48,6 +60,7 @@ final class PRDetailViewModel: ObservableObject {
|
||||
do {
|
||||
pr = try await client.pullRequest(owner: owner, repo: repo.name, number: prNumber)
|
||||
} catch {
|
||||
if isCancellation(error) { return } // pull-to-refresh superseded; not a real error
|
||||
LogStore.shared.log(.error, "PR \(prNumber): load failed: \(error.localizedDescription)")
|
||||
errorMessage = error.localizedDescription
|
||||
return
|
||||
@@ -79,8 +92,11 @@ final class PRDetailViewModel: ObservableObject {
|
||||
}
|
||||
} catch {
|
||||
// CI is best-effort; don't fail the whole detail view, but log it so
|
||||
// a token-scope 403 on the Actions endpoint is visible.
|
||||
LogStore.shared.log(.warn, "PR \(prNumber): actions/runs failed: \(error.localizedDescription)")
|
||||
// a token-scope 403 on the Actions endpoint is visible. Ignore
|
||||
// cancellations (refresh superseding an in-flight request).
|
||||
if !isCancellation(error) {
|
||||
LogStore.shared.log(.warn, "PR \(prNumber): actions/runs failed: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user