Skip to content

Commit

Permalink
Root command working
Browse files Browse the repository at this point in the history
  • Loading branch information
samdeane committed Aug 29, 2024
1 parent 5ef86f4 commit af47395
Show file tree
Hide file tree
Showing 24 changed files with 78 additions and 103 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"lldb.launch.expressions": "native",
"swift.debugger.useDebugAdapterFromToolchain": true,
"swift.backgroundCompilation": true,
"swift.sourcekit-lsp.backgroundIndexing": true,
"swift.sourcekit-lsp.backgroundIndexing": false,
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"apple-swift-format.enable": true,
}
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ let package = Package(
name: "ReleaseTools",

platforms: [
.macOS(.v12)
.macOS(.v13)
],

products: [
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/AppcastCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
// All code (c) 2019 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation
import Runner

import protocol ArgumentParser.AsyncParsableCommand

enum AppcastError: Error, CustomStringConvertible {
case buildAppcastGeneratorFailed(_ output: String)
case appcastGeneratorFailed(_ result: Runner.RunningProcess)
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/ArchiveCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
// All code (c) 2019 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation

import protocol ArgumentParser.AsyncParsableCommand

struct WorkspaceSpec: Decodable {
let name: String
let schemes: [String]
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/BootstrapCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
// All code (c) 2021 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Files
import Foundation
import Resources

import protocol ArgumentParser.AsyncParsableCommand

struct BootstrapCommand: AsyncParsableCommand {
enum Error: Swift.Error {
case couldntCopyConfigs(error: Swift.Error)
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/ChangesCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import AppKit
import ArgumentParser
import Foundation

import protocol ArgumentParser.AsyncParsableCommand

enum ChangesError: Error {
case couldntFetchLog(error: Error)

Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/CompressCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
// All code (c) 2019 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation
import Runner

import protocol ArgumentParser.AsyncParsableCommand

enum CompressError: Error {
case compressFailed(_ output: String)

Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/ExportCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
// All code (c) 2019 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation

import protocol ArgumentParser.AsyncParsableCommand

enum ExportError: Error {
case exportFailed(_ output: String)
case writingOptionsFailed(_ output: Error)
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/GetCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
// All code (c) 2020 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation

import protocol ArgumentParser.AsyncParsableCommand

struct GetCommand: AsyncParsableCommand {
static var configuration: CommandConfiguration {
CommandConfiguration(
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/InstallCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
// All code (c) 2019 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation

import protocol ArgumentParser.AsyncParsableCommand

enum InstallError: Error {
case couldntWriteStub

Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/NotarizeCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
// All code (c) 2020 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation
import Runner

import protocol ArgumentParser.AsyncParsableCommand

enum NotarizeError: Error, Sendable {
case compressingFailed(_ result: Runner.RunningProcess)
case notarizingFailed(
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/PublishCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
// All code (c) 2019 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation
import Runner

import protocol ArgumentParser.AsyncParsableCommand

enum PublishError: Error {
case commitFailed(_ result: Runner.RunningProcess)
case pushFailed(_ result: Runner.RunningProcess)
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/SetCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
// All code (c) 2020 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation

import protocol ArgumentParser.AsyncParsableCommand

struct SetCommand: AsyncParsableCommand {
static var configuration: CommandConfiguration {
CommandConfiguration(
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/SubmitCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
// All code (c) 2022 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation
import Runner

import protocol ArgumentParser.AsyncParsableCommand

/// Performs the following commands in order:
/// - archive
/// - export
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/UnsetCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
// All code (c) 2020 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation

import protocol ArgumentParser.AsyncParsableCommand

struct UnsetCommand: AsyncParsableCommand {
static var configuration: CommandConfiguration {
CommandConfiguration(
Expand Down
6 changes: 2 additions & 4 deletions Sources/ReleaseTools/Commands/UpdateBuildCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
// All code (c) 2019 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Files
import Foundation
import Resources
import Runner

import protocol ArgumentParser.AsyncParsableCommand

enum UpdateBuildError: Error {
case gettingBuildFailed(_ result: Runner.RunningProcess)
case gettingCommitFailed(_ result: Runner.RunningProcess)
Expand Down Expand Up @@ -104,7 +103,7 @@ struct UpdateBuildCommand: AsyncParsableCommand {
}
}

static func generateHeader(parsed: OptionParser, header: String, repo: String) async throws -> String {
static func generateHeader(parsed: OptionParser, header: String, repo: String) async throws {
let headerURL = URL(fileURLWithPath: header)
let repoURL = URL(fileURLWithPath: repo)

Expand All @@ -116,7 +115,6 @@ struct UpdateBuildCommand: AsyncParsableCommand {
try? FileManager.default.createDirectory(
at: headerURL.deletingLastPathComponent(), withIntermediateDirectories: true)
try header.write(to: headerURL, atomically: true, encoding: .utf8)
return build
}

static func generateConfig(parsed: OptionParser, config: String?) async throws {
Expand Down
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/Commands/UploadCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
// All code (c) 2020 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Foundation
import Runner

import protocol ArgumentParser.AsyncParsableCommand

enum UploadError: Error {
case uploadingFailed(_ result: Runner.RunningProcess)
case savingUploadReceiptFailed(_ error: Error)
Expand Down
111 changes: 54 additions & 57 deletions Sources/ReleaseTools/Commands/WaitForNotarizationCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
// All code (c) 2020 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Coercion
import Foundation
import Runner

import protocol ArgumentParser.AsyncParsableCommand

enum WaitForNotarizationError: Error {
case fetchingNotarizationStatusFailed(_ result: Runner.RunningProcess)
case fetchingNotarizationStatusThrew(_ error: Error)
Expand Down Expand Up @@ -51,6 +50,9 @@ struct WaitForNotarizationCommand: AsyncParsableCommand {
@OptionGroup() var platform: PlatformOption
@OptionGroup() var options: CommonOptions

/// Time to wait before checking the notarization status again.
static let retryDelay = 30

func run() async throws {
let parsed = try OptionParser(
requires: [.archive],
Expand All @@ -65,7 +67,15 @@ struct WaitForNotarizationCommand: AsyncParsableCommand {
}

parsed.log("Requesting notarization status...")
await check(request: requestUUID, parsed: parsed)
do {
while !(try await check(request: requestUUID, parsed: parsed)) {
parsed.log("Will retry in \(Self.retryDelay) seconds...")
try await Task.sleep(for: .seconds(Self.retryDelay))
parsed.log("Retrying fetch of notarization status...")
}
} catch {
throw WaitForNotarizationError.fetchingNotarizationStatusThrew(error)
}

parsed.log("Tagging.")
let git = GitRunner()
Expand All @@ -86,7 +96,7 @@ struct WaitForNotarizationCommand: AsyncParsableCommand {
return upload["RequestUUID"]
}

func exportNotarized(parsed: OptionParser) async {
func exportNotarized(parsed: OptionParser) async throws {
parsed.log("Stapling notarized app.")

do {
Expand All @@ -109,65 +119,52 @@ struct WaitForNotarizationCommand: AsyncParsableCommand {
}
}

func check(request: String, parsed: OptionParser) async {
func check(request: String, parsed: OptionParser) async throws -> Bool {
let xcrun = XCRunRunner(parsed: parsed)
do {
let result = try xcrun.run([
"altool", "--notarization-info", request, "--username", parsed.user, "--password",
"@keychain:AC_PASSWORD", "--output-format", "xml",
])
if result.status != 0 {
parsed.fail(WaitForNotarizationError.fetchingNotarizationStatusFailed(result))
}

parsed.log("Received response.")
if let data = result.stdout.data(using: .utf8),
let receipt = try? PropertyListSerialization.propertyList(
from: data, options: [], format: nil) as? [String: Any],
let info = receipt["notarization-info"] as? [String: Any],
let status = info[asString: "Status"]
{
parsed.log("Status was \(status).")
if status == "success" {
exportNotarized(parsed: parsed)
return
} else if status == "invalid" {
let message = (info[asString: "Status Message"]) ?? ""
var output = "\(message).\n"
if let logFile = info[asString: "LogFileURL"],
let url = URL(string: logFile),
let data = try? Data(contentsOf: url),
let log = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
{
let summary = (log[asString: "statusSummary"]) ?? ""
output.append("\(summary).\n")
if let issues = log["issues"] as? [[String: Any]] {
var count = 1
for issue in issues {
let message = issue[asString: "message"] ?? ""
let path = issue[asString: "path"] ?? ""
let name = URL(fileURLWithPath: path).lastPathComponent
let severity = issue[asString: "severity"] ?? ""
output.append("\n#\(count) \(name) (\(severity)):\n\(message)\n\(path)\n")
count += 1
}
let result = try xcrun.run([
"altool", "--notarization-info", request, "--username", parsed.user, "--password",
"@keychain:AC_PASSWORD", "--output-format", "xml",
])
try await result.throwIfFailed(WaitForNotarizationError.fetchingNotarizationStatusFailed(result))

parsed.log("Received response.")
let data = await Data(result.stdout)
if let receipt = try? PropertyListSerialization.propertyList(
from: data, options: [], format: nil) as? [String: Any],
let info = receipt["notarization-info"] as? [String: Any],
let status = info[asString: "Status"]
{
parsed.log("Status was \(status).")
if status == "success" {
try await exportNotarized(parsed: parsed)
return true
} else if status == "invalid" {
let message = (info[asString: "Status Message"]) ?? ""
var output = "\(message).\n"
if let logFile = info[asString: "LogFileURL"],
let url = URL(string: logFile),
let data = try? Data(contentsOf: url),
let log = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
{
let summary = (log[asString: "statusSummary"]) ?? ""
output.append("\(summary).\n")
if let issues = log["issues"] as? [[String: Any]] {
var count = 1
for issue in issues {
let message = issue[asString: "message"] ?? ""
let path = issue[asString: "path"] ?? ""
let name = URL(fileURLWithPath: path).lastPathComponent
let severity = issue[asString: "severity"] ?? ""
output.append("\n#\(count) \(name) (\(severity)):\n\(message)\n\(path)\n")
count += 1
}
}

parsed.fail(WaitForNotarizationError.notarizationFailed(output))
}
}
} catch {
parsed.fail(WaitForNotarizationError.fetchingNotarizationStatusThrew(error))
}

let delay = 30
let nextCheck = DispatchTime.now() + .seconds(delay)
parsed.log("Will retry in \(delay) seconds...")
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: nextCheck) {
parsed.log("Retrying fetch of notarization status...")
self.check(request: request, parsed: parsed)
parsed.fail(WaitForNotarizationError.notarizationFailed(output))
}
}

return false
}
}
3 changes: 1 addition & 2 deletions Sources/ReleaseTools/OptionParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
// All code (c) 2020 - present day, Elegant Chaos Limited.
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

import ArgumentParser
import Files
import Foundation
import Runner

import protocol ArgumentParser.AsyncParsableCommand

enum GeneralError: Error, CustomStringConvertible, Sendable {
case infoUnreadable(_ path: String)
case missingWorkspace
Expand Down
Loading

0 comments on commit af47395

Please sign in to comment.