Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addons #264

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
52 changes: 29 additions & 23 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module github.com/koyeb/koyeb-cli

go 1.21
go 1.23

toolchain go1.22.3
toolchain go1.23.3

require (
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
Expand All @@ -15,59 +15,65 @@ require (
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/manifoldco/promptui v0.9.0
github.com/mitchellh/go-homedir v1.1.0
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae
github.com/moby/term v0.5.0
github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/errors v0.9.1
github.com/replicate/cog v0.13.6
github.com/rhysd/go-github-selfupdate v1.2.3
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.5.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.13.0
github.com/stretchr/testify v1.8.0
github.com/stretchr/testify v1.10.0
github.com/yudai/gojsondiff v1.0.0
golang.org/x/term v0.8.0
golang.org/x/term v0.27.0
)

require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/google/go-github/v30 v30.1.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/onsi/gomega v1.34.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/tcnksm/go-gitconfig v0.1.2 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xeonx/timeago v1.0.0-rc5 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/yudai/pp v2.0.1+incompatible // indirect
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
golang.org/x/net v0.0.0-20220927171203-f486391704dc // indirect
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
golang.org/x/crypto v0.30.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

replace github.com/replicate/cog v0.13.6 => github.com/bchatelard/cog v0.0.0-20241219173637-45a302b8f76c
200 changes: 65 additions & 135 deletions go.sum

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/koyeb/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ $ koyeb completion fish > ~/.config/fish/completions/koyeb.fish
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.ExactValidArgs(1),
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
RunE: func(cmd *cobra.Command, args []string) error {
switch args[0] {
case "bash":
Expand Down
73 changes: 59 additions & 14 deletions pkg/koyeb/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,34 @@ func NewDeployCmd() *cobra.Command {
return err
}

if serviceId == "" {
createService := koyeb.NewCreateServiceWithDefaults()
createDefinition := koyeb.NewDeploymentDefinitionWithDefaults()
// Parse the flags for the addons.
addons, err := serviceHandler.parseAddonsFlags(ctx, cmd.Flags())
if err != nil {
return err
}
addonsHandler, err := NewAddonsHandler(addons)
if err != nil {
return err
}

log.Infof("Creating and uploading an archive from `%s`", args[0])
archiveReply, err := archiveHandler.CreateArchive(ctx, args[0])
// Setup the addons.
if err := addonsHandler.Setup(ctx, args[0]); err != nil {
return err
}
defer func() {
err := addonsHandler.Cleanup(ctx)
if err != nil {
return err
log.Errorf("Error while cleaning up addons: %s", err)
}
}()

if serviceId == "" {
createService := koyeb.NewCreateServiceWithDefaults()
createDefinition := koyeb.NewDeploymentDefinitionWithDefaults()

createDefinition.Name = koyeb.PtrString(serviceName)

archive := createDefinition.GetArchive()
archive.Id = archiveReply.GetArchive().Id
createDefinition.SetArchive(archive)
createDefinition.Git = nil
createDefinition.Docker = nil
Expand All @@ -77,12 +91,26 @@ func NewDeployCmd() *cobra.Command {
if err := serviceHandler.parseServiceDefinitionFlags(ctx, cmd.Flags(), createDefinition); err != nil {
return err
}

if err = addonsHandler.PreDeploy(ctx, createDefinition); err != nil {
return err
}

log.Infof("Creating and uploading an archive from `%s`", args[0])
archiveReply, err := archiveHandler.CreateArchive(ctx, args[0])
if err != nil {
return err
}
createDefinition.Archive.Id = archiveReply.GetArchive().Id
createService.SetDefinition(*createDefinition)

log.Infof("Creating the new service `%s`", serviceName)
if err := serviceHandler.Create(ctx, cmd, []string{args[1]}, createService); err != nil {
return err
}
if err = addonsHandler.PostDeploy(ctx, createDefinition); err != nil {
return err
}
} else {
updateService := koyeb.NewUpdateServiceWithDefaults()
latestDeploy, resp, err := ctx.Client.DeploymentsApi.
Expand Down Expand Up @@ -113,14 +141,7 @@ func NewDeployCmd() *cobra.Command {

updateDefinition := latestDeploy.GetDeployments()[0].Definition

log.Infof("Creating and uploading an archive from `%s`", args[0])
archiveReply, err := archiveHandler.CreateArchive(ctx, args[0])
if err != nil {
return err
}

archive := updateDefinition.GetArchive()
archive.Id = archiveReply.GetArchive().Id
updateDefinition.SetArchive(archive)
updateDefinition.Git = nil
updateDefinition.Docker = nil
Expand All @@ -134,19 +155,43 @@ func NewDeployCmd() *cobra.Command {
if err != nil {
return err
}

if err = addonsHandler.PreDeploy(ctx, updateDefinition); err != nil {
return err
}

log.Infof("Creating and uploading an archive from `%s`", args[0])
archiveReply, err := archiveHandler.CreateArchive(ctx, args[0])
if err != nil {
return err
}
updateDefinition.Archive.Id = archiveReply.GetArchive().Id
updateService.SetDefinition(*updateDefinition)

log.Infof("Updating the existing service `%s`", serviceName)
if err := serviceHandler.Update(ctx, cmd, []string{args[1]}, updateService); err != nil {
return err
}
if err = addonsHandler.PostDeploy(ctx, updateDefinition); err != nil {
return err
}
}

return nil
}),
}
deployCmd.Flags().String("app", "", "Service application. Can also be provided in the service name with the format <app>/<service>")
serviceHandler.addServiceDefinitionFlagsForAllSources(deployCmd.Flags())
serviceHandler.addServiceDefinitionFlagsForArchiveSource(deployCmd.Flags())

// Add addons flags to the deploy command.
deployCmd.Flags().StringSlice(
"addons",
[]string{},
"List of addons, the addons will be executed localy before the deployment",
)
_ = deployCmd.Flags().MarkHidden("addons")

return deployCmd
}

Expand Down
88 changes: 88 additions & 0 deletions pkg/koyeb/deploy_addons.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package koyeb

import (
"fmt"
"path/filepath"

"github.com/koyeb/koyeb-api-client-go/api/v1/koyeb"
log "github.com/sirupsen/logrus"
)

type addonsHandler struct {
addons []Addon
}

func NewAddonsHandler(addons []string) (*addonsHandler, error) {
handler := &addonsHandler{}

for _, addon := range addons {
log.Infof("Registering addon: %s", addon)
err := handler.RegisterAddon(addon)
if err != nil {
return nil, err
}
}

return handler, nil
}

type Addon interface {
Setup(ctx *CLIContext, dir string) error
PreDeploy(ctx *CLIContext, definition *koyeb.DeploymentDefinition) error
PostDeploy(ctx *CLIContext, definition *koyeb.DeploymentDefinition) error
Cleanup(ctx *CLIContext) error
}

func (h *addonsHandler) RegisterAddon(name string) error {
switch name {
case "cog":
h.addons = append(h.addons, &cogAddon{})
default:
return fmt.Errorf("unknown addon: %s", name)
}
return nil
}

func (h *addonsHandler) PreDeploy(ctx *CLIContext, definition *koyeb.DeploymentDefinition) error {
for _, addon := range h.addons {
log.Debugf("Running addon pre-deploy")
if err := addon.PreDeploy(ctx, definition); err != nil {
return err
}
}
return nil
}

func (h *addonsHandler) PostDeploy(ctx *CLIContext, definition *koyeb.DeploymentDefinition) error {
for _, addon := range h.addons {
log.Debugf("Running addon post-deploy")
if err := addon.PostDeploy(ctx, definition); err != nil {
return err
}
}
return nil
}

func (h *addonsHandler) Setup(ctx *CLIContext, dir string) error {
basePath, err := filepath.Abs(dir)
if err != nil {
return err
}
for _, addon := range h.addons {
log.Debugf("Running addon setup in dir %s", dir)
if err := addon.Setup(ctx, basePath); err != nil {
return err
}
}
return nil
}

func (h *addonsHandler) Cleanup(ctx *CLIContext) error {
for _, addon := range h.addons {
log.Debugf("Running addon cleanup")
if err := addon.Cleanup(ctx); err != nil {
return err
}
}
return nil
}
Loading
Loading