Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename upgrade option to --release and handle decode errors
--release avoids colliding with the inherited root --version flag
(argument-parser subcommands inherit the root's version option).
Also moves the GitHubRelease JSON decode inside the existing
do/catch so a malformed 200 response is reported as a clean
ContainerizationError instead of a raw DecodingError dump.
  • Loading branch information
Saviollage committed Jul 13, 2026
commit ca656378cad40d813bc9e38514723acd8c9f2132
22 changes: 10 additions & 12 deletions Sources/ContainerCommands/Upgrade/UpgradeCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ extension Application {
/// Launchd prefix of the services that must be stopped before upgrading.
private static let launchdPrefix = "com.apple.container."

@Option(name: .shortAndLong, help: "Upgrade to a specific release version (defaults to the latest release)")
var version: String?
@Option(name: [.customShort("v"), .customLong("release")], help: "Upgrade to a specific release version (defaults to the latest release)")
var release: String?

@Flag(name: .shortAndLong, help: "Force the upgrade even if the target version is already installed")
var force = false
Expand All @@ -52,25 +52,25 @@ extension Application {
)
}

let release = try await fetchRelease()
let target = release.tagName
let targetRelease = try await fetchRelease()
let target = targetRelease.tagName
let installed = ReleaseVersion.version()

guard UpgradePolicy.shouldUpgrade(target: target, installed: installed, force: force) else {
if version == nil {
if release == nil {
print("Container is already on latest version \(target) (use -f to force update)")
} else {
print("Container is already on version \(target) (use -f to force update)")
}
return
}
if version == nil {
if release == nil {
print("Updating to latest version \(target)")
} else {
print("Updating to release version \(target)")
}

guard let package = release.installerPackage() else {
guard let package = targetRelease.installerPackage() else {
throw ContainerizationError(.notFound, message: "No suitable package found")
}
if !package.isSigned {
Expand All @@ -94,23 +94,21 @@ extension Application {
}

private func fetchRelease() async throws -> GitHubRelease {
let endpoint = GitHubRelease.endpoint(forVersion: version)
let endpoint = GitHubRelease.endpoint(forVersion: release)
let failureMessage =
version.map { "Release '\($0)' not found" } ?? "Failed fetching latest release"
release.map { "Release '\($0)' not found" } ?? "Failed fetching latest release"

let data: Data
do {
let (body, response) = try await URLSession.shared.data(from: endpoint)
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else {
throw ContainerizationError(.notFound, message: failureMessage)
}
data = body
return try JSONDecoder().decode(GitHubRelease.self, from: body)
} catch let error as ContainerizationError {
throw error
} catch {
throw ContainerizationError(.internalError, message: "\(failureMessage): \(error)")
}
return try JSONDecoder().decode(GitHubRelease.self, from: data)
}

private func confirmUnsignedPackage() -> Bool {
Expand Down
10 changes: 5 additions & 5 deletions Tests/ContainerCommandsTests/UpgradeCommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,18 @@ struct UpgradeCommandTests {
@Test
func parsesDefaults() throws {
let command = try Application.UpgradeCommand.parse([])
#expect(command.version == nil)
#expect(command.release == nil)
#expect(command.force == false)
}

@Test
func parsesVersionAndForce() throws {
let long = try Application.UpgradeCommand.parse(["--version", "0.6.0", "--force"])
#expect(long.version == "0.6.0")
func parsesReleaseAndForce() throws {
let long = try Application.UpgradeCommand.parse(["--release", "0.6.0", "--force"])
#expect(long.release == "0.6.0")
#expect(long.force == true)

let short = try Application.UpgradeCommand.parse(["-v", "0.6.0", "-f"])
#expect(short.version == "0.6.0")
#expect(short.release == "0.6.0")
#expect(short.force == true)
}
}
6 changes: 3 additions & 3 deletions docs/command-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1587,12 +1587,12 @@ Upgrades the installed `container` toolset to a release published on GitHub. The
**Usage**

```bash
container upgrade [--version <version>] [--force] [--debug]
container upgrade [--release <release>] [--force] [--debug]
```

**Options**

* `-v, --version <version>`: Upgrade to a specific release version (defaults to the latest release)
* `-v, --release <release>`: Upgrade to a specific release version (defaults to the latest release)
* `-f, --force`: Force the upgrade even if the target version is already installed

**Examples**
Expand All @@ -1603,7 +1603,7 @@ container system stop
container upgrade

# Upgrade (or downgrade) to a specific release
container upgrade --version 0.6.0
container upgrade --release 0.6.0

# Reinstall the current version
container upgrade --force
Expand Down