Include commit metadata in cmux --version output

This commit is contained in:
Lawrence Chen 2026-02-24 20:51:43 -08:00
parent 915c01f9d0
commit f7ef0707c2
2 changed files with 175 additions and 20 deletions

View file

@ -4988,39 +4988,63 @@ struct CMUXCLI {
private func versionSummary() -> String {
let info = resolvedVersionInfo()
let commit = info["CMUXCommit"].flatMap { normalizedCommitHash($0) }
let baseSummary: String
if let version = info["CFBundleShortVersionString"], let build = info["CFBundleVersion"] {
return "cmux \(version) (\(build))"
baseSummary = "cmux \(version) (\(build))"
} else if let version = info["CFBundleShortVersionString"] {
baseSummary = "cmux \(version)"
} else if let build = info["CFBundleVersion"] {
baseSummary = "cmux build \(build)"
} else {
baseSummary = "cmux version unknown"
}
if let version = info["CFBundleShortVersionString"] {
return "cmux \(version)"
}
if let build = info["CFBundleVersion"] {
return "cmux build \(build)"
}
return "cmux version unknown"
guard let commit else { return baseSummary }
return "\(baseSummary) [\(commit)]"
}
private func resolvedVersionInfo() -> [String: String] {
var info: [String: String] = [:]
if let main = versionInfo(from: Bundle.main.infoDictionary) {
return main
info.merge(main, uniquingKeysWith: { current, _ in current })
}
for plistURL in candidateInfoPlistURLs() {
guard let data = try? Data(contentsOf: plistURL),
let raw = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil),
let dictionary = raw as? [String: Any],
let parsed = versionInfo(from: dictionary)
else {
continue
let needsPlistFallback =
info["CFBundleShortVersionString"] == nil ||
info["CFBundleVersion"] == nil ||
info["CMUXCommit"] == nil
if needsPlistFallback {
for plistURL in candidateInfoPlistURLs() {
guard let data = try? Data(contentsOf: plistURL),
let raw = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil),
let dictionary = raw as? [String: Any],
let parsed = versionInfo(from: dictionary)
else {
continue
}
info.merge(parsed, uniquingKeysWith: { current, _ in current })
if info["CFBundleShortVersionString"] != nil,
info["CFBundleVersion"] != nil,
info["CMUXCommit"] != nil {
break
}
}
return parsed
}
if let fromProject = versionInfoFromProjectFile() {
return fromProject
let needsProjectFallback =
info["CFBundleShortVersionString"] == nil ||
info["CFBundleVersion"] == nil ||
info["CMUXCommit"] == nil
if needsProjectFallback, let fromProject = versionInfoFromProjectFile() {
info.merge(fromProject, uniquingKeysWith: { current, _ in current })
}
return [:]
if info["CMUXCommit"] == nil,
let commit = normalizedCommitHash(ProcessInfo.processInfo.environment["CMUX_COMMIT"]) {
info["CMUXCommit"] = commit
}
return info
}
private func versionInfo(from dictionary: [String: Any]?) -> [String: String]? {
@ -5039,6 +5063,10 @@ struct CMUXCLI {
info["CFBundleVersion"] = trimmed
}
}
if let commit = dictionary["CMUXCommit"] as? String,
let normalizedCommit = normalizedCommitHash(commit) {
info["CMUXCommit"] = normalizedCommit
}
return info.isEmpty ? nil : info
}
@ -5064,6 +5092,9 @@ struct CMUXCLI {
if let build = firstProjectSetting("CURRENT_PROJECT_VERSION", in: contents) {
info["CFBundleVersion"] = build
}
if let commit = gitCommitHash(at: current) {
info["CMUXCommit"] = commit
}
if !info.isEmpty {
return info
}
@ -5100,6 +5131,45 @@ struct CMUXCLI {
return value
}
private func gitCommitHash(at directory: URL) -> String? {
let process = Process()
let stdout = Pipe()
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
process.arguments = ["git", "-C", directory.path, "rev-parse", "--short=9", "HEAD"]
process.standardOutput = stdout
process.standardError = Pipe()
do {
try process.run()
} catch {
return nil
}
process.waitUntilExit()
guard process.terminationStatus == 0 else {
return nil
}
let data = stdout.fileHandleForReading.readDataToEndOfFile()
guard let output = String(data: data, encoding: .utf8) else {
return nil
}
return normalizedCommitHash(output)
}
private func normalizedCommitHash(_ value: String?) -> String? {
guard let value else { return nil }
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty, !trimmed.contains("$(") else {
return nil
}
let normalized = trimmed.lowercased()
let allowed = CharacterSet(charactersIn: "0123456789abcdef")
guard normalized.unicodeScalars.allSatisfy({ allowed.contains($0) }) else {
return nil
}
return String(normalized.prefix(12))
}
private func candidateInfoPlistURLs() -> [URL] {
guard let executable = currentExecutablePath(), !executable.isEmpty else {
return []

View file

@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""Regression test: CLI version output wiring keeps commit metadata support."""
from __future__ import annotations
import subprocess
from pathlib import Path
def get_repo_root() -> Path:
result = subprocess.run(
["git", "rev-parse", "--show-toplevel"],
capture_output=True,
text=True,
check=False,
)
if result.returncode == 0:
return Path(result.stdout.strip())
return Path.cwd()
def require(content: str, needle: str, message: str, failures: list[str]) -> None:
if needle not in content:
failures.append(message)
def main() -> int:
repo_root = get_repo_root()
cli_path = repo_root / "CLI" / "cmux.swift"
if not cli_path.exists():
print(f"FAIL: missing expected file: {cli_path}")
return 1
content = cli_path.read_text(encoding="utf-8")
failures: list[str] = []
require(
content,
'let commit = info["CMUXCommit"].flatMap { normalizedCommitHash($0) }',
"versionSummary no longer reads CMUXCommit metadata",
failures,
)
require(
content,
'return "\\(baseSummary) [\\(commit)]"',
"versionSummary no longer appends commit metadata",
failures,
)
require(
content,
'if let commit = dictionary["CMUXCommit"] as? String,',
"Info.plist parsing no longer reads CMUXCommit",
failures,
)
require(
content,
"if let commit = gitCommitHash(at: current) {",
"Project fallback no longer probes git commit hash",
failures,
)
require(
content,
'["git", "-C", directory.path, "rev-parse", "--short=9", "HEAD"]',
"Git commit probe command changed unexpectedly",
failures,
)
require(
content,
'normalizedCommitHash(ProcessInfo.processInfo.environment["CMUX_COMMIT"])',
"Environment commit fallback (CMUX_COMMIT) is missing",
failures,
)
if failures:
print("FAIL: CLI version commit metadata regression(s) detected")
for failure in failures:
print(f"- {failure}")
return 1
print("PASS: CLI version commit metadata wiring is intact")
return 0
if __name__ == "__main__":
raise SystemExit(main())