Skip to content

Commit d2535ae

Browse files
ipmbclaude
andcommitted
Fix apppack.toml artifact archival when using custom APPPACK_TOML path
When APPPACK_TOML env var is set to a custom location, the build process now copies the file to the default location (apppack.toml) after the build completes. This ensures the configuration is properly included in build artifacts regardless of its source location. Changes: - Add CopyAppPackTomlToDefault() function to handle the copy operation - Call the function after build completion with non-fatal error handling - Add comprehensive test coverage for the new functionality - Use DefaultAppPackTomlFilename constant for consistency 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f46123a commit d2535ae

File tree

4 files changed

+117
-4
lines changed

4 files changed

+117
-4
lines changed

builder/build/apppacktoml.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66
"os"
77
"strings"
88

9-
"github.com/apppackio/codebuild-image/builder/filesystem"
109
"github.com/BurntSushi/toml"
10+
"github.com/apppackio/codebuild-image/builder/filesystem"
1111
"github.com/rs/zerolog/log"
1212
)
1313

builder/build/build.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"sync"
1010

1111
"github.com/apppackio/codebuild-image/builder/containers"
12+
"github.com/apppackio/codebuild-image/builder/filesystem"
1213
"github.com/docker/docker/api/types/container"
1314
"github.com/google/go-containerregistry/pkg/crane"
1415
cp "github.com/otiai10/copy"
@@ -121,6 +122,11 @@ func (b *Build) RunBuild() error {
121122
if err = cp.Copy(logFile.Name(), "build.log"); err != nil {
122123
return err
123124
}
125+
// Copy the apppack.toml file to the default location if it was read from a custom location
126+
if err = filesystem.CopyAppPackTomlToDefault(); err != nil {
127+
b.Log().Warn().Err(err).Msg("Failed to copy apppack.toml to default location for artifact archival")
128+
// Don't fail the build if we can't copy the file, just warn
129+
}
124130
return b.state.WriteCommitTxt()
125131
}
126132

builder/filesystem/filesystem.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import (
1717
"github.com/spf13/afero"
1818
)
1919

20-
const envFileFilename = "env.json"
20+
const (
21+
envFileFilename = "env.json"
22+
DefaultAppPackTomlFilename = "apppack.toml"
23+
)
2124

2225
type State interface {
2326
CreateIfNotExists() error
@@ -181,9 +184,26 @@ func (f *FileState) WriteJsonToFile(filename string, v interface{}) error {
181184
}
182185

183186
func GetAppPackTomlFilename() string {
184-
filename := "apppack.toml"
187+
filename := DefaultAppPackTomlFilename
185188
if envFile := os.Getenv("APPPACK_TOML"); envFile != "" {
186189
filename = envFile
187190
}
188191
return filename
189192
}
193+
194+
// CopyAppPackTomlToDefault copies the apppack.toml file from a custom location to the default location
195+
// This is needed for artifact archival when APPPACK_TOML env var is used to specify a custom location
196+
// Returns nil if the file is already at the default location or if copy succeeds
197+
func CopyAppPackTomlToDefault() error {
198+
apppackTomlPath := GetAppPackTomlFilename()
199+
if apppackTomlPath == DefaultAppPackTomlFilename {
200+
// File is already at the default location, nothing to do
201+
return nil
202+
}
203+
204+
log.Debug().Msgf("Copying %s to %s for artifact archival", apppackTomlPath, DefaultAppPackTomlFilename)
205+
if err := cp.Copy(apppackTomlPath, DefaultAppPackTomlFilename); err != nil {
206+
return fmt.Errorf("failed to copy %s to %s: %w", apppackTomlPath, DefaultAppPackTomlFilename, err)
207+
}
208+
return nil
209+
}

builder/filesystem/filesystem_test.go

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"fmt"
88
"io"
99
"os"
10+
"path/filepath"
11+
"strings"
1012
"testing"
1113

1214
"github.com/rs/zerolog"
@@ -117,7 +119,7 @@ func TestGetFilename(t *testing.T) {
117119
// Call GetAppPackTomlFilename and check the default value
118120

119121
filename := GetAppPackTomlFilename()
120-
if filename != "apppack.toml" {
122+
if filename != DefaultAppPackTomlFilename {
121123
t.Errorf("expected apppack.toml, got %s", filename)
122124
}
123125

@@ -130,6 +132,91 @@ func TestGetFilename(t *testing.T) {
130132
}
131133
}
132134

135+
func TestCopyAppPackTomlToDefault(t *testing.T) {
136+
tests := []struct {
137+
name string
138+
envValue string
139+
setupFiles map[string]string
140+
expectCopy bool
141+
expectError bool
142+
errorContains string
143+
}{
144+
{
145+
name: "no copy needed when using default location",
146+
envValue: "",
147+
expectCopy: false,
148+
},
149+
{
150+
name: "copies from custom location",
151+
envValue: "config/custom.toml",
152+
setupFiles: map[string]string{
153+
"config/custom.toml": "[build]\ntest = true\n",
154+
},
155+
expectCopy: true,
156+
},
157+
{
158+
name: "error when custom file doesn't exist",
159+
envValue: "nonexistent.toml",
160+
expectCopy: false,
161+
expectError: true,
162+
errorContains: "failed to copy nonexistent.toml",
163+
},
164+
}
165+
166+
for _, tt := range tests {
167+
t.Run(tt.name, func(t *testing.T) {
168+
// Set up environment
169+
if tt.envValue != "" {
170+
os.Setenv("APPPACK_TOML", tt.envValue)
171+
defer os.Unsetenv("APPPACK_TOML")
172+
}
173+
174+
// Create temp directory for test
175+
tempDir := t.TempDir()
176+
originalDir, _ := os.Getwd()
177+
os.Chdir(tempDir)
178+
defer os.Chdir(originalDir)
179+
180+
// Set up test files
181+
for path, content := range tt.setupFiles {
182+
dir := filepath.Dir(path)
183+
if dir != "." {
184+
os.MkdirAll(dir, 0o755)
185+
}
186+
os.WriteFile(path, []byte(content), 0o644)
187+
}
188+
189+
// Run the function
190+
err := CopyAppPackTomlToDefault()
191+
192+
// Check error
193+
if tt.expectError {
194+
if err == nil {
195+
t.Errorf("expected error, got nil")
196+
} else if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) {
197+
t.Errorf("expected error to contain %q, got %q", tt.errorContains, err.Error())
198+
}
199+
} else if err != nil {
200+
t.Errorf("unexpected error: %v", err)
201+
}
202+
203+
// Check if file was copied
204+
if tt.expectCopy {
205+
if _, err := os.Stat(DefaultAppPackTomlFilename); os.IsNotExist(err) {
206+
t.Errorf("expected %s to exist after copy", DefaultAppPackTomlFilename)
207+
} else {
208+
// Verify content matches
209+
expected := tt.setupFiles[tt.envValue]
210+
actual, _ := os.ReadFile(DefaultAppPackTomlFilename)
211+
if string(actual) != expected {
212+
t.Errorf("copied content mismatch: got %q, want %q", actual, expected)
213+
}
214+
}
215+
}
216+
})
217+
}
218+
}
219+
133220
func dummyTarBuffer() (*io.Reader, error) {
134221
var buf bytes.Buffer
135222
tw := tar.NewWriter(&buf)

0 commit comments

Comments
 (0)