diff --git a/Package.resolved b/Package.resolved index a492f87..e505b74 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/async-http-client.git", "state" : { - "revision" : "2fc4652fb4689eb24af10e55cabaa61d8ba774fd", - "version" : "1.32.0" + "revision" : "3a5b74a58782c3b4c1f0bc75e9b67b10c2494e8f", + "version" : "1.33.1" } }, { @@ -16,7 +16,7 @@ "location" : "https://github.com/mcrich23/container", "state" : { "branch" : "add-command-option-group-function-macro", - "revision" : "33a37da6dea26a2e8e3919b9cf5d1816a5337d0a" + "revision" : "ed2ea54292f268ef74f4778423f8aa3cc34b20cc" } }, { @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/containerization.git", "state" : { - "revision" : "d3ff56e5dd93a4573ce7950f3428710bbe467f9c", - "version" : "0.27.0" + "revision" : "56916452e9fb09ed8ff94b80d8a95dd1a8ca66ac", + "version" : "0.30.1" } }, { @@ -33,8 +33,35 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/grpc/grpc-swift.git", "state" : { - "revision" : "ac715c584bb1e2e5cdfb7684ccb46fab8dafc641", - "version" : "1.27.4" + "revision" : "6a8927df5a91710b414caba4f8a088dead4633db", + "version" : "1.27.5" + } + }, + { + "identity" : "grpc-swift-2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-2.git", + "state" : { + "revision" : "d19a94824cc6fa182211e8197ce391ff712b69f1", + "version" : "2.4.0" + } + }, + { + "identity" : "grpc-swift-nio-transport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-nio-transport.git", + "state" : { + "revision" : "f62a09000685b5b86ee383b63e042f286b1a5422", + "version" : "2.7.0" + } + }, + { + "identity" : "grpc-swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-protobuf.git", + "state" : { + "revision" : "8723cf856dc23d9c2fad4d874e7b9ed3254acf03", + "version" : "2.3.0" } }, { @@ -60,8 +87,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { - "revision" : "c5d11a805e765f52ba34ec7284bd4fcd6ba68615", - "version" : "1.7.0" + "revision" : "626b5b7b2f45e1b0b1c6f4a309296d1d21d7311b", + "version" : "1.7.1" } }, { @@ -69,8 +96,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { - "revision" : "810496cf121e525d660cd0ea89a758740476b85f", - "version" : "1.5.1" + "revision" : "eb50cbd14606a9161cbc5d452f18797c90ef0bab", + "version" : "1.7.0" } }, { @@ -96,8 +123,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-certificates.git", "state" : { - "revision" : "24ccdeeeed4dfaae7955fcac9dbf5489ed4f1a25", - "version" : "1.18.0" + "revision" : "5aa1c0d1bc204908df47c2075bdbb39573d05e8d", + "version" : "1.19.0" } }, { @@ -105,8 +132,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "8d9834a6189db730f6264db7556a7ffb751e99ee", - "version" : "1.4.0" + "revision" : "6675bc0ff86e61436e615df6fc5174e043e57924", + "version" : "1.4.1" } }, { @@ -141,8 +168,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-structured-headers.git", "state" : { - "revision" : "76d7627bd88b47bf5a0f8497dd244885960dde0b", - "version" : "1.6.0" + "revision" : "933538faa42c432d385f02e07df0ace7c5ecfc47", + "version" : "1.7.0" } }, { @@ -159,8 +186,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log.git", "state" : { - "revision" : "bbd81b6725ae874c69e9b8c8804d462356b55523", - "version" : "1.10.1" + "revision" : "5073617dac96330a486245e4c0179cb0a6fd2256", + "version" : "1.12.0" } }, { @@ -168,8 +195,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "b31565862a8f39866af50bc6676160d8dda7de35", - "version" : "2.96.0" + "revision" : "cd6710454f25733900e133c6caf5188952763c36", + "version" : "2.98.0" } }, { @@ -177,8 +204,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "3df009d563dc9f21a5c85b33d8c2e34d2e4f8c3b", - "version" : "1.32.1" + "revision" : "5a48717e29f62cb8326d6d42e46b562ca93847a6", + "version" : "1.34.0" } }, { @@ -186,8 +213,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "b6571f3db40799df5a7fc0e92c399aa71c883edd", - "version" : "1.40.0" + "revision" : "81cc18264f92cd307ff98430f89372711d4f6fe9", + "version" : "1.43.0" } }, { @@ -195,8 +222,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "173cc69a058623525a58ae6710e2f5727c663793", - "version" : "2.36.0" + "revision" : "3f337058ccd7243c4cac7911477d8ad4c598d4da", + "version" : "2.37.0" } }, { @@ -204,8 +231,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-transport-services.git", "state" : { - "revision" : "60c3e187154421171721c1a38e800b390680fb5d", - "version" : "1.26.0" + "revision" : "9d4e67af1eea85967c7de778ad73e7776e5f1f22", + "version" : "1.27.0" } }, { @@ -222,8 +249,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "a008af1a102ff3dd6cc3764bb69bf63226d0f5f6", - "version" : "1.36.1" + "revision" : "81558271e243f8f47dfe8e9fdd55f3c2b5413f68", + "version" : "1.37.0" } }, { @@ -240,8 +267,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/swift-service-lifecycle.git", "state" : { - "revision" : "89888196dd79c61c50bca9a103d8114f32e1e598", - "version" : "2.10.1" + "revision" : "9829955b385e5bb88128b73f1b8389e9b9c3191a", + "version" : "2.11.0" } }, { @@ -262,6 +289,15 @@ "version" : "1.6.4" } }, + { + "identity" : "swift-toml", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mattt/swift-toml.git", + "state" : { + "revision" : "827506c90475e82d5a7f191f950fb3025cbdc0d6", + "version" : "2.0.0" + } + }, { "identity" : "yams", "kind" : "remoteSourceControl", diff --git a/Sources/Container-Compose/Application.swift b/Sources/Container-Compose/Application.swift index a986d48..e456078 100644 --- a/Sources/Container-Compose/Application.swift +++ b/Sources/Container-Compose/Application.swift @@ -19,7 +19,7 @@ import ArgumentParser public struct Main: AsyncParsableCommand { private static let commandName: String = "container-compose" - private static let version: String = "0.10.0" + private static let version: String = "0.11.0" public static var versionString: String { "\(commandName) version \(version)" } diff --git a/Sources/Container-Compose/Commands/ComposeUp.swift b/Sources/Container-Compose/Commands/ComposeUp.swift index 756d793..2583ef8 100644 --- a/Sources/Container-Compose/Commands/ComposeUp.swift +++ b/Sources/Container-Compose/Commands/ComposeUp.swift @@ -335,7 +335,7 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable { print("Creating network: \(networkName) (Actual name: \(actualNetworkName))") print("Executing container network create: container \(networkCreateArgs.joined(separator: " "))") - guard (try? await ClientNetwork.get(id: actualNetworkName)) == nil else { + guard (try? await NetworkClient().get(id: actualNetworkName)) == nil else { print("Network '\(networkName)' already exists") return } @@ -660,7 +660,7 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable { commands.append(contentsOf: ["--cpus", "\(cpuCount)"]) commands.append(contentsOf: ["--memory", memoryLimit]) - let buildCommand = try Application.BuildCommand.parse(commands) + var buildCommand = try Application.BuildCommand.parse(commands) print("\n----------------------------------------") print("Building image for service: \(serviceName) (Tag: \(imageToRun))") try buildCommand.validate() diff --git a/Tests/Container-Compose-DynamicTests/ComposeUpTests.swift b/Tests/Container-Compose-DynamicTests/ComposeUpTests.swift index 62ef9e0..c7cef3f 100644 --- a/Tests/Container-Compose-DynamicTests/ComposeUpTests.swift +++ b/Tests/Container-Compose-DynamicTests/ComposeUpTests.swift @@ -92,61 +92,61 @@ struct ComposeUpTests { } // TODO: Reenable - // @Test("Test three-tier web application with multiple networks") - // func testThreeTierWebAppWithNetworks() async throws { - // let yaml = DockerComposeYamlFiles.dockerComposeYaml2 - // - // let tempLocation = URL.temporaryDirectory.appending(path: "Container-Compose_Tests_\(UUID().uuidString)/docker-compose.yaml") - // try? FileManager.default.createDirectory(at: tempLocation.deletingLastPathComponent(), withIntermediateDirectories: true) - // try yaml.write(to: tempLocation, atomically: false, encoding: .utf8) - // let folderName = tempLocation.deletingLastPathComponent().lastPathComponent - // - // var composeUp = try ComposeUp.parse(["-d", "--cwd", tempLocation.deletingLastPathComponent().path(percentEncoded: false)]) - // try await composeUp.run() - // - // // Get the containers created by this compose file - // let containers = try await ContainerClient().list() - // .filter({ - // $0.configuration.id.contains(folderName) - // }) - // - // guard let nginxContainer = containers.first(where: { $0.configuration.id == "\(folderName)-nginx" }), - // let appContainer = containers.first(where: { $0.configuration.id == "\(folderName)-app" }), - // let dbContainer = containers.first(where: { $0.configuration.id == "\(folderName)-db" }), - // let redisContainer = containers.first(where: { $0.configuration.id == "\(folderName)-redis" }) - // else { - // throw Errors.containerNotFound - // } - // - // // --- NGINX Container --- - // #expect(nginxContainer.configuration.image.reference == "docker.io/library/nginx:alpine") - // #expect(nginxContainer.configuration.publishedPorts.map({ "\($0.hostAddress):\($0.hostPort):\($0.containerPort)" }) == ["0.0.0.0:80:80"]) - // #expect(nginxContainer.networks.map(\.hostname).contains("frontend")) - // - // // --- APP Container --- - // #expect(appContainer.configuration.image.reference == "docker.io/library/node:18-alpine") - // - // let appEnv = parseEnvToDict(appContainer.configuration.initProcess.environment) - // #expect(appEnv["NODE_ENV"] == "production") - // #expect(appEnv["DATABASE_URL"] == "postgres://\(dbContainer.networks.first!.address.split(separator: "/")[0]):5432/myapp") - // - // #expect(appContainer.networks.map(\.hostname).sorted() == ["backend", "frontend"]) - // - // // --- DB Container --- - // #expect(dbContainer.configuration.image.reference == "docker.io/library/postgres:14-alpine") - // let dbEnv = parseEnvToDict(dbContainer.configuration.initProcess.environment) - // #expect(dbEnv["POSTGRES_DB"] == "myapp") - // #expect(dbEnv["POSTGRES_USER"] == "user") - // #expect(dbEnv["POSTGRES_PASSWORD"] == "password") - // - // // Verify volume mount - // #expect(dbContainer.configuration.mounts.map(\.destination) == ["/var/lib/postgresql/"]) - // #expect(dbContainer.networks.map(\.hostname) == ["backend"]) - // - // // --- Redis Container --- - // #expect(redisContainer.configuration.image.reference == "docker.io/library/redis:alpine") - // #expect(redisContainer.networks.map(\.hostname) == ["backend"]) - // } +// @Test("Test three-tier web application with multiple networks") +// func testThreeTierWebAppWithNetworks() async throws { +// let yaml = DockerComposeYamlFiles.dockerComposeYaml2 +// +// let tempLocation = URL.temporaryDirectory.appending(path: "Container-Compose_Tests_\(UUID().uuidString)/docker-compose.yaml") +// try? FileManager.default.createDirectory(at: tempLocation.deletingLastPathComponent(), withIntermediateDirectories: true) +// try yaml.write(to: tempLocation, atomically: false, encoding: .utf8) +// let folderName = tempLocation.deletingLastPathComponent().lastPathComponent +// +// var composeUp = try ComposeUp.parse(["-d", "--cwd", tempLocation.deletingLastPathComponent().path(percentEncoded: false)]) +// try await composeUp.run() +// +// // Get the containers created by this compose file +// let containers = try await ContainerClient().list() +// .filter({ +// $0.configuration.id.contains(folderName) +// }) +// +// guard let nginxContainer = containers.first(where: { $0.configuration.id == "\(folderName)-nginx" }), +// let appContainer = containers.first(where: { $0.configuration.id == "\(folderName)-app" }), +// let dbContainer = containers.first(where: { $0.configuration.id == "\(folderName)-db" }), +// let redisContainer = containers.first(where: { $0.configuration.id == "\(folderName)-redis" }) +// else { +// throw Errors.containerNotFound +// } +// +// // --- NGINX Container --- +// #expect(nginxContainer.configuration.image.reference == "docker.io/library/nginx:alpine") +// #expect(nginxContainer.configuration.publishedPorts.map({ "\($0.hostAddress):\($0.hostPort):\($0.containerPort)" }) == ["0.0.0.0:80:80"]) +// #expect(nginxContainer.networks.map(\.hostname).contains("frontend")) +// +// // --- APP Container --- +// #expect(appContainer.configuration.image.reference == "docker.io/library/node:18-alpine") +// +// let appEnv = parseEnvToDict(appContainer.configuration.initProcess.environment) +// #expect(appEnv["NODE_ENV"] == "production") +// #expect(appEnv["DATABASE_URL"] == "postgres://\(dbContainer.networks.first!.ipv4Gateway.description):5432/myapp") +// +// #expect(appContainer.networks.map(\.hostname).sorted() == ["backend", "frontend"]) +// +// // --- DB Container --- +// #expect(dbContainer.configuration.image.reference == "docker.io/library/postgres:14-alpine") +// let dbEnv = parseEnvToDict(dbContainer.configuration.initProcess.environment) +// #expect(dbEnv["POSTGRES_DB"] == "myapp") +// #expect(dbEnv["POSTGRES_USER"] == "user") +// #expect(dbEnv["POSTGRES_PASSWORD"] == "password") +// +// // Verify volume mount +// #expect(dbContainer.configuration.mounts.map(\.destination) == ["/var/lib/postgresql/"]) +// #expect(dbContainer.networks.map(\.hostname) == ["backend"]) +// +// // --- Redis Container --- +// #expect(redisContainer.configuration.image.reference == "docker.io/library/redis:alpine") +// #expect(redisContainer.networks.map(\.hostname) == ["backend"]) +// } // @Test("Parse development environment with build") // func parseDevelopmentEnvironment() throws {