Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
KO build works, tests as well
Browse files Browse the repository at this point in the history
  • Loading branch information
cardil committed Oct 9, 2021
1 parent 158b11e commit 13833e5
Show file tree
Hide file tree
Showing 8 changed files with 1,522 additions and 44 deletions.
9 changes: 4 additions & 5 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func Build() {
mg.Deps(Test, files.EnsureBuildDir)
t := tasks.Start("🔨", "Building", len(config.Actual().Artifacts) > 0)
for _, art := range config.Actual().Artifacts {
p := t.Part(art.GetName())
p := t.Part(fmt.Sprintf("%s %s", art.GetType(), art.GetName()))
pp := p.Starting()

buildArtifact(art, pp)
Expand All @@ -39,11 +39,10 @@ func buildArtifact(art config.Artifact, pp tasks.PartProcessing) {
if result.Failed() {
pp.Done(result.Error)
return
} else {
config.WithContext(func(ctx context.Context) context.Context {
return context.WithValue(ctx, artifact.BuildKey(art), result)
})
}
config.WithContext(func(ctx context.Context) context.Context {
return context.WithValue(ctx, artifact.BuildKey(art), result)
})
}
var err error
if !found {
Expand Down
8 changes: 3 additions & 5 deletions config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,12 @@ func (r Result) Failed() bool {

// Artifact represents a thing that can be built and published.
type Artifact interface {
GetType() string
GetName() string
}

// ResultKey represents a key to be used for caching artifact results.
type ResultKey struct {
Artifact
Name string
}
// ResultKey is used to store results of a build or publish.
type ResultKey string

// Version specifies the version information and how to set it into variable at
// compile time.
Expand Down
25 changes: 22 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,28 @@ module github.com/wavesoftware/go-magetasks
go 1.16

require (
github.com/fatih/color v1.9.0
github.com/hashicorp/go-multierror v1.1.0
github.com/magefile/mage v1.10.0
github.com/BurntSushi/toml v0.4.1 // indirect
github.com/containerd/containerd v1.5.7 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.9.0 // indirect
github.com/docker/cli v20.10.9+incompatible // indirect
github.com/docker/docker v20.10.9+incompatible // indirect
github.com/docker/docker-credential-helpers v0.6.4 // indirect
github.com/fatih/color v1.13.0
github.com/go-logr/logr v1.1.0 // indirect
github.com/google/ko v0.9.3
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1
github.com/magefile/mage v1.11.0
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/wavesoftware/go-ensure v1.0.0
golang.org/x/mod v0.5.1
golang.org/x/net v0.0.0-20211008194852-3b03d305991f // indirect
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.7 // indirect
google.golang.org/genproto v0.0.0-20211008145708-270636b82663 // indirect
google.golang.org/grpc v1.41.0 // indirect
gotest.tools/v3 v3.0.3
k8s.io/klog/v2 v2.20.0 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
1,381 changes: 1,371 additions & 10 deletions go.sum

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions pkg/artifact/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ type Binary struct {
Platforms []Platform
}

func (b Binary) GetType() string {
return "📦"
}

// BinaryBuilder is a regular binary Golang builder.
type BinaryBuilder struct{}

Expand Down Expand Up @@ -57,9 +61,8 @@ func (bb BinaryBuilder) Build(artifact config.Artifact, notifier config.Notifier

// BuildKey returns the config.ResultKey for a build command.
func BuildKey(artifact config.Artifact) config.ResultKey {
return config.ResultKey{
Artifact: artifact, Name: ResultBinaries,
}
return config.ResultKey(fmt.Sprintf("%s-%s-%s",
artifact.GetType(), artifact.GetName(), ResultBinaries))
}

func (b Binary) buildForPlatform(
Expand Down
19 changes: 2 additions & 17 deletions pkg/artifact/image.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package artifact

import (
"errors"
"fmt"

"github.com/wavesoftware/go-magetasks/config"
"github.com/wavesoftware/go-magetasks/pkg/artifact/platform"
"github.com/wavesoftware/go-magetasks/pkg/output"
Expand All @@ -12,26 +9,14 @@ import (

const imageReferenceKey = "oci.image.reference"

var errNotYetImplemented = errors.New("not yet implemented")

// Image is an OCI image that will be built from a binary.
type Image struct {
config.Metadata
Architectures []platform.Architecture
}

// KoBuilder builds images with Google's KO.
type KoBuilder struct{}

func (kb KoBuilder) Accepts(artifact config.Artifact) bool {
_, ok := artifact.(Image)
return ok
}

func (kb KoBuilder) Build(artifact config.Artifact, notifier config.Notifier) config.Result {
// TODO: not yet implemented
return config.Result{
Error: fmt.Errorf("%w: ko builder", errNotYetImplemented)}
func (i Image) GetType() string {
return "💿"
}

// ImageReferenceOf will try to fetch an image reference from image build result.
Expand Down
113 changes: 113 additions & 0 deletions pkg/artifact/ko.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package artifact

import (
"errors"
"fmt"
"io/ioutil"
"path"
"strings"

"github.com/google/ko/pkg/commands"
"github.com/google/ko/pkg/commands/options"
"github.com/wavesoftware/go-magetasks/config"
"github.com/wavesoftware/go-magetasks/pkg/files"
"golang.org/x/mod/modfile"
)

const koImportPath = "ko.import-path"

// ErrKoBuildFailed when th Google's ko fails to build.
var ErrKoBuildFailed = errors.New("ko build failed")

// KoBuilder builds images with Google's KO.
type KoBuilder struct{}

func (kb KoBuilder) Accepts(artifact config.Artifact) bool {
_, ok := artifact.(Image)
return ok
}

func (kb KoBuilder) Build(artifact config.Artifact, notifier config.Notifier) config.Result {
image, ok := artifact.(Image)
if !ok {
return config.Result{Error: ErrInvalidArtifact}
}
bo := &options.BuildOptions{}
ctx := config.Actual().Context
builder, err := commands.NewBuilder(ctx, bo)
if err != nil {
return resultErrKoBuildFailed(err)
}
importPath, err := imageImportPath(image)
if err != nil {
return resultErrKoBuildFailed(err)
}
result, err := builder.Build(ctx, importPath)
if err != nil {
return resultErrKoBuildFailed(err)
}
digest, err := result.Digest()
if err != nil {
return resultErrKoBuildFailed(err)
}
notifier.Notify(fmt.Sprintf("built image: %s", digest))
return config.Result{Info: map[string]string{
imageReferenceKey: digest.String(),
}}
}

func resultErrKoBuildFailed(err error) config.Result {
return config.Result{
Error: fmt.Errorf("%w: %v", ErrKoBuildFailed, err),
}
}

func imageImportPath(image Image) (string, error) {
binDir := fullBinaryDirectory(image.GetName())
rs, err := lookForGoModule(binDir)
if err != nil {
return "", err
}
importPath := rs.resolve(binDir)
if resolver, ok := image.Args[koImportPath]; ok {
importPath = resolver()
}
return importPath, nil
}

func lookForGoModule(dir string) (lookupGoModuleResult, error) {
rs := lookupGoModuleResult{}
for i := 0; i < 10_000; i++ {
modFile := path.Join(dir, "go.mod")
if files.DontExists(modFile) {
dir = path.Dir(dir)
rs.directoryDistance++
continue
}
bytes, err := ioutil.ReadFile(modFile)
if err != nil {
return rs, err
}
file, err := modfile.Parse(modFile, bytes, nil)
if err != nil {
return rs, err
}
rs.module = file
return rs, nil
}
return rs, fmt.Errorf("%w: can't find go module", ErrKoBuildFailed)
}

type lookupGoModuleResult struct {
module *modfile.File
directoryDistance int
}

func (r lookupGoModuleResult) resolve(dir string) string {
root := dir
for i := 0; i < r.directoryDistance; i++ {
root = path.Dir(root)
}
p := strings.Replace(dir, root, "", 1)
return path.Join(r.module.Module.Mod.Path, p)
}
2 changes: 1 addition & 1 deletion tests/project_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

func TestProjectBuild(t *testing.T) {
execCmd(t, "./example", "./mage", "clean", "build")
execCmd(t, "./example/build/_output/bin", fmt.Sprintf("./dummy-%s-%s",
execCmd(t, "./example/build/_output/bin", fmt.Sprintf("./other-%s-%s",
runtime.GOOS, runtime.GOARCH))
}

Expand Down

0 comments on commit 13833e5

Please sign in to comment.