~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
73 lines · 3.9 KB Raw History
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"
    }
}