1
0
mirror of https://github.com/ko-build/ko.git synced 2025-03-03 15:32:20 +02:00

Return better error messages (#33)

This hoists the publisher creation out of the loop for `ko publish` to
avoid needlessly resolving credentials multiple times.

This pulls the publisher creation outside of resolveFilesToWriter so we
can fail earlier if e.g. KO_DOCKER_REPO is unset, otherwise we start up
the kubectl goroutine and it would asynchronously fail with:

  error: no objects passed to apply
This commit is contained in:
jonjohnsonjr 2019-04-30 13:08:54 -05:00 committed by GitHub
parent 7c4a93a717
commit cef9764e3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 77 additions and 63 deletions

View File

@ -15,14 +15,14 @@
package commands package commands
import ( import (
"github.com/google/ko/pkg/commands/options"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"github.com/google/ko/pkg/commands/options"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
) )
// addApply augments our CLI surface with apply. // addApply augments our CLI surface with apply.
@ -62,6 +62,14 @@ func addApply(topLevel *cobra.Command) {
cat config.yaml | ko apply -f -`, cat config.yaml | ko apply -f -`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
builder, err := makeBuilder(do)
if err != nil {
log.Fatalf("error creating builder: %v", err)
}
publisher, err := makePublisher(no, lo, ta)
if err != nil {
log.Fatalf("error creating publisher: %v", err)
}
// Create a set of ko-specific flags to ignore when passing through // Create a set of ko-specific flags to ignore when passing through
// kubectl global flags. // kubectl global flags.
ignoreSet := make(map[string]struct{}) ignoreSet := make(map[string]struct{})
@ -107,7 +115,7 @@ func addApply(topLevel *cobra.Command) {
stdin.Write([]byte("---\n")) stdin.Write([]byte("---\n"))
} }
// Once primed kick things off. // Once primed kick things off.
resolveFilesToWriter(fo, no, lo, ta, do, stdin) resolveFilesToWriter(builder, publisher, fo, stdin)
}() }()
// Run it. // Run it.

View File

@ -21,12 +21,11 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/spf13/viper"
"github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/spf13/viper"
) )
var ( var (
@ -51,7 +50,7 @@ func getCreationTime() (*v1.Time, error) {
seconds, err := strconv.ParseInt(epoch, 10, 64) seconds, err := strconv.ParseInt(epoch, 10, 64)
if err != nil { if err != nil {
return nil, fmt.Errorf("the environment variable SOURCE_DATE_EPOCH is invalid. It's must be a number of seconds since January 1st 1970, 00:00 UTC, got %v", err) return nil, fmt.Errorf("the environment variable SOURCE_DATE_EPOCH should be the number of seconds since January 1st 1970, 00:00 UTC, got: %v", err)
} }
return &v1.Time{time.Unix(seconds, 0)}, nil return &v1.Time{time.Unix(seconds, 0)}, nil
} }

View File

@ -15,14 +15,14 @@
package commands package commands
import ( import (
"github.com/google/ko/pkg/commands/options"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"github.com/google/ko/pkg/commands/options"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
) )
// addCreate augments our CLI surface with apply. // addCreate augments our CLI surface with apply.
@ -62,6 +62,14 @@ func addCreate(topLevel *cobra.Command) {
cat config.yaml | ko create -f -`, cat config.yaml | ko create -f -`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
builder, err := makeBuilder(do)
if err != nil {
log.Fatalf("error creating builder: %v", err)
}
publisher, err := makePublisher(no, lo, ta)
if err != nil {
log.Fatalf("error creating publisher: %v", err)
}
// Create a set of ko-specific flags to ignore when passing through // Create a set of ko-specific flags to ignore when passing through
// kubectl global flags. // kubectl global flags.
ignoreSet := make(map[string]struct{}) ignoreSet := make(map[string]struct{})
@ -107,7 +115,7 @@ func addCreate(topLevel *cobra.Command) {
stdin.Write([]byte("---\n")) stdin.Write([]byte("---\n"))
} }
// Once primed kick things off. // Once primed kick things off.
resolveFilesToWriter(fo, no, lo, ta, do, stdin) resolveFilesToWriter(builder, publisher, fo, stdin)
}() }()
// Run it. // Run it.

View File

