Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions cmd/wodby/ci/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ var Cmd = &cobra.Command{
for _, appServiceBuildConfig := range appServiceBuildConfigs {
buildArgs := make(map[string]string)
var redactValues []string
buildArgs["COPY_FROM"] = opts.from
// A service can narrow the build to a subdirectory of the context, so
// the flags give the roots and the service gives the path within them.
buildArgs["COPY_FROM"] = joinCopyPath(opts.from, appServiceBuildConfig.CopyFrom)
buildArgs["WODBY_BASE_IMAGE"] = appServiceBuildConfig.Image
buildFiles := newBuildFiles(context, appServiceBuildConfig.Name, opts.dockerfile)
cacheFrom, cacheTo, err := resolveCacheOptions(config, appServiceBuildConfig.Name, opts)
Expand Down Expand Up @@ -172,7 +174,7 @@ var Cmd = &cobra.Command{
return errors.WithStack(err)
}
dockerfile = string(d)
if err := addDockerfileBuildArgs(buildArgs, dockerfile, appServiceBuildConfig, opts.to, logger, &redactValues); err != nil {
if err := addDockerfileBuildArgs(buildArgs, dockerfile, appServiceBuildConfig, joinCopyPath(opts.to, appServiceBuildConfig.CopyTo), logger, &redactValues); err != nil {
return errors.WithStack(err)
}
} else if fileExists(buildFiles.dockerfilePath) {
Expand All @@ -183,21 +185,21 @@ var Cmd = &cobra.Command{
return errors.WithStack(err)
}
dockerfile = string(d)
if err := addDockerfileBuildArgs(buildArgs, dockerfile, appServiceBuildConfig, opts.to, logger, &redactValues); err != nil {
if err := addDockerfileBuildArgs(buildArgs, dockerfile, appServiceBuildConfig, joinCopyPath(opts.to, appServiceBuildConfig.CopyTo), logger, &redactValues); err != nil {
return errors.WithStack(err)
}
} else {
if appServiceBuildConfig.Dockerfile != nil {
dockerfileSource = dockerfileSourceService
fmt.Println("Dockerfile provided by app service")
dockerfile = *appServiceBuildConfig.Dockerfile
if err := addDockerfileBuildArgs(buildArgs, dockerfile, appServiceBuildConfig, opts.to, logger, &redactValues); err != nil {
if err := addDockerfileBuildArgs(buildArgs, dockerfile, appServiceBuildConfig, joinCopyPath(opts.to, appServiceBuildConfig.CopyTo), logger, &redactValues); err != nil {
return errors.WithStack(err)
}
} else {
dockerfileSource = dockerfileSourceDefault
fmt.Println("No Dockerfile provided by app service, using the default")
buildArgs["COPY_TO"] = opts.to
buildArgs["COPY_TO"] = joinCopyPath(opts.to, appServiceBuildConfig.CopyTo)
// Replace default image user in dockerfile template.
defaultUser, err := dockerClient.GetImageDefaultUser(appServiceBuildConfig.Image)
if err != nil {
Expand Down Expand Up @@ -347,6 +349,24 @@ func dockerfileContentHash(dockerfile string) string {
return "sha256:" + hex.EncodeToString(sum[:])
}

// joinCopyPath places a service's copy subdirectory under the root given by the
// --from/--to flags. An empty subdirectory leaves the root untouched, which is
// the default whole-context build.
func joinCopyPath(root string, subdir string) string {
if subdir == "" {
if root == "" {
return "."
}

return root
}
if root == "" {
root = "."
}

return path.Join(root, subdir)
}

func authoredDockerfile(source string) bool {
return source == dockerfileSourceFlag || source == dockerfileSourceContext
}
Expand Down
24 changes: 24 additions & 0 deletions cmd/wodby/ci/build/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,3 +468,27 @@ func TestDockerfileContentHash(t *testing.T) {
t.Fatalf("dockerfileContentHash(\"\") = %q, want empty", dockerfileContentHash(""))
}
}

func TestJoinCopyPath(t *testing.T) {
for _, tc := range []struct {
name string
root string
subdir string
want string
}{
{name: "default root, no subdir", root: ".", subdir: "", want: "."},
{name: "default root with subdir", root: ".", subdir: "web", want: "web"},
{name: "explicit root with subdir", root: "static", subdir: "web", want: "static/web"},
{name: "absolute destination with subdir", root: "/var/www/html", subdir: "web", want: "/var/www/html/web"},
{name: "explicit root, no subdir", root: "static", subdir: "", want: "static"},
{name: "empty root, no subdir", root: "", subdir: "", want: "."},
{name: "empty root with subdir", root: "", subdir: "web", want: "web"},
{name: "nested subdir", root: ".", subdir: "apps/web", want: "apps/web"},
} {
t.Run(tc.name, func(t *testing.T) {
if got := joinCopyPath(tc.root, tc.subdir); got != tc.want {
t.Fatalf("joinCopyPath(%q, %q) = %q, want %q", tc.root, tc.subdir, got, tc.want)
}
})
}
}
20 changes: 12 additions & 8 deletions pkg/types/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,18 @@ type (
Services []*AppServiceBuildConfig `json:"services"`
}
AppServiceBuildConfig struct {
Name string `json:"name"`
Title string `json:"title"`
Image string `json:"image"`
Managed bool `json:"managed"`
Main bool `json:"main"`
Dockerfile *string `json:"dockerfile"`
Dockerignore *string `json:"dockerignore"`
Args []*AppServiceBuildArg `json:"args"`
Name string `json:"name"`
Title string `json:"title"`
Image string `json:"image"`
Managed bool `json:"managed"`
Main bool `json:"main"`
Dockerfile *string `json:"dockerfile"`
Dockerignore *string `json:"dockerignore"`
// CopyFrom and CopyTo narrow the build to a subdirectory, relative to the
// --from and --to paths. Empty means copy the whole context.
CopyFrom string `json:"copyFrom"`
CopyTo string `json:"copyTo"`
Args []*AppServiceBuildArg `json:"args"`
}
AppServiceBuildArg struct {
Name string `json:"name"`
Expand Down