Auto-update branch when merge conflicts (branch behind main); bump to 2.6
Build iOS App / Build .ipa and publish source (push) Successful in 22s
Build iOS App / Build .ipa and publish source (push) Successful in 22s
When a PR's head branch is behind main (or conflicts), Gitea's merge returns
409. Previously the app just showed an error. Now: on a 409 the app calls
POST /pulls/{index}/update (merges base into head), then retries the merge
once. Add APIError.mergeConflict for a clear message and map 409 in the
client. Bump to 2.6.
This commit is contained in:
1 parent
0d2c4a3cb6
commit
a1ffcaffd2
4 files changed
+38
-4
No files matched your search
@@ -187,7 +187,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 16;
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "GiteaPR";
|
INFOPLIST_KEY_CFBundleDisplayName = "GiteaPR";
|
||||||
@@ -197,7 +197,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 2.5;
|
MARKETING_VERSION = 2.6;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.bueso.giteapr;
|
PRODUCT_BUNDLE_IDENTIFIER = com.bueso.giteapr;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 16;
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "GiteaPR";
|
INFOPLIST_KEY_CFBundleDisplayName = "GiteaPR";
|
||||||
@@ -221,7 +221,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 2.5;
|
MARKETING_VERSION = 2.6;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.bueso.giteapr;
|
PRODUCT_BUNDLE_IDENTIFIER = com.bueso.giteapr;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
|||||||
@@ -144,6 +144,23 @@ final class PRDetailViewModel: ObservableObject {
|
|||||||
pr = try? await client.pullRequest(owner: owner, repo: repo.name,
|
pr = try? await client.pullRequest(owner: owner, repo: repo.name,
|
||||||
number: prNumber)
|
number: prNumber)
|
||||||
return true
|
return true
|
||||||
|
} catch APIError.mergeConflict {
|
||||||
|
// Branch is behind main (or conflicts). Update it and retry once.
|
||||||
|
busyMessage = "Updating branch…"
|
||||||
|
do {
|
||||||
|
try await client.updateBranch(owner: owner, repo: repo.name,
|
||||||
|
number: prNumber)
|
||||||
|
busyMessage = "Merging…"
|
||||||
|
try await client.merge(owner: owner, repo: repo.name,
|
||||||
|
number: prNumber, method: method,
|
||||||
|
deleteBranchAfterMerge: SettingsStore.shared.deleteBranchAfterMerge)
|
||||||
|
pr = try? await client.pullRequest(owner: owner, repo: repo.name,
|
||||||
|
number: prNumber)
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
errorMessage = error.localizedDescription
|
||||||
|
return false
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
errorMessage = error.localizedDescription
|
errorMessage = error.localizedDescription
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ enum APIError: LocalizedError, Equatable {
|
|||||||
case decoding(String)
|
case decoding(String)
|
||||||
case unauthorized
|
case unauthorized
|
||||||
case notFound
|
case notFound
|
||||||
|
case mergeConflict
|
||||||
|
|
||||||
var errorDescription: String? {
|
var errorDescription: String? {
|
||||||
switch self {
|
switch self {
|
||||||
@@ -18,6 +19,9 @@ enum APIError: LocalizedError, Equatable {
|
|||||||
if code == 401 || code == 403 {
|
if code == 401 || code == 403 {
|
||||||
return "Authentication failed. Check your token."
|
return "Authentication failed. Check your token."
|
||||||
}
|
}
|
||||||
|
if code == 409 {
|
||||||
|
return "This branch is out of date or conflicts with the base branch. Update the branch and try again."
|
||||||
|
}
|
||||||
return message?.isEmpty == false
|
return message?.isEmpty == false
|
||||||
? "Server error (\(code)): \(message!)"
|
? "Server error (\(code)): \(message!)"
|
||||||
: "Server error (\(code))."
|
: "Server error (\(code))."
|
||||||
@@ -27,6 +31,8 @@ enum APIError: LocalizedError, Equatable {
|
|||||||
return "Authentication failed. Check your token."
|
return "Authentication failed. Check your token."
|
||||||
case .notFound:
|
case .notFound:
|
||||||
return "Not found."
|
return "Not found."
|
||||||
|
case .mergeConflict:
|
||||||
|
return "This branch is out of date or conflicts with the base branch. Update the branch and try again."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,6 +93,9 @@ struct GiteaClient {
|
|||||||
case 404:
|
case 404:
|
||||||
await LogStore.shared.log(.error, "\(method) \(path) → 404 not found")
|
await LogStore.shared.log(.error, "\(method) \(path) → 404 not found")
|
||||||
throw APIError.notFound
|
throw APIError.notFound
|
||||||
|
case 409:
|
||||||
|
await LogStore.shared.log(.warn, "\(method) \(path) → 409 conflict")
|
||||||
|
throw APIError.mergeConflict
|
||||||
default:
|
default:
|
||||||
let message = (try? Self.decoder.decode([String: String].self,
|
let message = (try? Self.decoder.decode([String: String].self,
|
||||||
from: data))?["message"]
|
from: data))?["message"]
|
||||||
@@ -230,6 +233,14 @@ struct GiteaClient {
|
|||||||
method: "DELETE")
|
method: "DELETE")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Merge the base branch into the head branch (`POST /pulls/{index}/update`).
|
||||||
|
/// When a PR is behind `main` (e.g. conflicts), the merge returns 409; this
|
||||||
|
/// rebases/syncs the head onto the base so it can then be merged.
|
||||||
|
func updateBranch(owner: String, repo: String, number: Int) async throws {
|
||||||
|
_ = try await request("repos/\(owner)/\(repo)/pulls/\(number)/update",
|
||||||
|
method: "POST")
|
||||||
|
}
|
||||||
|
|
||||||
func setState(owner: String, repo: String, number: Int,
|
func setState(owner: String, repo: String, number: Int,
|
||||||
state: String) async throws {
|
state: String) async throws {
|
||||||
struct Body: Encodable { let state: String }
|
struct Body: Encodable { let state: String }
|
||||||
|
|||||||
Reference in new issue
Block a user