Skip to content

Commit

Permalink
Implement Target support for ko builder
Browse files Browse the repository at this point in the history
This implements support for the Target config field for the ko builder.
The Target field allows users to specify a target for `go build`. This
is necessary where the main package is not in the context directory.

Tracking: #6041
Related: #6054, #6437
  • Loading branch information
halvards committed Aug 17, 2021
1 parent f88c88e commit 825ea4b
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 13 deletions.
21 changes: 13 additions & 8 deletions pkg/skaffold/build/ko/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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 {
Expand All @@ -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`),
Expand Down
25 changes: 20 additions & 5 deletions pkg/skaffold/build/ko/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
Expand All @@ -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 {
Expand All @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions pkg/skaffold/build/ko/schema/temporary.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions pkg/skaffold/build/ko/testdata/package-main-in-root/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/ko/testdata/package-main-in-root

go 1.13
14 changes: 14 additions & 0 deletions pkg/skaffold/build/ko/testdata/package-main-in-root/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"fmt"
"time"
)

func main() {
for {
fmt.Println("Hello world!")

time.Sleep(time.Second * 1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"fmt"
"time"
)

func main() {
for {
fmt.Println("Hello world!")

time.Sleep(time.Second * 1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/ko/testdata/package-main-not-in-root

go 1.13

0 comments on commit 825ea4b

Please sign in to comment.