johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
import Foundation
/// Where a pull stands on landing, in the app's own words. An answer's `reason`
/// is written for the command line, with commands to run, so it isn't shown.
struct Standing: Equatable {
enum Tone { case good, waiting, bad, neutral }
let title: String
let icon: String
let tone: Tone
var lines: [String] = []
static func of(_ s: MergeStatus, base: String) -> Standing {
let queues = s.may?.queue == true && s.queueBlocked == nil
var after: [String] = []
if s.queueBlocked != nil { after.append("The merge queue is off until the owner delegates writes to this server.") }
if s.may?.merge != true { after.append("Only the owner and collaborators merge it.") }
if s.state == "draft" {
return Standing(title: "Still a draft", icon: "git-pull-request-draft", tone: .neutral, lines: ["It can't be merged or queued until it's marked ready for review."])
}
if s.state == "conflicting" {
return Standing(title: "Conflicts with \(base)", icon: "alert-fill", tone: .bad, lines: ["Merge \(base) into its branch, resolve the files that conflict, then push."])
}
if s.reviews == "blocked" {
let missing = (s.reviewsMissing ?? []).map { $0.text.prefix(1).uppercased() + $0.text.dropFirst() }
return Standing(title: "Review required", icon: "x-circle-fill", tone: .bad, lines: missing + after)
}
switch s.checks {
case "failed":
return Standing(title: "Checks failed", icon: "x-circle-fill", tone: .bad, lines: ["It can land once they pass. Fix what failed and push."] + after)
case "running":
let line = queues ? "It can land once they pass. Queued now, it lands then." : "It can land once they pass."
return Standing(title: "Checks are running", icon: "clock", tone: .waiting, lines: [line] + after)
case "pending":
let line = queues
? "The merge queue checks it against \(base) as it is now, then lands it."
: "Its checks must pass against \(base) as it is now first."
return Standing(title: "Not checked yet", icon: "clock", tone: .waiting, lines: [line] + after)
default:
break
}
if s.queueOnly == true {
return Standing(title: "Ready for the merge queue", icon: "check-circle-fill", tone: .good, lines: ["\(base) takes pulls only through the merge queue."] + after)
}
if s.state == "clean" {
return Standing(title: "Ready to merge", icon: "check-circle-fill", tone: .good, lines: after)
}
return Standing(title: "Not ready to merge", icon: "clock", tone: .waiting, lines: after)
}
/// One the queue turned away, which can be queued again once fixed. The
/// commits it names mean nothing on a phone, and an older runner's reason
/// ends with a command to run.
static func ejected(reason: String?) -> Standing {
var why = reason ?? ""
for pattern in [#"[.;] [Tt]heir logs: `knotless run list [^`]*`.*$"#, #"\. Anyone but its author who may write approves it with `knotless comment add .*$"#, #",? on \S+ at [0-9a-f]{7,40}"#, #" at [0-9a-f]{7,40}"#] {
why = why.replacingOccurrences(of: pattern, with: "", options: .regularExpression)
}
let line = why.prefix(1).uppercased() + why.dropFirst()
return Standing(title: "Taken out of the merge queue", icon: "x-circle-fill", tone: .bad, lines: line.isEmpty ? [] : [line])
}
/// Whether the queue would take it, as the server would answer if asked.
static func canQueue(_ s: MergeStatus) -> Bool {
s.may?.queue == true && s.queueBlocked == nil && s.state != "conflicting" && s.state != "draft"
&& s.checks != "failed" && s.reviews != "blocked"
}
static func canMerge(_ s: MergeStatus) -> Bool {
s.may?.merge == true && s.queueOnly != true && s.state == "clean"
}
}