From ef696f918b0f2a0e2668de55cf745f17aef8106a Mon Sep 17 00:00:00 2001 From: Sam Deane Date: Wed, 4 Sep 2024 23:22:06 +0100 Subject: [PATCH] Cleaned up error descriptions. --- Package.resolved | 6 +-- Package.swift | 2 +- .../Commands/AppcastCommand.swift | 38 +++++++++++------- .../Commands/ArchiveCommand.swift | 1 - .../Commands/CompressCommand.swift | 7 ++-- .../ReleaseTools/Commands/ExportCommand.swift | 18 +++++++-- .../Commands/NotarizeCommand.swift | 26 +++++++----- .../Commands/PublishCommand.swift | 10 ++--- .../Commands/UpdateBuildCommand.swift | 14 +++---- .../ReleaseTools/Commands/UploadCommand.swift | 17 ++++++-- .../Commands/WaitForNotarizationCommand.swift | 40 ++++++++++++------- 11 files changed, 112 insertions(+), 67 deletions(-) diff --git a/Package.resolved b/Package.resolved index 5ffdde4..8c01aa1 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "92178e92fabf6a8864901844cc48754f97a15bf30fdb9c05fdab9f08af800e57", + "originHash" : "e5a8a0c5504f820e0bf8dbbd92ac72ff05ef8f1a3d78f18b21a465ed1b9d1fe2", "pins" : [ { "identity" : "chaosbytestreams", @@ -42,8 +42,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/elegantchaos/Runner.git", "state" : { - "revision" : "31c1b80190630f7887eb1a0442c9618cbaad7d17", - "version" : "2.0.9" + "revision" : "8034c25c136733d25da0c10f1ff27f1cecd1ab7a", + "version" : "2.0.10" } }, { diff --git a/Package.swift b/Package.swift index 5bb4e79..4f0d924 100644 --- a/Package.swift +++ b/Package.swift @@ -19,7 +19,7 @@ let package = Package( .package(url: "https://github.com/elegantchaos/Coercion.git", from: "1.1.2"), .package(url: "https://github.com/elegantchaos/Files.git", from: "1.2.0"), .package(url: "https://github.com/elegantchaos/Logger.git", branch: "v2-wip"), - .package(url: "https://github.com/elegantchaos/Runner.git", from: "2.0.9"), + .package(url: "https://github.com/elegantchaos/Runner.git", from: "2.0.10"), .package(url: "https://github.com/elegantchaos/ChaosByteStreams", from: "1.0.0"), .package(url: "https://github.com/elegantchaos/Versionator.git", from: "2.0.2"), .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"), diff --git a/Sources/ReleaseTools/Commands/AppcastCommand.swift b/Sources/ReleaseTools/Commands/AppcastCommand.swift index 635ef1b..9f51a5e 100644 --- a/Sources/ReleaseTools/Commands/AppcastCommand.swift +++ b/Sources/ReleaseTools/Commands/AppcastCommand.swift @@ -7,25 +7,32 @@ import ArgumentParser import Foundation import Runner -enum AppcastError: Error, CustomStringConvertible { +enum GenerationError: Error, CustomStringConvertible { + case generatedKeys(_ name: String) + + public var description: String { + switch self { + case .generatedKeys(let name): + return """ + The appcast private key was missing, so we've generated one. + Open the keychain, rename the key `Imported Private Key` as `\(name)`, then try running this command again. + """ + } + } +} +enum AppcastError: RunnerError { case buildAppcastGeneratorFailed case appcastGeneratorFailed case keyGenerationFailed case keyImportFailed - case generatedKeys(_ name: String) - public var description: String { + func description(for session: Runner.Session) async -> String { + async let stderr = String(session.stderr) switch self { - case .buildAppcastGeneratorFailed: - return "Failed to build the generate_appcast tool." - case .appcastGeneratorFailed: return "Failed to generate the appcast." - case .keyGenerationFailed: return "Failed to generate appcast keys." - case .keyImportFailed: return "Failed to import appcast keys." - case .generatedKeys(let name): - return """ - The appcast private key was missing, so we've generated one. - Open the keychain, rename the key `Imported Private Key` as `\(name)`, then try running this command again. - """ + case .buildAppcastGeneratorFailed: return "Failed to build the generate_appcast tool.\n\n\(await stderr)" + case .appcastGeneratorFailed: return "Failed to generate the appcast.\n\n\(await stderr)" + case .keyGenerationFailed: return "Failed to generate appcast keys.\n\n\(await stderr)" + case .keyImportFailed: return "Failed to import appcast keys.\n\n\(await stderr)" } } } @@ -76,6 +83,9 @@ struct AppcastCommand: AsyncParsableCommand { let generator = Runner(for: URL(fileURLWithPath: ".build/Release/generate_appcast")) let genResult = try generator.run(["-n", keyName, "-k", keyChainPath, updates.path]) + + try await genResult.throwIfFailed(!(await String(genResult.stdout)).contains("Unable to load DSA private key") ? AppcastError.appcastGeneratorFailed : nil) + for await state in genResult.state { if state != .succeeded { let output = await String(genResult.stdout) @@ -109,7 +119,7 @@ struct AppcastCommand: AsyncParsableCommand { try? fm.removeItem(at: rootURL.appendingPathComponent("dsa_priv.pem")) - throw AppcastError.generatedKeys(keyName) + throw GenerationError.generatedKeys(keyName) } try? fm.removeItem(at: updates.url.appendingPathComponent(".tmp")) diff --git a/Sources/ReleaseTools/Commands/ArchiveCommand.swift b/Sources/ReleaseTools/Commands/ArchiveCommand.swift index 3320129..c7a8aa0 100644 --- a/Sources/ReleaseTools/Commands/ArchiveCommand.swift +++ b/Sources/ReleaseTools/Commands/ArchiveCommand.swift @@ -20,7 +20,6 @@ enum ArchiveError: RunnerError { case archiveFailed func description(for session: Runner.Session) async -> String { - async let stdout = String(session.stdout) async let stderr = String(session.stderr) switch self { case .archiveFailed: return "Archiving failed.\n\n\(await stderr)" diff --git a/Sources/ReleaseTools/Commands/CompressCommand.swift b/Sources/ReleaseTools/Commands/CompressCommand.swift index 02abfee..edde301 100644 --- a/Sources/ReleaseTools/Commands/CompressCommand.swift +++ b/Sources/ReleaseTools/Commands/CompressCommand.swift @@ -7,12 +7,13 @@ import ArgumentParser import Foundation import Runner -enum CompressError: Error { +enum CompressError: RunnerError { case compressFailed - public var description: String { + func description(for session: Runner.Session) async -> String { + async let stderr = String(session.stderr) switch self { - case .compressFailed: return "Compressing failed." + case .compressFailed: return "Compressing failed.\n\(await stderr)" } } } diff --git a/Sources/ReleaseTools/Commands/ExportCommand.swift b/Sources/ReleaseTools/Commands/ExportCommand.swift index e3d7281..aa5f77d 100644 --- a/Sources/ReleaseTools/Commands/ExportCommand.swift +++ b/Sources/ReleaseTools/Commands/ExportCommand.swift @@ -5,15 +5,25 @@ import ArgumentParser import Foundation +import Runner enum ExportError: Error { - case exportFailed case writingOptionsFailed(Error) public var description: String { switch self { - case .exportFailed: return "Exporting failed." - case .writingOptionsFailed(let error): return "Writing export options file failed.\n\(error)" + case .writingOptionsFailed(let error): return "Writing export options file failed.\n\(error)" + } + } +} + +enum ExportRunnerError: RunnerError { + case exportFailed + + func description(for session: Runner.Session) async -> String { + async let stderr = String(session.stderr) + switch self { + case .exportFailed: return "Exporting failed.\n\(await stderr)" } } } @@ -67,6 +77,6 @@ struct ExportCommand: AsyncParsableCommand { "-allowProvisioningUpdates", ]) - try await result.throwIfFailed(ExportError.exportFailed) + try await result.throwIfFailed(ExportRunnerError.exportFailed) } } diff --git a/Sources/ReleaseTools/Commands/NotarizeCommand.swift b/Sources/ReleaseTools/Commands/NotarizeCommand.swift index 46345bb..8ad78bf 100644 --- a/Sources/ReleaseTools/Commands/NotarizeCommand.swift +++ b/Sources/ReleaseTools/Commands/NotarizeCommand.swift @@ -7,22 +7,28 @@ import ArgumentParser import Foundation import Runner -enum NotarizeError: Error, Sendable { - case compressingFailed - case notarizingFailed +enum NotarizeError: Error { case savingNotarizationReceiptFailed(Error) public var description: String { switch self { - case .compressingFailed: return "Compressing failed." - case .notarizingFailed: return "Notarizing failed." - case .savingNotarizationReceiptFailed(let error): - return "Saving notarization receipt failed.\n\(error)" + case .savingNotarizationReceiptFailed(let error): + return "Saving notarization receipt failed.\n\(error)" } } } -extension Result { +enum NotarizeRunnerError: RunnerError { + case compressingFailed + case notarizingFailed + + func description(for session: Runner.Session) async -> String { + async let stderr = String(session.stderr) + switch self { + case .compressingFailed: return "Compressing failed.\n\(await stderr)" + case .notarizingFailed: return "Notarizing failed.\n\(await stderr)" + } + } } struct NotarizeCommand: AsyncParsableCommand { @@ -53,7 +59,7 @@ struct NotarizeCommand: AsyncParsableCommand { let ditto = DittoRunner(parsed: parsed) let zipResult = try ditto.zip(parsed.exportedAppURL, as: parsed.exportedZipURL) - try await zipResult.throwIfFailed(NotarizeError.compressingFailed) + try await zipResult.throwIfFailed(NotarizeRunnerError.compressingFailed) parsed.log("Uploading \(parsed.versionTag) to notarization service.") let xcrun = XCRunRunner(parsed: parsed) @@ -62,7 +68,7 @@ struct NotarizeCommand: AsyncParsableCommand { parsed.user, "--password", "@keychain:AC_PASSWORD", "--team-id", parsed.archive.team, "--file", parsed.exportedZipURL.path, "--output-format", "xml", ]) - try await result.throwIfFailed(NotarizeError.notarizingFailed) + try await result.throwIfFailed(NotarizeRunnerError.notarizingFailed) parsed.log("Requested notarization.") do { diff --git a/Sources/ReleaseTools/Commands/PublishCommand.swift b/Sources/ReleaseTools/Commands/PublishCommand.swift index c079b31..178ea71 100644 --- a/Sources/ReleaseTools/Commands/PublishCommand.swift +++ b/Sources/ReleaseTools/Commands/PublishCommand.swift @@ -7,15 +7,15 @@ import ArgumentParser import Foundation import Runner -enum PublishError: Error { +enum PublishError: RunnerError { case commitFailed case pushFailed - public var description: String { + func description(for session: Runner.Session) async -> String { + async let stderr = String(session.stderr) switch self { - case .commitFailed: - return "Failed to commit the appcast feed and updates." - case .pushFailed: return "Failed to push the appcast feed and updates." + case .commitFailed: return "Failed to commit the appcast feed and updates.\n\n\(await stderr)" + case .pushFailed: return "Failed to push the appcast feed and updates.\n\n\(await stderr)" } } } diff --git a/Sources/ReleaseTools/Commands/UpdateBuildCommand.swift b/Sources/ReleaseTools/Commands/UpdateBuildCommand.swift index 968aae2..e6a98ee 100644 --- a/Sources/ReleaseTools/Commands/UpdateBuildCommand.swift +++ b/Sources/ReleaseTools/Commands/UpdateBuildCommand.swift @@ -10,19 +10,19 @@ import Foundation import Resources import Runner -enum UpdateBuildError: Error { +enum UpdateBuildError: RunnerError { case gettingBuildFailed case gettingCommitFailed case writingConfigFailed case updatingIndexFailed - public var description: String { + func description(for session: Runner.Session) async -> String { + async let stderr = String(session.stderr) switch self { - case .gettingBuildFailed: - return "Failed to get the build number from git." - case .gettingCommitFailed: return "Failed to get the commit from git." - case .writingConfigFailed: return "Failed to write the config file." - case .updatingIndexFailed: return "Failed to tell git to ignore the config file." + case .gettingBuildFailed: return "Failed to get the build number from git.\n\n\(await stderr)" + case .gettingCommitFailed: return "Failed to get the commit from git.\n\n\(await stderr)" + case .writingConfigFailed: return "Failed to write the config file.\n\n\(await stderr)" + case .updatingIndexFailed: return "Failed to tell git to ignore the config file.\n\n\(await stderr)" } } } diff --git a/Sources/ReleaseTools/Commands/UploadCommand.swift b/Sources/ReleaseTools/Commands/UploadCommand.swift index de1a1f7..eb4a802 100644 --- a/Sources/ReleaseTools/Commands/UploadCommand.swift +++ b/Sources/ReleaseTools/Commands/UploadCommand.swift @@ -8,13 +8,22 @@ import Foundation import Runner enum UploadError: Error { - case uploadingFailed case savingUploadReceiptFailed(Error) public var description: String { switch self { - case .uploadingFailed: return "Uploading failed." - case .savingUploadReceiptFailed(let error): return "Saving upload receipt failed.\n\(error)" + case .savingUploadReceiptFailed(let error): return "Saving upload receipt failed.\n\(error)" + } + } +} + +enum UploadRunnerError: RunnerError { + case uploadingFailed + + func description(for session: Runner.Session) async -> String { + async let stderr = String(session.stderr) + switch self { + case .uploadingFailed: return "Uploading failed.\n\(await stderr)" } } } @@ -67,7 +76,7 @@ struct UploadCommand: AsyncParsableCommand { ]) } - try await uploadResult.throwIfFailed(UploadError.uploadingFailed) + try await uploadResult.throwIfFailed(UploadRunnerError.uploadingFailed) parsed.log("Finished uploading.") do { diff --git a/Sources/ReleaseTools/Commands/WaitForNotarizationCommand.swift b/Sources/ReleaseTools/Commands/WaitForNotarizationCommand.swift index 07ca932..5df2876 100644 --- a/Sources/ReleaseTools/Commands/WaitForNotarizationCommand.swift +++ b/Sources/ReleaseTools/Commands/WaitForNotarizationCommand.swift @@ -9,30 +9,40 @@ import Foundation import Runner enum WaitForNotarizationError: Error { - case fetchingNotarizationStatusFailed case fetchingNotarizationStatusThrew(Error) - case loadingNotarizationReceiptFailed case notarizationFailed(String) - case exportingNotarizedAppFailed case exportingNotarizedAppThrew(Error) case missingArchive + case loadingNotarizationReceiptFailed public var description: String { switch self { - case .fetchingNotarizationStatusFailed: - return "Fetching notarization status failed." - case .fetchingNotarizationStatusThrew(let error): - return "Fetching notarization status failed.\n\(error)" - case .loadingNotarizationReceiptFailed: return "Loading notarization receipt failed." - case .notarizationFailed: return "Notarization failed." - case .exportingNotarizedAppFailed: - return "Exporting notarized app failed." - case .exportingNotarizedAppThrew(let error): return "Exporting notarized app failed.\n\(error)" - case .missingArchive: return "Exporting notarized app couldn't find archive." + case .fetchingNotarizationStatusThrew(let error): + return "Fetching notarization status failed.\n\(error)" + case .notarizationFailed: + return "Notarization failed." + case .exportingNotarizedAppThrew(let error): return "Exporting notarized app failed.\n\(error)" + case .missingArchive: return "Exporting notarized app couldn't find archive." + case .loadingNotarizationReceiptFailed: + return "Loading notarization receipt failed." } } } +enum WaitForNotarizationRunnerError: RunnerError { + case fetchingNotarizationStatusFailed + case exportingNotarizedAppFailed + + func description(for session: Runner.Session) async -> String { + async let stderr = String(session.stderr) + switch self { + case .fetchingNotarizationStatusFailed: + return "Fetching notarization status failed.\n\(await stderr)" + case .exportingNotarizedAppFailed: + return "Exporting notarized app failed.\n\(await stderr)" + } + } +} struct WaitForNotarizationCommand: AsyncParsableCommand { static var configuration: CommandConfiguration { CommandConfiguration( @@ -110,7 +120,7 @@ struct WaitForNotarizationCommand: AsyncParsableCommand { try? fm.copyItem(at: parsed.exportedAppURL, to: stapledAppURL) let xcrun = XCRunRunner(parsed: parsed) let result = try xcrun.run(["stapler", "staple", stapledAppURL.path]) - try await result.throwIfFailed(WaitForNotarizationError.exportingNotarizedAppFailed) + try await result.throwIfFailed(WaitForNotarizationRunnerError.exportingNotarizedAppFailed) } else { throw WaitForNotarizationError.missingArchive } @@ -125,7 +135,7 @@ struct WaitForNotarizationCommand: AsyncParsableCommand { "altool", "--notarization-info", request, "--username", parsed.user, "--password", "@keychain:AC_PASSWORD", "--output-format", "xml", ]) - try await result.throwIfFailed(WaitForNotarizationError.fetchingNotarizationStatusFailed) + try await result.throwIfFailed(WaitForNotarizationRunnerError.fetchingNotarizationStatusFailed) parsed.log("Received response.") let data = await Data(result.stdout)