From 472cb1950fed0f799767ec2ad8a4e3844275209a Mon Sep 17 00:00:00 2001 From: J Logan Date: Thu, 30 Apr 2026 10:29:13 -0700 Subject: [PATCH] Build output should just be tags/paths. (#1478) - Closes #1477. ## Type of Change - [x] Bug fix - [ ] New feature - [ ] Breaking change - [ ] Documentation update ## Motivation and Context stdout should contain results that can be piped ## Testing - [x] Tested locally - [x] Added/updated tests - [ ] Added/updated docs --- Sources/ContainerCommands/BuildCommand.swift | 6 +++--- .../Subcommands/Build/CLIBuilderLocalOutputTest.swift | 10 +++++----- .../Subcommands/Build/CLIBuilderTarExportTest.swift | 4 ++-- Tests/CLITests/Subcommands/Build/CLIBuilderTest.swift | 9 +++++++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Sources/ContainerCommands/BuildCommand.swift b/Sources/ContainerCommands/BuildCommand.swift index a4af293b..892fc185 100644 --- a/Sources/ContainerCommands/BuildCommand.swift +++ b/Sources/ContainerCommands/BuildCommand.swift @@ -367,7 +367,7 @@ extension Application { } unpackProgress.start() - var finalMessage = "Successfully built \(imageNames.joined(separator: ", "))" + var finalMessage = imageNames.joined(separator: "\n") let taskManager = ProgressTaskCoordinator() // Currently, only a single export can be specified. for exp in exports { @@ -400,7 +400,7 @@ extension Application { } let tarURL = tempURL.appendingPathComponent("out.tar") try FileManager.default.moveItem(at: tarURL, to: dest) - finalMessage = "Successfully exported to \(dest.absolutePath())" + finalMessage = dest.absolutePath() case "local": guard let dest = exp.destination else { throw ContainerizationError(.invalidArgument, message: "dest is required \(exp.rawValue)") @@ -411,7 +411,7 @@ extension Application { throw ContainerizationError(.invalidArgument, message: "expected local output not found") } try FileManager.default.copyItem(at: localDir, to: dest) - finalMessage = "Successfully exported to \(dest.absolutePath())" + finalMessage = dest.absolutePath() default: throw ContainerizationError(.invalidArgument, message: "invalid exporter \(exp.rawValue)") } diff --git a/Tests/CLITests/Subcommands/Build/CLIBuilderLocalOutputTest.swift b/Tests/CLITests/Subcommands/Build/CLIBuilderLocalOutputTest.swift index bf7b3795..edf0feca 100644 --- a/Tests/CLITests/Subcommands/Build/CLIBuilderLocalOutputTest.swift +++ b/Tests/CLITests/Subcommands/Build/CLIBuilderLocalOutputTest.swift @@ -61,7 +61,7 @@ extension TestCLIBuildBase { ) // Verify the build succeeded - #expect(response.contains("Successfully exported to"), "Expected successful local export message") + #expect(response.contains(outputDir.absolutePath()), "Expected successful local export message") // Verify the output directory was created #expect(FileManager.default.fileExists(atPath: outputDir.path), "Expected local output directory to exist") @@ -89,7 +89,7 @@ extension TestCLIBuildBase { let basicResponse = try buildWithLocalOutput(tag: basicImageName, tempDir: basicTempDir, outputDir: basicOutputDir) // Verify basic build succeeded - #expect(basicResponse.contains("Successfully exported to"), "Expected successful basic local export message") + #expect(basicResponse.contains(basicOutputDir.absolutePath()), "Expected successful basic local export message") #expect(FileManager.default.fileExists(atPath: basicOutputDir.path), "Expected basic local output directory to exist") // Test context functionality - verify COPY works with context @@ -111,7 +111,7 @@ extension TestCLIBuildBase { let contextResponse = try buildWithLocalOutput(tag: contextImageName, tempDir: contextTempDir, outputDir: contextOutputDir) // Verify context build succeeded - #expect(contextResponse.contains("Successfully exported to"), "Expected successful context local export message") + #expect(contextResponse.contains(contextOutputDir.absolutePath()), "Expected successful context local export message") #expect(FileManager.default.fileExists(atPath: contextOutputDir.path), "Expected context local output directory to exist") } @@ -146,7 +146,7 @@ extension TestCLIBuildBase { ) // Verify the build succeeded - #expect(response.contains("Successfully exported to"), "Expected successful local export message") + #expect(response.contains(outputDir.absolutePath()), "Expected successful local export message") // Verify the output directory exists #expect(FileManager.default.fileExists(atPath: outputDir.path), "Expected local output directory to exist") @@ -176,7 +176,7 @@ extension TestCLIBuildBase { let existingResponse = try buildWithLocalOutput(tag: existingImageName, tempDir: existingTempDir, outputDir: existingOutputDir) // Verify the build succeeded - #expect(existingResponse.contains("Successfully exported to"), "Expected successful local export message") + #expect(existingResponse.contains(existingOutputDir.absolutePath()), "Expected successful local export message") // Verify the output directory exists #expect(FileManager.default.fileExists(atPath: existingOutputDir.path), "Expected local output directory to exist") diff --git a/Tests/CLITests/Subcommands/Build/CLIBuilderTarExportTest.swift b/Tests/CLITests/Subcommands/Build/CLIBuilderTarExportTest.swift index a47998fd..d9ee962a 100644 --- a/Tests/CLITests/Subcommands/Build/CLIBuilderTarExportTest.swift +++ b/Tests/CLITests/Subcommands/Build/CLIBuilderTarExportTest.swift @@ -49,7 +49,7 @@ extension TestCLIBuildBase { #expect(response.status == 0, "build with tar export should succeed") #expect(FileManager.default.fileExists(atPath: exportPath.path), "tar file should exist at \(exportPath.path)") - #expect(response.output.contains("Successfully exported to \(exportPath.path)"), "should show export success message") + #expect(response.output.contains(exportPath.path), "should show export success message") let attributes = try FileManager.default.attributesOfItem(atPath: exportPath.path) let fileSize = attributes[.size] as? Int ?? 0 @@ -79,7 +79,7 @@ extension TestCLIBuildBase { let expectedTar = exportDir.appendingPathComponent("out.tar") #expect(FileManager.default.fileExists(atPath: expectedTar.path), "tar file should exist at \(expectedTar.path)") - #expect(response.output.contains("Successfully exported to \(expectedTar.path)"), "should show export success message") + #expect(response.output.contains(expectedTar.path), "should show export success message") } @Test func testBuildExportTarMultipleRuns() throws { diff --git a/Tests/CLITests/Subcommands/Build/CLIBuilderTest.swift b/Tests/CLITests/Subcommands/Build/CLIBuilderTest.swift index dd240daf..da7a2f2f 100644 --- a/Tests/CLITests/Subcommands/Build/CLIBuilderTest.swift +++ b/Tests/CLITests/Subcommands/Build/CLIBuilderTest.swift @@ -146,7 +146,8 @@ extension TestCLIBuildBase { ] try createContext(tempDir: tempDir, dockerfile: dockerfile, context: context) let imageName: String = "registry.local/add-all:\(UUID().uuidString)" - try self.build(tag: imageName, tempDir: tempDir) + let outputRef = try self.build(tag: imageName, tempDir: tempDir) + #expect(outputRef.contains(imageName), "expected stdout to container image reference") #expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)") } @@ -488,7 +489,11 @@ extension TestCLIBuildBase { let tag2 = "registry.local/multi-tag-test:latest" let tag3 = "registry.local/multi-tag-test:v1.0.0" - try self.build(tags: [tag1, tag2, tag3], tempDir: tempDir) + let outputRef = try self.build(tags: [tag1, tag2, tag3], tempDir: tempDir) + + #expect(outputRef.contains(tag1), "expected tag in output") + #expect(outputRef.contains(tag2), "expected tag in output") + #expect(outputRef.contains(tag3), "expected tag in output") // Verify all three tags exist and point to the same image #expect(try self.inspectImage(tag1) == tag1, "expected to have successfully built \(tag1)")