From c8dda1787a1d0439f6e4b844e954d1e9f3e58343 Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 11:49:19 -0700
Subject: [PATCH 1/9] fix healthcheck struct so tests can be an decoded from an
array or single string
---
.../xcschemes/Container-Compose.xcscheme | 2 +-
.../Healthchecked Redis/docker-compose.yaml | 12 ++++++++++++
.../Codable Structs/Healthcheck.swift | 18 ++++++++++++++++++
3 files changed, 31 insertions(+), 1 deletion(-)
create mode 100644 Sample Compose Files/Healthchecked Redis/docker-compose.yaml
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme
index c9d1c50..127ff5d 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme
@@ -106,7 +106,7 @@
isEnabled = "YES">
diff --git a/Sample Compose Files/Healthchecked Redis/docker-compose.yaml b/Sample Compose Files/Healthchecked Redis/docker-compose.yaml
new file mode 100644
index 0000000..d8c5ce6
--- /dev/null
+++ b/Sample Compose Files/Healthchecked Redis/docker-compose.yaml
@@ -0,0 +1,12 @@
+services:
+ redis:
+ restart: always
+ image: redis:7-alpine
+ volumes:
+ - redis-data:/data
+ healthcheck:
+ test: "redis-cli ping"
+ interval: 5s
+ retries: 20
+ ports:
+ - "6379:6379"
diff --git a/Sources/Container-Compose/Codable Structs/Healthcheck.swift b/Sources/Container-Compose/Codable Structs/Healthcheck.swift
index c26e23a..3c3d94e 100644
--- a/Sources/Container-Compose/Codable Structs/Healthcheck.swift
+++ b/Sources/Container-Compose/Codable Structs/Healthcheck.swift
@@ -48,4 +48,22 @@ public struct Healthcheck: Codable, Hashable {
self.retries = retries
self.timeout = timeout
}
+
+ public init(from decoder: any Decoder) throws {
+ let container = try decoder.container(keyedBy: CodingKeys.self)
+
+ // Handle if `test` is a single string instead of an array
+ if let test = try? container.decodeIfPresent([String].self, forKey: .test) {
+ self.test = test
+ } else if let testString = try? container.decodeIfPresent(String.self, forKey: .test) {
+ self.test = [testString]
+ } else {
+ self.test = nil
+ }
+
+ self.start_period = try container.decodeIfPresent(String.self, forKey: .start_period)
+ self.interval = try container.decodeIfPresent(String.self, forKey: .interval)
+ self.retries = try container.decodeIfPresent(Int.self, forKey: .retries)
+ self.timeout = try container.decodeIfPresent(String.self, forKey: .timeout)
+ }
}
From c2be73403746ced5949b7e5ec5aa693c3a1ec5aa Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 11:51:23 -0700
Subject: [PATCH 2/9] add test for parsing single test command
---
.../HealthcheckConfigurationTests.swift | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
index 72ecf8b..06daabd 100644
--- a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
+++ b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
@@ -35,6 +35,19 @@ struct HealthcheckConfigurationTests {
#expect(healthcheck.test?.first == "CMD")
}
+ @Test("Parse healthcheck with test command")
+ func parseHealthcheckWithTestAsSignleString() throws {
+ let yaml = """
+ test: "redis-cli ping"
+ """
+
+ let decoder = YAMLDecoder()
+ let healthcheck = try decoder.decode(Healthcheck.self, from: yaml)
+
+ #expect(healthcheck.test?.count == 1)
+ #expect(healthcheck.test?.first == "redis-cli ping")
+ }
+
@Test("Parse healthcheck with interval")
func parseHealthcheckWithInterval() throws {
let yaml = """
From 8a963ae730ddd984178ca79c3af8f34e0e759630 Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 11:55:55 -0700
Subject: [PATCH 3/9] fix test command separation for single string to be split
by space
This aligns with the compose spec https://docs.docker.com/reference/compose-file/services/
---
Sources/Container-Compose/Codable Structs/Healthcheck.swift | 2 +-
.../HealthcheckConfigurationTests.swift | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Sources/Container-Compose/Codable Structs/Healthcheck.swift b/Sources/Container-Compose/Codable Structs/Healthcheck.swift
index 3c3d94e..153d14c 100644
--- a/Sources/Container-Compose/Codable Structs/Healthcheck.swift
+++ b/Sources/Container-Compose/Codable Structs/Healthcheck.swift
@@ -56,7 +56,7 @@ public struct Healthcheck: Codable, Hashable {
if let test = try? container.decodeIfPresent([String].self, forKey: .test) {
self.test = test
} else if let testString = try? container.decodeIfPresent(String.self, forKey: .test) {
- self.test = [testString]
+ self.test = ["CMD-SHELL"] + testString.components(separatedBy: " ")
} else {
self.test = nil
}
diff --git a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
index 06daabd..6cb2b5c 100644
--- a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
+++ b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
@@ -44,8 +44,8 @@ struct HealthcheckConfigurationTests {
let decoder = YAMLDecoder()
let healthcheck = try decoder.decode(Healthcheck.self, from: yaml)
- #expect(healthcheck.test?.count == 1)
- #expect(healthcheck.test?.first == "redis-cli ping")
+ #expect(healthcheck.test?.count == 2)
+ #expect(healthcheck.test?.first == "redis-cli")
}
@Test("Parse healthcheck with interval")
From 068bb9194dc0f18eb04d23fc4addaff4c570cb3c Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 11:56:09 -0700
Subject: [PATCH 4/9] Update HealthcheckConfigurationTests.swift
---
.../HealthcheckConfigurationTests.swift | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
index 6cb2b5c..fe98e77 100644
--- a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
+++ b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
@@ -44,8 +44,8 @@ struct HealthcheckConfigurationTests {
let decoder = YAMLDecoder()
let healthcheck = try decoder.decode(Healthcheck.self, from: yaml)
- #expect(healthcheck.test?.count == 2)
- #expect(healthcheck.test?.first == "redis-cli")
+ #expect(healthcheck.test?.count == 3)
+ #expect(healthcheck.test?.first == "CMD-SHELL")
}
@Test("Parse healthcheck with interval")
From c3fa7de53756103ab16b880596f1ddeabf3629c6 Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 11:59:51 -0700
Subject: [PATCH 5/9] Update
.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../xcode/xcshareddata/xcschemes/Container-Compose.xcscheme | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme
index 127ff5d..1af42bf 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/Container-Compose.xcscheme
@@ -106,7 +106,7 @@
isEnabled = "YES">
From 18a473a77f9f8a6554faea18bd22bb2d5f8c96db Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 12:00:58 -0700
Subject: [PATCH 6/9] Update
Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../HealthcheckConfigurationTests.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
index fe98e77..bc45069 100644
--- a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
+++ b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
@@ -35,7 +35,7 @@ struct HealthcheckConfigurationTests {
#expect(healthcheck.test?.first == "CMD")
}
- @Test("Parse healthcheck with test command")
+ @Test("Parse healthcheck with test command (string)")
func parseHealthcheckWithTestAsSignleString() throws {
let yaml = """
test: "redis-cli ping"
From ea473d1304ff108c13366916f5506469bec204a2 Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 12:01:16 -0700
Subject: [PATCH 7/9] Update
Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../HealthcheckConfigurationTests.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
index bc45069..fa25ada 100644
--- a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
+++ b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
@@ -36,7 +36,7 @@ struct HealthcheckConfigurationTests {
}
@Test("Parse healthcheck with test command (string)")
- func parseHealthcheckWithTestAsSignleString() throws {
+ func parseHealthcheckWithTestAsSingleString() throws {
let yaml = """
test: "redis-cli ping"
"""
From 80b4e827adc0e95ca977a67573d5769b44d84ed1 Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 12:01:39 -0700
Subject: [PATCH 8/9] Update
Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../HealthcheckConfigurationTests.swift | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
index fa25ada..eb2c6c9 100644
--- a/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
+++ b/Tests/Container-Compose-StaticTests/HealthcheckConfigurationTests.swift
@@ -44,8 +44,9 @@ struct HealthcheckConfigurationTests {
let decoder = YAMLDecoder()
let healthcheck = try decoder.decode(Healthcheck.self, from: yaml)
- #expect(healthcheck.test?.count == 3)
+ #expect(healthcheck.test?.count == 2)
#expect(healthcheck.test?.first == "CMD-SHELL")
+ #expect(healthcheck.test?[1] == "redis-cli ping")
}
@Test("Parse healthcheck with interval")
From 3528a5b84c261e0982188e4972e9074f241712d6 Mon Sep 17 00:00:00 2001
From: Morris Richman <81453549+Mcrich23@users.noreply.github.com>
Date: Tue, 10 Mar 2026 12:01:57 -0700
Subject: [PATCH 9/9] fix test command parsing to align with docker spec
---
Sources/Container-Compose/Codable Structs/Healthcheck.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Sources/Container-Compose/Codable Structs/Healthcheck.swift b/Sources/Container-Compose/Codable Structs/Healthcheck.swift
index 153d14c..b7e8fc5 100644
--- a/Sources/Container-Compose/Codable Structs/Healthcheck.swift
+++ b/Sources/Container-Compose/Codable Structs/Healthcheck.swift
@@ -56,7 +56,7 @@ public struct Healthcheck: Codable, Hashable {
if let test = try? container.decodeIfPresent([String].self, forKey: .test) {
self.test = test
} else if let testString = try? container.decodeIfPresent(String.self, forKey: .test) {
- self.test = ["CMD-SHELL"] + testString.components(separatedBy: " ")
+ self.test = ["CMD-SHELL", testString]
} else {
self.test = nil
}