Build iOS App / Build .ipa and publish source (push) Failing after 35s
Multi-repo PR inbox, review (approve/request changes/comment), merge with gating toggle, read-only diff viewer, and Gitea Actions check status with one-tap re-run. Ships unsigned via the iMac runner to the SideStore source.
136 lines
5.0 KiB
Swift
136 lines
5.0 KiB
Swift
import SwiftUI
|
|
|
|
/// Composes a comment. `mode` picks whether it posts a plain comment or a
|
|
/// review with a state (Approve / Request changes / Comment).
|
|
struct CommentSheet: View {
|
|
@ObservedObject var vm: PRDetailViewModel
|
|
@Environment(\.dismiss) private var dismiss
|
|
@State private var text = ""
|
|
var mode: CommentMode = .comment
|
|
|
|
enum CommentMode { case comment, approve, requestChanges }
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
VStack(alignment: .leading, spacing: 12) {
|
|
Text(title).font(.headline)
|
|
TextEditor(text: $text)
|
|
.frame(minHeight: 150)
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: 8)
|
|
.stroke(Color(.separator)))
|
|
Text("\(text.count) characters")
|
|
.font(.caption2)
|
|
.foregroundColor(.secondary)
|
|
Spacer()
|
|
}
|
|
.padding()
|
|
.navigationTitle(title)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button("Cancel") { dismiss() }
|
|
}
|
|
ToolbarItem(placement: .confirmationAction) {
|
|
Button("Submit") { submit() }
|
|
.disabled(text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private var title: String {
|
|
switch mode {
|
|
case .approve: return "Approve"
|
|
case .requestChanges: return "Request changes"
|
|
case .comment: return "Comment"
|
|
}
|
|
}
|
|
|
|
private func submit() {
|
|
let body = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
switch mode {
|
|
case .approve:
|
|
Task { await vm.submitReview(state: "approved", comment: body) }
|
|
case .requestChanges:
|
|
Task { await vm.submitReview(state: "changes", comment: body) }
|
|
case .comment:
|
|
Task { await vm.postComment(body) }
|
|
}
|
|
dismiss()
|
|
}
|
|
}
|
|
|
|
struct MergeSheet: View {
|
|
@ObservedObject var vm: PRDetailViewModel
|
|
@Environment(\.dismiss) private var dismiss
|
|
@State private var method = "merge"
|
|
|
|
private let methods = [("merge", "Create merge commit"),
|
|
("rebase", "Rebase and merge"),
|
|
("squash", "Squash and merge")]
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
Form {
|
|
Section("Merge method") {
|
|
Picker("Method", selection: $method) {
|
|
ForEach(methods, id: \.0) { m in
|
|
Text(m.1).tag(m.0)
|
|
}
|
|
}
|
|
.pickerStyle(.inline)
|
|
}
|
|
Section {
|
|
HStack {
|
|
Text("CI")
|
|
Spacer()
|
|
switch vm.ciStatus {
|
|
case .success: Label("Passing", systemImage: "checkmark.circle.fill")
|
|
.foregroundColor(.green)
|
|
case .failure: Label("Failing", systemImage: "xmark.circle.fill")
|
|
.foregroundColor(.red)
|
|
case .running: Label("Running", systemImage: "hourglass")
|
|
.foregroundColor(.orange)
|
|
case .cancelled, .unknown: Label("Unknown", systemImage: "questionmark.circle")
|
|
.foregroundColor(.secondary)
|
|
}
|
|
}
|
|
if vm.ciStatus == .failure {
|
|
if SettingsStore.shared.mergeGateMode == .block {
|
|
Label("Merging is blocked while CI is red (Settings).",
|
|
systemImage: "lock")
|
|
.font(.caption)
|
|
.foregroundColor(.secondary)
|
|
} else {
|
|
Label("CI is red — you can still merge (Settings allows it).",
|
|
systemImage: "exclamationmark.triangle")
|
|
.font(.caption)
|
|
.foregroundColor(.orange)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.navigationTitle("Merge")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button("Cancel") { dismiss() }
|
|
}
|
|
ToolbarItem(placement: .confirmationAction) {
|
|
Button("Merge") { performMerge() }
|
|
.disabled(SettingsStore.shared.mergeGateMode == .block
|
|
&& vm.ciStatus == .failure)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func performMerge() {
|
|
Task {
|
|
let success = await vm.merge(method: method)
|
|
if success { dismiss() }
|
|
}
|
|
}
|
|
}
|