package publishers import ( "bytes" "os" "os/exec" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestLinuxKitPublisher_Name_Good(t *testing.T) { t.Run("returns linuxkit", func(t *testing.T) { p := NewLinuxKitPublisher() assert.Equal(t, "linuxkit", p.Name()) }) } func TestLinuxKitPublisher_ParseConfig_Good(t *testing.T) { p := NewLinuxKitPublisher() t.Run("uses defaults when no extended config", func(t *testing.T) { pubCfg := PublisherConfig{Type: "linuxkit"} cfg := p.parseConfig(pubCfg, "/project") assert.Equal(t, "/project/.core/linuxkit/server.yml", cfg.Config) assert.Equal(t, []string{"iso"}, cfg.Formats) assert.Equal(t, []string{"linux/amd64"}, cfg.Platforms) }) t.Run("parses extended config", func(t *testing.T) { pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{ "config": ".core/linuxkit/custom.yml", "formats": []any{"iso", "qcow2", "vmdk"}, "platforms": []any{"linux/amd64", "linux/arm64"}, }, } cfg := p.parseConfig(pubCfg, "/project") assert.Equal(t, "/project/.core/linuxkit/custom.yml", cfg.Config) assert.Equal(t, []string{"iso", "qcow2", "vmdk"}, cfg.Formats) assert.Equal(t, []string{"linux/amd64", "linux/arm64"}, cfg.Platforms) }) t.Run("handles absolute config path", func(t *testing.T) { pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{ "config": "/absolute/path/to/config.yml", }, } cfg := p.parseConfig(pubCfg, "/project") assert.Equal(t, "/absolute/path/to/config.yml", cfg.Config) }) } func TestLinuxKitPublisher_BuildLinuxKitArgs_Good(t *testing.T) { p := NewLinuxKitPublisher() t.Run("builds basic args for amd64", func(t *testing.T) { args := p.buildLinuxKitArgs("/config/server.yml", "iso", "linuxkit-1.0.0-amd64", "/output", "amd64") assert.Contains(t, args, "build") assert.Contains(t, args, "-format") assert.Contains(t, args, "iso") assert.Contains(t, args, "-name") assert.Contains(t, args, "linuxkit-1.0.0-amd64") assert.Contains(t, args, "-dir") assert.Contains(t, args, "/output") assert.Contains(t, args, "/config/server.yml") // Should not contain -arch for amd64 (default) assert.NotContains(t, args, "-arch") }) t.Run("builds args with arch for arm64", func(t *testing.T) { args := p.buildLinuxKitArgs("/config/server.yml", "qcow2", "linuxkit-1.0.0-arm64", "/output", "arm64") assert.Contains(t, args, "-arch") assert.Contains(t, args, "arm64") assert.Contains(t, args, "qcow2") }) } func TestLinuxKitPublisher_BuildBaseName_Good(t *testing.T) { p := NewLinuxKitPublisher() t.Run("strips v prefix", func(t *testing.T) { name := p.buildBaseName("v1.2.3") assert.Equal(t, "linuxkit-1.2.3", name) }) t.Run("handles version without v prefix", func(t *testing.T) { name := p.buildBaseName("1.2.3") assert.Equal(t, "linuxkit-1.2.3", name) }) } func TestLinuxKitPublisher_GetArtifactPath_Good(t *testing.T) { p := NewLinuxKitPublisher() tests := []struct { name string outputDir string outputName string format string expected string }{ { name: "ISO format", outputDir: "/dist/linuxkit", outputName: "linuxkit-1.0.0-amd64", format: "iso", expected: "/dist/linuxkit/linuxkit-1.0.0-amd64.iso", }, { name: "raw format", outputDir: "/dist/linuxkit", outputName: "linuxkit-1.0.0-amd64", format: "raw", expected: "/dist/linuxkit/linuxkit-1.0.0-amd64.raw", }, { name: "qcow2 format", outputDir: "/dist/linuxkit", outputName: "linuxkit-1.0.0-arm64", format: "qcow2", expected: "/dist/linuxkit/linuxkit-1.0.0-arm64.qcow2", }, { name: "vmdk format", outputDir: "/dist/linuxkit", outputName: "linuxkit-1.0.0-amd64", format: "vmdk", expected: "/dist/linuxkit/linuxkit-1.0.0-amd64.vmdk", }, { name: "gcp format", outputDir: "/dist/linuxkit", outputName: "linuxkit-1.0.0-amd64", format: "gcp", expected: "/dist/linuxkit/linuxkit-1.0.0-amd64.img.tar.gz", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { path := p.getArtifactPath(tc.outputDir, tc.outputName, tc.format) assert.Equal(t, tc.expected, path) }) } } func TestLinuxKitPublisher_GetFormatExtension_Good(t *testing.T) { p := NewLinuxKitPublisher() tests := []struct { format string expected string }{ {"iso", ".iso"}, {"raw", ".raw"}, {"qcow2", ".qcow2"}, {"vmdk", ".vmdk"}, {"vhd", ".vhd"}, {"gcp", ".img.tar.gz"}, {"aws", ".raw"}, {"unknown", ".unknown"}, } for _, tc := range tests { t.Run(tc.format, func(t *testing.T) { ext := p.getFormatExtension(tc.format) assert.Equal(t, tc.expected, ext) }) } } func TestLinuxKitPublisher_Publish_Bad(t *testing.T) { p := NewLinuxKitPublisher() t.Run("fails when config file not found with linuxkit installed", func(t *testing.T) { if err := validateLinuxKitCli(); err != nil { t.Skip("skipping test: linuxkit CLI not available") } release := &Release{ Version: "v1.0.0", ProjectDir: "/nonexistent", } pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{ "config": "/nonexistent/config.yml", }, } relCfg := &mockReleaseConfig{repository: "owner/repo"} err := p.Publish(nil, release, pubCfg, relCfg, false) assert.Error(t, err) assert.Contains(t, err.Error(), "config file not found") }) t.Run("fails when linuxkit CLI not available", func(t *testing.T) { if err := validateLinuxKitCli(); err == nil { t.Skip("skipping test: linuxkit CLI is available") } release := &Release{ Version: "v1.0.0", ProjectDir: "/tmp", } pubCfg := PublisherConfig{Type: "linuxkit"} relCfg := &mockReleaseConfig{repository: "owner/repo"} err := p.Publish(nil, release, pubCfg, relCfg, false) assert.Error(t, err) assert.Contains(t, err.Error(), "linuxkit CLI not found") }) t.Run("fails when repository cannot be detected and not provided", func(t *testing.T) { if err := validateLinuxKitCli(); err != nil { t.Skip("skipping test: linuxkit CLI not available") } // Create temp directory that is NOT a git repo tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) // Create a config file configPath := filepath.Join(tmpDir, "config.yml") err = os.WriteFile(configPath, []byte("kernel:\n image: test\n"), 0644) require.NoError(t, err) release := &Release{ Version: "v1.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{ "config": "config.yml", }, } relCfg := &mockReleaseConfig{repository: ""} // Empty repository err = p.Publish(nil, release, pubCfg, relCfg, true) assert.Error(t, err) assert.Contains(t, err.Error(), "could not determine repository") }) } func TestValidateLinuxKitCli_Good(t *testing.T) { t.Run("returns expected error when linuxkit not installed", func(t *testing.T) { err := validateLinuxKitCli() if err != nil { // LinuxKit is not installed assert.Contains(t, err.Error(), "linuxkit CLI not found") } // If err is nil, linuxkit is installed - that's OK }) } func TestLinuxKitPublisher_Publish_WithCLI_Good(t *testing.T) { // These tests run only when linuxkit CLI is available if err := validateLinuxKitCli(); err != nil { t.Skip("skipping test: linuxkit CLI not available") } p := NewLinuxKitPublisher() t.Run("succeeds with dry run and valid config", func(t *testing.T) { tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) // Create config directory and file configDir := filepath.Join(tmpDir, ".core", "linuxkit") err = os.MkdirAll(configDir, 0755) require.NoError(t, err) configPath := filepath.Join(configDir, "server.yml") err = os.WriteFile(configPath, []byte("kernel:\n image: linuxkit/kernel:5.10\n"), 0644) require.NoError(t, err) oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v1.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{Type: "linuxkit"} relCfg := &mockReleaseConfig{repository: "owner/repo"} err = p.Publish(nil, release, pubCfg, relCfg, true) w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "DRY RUN: LinuxKit Build & Publish") }) t.Run("fails with missing config file", func(t *testing.T) { tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) release := &Release{ Version: "v1.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{Type: "linuxkit"} relCfg := &mockReleaseConfig{repository: "owner/repo"} err = p.Publish(nil, release, pubCfg, relCfg, false) assert.Error(t, err) assert.Contains(t, err.Error(), "config file not found") }) t.Run("uses relCfg repository", func(t *testing.T) { tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) configDir := filepath.Join(tmpDir, ".core", "linuxkit") err = os.MkdirAll(configDir, 0755) require.NoError(t, err) configPath := filepath.Join(configDir, "server.yml") err = os.WriteFile(configPath, []byte("kernel:\n image: test\n"), 0644) require.NoError(t, err) oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v1.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{Type: "linuxkit"} relCfg := &mockReleaseConfig{repository: "custom-owner/custom-repo"} err = p.Publish(nil, release, pubCfg, relCfg, true) w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "custom-owner/custom-repo") }) t.Run("detects repository when not provided", func(t *testing.T) { tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) // Create config file configDir := filepath.Join(tmpDir, ".core", "linuxkit") err = os.MkdirAll(configDir, 0755) require.NoError(t, err) configPath := filepath.Join(configDir, "server.yml") err = os.WriteFile(configPath, []byte("kernel:\n image: test\n"), 0644) require.NoError(t, err) // Initialize git repo cmd := exec.Command("git", "init") cmd.Dir = tmpDir require.NoError(t, cmd.Run()) cmd = exec.Command("git", "remote", "add", "origin", "git@github.com:detected-owner/detected-repo.git") cmd.Dir = tmpDir require.NoError(t, cmd.Run()) oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v1.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{Type: "linuxkit"} relCfg := &mockReleaseConfig{repository: ""} // Empty to trigger detection err = p.Publish(nil, release, pubCfg, relCfg, true) w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "detected-owner/detected-repo") }) } func TestLinuxKitPublisher_Publish_NilRelCfg_Good(t *testing.T) { if err := validateLinuxKitCli(); err != nil { t.Skip("skipping test: linuxkit CLI not available") } p := NewLinuxKitPublisher() t.Run("handles nil relCfg by detecting repo", func(t *testing.T) { tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) // Create config file configDir := filepath.Join(tmpDir, ".core", "linuxkit") err = os.MkdirAll(configDir, 0755) require.NoError(t, err) configPath := filepath.Join(configDir, "server.yml") err = os.WriteFile(configPath, []byte("kernel:\n image: test\n"), 0644) require.NoError(t, err) // Initialize git repo cmd := exec.Command("git", "init") cmd.Dir = tmpDir require.NoError(t, cmd.Run()) cmd = exec.Command("git", "remote", "add", "origin", "git@github.com:nil-owner/nil-repo.git") cmd.Dir = tmpDir require.NoError(t, cmd.Run()) oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v1.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{Type: "linuxkit"} err = p.Publish(nil, release, pubCfg, nil, true) // nil relCfg w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "nil-owner/nil-repo") }) } // mockReleaseConfig implements ReleaseConfig for testing. type mockReleaseConfig struct { repository string projectName string } func (m *mockReleaseConfig) GetRepository() string { return m.repository } func (m *mockReleaseConfig) GetProjectName() string { return m.projectName } func TestLinuxKitPublisher_DryRunPublish_Good(t *testing.T) { p := NewLinuxKitPublisher() t.Run("outputs expected dry run information", func(t *testing.T) { oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v1.0.0", ProjectDir: "/project", } cfg := LinuxKitConfig{ Config: "/project/.core/linuxkit/server.yml", Formats: []string{"iso", "qcow2"}, Platforms: []string{"linux/amd64", "linux/arm64"}, } err := p.dryRunPublish(release, cfg, "owner/repo") w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "DRY RUN: LinuxKit Build & Publish") assert.Contains(t, output, "Repository: owner/repo") assert.Contains(t, output, "Version: v1.0.0") assert.Contains(t, output, "Config: /project/.core/linuxkit/server.yml") assert.Contains(t, output, "Formats: iso, qcow2") assert.Contains(t, output, "Platforms: linux/amd64, linux/arm64") assert.Contains(t, output, "Would execute commands:") assert.Contains(t, output, "linuxkit build") assert.Contains(t, output, "Would upload artifacts to release:") assert.Contains(t, output, "linuxkit-1.0.0-amd64.iso") assert.Contains(t, output, "linuxkit-1.0.0-amd64.qcow2") assert.Contains(t, output, "linuxkit-1.0.0-arm64.iso") assert.Contains(t, output, "linuxkit-1.0.0-arm64.qcow2") assert.Contains(t, output, "END DRY RUN") }) t.Run("shows docker format usage hint", func(t *testing.T) { oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v1.0.0", ProjectDir: "/project", } cfg := LinuxKitConfig{ Config: "/config.yml", Formats: []string{"docker"}, Platforms: []string{"linux/amd64"}, } err := p.dryRunPublish(release, cfg, "owner/repo") w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "linuxkit-1.0.0-amd64.docker.tar") assert.Contains(t, output, "Usage: docker load <") }) t.Run("handles single platform and format", func(t *testing.T) { oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v2.0.0", ProjectDir: "/project", } cfg := LinuxKitConfig{ Config: "/config.yml", Formats: []string{"iso"}, Platforms: []string{"linux/amd64"}, } err := p.dryRunPublish(release, cfg, "owner/repo") w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "linuxkit-2.0.0-amd64.iso") assert.NotContains(t, output, "arm64") }) } func TestLinuxKitPublisher_GetFormatExtension_AllFormats_Good(t *testing.T) { p := NewLinuxKitPublisher() tests := []struct { format string expected string }{ {"iso", ".iso"}, {"iso-bios", ".iso"}, {"iso-efi", ".iso"}, {"raw", ".raw"}, {"raw-bios", ".raw"}, {"raw-efi", ".raw"}, {"qcow2", ".qcow2"}, {"qcow2-bios", ".qcow2"}, {"qcow2-efi", ".qcow2"}, {"vmdk", ".vmdk"}, {"vhd", ".vhd"}, {"gcp", ".img.tar.gz"}, {"aws", ".raw"}, {"docker", ".docker.tar"}, {"tar", ".tar"}, {"kernel+initrd", "-initrd.img"}, {"custom-format", ".custom-format"}, } for _, tc := range tests { t.Run(tc.format, func(t *testing.T) { ext := p.getFormatExtension(tc.format) assert.Equal(t, tc.expected, ext) }) } } func TestLinuxKitPublisher_BuildLinuxKitArgs_AllArchitectures_Good(t *testing.T) { p := NewLinuxKitPublisher() t.Run("amd64 does not include arch flag", func(t *testing.T) { args := p.buildLinuxKitArgs("/config.yml", "iso", "output-name", "/output", "amd64") assert.Contains(t, args, "build") assert.Contains(t, args, "-format") assert.Contains(t, args, "iso") assert.Contains(t, args, "-name") assert.Contains(t, args, "output-name") assert.Contains(t, args, "-dir") assert.Contains(t, args, "/output") assert.Contains(t, args, "/config.yml") assert.NotContains(t, args, "-arch") }) t.Run("arm64 includes arch flag", func(t *testing.T) { args := p.buildLinuxKitArgs("/config.yml", "qcow2", "output-name", "/output", "arm64") assert.Contains(t, args, "-arch") assert.Contains(t, args, "arm64") }) t.Run("other architectures include arch flag", func(t *testing.T) { args := p.buildLinuxKitArgs("/config.yml", "raw", "output-name", "/output", "riscv64") assert.Contains(t, args, "-arch") assert.Contains(t, args, "riscv64") }) } func TestLinuxKitPublisher_ParseConfig_EdgeCases_Good(t *testing.T) { p := NewLinuxKitPublisher() t.Run("handles nil extended config", func(t *testing.T) { pubCfg := PublisherConfig{ Type: "linuxkit", Extended: nil, } cfg := p.parseConfig(pubCfg, "/project") assert.Equal(t, "/project/.core/linuxkit/server.yml", cfg.Config) assert.Equal(t, []string{"iso"}, cfg.Formats) assert.Equal(t, []string{"linux/amd64"}, cfg.Platforms) }) t.Run("handles empty extended config", func(t *testing.T) { pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{}, } cfg := p.parseConfig(pubCfg, "/project") assert.Equal(t, "/project/.core/linuxkit/server.yml", cfg.Config) assert.Equal(t, []string{"iso"}, cfg.Formats) assert.Equal(t, []string{"linux/amd64"}, cfg.Platforms) }) t.Run("handles mixed format types in extended config", func(t *testing.T) { pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{ "formats": []any{"iso", 123, "qcow2"}, // includes non-string }, } cfg := p.parseConfig(pubCfg, "/project") assert.Equal(t, []string{"iso", "qcow2"}, cfg.Formats) }) t.Run("handles mixed platform types in extended config", func(t *testing.T) { pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{ "platforms": []any{"linux/amd64", nil, "linux/arm64"}, }, } cfg := p.parseConfig(pubCfg, "/project") assert.Equal(t, []string{"linux/amd64", "linux/arm64"}, cfg.Platforms) }) } func TestLinuxKitPublisher_BuildBaseName_EdgeCases_Good(t *testing.T) { p := NewLinuxKitPublisher() tests := []struct { name string version string expected string }{ {"strips v prefix", "v1.2.3", "linuxkit-1.2.3"}, {"no v prefix", "1.2.3", "linuxkit-1.2.3"}, {"prerelease version", "v1.0.0-alpha.1", "linuxkit-1.0.0-alpha.1"}, {"build metadata", "v1.0.0+build.123", "linuxkit-1.0.0+build.123"}, {"only v", "v", "linuxkit-"}, {"empty string", "", "linuxkit-"}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { name := p.buildBaseName(tc.version) assert.Equal(t, tc.expected, name) }) } } func TestLinuxKitPublisher_GetArtifactPath_AllFormats_Good(t *testing.T) { p := NewLinuxKitPublisher() tests := []struct { name string outputDir string outputName string format string expected string }{ { name: "ISO format", outputDir: "/dist", outputName: "linuxkit-1.0.0-amd64", format: "iso", expected: "/dist/linuxkit-1.0.0-amd64.iso", }, { name: "ISO-BIOS format", outputDir: "/dist", outputName: "linuxkit-1.0.0-amd64", format: "iso-bios", expected: "/dist/linuxkit-1.0.0-amd64.iso", }, { name: "docker format", outputDir: "/output", outputName: "linuxkit-2.0.0-arm64", format: "docker", expected: "/output/linuxkit-2.0.0-arm64.docker.tar", }, { name: "tar format", outputDir: "/output", outputName: "linuxkit-1.0.0", format: "tar", expected: "/output/linuxkit-1.0.0.tar", }, { name: "kernel+initrd format", outputDir: "/output", outputName: "linuxkit-1.0.0", format: "kernel+initrd", expected: "/output/linuxkit-1.0.0-initrd.img", }, { name: "GCP format", outputDir: "/output", outputName: "linuxkit-1.0.0", format: "gcp", expected: "/output/linuxkit-1.0.0.img.tar.gz", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { path := p.getArtifactPath(tc.outputDir, tc.outputName, tc.format) assert.Equal(t, tc.expected, path) }) } } func TestLinuxKitPublisher_Publish_DryRun_Good(t *testing.T) { if testing.Short() { t.Skip("skipping integration test in short mode") } // Skip if linuxkit CLI is not available if err := validateLinuxKitCli(); err != nil { t.Skip("skipping test: linuxkit CLI not available") } p := NewLinuxKitPublisher() t.Run("dry run succeeds with valid config file", func(t *testing.T) { // Create temp directory with config file tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) configDir := filepath.Join(tmpDir, ".core", "linuxkit") err = os.MkdirAll(configDir, 0755) require.NoError(t, err) configPath := filepath.Join(configDir, "server.yml") err = os.WriteFile(configPath, []byte("kernel:\n image: linuxkit/kernel:5.10\n"), 0644) require.NoError(t, err) oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v1.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{Type: "linuxkit"} relCfg := &mockReleaseConfig{repository: "owner/repo"} err = p.Publish(nil, release, pubCfg, relCfg, true) w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "DRY RUN: LinuxKit Build & Publish") }) t.Run("dry run uses custom config path", func(t *testing.T) { tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) customConfigPath := filepath.Join(tmpDir, "custom-config.yml") err = os.WriteFile(customConfigPath, []byte("kernel:\n image: custom\n"), 0644) require.NoError(t, err) oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v1.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{ "config": customConfigPath, }, } relCfg := &mockReleaseConfig{repository: "owner/repo"} err = p.Publish(nil, release, pubCfg, relCfg, true) w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() assert.Contains(t, output, "custom-config.yml") }) t.Run("dry run with multiple formats and platforms", func(t *testing.T) { tmpDir, err := os.MkdirTemp("", "linuxkit-test") require.NoError(t, err) defer os.RemoveAll(tmpDir) configPath := filepath.Join(tmpDir, "config.yml") err = os.WriteFile(configPath, []byte("kernel:\n image: test\n"), 0644) require.NoError(t, err) oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w release := &Release{ Version: "v2.0.0", ProjectDir: tmpDir, } pubCfg := PublisherConfig{ Type: "linuxkit", Extended: map[string]any{ "config": "config.yml", "formats": []any{"iso", "qcow2", "vmdk"}, "platforms": []any{"linux/amd64", "linux/arm64"}, }, } relCfg := &mockReleaseConfig{repository: "owner/repo"} err = p.Publish(nil, release, pubCfg, relCfg, true) w.Close() var buf bytes.Buffer _, _ = buf.ReadFrom(r) os.Stdout = oldStdout require.NoError(t, err) output := buf.String() // Check all format/platform combinations are listed assert.Contains(t, output, "linuxkit-2.0.0-amd64.iso") assert.Contains(t, output, "linuxkit-2.0.0-amd64.qcow2") assert.Contains(t, output, "linuxkit-2.0.0-amd64.vmdk") assert.Contains(t, output, "linuxkit-2.0.0-arm64.iso") assert.Contains(t, output, "linuxkit-2.0.0-arm64.qcow2") assert.Contains(t, output, "linuxkit-2.0.0-arm64.vmdk") }) }