@ -15,11 +15,12 @@
package commands package commands
import ( import (
"log"
"github.com/google/ko/pkg/commands/options" "github.com/google/ko/pkg/commands/options"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
// addPublish augments our CLI surface with publish. // addPublish augments our CLI surface with publish.
func addPublish(topLevel *cobra.Command) { func addPublish(topLevel *cobra.Command) {
lo := &options.LocalOptions{} lo := &options.LocalOptions{}
@ -58,7 +59,17 @@ func addPublish(topLevel *cobra.Command) {
ko publish --local github.com/foo/bar/cmd/baz github.com/foo/bar/cmd/blah`, ko publish --local github.com/foo/bar/cmd/baz github.com/foo/bar/cmd/blah`,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
Run: func(_ *cobra.Command, args []string) { Run: func(_ *cobra.Command, args []string) {
publishImages(args, no, lo, ta, do) builder, err := makeBuilder(do)
if err != nil {
log.Fatalf("error creating builder: %v", err)
}
publisher, err := makePublisher(no, lo, ta)
if err != nil {
log.Fatalf("error creating publisher: %v", err)
}
if _, err := publishImages(args, publisher, builder); err != nil {
log.Fatalf("failed to publish images: %v", err)
}
}, },
} }
options.AddLocalArg(publish, lo) options.AddLocalArg(publish, lo)

View File

@ -16,14 +16,11 @@ package commands
import ( import (
"fmt" "fmt"
"github.com/google/ko/pkg/commands/options"
gb "go/build" gb "go/build"
"log"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/name"
"github.com/google/ko/pkg/build" "github.com/google/ko/pkg/build"
"github.com/google/ko/pkg/publish" "github.com/google/ko/pkg/publish"
@ -39,15 +36,7 @@ func qualifyLocalImport(importpath, gopathsrc, pwd string) (string, error) {
return filepath.Join(strings.TrimPrefix(pwd, gopathsrc+string(filepath.Separator)), importpath), nil return filepath.Join(strings.TrimPrefix(pwd, gopathsrc+string(filepath.Separator)), importpath), nil
} }
func publishImages(importpaths []string, no *options.NameOptions, lo *options.LocalOptions, ta *options.TagsOptions, do *options.DebugOptions) map[string]name.Reference { func publishImages(importpaths []string, pub publish.Interface, b build.Interface) (map[string]name.Reference, error) {
opt, err := gobuildOptions(do)
if err != nil {
log.Fatalf("error setting up builder options: %v", err)
}
b, err := build.NewGo(opt...)
if err != nil {
log.Fatalf("error creating go builder: %v", err)
}
imgs := make(map[string]name.Reference) imgs := make(map[string]name.Reference)
for _, importpath := range importpaths { for _, importpath := range importpaths {
if gb.IsLocalImport(importpath) { if gb.IsLocalImport(importpath) {
@ -56,44 +45,27 @@ func publishImages(importpaths []string, no *options.NameOptions, lo *options.Lo
gopathsrc := filepath.Join(gb.Default.GOPATH, "src") gopathsrc := filepath.Join(gb.Default.GOPATH, "src")
pwd, err := os.Getwd() pwd, err := os.Getwd()
if err != nil { if err != nil {
log.Fatalf("error getting current working directory: %v", err) return nil, fmt.Errorf("error getting current working directory: %v", err)
} }
importpath, err = qualifyLocalImport(importpath, gopathsrc, pwd) importpath, err = qualifyLocalImport(importpath, gopathsrc, pwd)
if err != nil { if err != nil {
log.Fatal(err) return nil, err
} }
} }
if !b.IsSupportedReference(importpath) { if !b.IsSupportedReference(importpath) {
log.Fatalf("importpath %q is not supported", importpath) return nil, fmt.Errorf("importpath %q is not supported", importpath)
} }
img, err := b.Build(importpath) img, err := b.Build(importpath)
if err != nil { if err != nil {
log.Fatalf("error building %q: %v", importpath, err) return nil, fmt.Errorf("error building %q: %v", importpath, err)
}
var pub publish.Interface
repoName := os.Getenv("KO_DOCKER_REPO")
namer := options.MakeNamer(no)
if lo.Local || repoName == publish.LocalDomain {
pub = publish.NewDaemon(namer, ta.Tags)
} else {
if _, err := name.NewRepository(repoName, name.WeakValidation); err != nil {
log.Fatalf("the environment variable KO_DOCKER_REPO must be set to a valid docker repository, got %v", err)
}
opts := []publish.Option{publish.WithAuthFromKeychain(authn.DefaultKeychain), publish.WithNamer(namer), publish.WithTags(ta.Tags)}
pub, err = publish.NewDefault(repoName, opts...)
if err != nil {
log.Fatalf("error setting up default image publisher: %v", err)
}
} }
ref, err := pub.Publish(img, importpath) ref, err := pub.Publish(img, importpath)
if err != nil { if err != nil {
log.Fatalf("error publishing %s: %v", importpath, err) return nil, fmt.Errorf("error publishing %s: %v", importpath, err)
} }
imgs[importpath] = ref imgs[importpath] = ref
} }
return imgs return imgs, nil
} }

View File

@ -15,9 +15,11 @@
package commands package commands
import ( import (
"log"
"os"
"github.com/google/ko/pkg/commands/options" "github.com/google/ko/pkg/commands/options"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"os"
) )
// addResolve augments our CLI surface with resolve. // addResolve augments our CLI surface with resolve.
@ -55,7 +57,15 @@ func addResolve(topLevel *cobra.Command) {
ko resolve --local -f config/`, ko resolve --local -f config/`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
resolveFilesToWriter(fo, no, lo, ta, do, os.Stdout) builder, err := makeBuilder(do)
if err != nil {
log.Fatalf("error creating builder: %v", err)
}
publisher, err := makePublisher(no, lo, ta)
if err != nil {
log.Fatalf("error creating publisher: %v", err)
}
resolveFilesToWriter(builder, publisher, fo, os.Stdout)
}, },
} }
options.AddLocalArg(resolve, lo) options.AddLocalArg(resolve, lo)

View File

@ -15,8 +15,8 @@
package commands package commands
import ( import (
"errors"
"fmt" "fmt"
"github.com/google/ko/pkg/commands/options"
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
@ -26,6 +26,7 @@ import (
"github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/name"
"github.com/google/ko/pkg/build" "github.com/google/ko/pkg/build"
"github.com/google/ko/pkg/commands/options"
"github.com/google/ko/pkg/publish" "github.com/google/ko/pkg/publish"
"github.com/google/ko/pkg/resolve" "github.com/google/ko/pkg/resolve"
"github.com/mattmoor/dep-notify/pkg/graph" "github.com/mattmoor/dep-notify/pkg/graph"
@ -87,9 +88,12 @@ func makePublisher(no *options.NameOptions, lo *options.LocalOptions, ta *option
if lo.Local || repoName == publish.LocalDomain { if lo.Local || repoName == publish.LocalDomain {
return publish.NewDaemon(namer, ta.Tags), nil return publish.NewDaemon(namer, ta.Tags), nil
} }
if repoName == "" {
return nil, errors.New("KO_DOCKER_REPO environment variable is unset")
}
_, err := name.NewRepository(repoName, name.WeakValidation) _, err := name.NewRepository(repoName, name.WeakValidation)
if err != nil { if err != nil {
return nil, fmt.Errorf("the environment variable KO_DOCKER_REPO must be set to a valid docker repository, got %v", err) return nil, fmt.Errorf("failed to parse environment variable KO_DOCKER_REPO=%q as repository: %v", repoName, err)
} }
return publish.NewDefault(repoName, return publish.NewDefault(repoName,
@ -108,18 +112,8 @@ func makePublisher(no *options.NameOptions, lo *options.LocalOptions, ta *option
// resolvedFuture represents a "future" for the bytes of a resolved file. // resolvedFuture represents a "future" for the bytes of a resolved file.
type resolvedFuture chan []byte type resolvedFuture chan []byte
func resolveFilesToWriter(fo *options.FilenameOptions, no *options.NameOptions, lo *options.LocalOptions, ta *options.TagsOptions, do *options.DebugOptions, out io.WriteCloser) { func resolveFilesToWriter(builder *build.Caching, publisher publish.Interface, fo *options.FilenameOptions, out io.WriteCloser) {
defer out.Close() defer out.Close()
builder, err := makeBuilder(do)
if err != nil {
log.Fatalf("error creating builder: %v", err)
}
// Wrap publisher in a memoizing publisher implementation.
publisher, err := makePublisher(no, lo, ta)
if err != nil {
log.Fatalf("error creating publisher: %v", err)
}
// By having this as a channel, we can hook this up to a filesystem // By having this as a channel, we can hook this up to a filesystem
// watcher and leave `fs` open to stream the names of yaml files // watcher and leave `fs` open to stream the names of yaml files
@ -132,6 +126,7 @@ func resolveFilesToWriter(fo *options.FilenameOptions, no *options.NameOptions,
var g graph.Interface var g graph.Interface
var errCh chan error var errCh chan error
var err error
if fo.Watch { if fo.Watch {
// Start a dep-notify process that on notifications scans the // Start a dep-notify process that on notifications scans the
// file-to-recorded-build map and for each affected file resends // file-to-recorded-build map and for each affected file resends

View File

@ -15,11 +15,11 @@
package commands package commands
import ( import (
"github.com/google/ko/pkg/commands/options"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"github.com/google/ko/pkg/commands/options"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -45,7 +45,18 @@ func addRun(topLevel *cobra.Command) {
# This supports relative import paths as well. # This supports relative import paths as well.
ko run foo --image=./cmd/baz`, ko run foo --image=./cmd/baz`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
imgs := publishImages([]string{bo.Path}, no, lo, ta, do) builder, err := makeBuilder(do)
if err != nil {
log.Fatalf("error creating builder: %v", err)
}
publisher, err := makePublisher(no, lo, ta)
if err != nil {
log.Fatalf("error creating publisher: %v", err)
}
imgs, err := publishImages([]string{bo.Path}, publisher, builder)
if err != nil {
log.Fatalf("failed to publish images: %v", err)
}
// There's only one, but this is the simple way to access the // There's only one, but this is the simple way to access the
// reference since the import path may have been qualified. // reference since the import path may have been qualified.