diff --git a/pkg/skaffold/build/ko/build.go b/pkg/skaffold/build/ko/build.go index 632e50bfcfa..b717b4fa053 100644 --- a/pkg/skaffold/build/ko/build.go +++ b/pkg/skaffold/build/ko/build.go @@ -50,7 +50,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, a *latestV1.Artifact } defer koPublisher.Close() - imageRef, err := b.buildAndPublish(ctx, a.ImageName, koBuilder, koPublisher) + imageRef, err := b.buildAndPublish(ctx, a, koBuilder, koPublisher) if err != nil { return "", fmt.Errorf("could not build and publish ko image %q: %w", a.ImageName, err) } @@ -60,10 +60,10 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, a *latestV1.Artifact } // buildAndPublish the image using the ko builder and publisher. -func (b *Builder) buildAndPublish(ctx context.Context, imageName string, koBuilder build.Interface, koPublisher publish.Interface) (name.Reference, error) { - importpath, err := getImportPath(imageName, koBuilder) +func (b *Builder) buildAndPublish(ctx context.Context, a *latestV1.Artifact, koBuilder build.Interface, koPublisher publish.Interface) (name.Reference, error) { + importpath, err := getImportPath(a, koBuilder) if err != nil { - return nil, fmt.Errorf("could not determine Go import path for ko image %q: %w", imageName, err) + return nil, fmt.Errorf("could not determine Go import path for ko image %q: %w", a.ImageName, err) } imageMap, err := b.publishImages(ctx, []string{importpath}, koPublisher, koBuilder) if err != nil { @@ -86,11 +86,16 @@ func (b *Builder) buildAndPublish(ctx context.Context, imageName string, koBuild // // If the image name does _not_ start with `ko://`, determine the Go import // path of the image workspace directory. -func getImportPath(imageName string, koBuilder build.Interface) (string, error) { - if strings.HasPrefix(imageName, build.StrictScheme) { - return imageName, nil +func getImportPath(a *latestV1.Artifact, koBuilder build.Interface) (string, error) { + if strings.HasPrefix(a.ImageName, build.StrictScheme) { + return a.ImageName, nil } - return koBuilder.QualifyImport(".") + target := a.KoArtifact.Target + if target == "" { + // default to context directory + target = "." + } + return koBuilder.QualifyImport(target) } // getImageIdentifier returns the image tag or digest for published images (`pushImages=true`), diff --git a/pkg/skaffold/build/ko/build_test.go b/pkg/skaffold/build/ko/build_test.go index e4b36fa3fec..6e598678ab0 100644 --- a/pkg/skaffold/build/ko/build_test.go +++ b/pkg/skaffold/build/ko/build_test.go @@ -87,10 +87,12 @@ func Test_getImportPath(t *testing.T) { expectedImportPath string }{ { - description: "image name is ko-prefixed full Go import path", + description: "target is ignored when image name is ko-prefixed full Go import path", artifact: &latestV1.Artifact{ ArtifactType: latestV1.ArtifactType{ - KoArtifact: &latestV1.KoArtifact{}, + KoArtifact: &latestV1.KoArtifact{ + Target: "./target-should-be-ignored", + }, }, ImageName: "ko://git.example.com/org/foo", }, @@ -113,9 +115,22 @@ func Test_getImportPath(t *testing.T) { KoArtifact: &latestV1.KoArtifact{}, }, ImageName: "bar", - Workspace: "../docker", + Workspace: "./testdata/package-main-in-root", + }, + expectedImportPath: "ko://github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/ko/testdata/package-main-in-root", + }, + { + description: "plain image name with workspace directory and target", + artifact: &latestV1.Artifact{ + ArtifactType: latestV1.ArtifactType{ + KoArtifact: &latestV1.KoArtifact{ + Target: "./baz", + }, + }, + ImageName: "baz-image", + Workspace: "./testdata/package-main-not-in-root", }, - expectedImportPath: "ko://github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/docker", // this package + "../docker" + expectedImportPath: "ko://github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/ko/testdata/package-main-not-in-root/baz", }, } for _, test := range tests { @@ -124,7 +139,7 @@ func Test_getImportPath(t *testing.T) { koBuilder, err := b.newKoBuilder(context.Background(), test.artifact) t.CheckNoError(err) - gotImportPath, err := getImportPath(test.artifact.ImageName, koBuilder) + gotImportPath, err := getImportPath(test.artifact, koBuilder) t.CheckNoError(err) t.CheckDeepEqual(test.expectedImportPath, gotImportPath) diff --git a/pkg/skaffold/build/ko/schema/temporary.go b/pkg/skaffold/build/ko/schema/temporary.go index e9c553709d1..19eee6600f8 100644 --- a/pkg/skaffold/build/ko/schema/temporary.go +++ b/pkg/skaffold/build/ko/schema/temporary.go @@ -36,6 +36,14 @@ type KoArtifact struct { // Defaults to `all` to build for all platforms supported by the // base image. Platforms []string `yaml:"platforms,omitempty"` + + // Target is the location of the main package. + // If target is specified as a relative path, it is relative to the `context` directory. + // If target is empty, the ko builder looks for the main package in the `context` directory only, but not in any subdirectories. + // If target is a pattern with wildcards, such as `./...`, the expansion must contain only one main package, otherwise ko fails. + // Target is ignored if the `ImageName` starts with `ko://`. + // Example: `./cmd/foo` + Target string `yaml:"target,omitempty"` } // KoDependencies is used to specify dependencies for an artifact built by ko. diff --git a/pkg/skaffold/build/ko/testdata/package-main-in-root/go.mod b/pkg/skaffold/build/ko/testdata/package-main-in-root/go.mod new file mode 100644 index 00000000000..1a97b830b41 --- /dev/null +++ b/pkg/skaffold/build/ko/testdata/package-main-in-root/go.mod @@ -0,0 +1,3 @@ +module github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/ko/testdata/package-main-in-root + +go 1.13 diff --git a/pkg/skaffold/build/ko/testdata/package-main-in-root/main.go b/pkg/skaffold/build/ko/testdata/package-main-in-root/main.go new file mode 100644 index 00000000000..593721cfe2e --- /dev/null +++ b/pkg/skaffold/build/ko/testdata/package-main-in-root/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + for { + fmt.Println("Hello world!") + + time.Sleep(time.Second * 1) + } +} diff --git a/pkg/skaffold/build/ko/testdata/package-main-not-in-root/baz/main.go b/pkg/skaffold/build/ko/testdata/package-main-not-in-root/baz/main.go new file mode 100644 index 00000000000..593721cfe2e --- /dev/null +++ b/pkg/skaffold/build/ko/testdata/package-main-not-in-root/baz/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + for { + fmt.Println("Hello world!") + + time.Sleep(time.Second * 1) + } +} diff --git a/pkg/skaffold/build/ko/testdata/package-main-not-in-root/go.mod b/pkg/skaffold/build/ko/testdata/package-main-not-in-root/go.mod new file mode 100644 index 00000000000..ec4ff63a82f --- /dev/null +++ b/pkg/skaffold/build/ko/testdata/package-main-not-in-root/go.mod @@ -0,0 +1,3 @@ +module github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/ko/testdata/package-main-not-in-root + +go 1.13