mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Fixes #220, uses FN_REGISTRY and --registry flag on push and deploy. Also, cleanup.
This commit is contained in:
@@ -4,6 +4,9 @@ all: vendor build
|
||||
build:
|
||||
go build -o fn
|
||||
|
||||
install:
|
||||
go build -o ${GOPATH}/bin/fn
|
||||
|
||||
docker: vendor
|
||||
GOOS=linux go build -o fn
|
||||
docker build -t treeder/fn .
|
||||
@@ -23,3 +26,5 @@ release:
|
||||
GOOS=darwin go build -o fn_mac
|
||||
GOOS=windows go build -o fn.exe
|
||||
docker run --rm -v ${PWD}:/go/src/github.com/fnproject/fn/cli -w /go/src/github.com/fnproject/fn/cli funcy/go:dev go build -o fn_alpine
|
||||
|
||||
.PHONY: install
|
||||
|
||||
@@ -12,13 +12,13 @@ if you are using Node, put the code that you want to execute in the file `func.j
|
||||
Run:
|
||||
|
||||
```sh
|
||||
fn init <DOCKER_HUB_USERNAME>/<FUNCTION_NAME>
|
||||
fn init [<FUNCTION_NAME>]
|
||||
```
|
||||
|
||||
If you want to override the convention with configuration, you can do that as well using:
|
||||
|
||||
```sh
|
||||
fn init [--runtime node] [--entrypoint "node hello.js"] <DOCKER_HUB_USERNAME>/<FUNCTION_NAME>
|
||||
fn init [--runtime node] [--entrypoint "node hello.js"] [<FUNCTION_NAME>]
|
||||
```
|
||||
|
||||
Or, if you want full control, just make a Dockerfile. If `init` finds a Dockerfile, it will use that instead of runtime and entrypoint.
|
||||
|
||||
@@ -40,8 +40,6 @@ func (b *buildcmd) flags() []cli.Flag {
|
||||
|
||||
// build will take the found valid function and build it
|
||||
func (b *buildcmd) build(c *cli.Context) error {
|
||||
verbwriter := verbwriter(b.verbose)
|
||||
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -51,11 +49,11 @@ func (b *buildcmd) build(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ff, err := buildfunc(verbwriter, fn, b.noCache)
|
||||
ff, err := buildfunc(fn, b.noCache)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Function %v built successfully.\n", ff.FullName())
|
||||
fmt.Printf("Function %v built successfully.\n", ff.ImageName())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ func (b *bumpcmd) flags() []cli.Flag {
|
||||
|
||||
// bump will take the found valid function and bump its version
|
||||
func (b *bumpcmd) bump(c *cli.Context) error {
|
||||
verbwriter := verbwriter(b.verbose)
|
||||
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
@@ -52,7 +51,7 @@ func (b *bumpcmd) bump(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintln(verbwriter, "bumping version for", fn)
|
||||
fmt.Println("bumping version for", fn)
|
||||
|
||||
funcfile, err := parsefuncfile(fn)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,6 +11,10 @@ import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
const (
|
||||
envFnToken = "FN_TOKEN"
|
||||
)
|
||||
|
||||
func Host() string {
|
||||
apiURL := os.Getenv("API_URL")
|
||||
if apiURL == "" {
|
||||
@@ -26,8 +30,8 @@ func Host() string {
|
||||
|
||||
func APIClient() *fnclient.Functions {
|
||||
transport := httptransport.New(Host(), "/v1", []string{"http"})
|
||||
if os.Getenv("FN_TOKEN") != "" {
|
||||
transport.DefaultAuthentication = httptransport.BearerToken(os.Getenv("FN_TOKEN"))
|
||||
if os.Getenv(envFnToken) != "" {
|
||||
transport.DefaultAuthentication = httptransport.BearerToken(os.Getenv(envFnToken))
|
||||
}
|
||||
|
||||
// create the API client, with the transport
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
@@ -22,18 +23,23 @@ import (
|
||||
const (
|
||||
functionsDockerImage = "funcy/functions"
|
||||
minRequiredDockerVersion = "17.5.0"
|
||||
envFnRegistry = "FN_REGISTRY"
|
||||
)
|
||||
|
||||
func verbwriter(verbose bool) io.Writer {
|
||||
// this is too limiting, removes all logs which isn't what we want
|
||||
// verbwriter := ioutil.Discard
|
||||
// if verbose {
|
||||
verbwriter := os.Stderr
|
||||
// }
|
||||
return verbwriter
|
||||
type HasRegistry interface {
|
||||
Registry() string
|
||||
}
|
||||
|
||||
func buildfunc(verbwriter io.Writer, fn string, noCache bool) (*funcfile, error) {
|
||||
func setRegistryEnv(hr HasRegistry) {
|
||||
if hr.Registry() != "" {
|
||||
err := os.Setenv(envFnRegistry, hr.Registry())
|
||||
if err != nil {
|
||||
log.Fatalf("Couldn't set %s env var: %v\n", envFnRegistry, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func buildfunc(fn string, noCache bool) (*funcfile, error) {
|
||||
funcfile, err := parsefuncfile(fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -53,23 +59,21 @@ func buildfunc(verbwriter io.Writer, fn string, noCache bool) (*funcfile, error)
|
||||
}
|
||||
}
|
||||
|
||||
if err := localbuild(verbwriter, fn, funcfile.Build); err != nil {
|
||||
if err := localbuild(fn, funcfile.Build); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := dockerbuild(verbwriter, fn, funcfile, noCache); err != nil {
|
||||
if err := dockerbuild(fn, funcfile, noCache); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return funcfile, nil
|
||||
}
|
||||
|
||||
func localbuild(verbwriter io.Writer, path string, steps []string) error {
|
||||
func localbuild(path string, steps []string) error {
|
||||
for _, cmd := range steps {
|
||||
exe := exec.Command("/bin/sh", "-c", cmd)
|
||||
exe.Dir = filepath.Dir(path)
|
||||
exe.Stderr = verbwriter
|
||||
exe.Stdout = verbwriter
|
||||
if err := exe.Run(); err != nil {
|
||||
return fmt.Errorf("error running command %v (%v)", cmd, err)
|
||||
}
|
||||
@@ -78,7 +82,7 @@ func localbuild(verbwriter io.Writer, path string, steps []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func dockerbuild(verbwriter io.Writer, path string, ff *funcfile, noCache bool) error {
|
||||
func dockerbuild(path string, ff *funcfile, noCache bool) error {
|
||||
err := dockerVersionCheck()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -89,9 +93,9 @@ func dockerbuild(verbwriter io.Writer, path string, ff *funcfile, noCache bool)
|
||||
var helper langs.LangHelper
|
||||
dockerfile := filepath.Join(dir, "Dockerfile")
|
||||
if !exists(dockerfile) {
|
||||
helper = langs.GetLangHelper(*ff.Runtime)
|
||||
helper = langs.GetLangHelper(ff.Runtime)
|
||||
if helper == nil {
|
||||
return fmt.Errorf("Cannot build, no language helper found for %v", *ff.Runtime)
|
||||
return fmt.Errorf("Cannot build, no language helper found for %v", ff.Runtime)
|
||||
}
|
||||
dockerfile, err = writeTmpDockerfile(helper, dir, ff)
|
||||
if err != nil {
|
||||
@@ -106,7 +110,7 @@ func dockerbuild(verbwriter io.Writer, path string, ff *funcfile, noCache bool)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Building image %v\n", ff.FullName())
|
||||
fmt.Printf("Building image %v\n", ff.ImageName())
|
||||
|
||||
cancel := make(chan os.Signal, 3)
|
||||
signal.Notify(cancel, os.Interrupt) // and others perhaps
|
||||
@@ -117,7 +121,7 @@ func dockerbuild(verbwriter io.Writer, path string, ff *funcfile, noCache bool)
|
||||
go func(done chan<- error) {
|
||||
args := []string{
|
||||
"build",
|
||||
"-t", ff.FullName(),
|
||||
"-t", ff.ImageName(),
|
||||
"-f", dockerfile,
|
||||
}
|
||||
if noCache {
|
||||
@@ -261,8 +265,12 @@ func extractEnvConfig(configs []string) map[string]string {
|
||||
}
|
||||
|
||||
func dockerpush(ff *funcfile) error {
|
||||
fmt.Println("Pushing to docker registry...")
|
||||
cmd := exec.Command("docker", "push", ff.FullName())
|
||||
err := validImageName(ff.ImageName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Pushing %v to docker registry...", ff.ImageName())
|
||||
cmd := exec.Command("docker", "push", ff.ImageName())
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
if err := cmd.Run(); err != nil {
|
||||
@@ -271,6 +279,19 @@ func dockerpush(ff *funcfile) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validImageName(n string) error {
|
||||
// must have at least owner name and a tag
|
||||
split := strings.Split(n, ":")
|
||||
if len(split) < 2 {
|
||||
return errors.New("image name must have a tag")
|
||||
}
|
||||
split2 := strings.Split(split[0], "/")
|
||||
if len(split2) < 2 {
|
||||
return errors.New("image name must have an owner and name, eg: username/myfunc. Be sure to set FN_REGISTRY env var or pass in --registry.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appNamePath(img string) (string, string) {
|
||||
sep := strings.Index(img, "/")
|
||||
if sep < 0 {
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
@@ -40,8 +39,11 @@ type deploycmd struct {
|
||||
incremental bool
|
||||
skippush bool
|
||||
noCache bool
|
||||
registry string
|
||||
}
|
||||
|
||||
verbwriter io.Writer
|
||||
func (cmd *deploycmd) Registry() string {
|
||||
return cmd.registry
|
||||
}
|
||||
|
||||
func (p *deploycmd) flags() []cli.Flag {
|
||||
@@ -73,18 +75,23 @@ func (p *deploycmd) flags() []cli.Flag {
|
||||
Usage: "does not push Docker built images onto Docker Hub - useful for local development.",
|
||||
Destination: &p.skippush,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "registry",
|
||||
Usage: "Sets the Docker owner for images and optionally the registry. This will be prefixed to your function name for pushing to Docker registries. eg: `--registry username` will set your Docker Hub owner. `--registry registry.hub.docker.com/username` will set the registry and owner.",
|
||||
Destination: &p.registry,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *deploycmd) scan(c *cli.Context) error {
|
||||
p.appName = c.Args().First()
|
||||
p.verbwriter = verbwriter(p.verbose)
|
||||
|
||||
var walked bool
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatalln("Couldn't get working directory:", err)
|
||||
}
|
||||
setRegistryEnv(p)
|
||||
|
||||
err = filepath.Walk(wd, func(path string, info os.FileInfo, err error) error {
|
||||
if path != wd && info.IsDir() {
|
||||
@@ -101,7 +108,7 @@ func (p *deploycmd) scan(c *cli.Context) error {
|
||||
|
||||
e := p.deploy(c, path)
|
||||
if err != nil {
|
||||
fmt.Fprintln(p.verbwriter, path, e)
|
||||
fmt.Println(path, e)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
@@ -110,7 +117,7 @@ func (p *deploycmd) scan(c *cli.Context) error {
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(p.verbwriter, "error: %s\n", err)
|
||||
fmt.Printf("error: %s\n", err)
|
||||
}
|
||||
|
||||
if !walked {
|
||||
@@ -132,7 +139,7 @@ func (p *deploycmd) deploy(c *cli.Context, funcFilePath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
funcfile, err := buildfunc(p.verbwriter, funcFileName, p.noCache)
|
||||
funcfile, err := buildfunc(funcFileName, p.noCache)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -152,7 +159,7 @@ func (p *deploycmd) deploy(c *cli.Context, funcFilePath string) error {
|
||||
}
|
||||
|
||||
func (p *deploycmd) route(c *cli.Context, ff *funcfile) error {
|
||||
fmt.Printf("Updating route %s using image %s...\n", ff.Path, ff.FullName())
|
||||
fmt.Printf("Updating route %s using image %s...\n", ff.Path, ff.ImageName())
|
||||
if err := resetBasePath(p.Configuration); err != nil {
|
||||
return fmt.Errorf("error setting endpoint: %v", err)
|
||||
}
|
||||
|
||||
114
cli/funcfile.go
114
cli/funcfile.go
@@ -9,7 +9,6 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
fnmodels "github.com/funcy/functions_go/models"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
@@ -39,43 +38,9 @@ type fftest struct {
|
||||
}
|
||||
|
||||
type funcfile struct {
|
||||
fnmodels.Route
|
||||
|
||||
Name string `yaml:"name,omitempty" json:"name,omitempty"`
|
||||
Version string `yaml:"version,omitempty" json:"version,omitempty"`
|
||||
Runtime *string `yaml:"runtime,omitempty" json:"runtime,omitempty"`
|
||||
Entrypoint string `yaml:"entrypoint,omitempty" json:"entrypoint,omitempty"`
|
||||
Cmd string `yaml:"cmd,omitempty" json:"cmd,omitempty"`
|
||||
Build []string `yaml:"build,omitempty" json:"build,omitempty"`
|
||||
Tests []fftest `yaml:"tests,omitempty" json:"tests,omitempty"`
|
||||
}
|
||||
|
||||
func (ff *funcfile) FullName() string {
|
||||
fname := ff.Name
|
||||
if ff.Version != "" {
|
||||
fname = fmt.Sprintf("%s:%s", fname, ff.Version)
|
||||
}
|
||||
return fname
|
||||
}
|
||||
|
||||
func (ff *funcfile) RuntimeTag() (runtime, tag string) {
|
||||
if ff.Runtime == nil {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
rt := *ff.Runtime
|
||||
tagpos := strings.Index(rt, ":")
|
||||
if tagpos == -1 {
|
||||
return rt, ""
|
||||
}
|
||||
|
||||
return rt[:tagpos], rt[tagpos+1:]
|
||||
}
|
||||
|
||||
type flatfuncfile struct {
|
||||
Name string `yaml:"name,omitempty" json:"name,omitempty"`
|
||||
Version string `yaml:"version,omitempty" json:"version,omitempty"`
|
||||
Runtime *string `yaml:"runtime,omitempty" json:"runtime,omitempty"`
|
||||
Runtime string `yaml:"runtime,omitempty" json:"runtime,omitempty"`
|
||||
Entrypoint string `yaml:"entrypoint,omitempty" json:"entrypoint,omitempty"`
|
||||
Cmd string `yaml:"cmd,omitempty" json:"cmd,omitempty"`
|
||||
Build []string `yaml:"build,omitempty" json:"build,omitempty"`
|
||||
@@ -91,44 +56,36 @@ type flatfuncfile struct {
|
||||
Headers map[string][]string `yaml:"headers,omitempty" json:"headers,omitempty"`
|
||||
}
|
||||
|
||||
func (ff *funcfile) MakeFlat() flatfuncfile {
|
||||
return flatfuncfile{
|
||||
Name: ff.Name,
|
||||
Version: ff.Version,
|
||||
Runtime: ff.Runtime,
|
||||
Entrypoint: ff.Entrypoint,
|
||||
Cmd: ff.Cmd,
|
||||
Build: ff.Build,
|
||||
Tests: ff.Tests,
|
||||
// route-specific
|
||||
Type: ff.Type,
|
||||
Memory: ff.Memory,
|
||||
Format: ff.Format,
|
||||
Timeout: ff.Timeout,
|
||||
Path: ff.Path,
|
||||
Config: ff.Config,
|
||||
Headers: ff.Headers,
|
||||
func (ff *funcfile) ImageName() string {
|
||||
fname := ff.Name
|
||||
if !strings.Contains(fname, "/") {
|
||||
// then we'll prefix FN_REGISTRY
|
||||
reg := os.Getenv(envFnRegistry)
|
||||
if reg != "" {
|
||||
if reg[len(reg)-1] != '/' {
|
||||
reg += "/"
|
||||
}
|
||||
fname = fmt.Sprintf("%s%s", reg, fname)
|
||||
}
|
||||
}
|
||||
if ff.Version != "" {
|
||||
fname = fmt.Sprintf("%s:%s", fname, ff.Version)
|
||||
}
|
||||
return fname
|
||||
}
|
||||
|
||||
func (fff *flatfuncfile) MakeFuncFile() *funcfile {
|
||||
ff := &funcfile{
|
||||
Name: fff.Name,
|
||||
Version: fff.Version,
|
||||
Runtime: fff.Runtime,
|
||||
Entrypoint: fff.Entrypoint,
|
||||
Cmd: fff.Cmd,
|
||||
Build: fff.Build,
|
||||
Tests: fff.Tests,
|
||||
func (ff *funcfile) RuntimeTag() (runtime, tag string) {
|
||||
if ff.Runtime == "" {
|
||||
return "", ""
|
||||
}
|
||||
ff.Type = fff.Type
|
||||
ff.Memory = fff.Memory
|
||||
ff.Format = fff.Format
|
||||
ff.Timeout = fff.Timeout
|
||||
ff.Path = fff.Path
|
||||
ff.Config = fff.Config
|
||||
ff.Headers = fff.Headers
|
||||
return ff
|
||||
|
||||
rt := ff.Runtime
|
||||
tagpos := strings.Index(rt, ":")
|
||||
if tagpos == -1 {
|
||||
return rt, ""
|
||||
}
|
||||
|
||||
return rt[:tagpos], rt[tagpos+1:]
|
||||
}
|
||||
|
||||
func findFuncfile(path string) (string, error) {
|
||||
@@ -176,9 +133,10 @@ func decodeFuncfileJSON(path string) (*funcfile, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not open %s for parsing. Error: %v", path, err)
|
||||
}
|
||||
fff := new(flatfuncfile)
|
||||
err = json.NewDecoder(f).Decode(fff)
|
||||
ff := fff.MakeFuncFile()
|
||||
ff := &funcfile{}
|
||||
// ff.Route = &fnmodels.Route{}
|
||||
err = json.NewDecoder(f).Decode(ff)
|
||||
// ff := fff.MakeFuncFile()
|
||||
return ff, err
|
||||
}
|
||||
|
||||
@@ -187,9 +145,9 @@ func decodeFuncfileYAML(path string) (*funcfile, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not open %s for parsing. Error: %v", path, err)
|
||||
}
|
||||
fff := new(flatfuncfile)
|
||||
err = yaml.Unmarshal(b, fff)
|
||||
ff := fff.MakeFuncFile()
|
||||
ff := &funcfile{}
|
||||
err = yaml.Unmarshal(b, ff)
|
||||
// ff := fff.MakeFuncFile()
|
||||
return ff, err
|
||||
}
|
||||
|
||||
@@ -198,11 +156,11 @@ func encodeFuncfileJSON(path string, ff *funcfile) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not open %s for encoding. Error: %v", path, err)
|
||||
}
|
||||
return json.NewEncoder(f).Encode(ff.MakeFlat())
|
||||
return json.NewEncoder(f).Encode(ff)
|
||||
}
|
||||
|
||||
func encodeFuncfileYAML(path string, ff *funcfile) error {
|
||||
b, err := yaml.Marshal(ff.MakeFlat())
|
||||
b, err := yaml.Marshal(ff)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not encode function file. Error: %v", err)
|
||||
}
|
||||
|
||||
88
cli/init.go
88
cli/init.go
@@ -45,12 +45,8 @@ func init() {
|
||||
}
|
||||
|
||||
type initFnCmd struct {
|
||||
name string
|
||||
force bool
|
||||
runtime string
|
||||
entrypoint string
|
||||
cmd string
|
||||
version string
|
||||
force bool
|
||||
funcfile
|
||||
}
|
||||
|
||||
func initFlags(a *initFnCmd) []cli.Flag {
|
||||
@@ -63,17 +59,22 @@ func initFlags(a *initFnCmd) []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "choose an existing runtime - " + strings.Join(fnInitRuntimes, ", "),
|
||||
Destination: &a.runtime,
|
||||
Destination: &a.Runtime,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "entrypoint",
|
||||
Usage: "entrypoint is the command to run to start this function - equivalent to Dockerfile ENTRYPOINT.",
|
||||
Destination: &a.entrypoint,
|
||||
Destination: &a.Entrypoint,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cmd",
|
||||
Usage: "command to run to start this function - equivalent to Dockerfile CMD.",
|
||||
Destination: &a.Entrypoint,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "version",
|
||||
Usage: "function version",
|
||||
Destination: &a.version,
|
||||
Destination: &a.Version,
|
||||
Value: initialVersion,
|
||||
},
|
||||
}
|
||||
@@ -82,15 +83,16 @@ func initFlags(a *initFnCmd) []cli.Flag {
|
||||
}
|
||||
|
||||
func initFn() cli.Command {
|
||||
a := initFnCmd{}
|
||||
a := &initFnCmd{}
|
||||
// funcfile := &funcfile{}
|
||||
|
||||
return cli.Command{
|
||||
Name: "init",
|
||||
Usage: "create a local func.yaml file",
|
||||
Description: "Creates a func.yaml file in the current directory. ",
|
||||
ArgsUsage: "<DOCKERHUB_USERNAME/FUNCTION_NAME>",
|
||||
Description: "Creates a func.yaml file in the current directory.",
|
||||
ArgsUsage: "[FUNCTION_NAME]",
|
||||
Action: a.init,
|
||||
Flags: initFlags(&a),
|
||||
Flags: initFlags(a),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,13 +111,13 @@ func (a *initFnCmd) init(c *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
runtimeSpecified := a.runtime != ""
|
||||
|
||||
err := a.buildFuncFile(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtimeSpecified := a.Runtime != ""
|
||||
|
||||
if runtimeSpecified {
|
||||
err := a.generateBoilerplate()
|
||||
if err != nil {
|
||||
@@ -123,21 +125,12 @@ func (a *initFnCmd) init(c *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
ff := &funcfile{
|
||||
*rt,
|
||||
a.name,
|
||||
a.version,
|
||||
&a.runtime,
|
||||
a.entrypoint,
|
||||
a.cmd,
|
||||
[]string{},
|
||||
[]fftest{},
|
||||
}
|
||||
ff := a.funcfile
|
||||
|
||||
_, path := appNamePath(ff.FullName())
|
||||
_, path := appNamePath(ff.ImageName())
|
||||
ff.Path = path
|
||||
|
||||
if err := encodeFuncfileYAML("func.yaml", ff); err != nil {
|
||||
if err := encodeFuncfileYAML("func.yaml", &ff); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -146,7 +139,7 @@ func (a *initFnCmd) init(c *cli.Context) error {
|
||||
}
|
||||
|
||||
func (a *initFnCmd) generateBoilerplate() error {
|
||||
helper := langs.GetLangHelper(a.runtime)
|
||||
helper := langs.GetLangHelper(a.Runtime)
|
||||
if helper != nil && helper.HasBoilerplate() {
|
||||
if err := helper.GenerateBoilerplate(); err != nil {
|
||||
if err == langs.ErrBoilerplateExists {
|
||||
@@ -162,47 +155,52 @@ func (a *initFnCmd) generateBoilerplate() error {
|
||||
func (a *initFnCmd) buildFuncFile(c *cli.Context) error {
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error detecting current working directory: %s", err)
|
||||
return fmt.Errorf("error detecting current working directory: %v", err)
|
||||
}
|
||||
|
||||
a.name = c.Args().First()
|
||||
if a.name == "" || strings.Contains(a.name, ":") {
|
||||
return errors.New("please specify a name for your function in the following format <DOCKERHUB_USERNAME>/<FUNCTION_NAME>.\nTry: fn init <DOCKERHUB_USERNAME>/<FUNCTION_NAME>")
|
||||
a.Name = c.Args().First()
|
||||
// if a.name == "" {
|
||||
// // return errors.New("please specify a name for your function.\nTry: fn init <FUNCTION_NAME>")
|
||||
// } else
|
||||
if a.Name == "" {
|
||||
// then use current directory for name
|
||||
a.Name = filepath.Base(pwd)
|
||||
} else if strings.Contains(a.Name, ":") {
|
||||
return errors.New("function name cannot contain a colon")
|
||||
}
|
||||
|
||||
if exists("Dockerfile") {
|
||||
fmt.Println("Dockerfile found. Let's use that to build...")
|
||||
return nil
|
||||
}
|
||||
|
||||
var rt string
|
||||
if a.runtime == "" {
|
||||
if a.Runtime == "" {
|
||||
rt, err = detectRuntime(pwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.runtime = rt
|
||||
a.Runtime = rt
|
||||
fmt.Printf("Found %v, assuming %v runtime.\n", rt, rt)
|
||||
} else {
|
||||
fmt.Println("Runtime:", a.runtime)
|
||||
fmt.Println("Runtime:", a.Runtime)
|
||||
}
|
||||
helper := langs.GetLangHelper(a.runtime)
|
||||
helper := langs.GetLangHelper(a.Runtime)
|
||||
if helper == nil {
|
||||
fmt.Printf("init does not support the %s runtime, you'll have to create your own Dockerfile for this function", a.runtime)
|
||||
fmt.Printf("init does not support the %s runtime, you'll have to create your own Dockerfile for this function", a.Runtime)
|
||||
}
|
||||
|
||||
if a.entrypoint == "" {
|
||||
if a.Entrypoint == "" {
|
||||
if helper != nil {
|
||||
a.entrypoint = helper.Entrypoint()
|
||||
a.Entrypoint = helper.Entrypoint()
|
||||
}
|
||||
}
|
||||
if a.cmd == "" {
|
||||
if a.Cmd == "" {
|
||||
if helper != nil {
|
||||
a.cmd = helper.Cmd()
|
||||
a.Cmd = helper.Cmd()
|
||||
}
|
||||
}
|
||||
if a.entrypoint == "" && a.cmd == "" {
|
||||
return fmt.Errorf("could not detect entrypoint or cmd for %v, use --entrypoint and/or --cmd to set them explicitly", a.runtime)
|
||||
if a.Entrypoint == "" && a.Cmd == "" {
|
||||
return fmt.Errorf("could not detect entrypoint or cmd for %v, use --entrypoint and/or --cmd to set them explicitly", a.Runtime)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -221,5 +219,5 @@ func detectRuntime(path string) (runtime string, err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("no supported files found to guess runtime, please set runtime explicitly with --runtime flag.")
|
||||
return "", fmt.Errorf("no supported files found to guess runtime, please set runtime explicitly with --runtime flag")
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ func createFunctionYaml(opts createImageOptions, functionName string) error {
|
||||
funcDesc := &funcfile{
|
||||
Name: opts.Name,
|
||||
Version: "0.0.1",
|
||||
Runtime: &opts.Base,
|
||||
Runtime: opts.Base,
|
||||
Cmd: opts.Handler,
|
||||
}
|
||||
funcDesc.Config = opts.Config
|
||||
|
||||
@@ -132,7 +132,7 @@ func main() {
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
// TODO: this doesn't seem to get called even when an error returns from a command, but maybe urfave is doing a non zero exit anyways? nope: https://github.com/urfave/cli/issues/610
|
||||
fmt.Printf("Error occurred: %v, exiting...\n", err)
|
||||
fmt.Fprintf(os.Stderr, "Error occurred: %v, exiting...\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
18
cli/push.go
18
cli/push.go
@@ -20,7 +20,12 @@ func push() cli.Command {
|
||||
}
|
||||
|
||||
type pushcmd struct {
|
||||
verbose bool
|
||||
verbose bool
|
||||
registry string
|
||||
}
|
||||
|
||||
func (cmd *pushcmd) Registry() string {
|
||||
return cmd.registry
|
||||
}
|
||||
|
||||
func (p *pushcmd) flags() []cli.Flag {
|
||||
@@ -30,6 +35,11 @@ func (p *pushcmd) flags() []cli.Flag {
|
||||
Usage: "verbose mode",
|
||||
Destination: &p.verbose,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "registry",
|
||||
Usage: "Sets the Docker owner for images and optionally the registry. This will be prefixed to your function name for pushing to Docker registries. eg: `--registry username` will set your Docker Hub owner. `--registry registry.hub.docker.com/username` will set the registry and owner.",
|
||||
Destination: &p.registry,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +48,7 @@ func (p *pushcmd) flags() []cli.Flag {
|
||||
// push the container, and finally it will update function's route. Optionally,
|
||||
// the route can be overriden inside the functions file.
|
||||
func (p *pushcmd) push(c *cli.Context) error {
|
||||
verbwriter := verbwriter(p.verbose)
|
||||
setRegistryEnv(p)
|
||||
|
||||
ff, err := loadFuncfile()
|
||||
if err != nil {
|
||||
@@ -48,12 +58,12 @@ func (p *pushcmd) push(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintln(verbwriter, "pushing", ff.FullName())
|
||||
fmt.Println("pushing", ff.ImageName())
|
||||
|
||||
if err := dockerpush(ff); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Function %v pushed successfully to Docker Hub.\n", ff.FullName())
|
||||
fmt.Printf("Function %v pushed successfully to Docker Hub.\n", ff.ImageName())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -268,8 +268,8 @@ func routeWithFuncFile(c *cli.Context, ff *funcfile, rt *fnmodels.Route) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if ff.FullName() != "" { // args take precedence
|
||||
rt.Image = ff.FullName()
|
||||
if ff.ImageName() != "" { // args take precedence
|
||||
rt.Image = ff.ImageName()
|
||||
}
|
||||
if ff.Format != "" {
|
||||
rt.Format = ff.Format
|
||||
|
||||
@@ -176,7 +176,7 @@ func runff(ff *funcfile, stdin io.Reader, stdout, stderr io.Writer, method strin
|
||||
stdin = strings.NewReader(body)
|
||||
}
|
||||
|
||||
sh = append(sh, ff.FullName())
|
||||
sh = append(sh, ff.ImageName())
|
||||
cmd := exec.Command(sh[0], sh[1:]...)
|
||||
cmd.Stdin = stdin
|
||||
cmd.Stdout = stdout
|
||||
|
||||
@@ -95,7 +95,7 @@ func (t *testcmd) test(c *cli.Context) error {
|
||||
|
||||
fmt.Printf("Running %v tests...", len(tests))
|
||||
|
||||
target := ff.FullName()
|
||||
target := ff.ImageName()
|
||||
runtest := runlocaltest
|
||||
if t.remote != "" {
|
||||
if ff.Path == "" {
|
||||
@@ -116,7 +116,7 @@ func (t *testcmd) test(c *cli.Context) error {
|
||||
}
|
||||
|
||||
errorCount := 0
|
||||
fmt.Println("running tests on", ff.FullName(), ":")
|
||||
fmt.Println("running tests on", ff.ImageName(), ":")
|
||||
for i, tt := range tests {
|
||||
fmt.Printf("\nTest %v\n", i+1)
|
||||
start := time.Now()
|
||||
|
||||
Reference in New Issue
Block a user