Skip to content

Commit

Permalink
adds name to framework; defaults export commands to stdout; omitempty…
Browse files Browse the repository at this point in the history
… on application.version
  • Loading branch information
stinkyfingers committed Jul 20, 2021
1 parent 92056ca commit c5d14ee
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 40 deletions.
2 changes: 1 addition & 1 deletion cmd/ketch/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func newAppCmd(cfg config, out io.Writer, packSvc *pack.Client, configDefaultBui
cmd.AddCommand(newAppInfoCmd(cfg, out))
cmd.AddCommand(newAppStartCmd(cfg, out, appStart))
cmd.AddCommand(newAppStopCmd(cfg, out, appStop))
cmd.AddCommand(newAppExportCmd(cfg, exportApp))
cmd.AddCommand(newAppExportCmd(cfg, exportApp, out))
return cmd
}

Expand Down
34 changes: 19 additions & 15 deletions cmd/ketch/app_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"io"
"os"

"github.com/spf13/cobra"
Expand All @@ -17,9 +18,9 @@ const appExportHelp = `
Export an application as a yaml file.
`

type appExportFn func(ctx context.Context, cfg config, options appExportOptions) error
type appExportFn func(ctx context.Context, cfg config, options appExportOptions, out io.Writer) error

func newAppExportCmd(cfg config, appExport appExportFn) *cobra.Command {
func newAppExportCmd(cfg config, appExport appExportFn, out io.Writer) *cobra.Command {
options := appExportOptions{}
cmd := &cobra.Command{
Use: "export APPNAME",
Expand All @@ -28,13 +29,13 @@ func newAppExportCmd(cfg config, appExport appExportFn) *cobra.Command {
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
options.appName = args[0]
return appExport(cmd.Context(), cfg, options)
return appExport(cmd.Context(), cfg, options, out)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return autoCompleteAppNames(cfg, toComplete)
},
}
cmd.Flags().StringVarP(&options.filename, "file", "f", "app.yaml", "filename for app export")
cmd.Flags().StringVarP(&options.filename, "file", "f", "", "filename for app export")
return cmd
}

Expand All @@ -43,26 +44,29 @@ type appExportOptions struct {
filename string
}

func exportApp(ctx context.Context, cfg config, options appExportOptions) error {
func exportApp(ctx context.Context, cfg config, options appExportOptions, out io.Writer) error {
app := ketchv1.App{}
if err := cfg.Client().Get(ctx, types.NamespacedName{Name: options.appName}, &app); err != nil {
return fmt.Errorf("failed to get app: %w", err)
}
application := deploy.GetApplicationFromKetchApp(app)
// open file, err if exist, write application
_, err := os.Stat(options.filename)
if !os.IsNotExist(err) {
return errFileExists
if options.filename != "" {
// open file, err if exist, write application
_, err := os.Stat(options.filename)
if !os.IsNotExist(err) {
return errFileExists
}
f, err := os.Create(options.filename)
if err != nil {
return err
}
defer f.Close()
out = f
}
f, err := os.Create(options.filename)
if err != nil {
return err
}
defer f.Close()
b, err := yaml.Marshal(application)
if err != nil {
return err
}
_, err = f.Write(b)
_, err = out.Write(b)
return err
}
36 changes: 32 additions & 4 deletions cmd/ketch/app_export_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"bytes"
"context"
"io"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -29,7 +31,7 @@ func Test_newAppExportCmd(t *testing.T) {
{
name: "happy path",
args: []string{"foo-bar"},
appExport: func(ctx context.Context, cfg config, options appExportOptions) error {
appExport: func(ctx context.Context, cfg config, options appExportOptions, out io.Writer) error {
require.Equal(t, "foo-bar", options.appName)
return nil
},
Expand All @@ -42,7 +44,7 @@ func Test_newAppExportCmd(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := newAppExportCmd(nil, tt.appExport)
cmd := newAppExportCmd(nil, tt.appExport, &bytes.Buffer{})
cmd.SetArgs(tt.args)
err := cmd.Execute()
if tt.wantErr {
Expand Down Expand Up @@ -112,6 +114,27 @@ func Test_appExport(t *testing.T) {
},
},
},
options: appExportOptions{
appName: "dashboard",
filename: "app.yaml",
},
wantOut: `framework: gke
name: dashboard
type: Application
version: v1
`,
},
{
name: "success - stdout",
cfg: &mocks.Configuration{
CtrlClientObjects: []runtime.Object{dashboard, gke},
StorageInstance: &mockStorage{
OnGet: func(name string) (*templates.Templates, error) {
require.Equal(t, templates.IngressConfigMapName(ketchv1.IstioIngressControllerType.String()), name)
return &templates.Templates{}, nil
},
},
},
options: appExportOptions{
appName: "dashboard",
},
Expand All @@ -136,15 +159,20 @@ version: v1
t.Run(tt.name, func(t *testing.T) {
tt.options.filename = filepath.Join(t.TempDir(), "app.yaml")
defer os.Remove(tt.options.filename)

err := exportApp(context.Background(), tt.cfg, tt.options)
buf := &bytes.Buffer{}
err := exportApp(context.Background(), tt.cfg, tt.options, buf)
if tt.wantErr != "" {
require.Equal(t, err.Error(), tt.wantErr)
return
} else {
require.Nil(t, err)
}
if tt.options.filename != "" {
b, err := os.ReadFile(tt.options.filename)
require.Nil(t, err)
require.Equal(t, tt.wantOut, string(b))
} else {
require.Equal(t, tt.wantOut, buf.String())
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/ketch/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func newFrameworkCmd(cfg config, out io.Writer) *cobra.Command {
cmd.AddCommand(newFrameworkAddCmd(cfg, out, addFramework))
cmd.AddCommand(newFrameworkRemoveCmd(cfg, out))
cmd.AddCommand(newFrameworkUpdateCmd(cfg, out))
cmd.AddCommand(newFrameworkExportCmd(cfg))
cmd.AddCommand(newFrameworkExportCmd(cfg, out))
return cmd
}

Expand Down
1 change: 1 addition & 0 deletions cmd/ketch/framework_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func newFrameworkFromArgs(options frameworkAddOptions) *ketchv1.Framework {
Name: options.name,
},
Spec: ketchv1.FrameworkSpec{
Name: options.name,
NamespaceName: namespace,
AppQuotaLimit: &options.appQuotaLimit,
IngressController: ketchv1.IngressControllerSpec{
Expand Down
5 changes: 5 additions & 0 deletions cmd/ketch/framework_add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ ingressController:
ingressClusterIssuer: "le-production",
},
wantFrameworkSpec: ketchv1.FrameworkSpec{
Name: "hello",
NamespaceName: "gke",
AppQuotaLimit: conversions.IntPtr(5),
IngressController: ketchv1.IngressControllerSpec{
Expand Down Expand Up @@ -135,6 +136,7 @@ ingressController:
ingressClusterIssuer: "le-production",
},
wantFrameworkSpec: ketchv1.FrameworkSpec{
Name: "hello",
NamespaceName: "gke",
AppQuotaLimit: conversions.IntPtr(5),
IngressController: ketchv1.IngressControllerSpec{
Expand All @@ -160,6 +162,7 @@ ingressController:
ingressType: traefik,
},
wantFrameworkSpec: ketchv1.FrameworkSpec{
Name: "aws",
NamespaceName: "ketch-aws",
AppQuotaLimit: conversions.IntPtr(5),
IngressController: ketchv1.IngressControllerSpec{
Expand Down Expand Up @@ -367,6 +370,7 @@ func TestNewFrameworkFromArgs(t *testing.T) {
Name: "hello",
},
Spec: ketchv1.FrameworkSpec{
Name: "hello",
NamespaceName: "my-namespace",
AppQuotaLimit: conversions.IntPtr(5),
IngressController: ketchv1.IngressControllerSpec{
Expand All @@ -389,6 +393,7 @@ func TestNewFrameworkFromArgs(t *testing.T) {
Name: "hello",
},
Spec: ketchv1.FrameworkSpec{
Name: "hello",
NamespaceName: "ketch-hello",
AppQuotaLimit: conversions.IntPtr(5),
IngressController: ketchv1.IngressControllerSpec{
Expand Down
33 changes: 19 additions & 14 deletions cmd/ketch/framework_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"errors"
"io"
"os"

"github.com/spf13/cobra"
Expand All @@ -21,7 +22,7 @@ const frameworkExportHelp = `Export a framework's configuration file.`

var errFileExists = errors.New("file already exists")

func newFrameworkExportCmd(cfg config) *cobra.Command {
func newFrameworkExportCmd(cfg config, out io.Writer) *cobra.Command {
var options frameworkExportOptions

cmd := &cobra.Command{
Expand All @@ -31,34 +32,38 @@ func newFrameworkExportCmd(cfg config) *cobra.Command {
Long: frameworkExportHelp,
RunE: func(cmd *cobra.Command, args []string) error {
options.frameworkName = args[0]
return exportFramework(cmd.Context(), cfg, options)
return exportFramework(cmd.Context(), cfg, options, out)
},
}
cmd.Flags().StringVarP(&options.filename, "file", "f", "framework.yaml", "filename for framework export")
cmd.Flags().StringVarP(&options.filename, "file", "f", "", "filename for framework export")
return cmd
}

func exportFramework(ctx context.Context, cfg config, options frameworkExportOptions) error {
func exportFramework(ctx context.Context, cfg config, options frameworkExportOptions, out io.Writer) error {
var framework ketchv1.Framework
err := cfg.Client().Get(ctx, types.NamespacedName{Name: options.frameworkName}, &framework)
if err != nil {
return err
}
framework.Spec.Name = framework.Name
// open file, err if exist, write framework.Spec
_, err = os.Stat(options.filename)
if !os.IsNotExist(err) {
return errFileExists
}
f, err := os.Create(options.filename)
if err != nil {
return err

if options.filename != "" {
// open file, err if exist, write framework.Spec
_, err = os.Stat(options.filename)
if !os.IsNotExist(err) {
return errFileExists
}
f, err := os.Create(options.filename)
if err != nil {
return err
}
defer f.Close()
out = f
}
defer f.Close()
b, err := yaml.Marshal(framework.Spec)
if err != nil {
return err
}
_, err = f.Write(b)
_, err = out.Write(b)
return err
}
32 changes: 28 additions & 4 deletions cmd/ketch/framework_export_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"bytes"
"context"
"os"
"testing"
Expand Down Expand Up @@ -51,6 +52,24 @@ ingressController:
name: myframework
namespace: ketch-myframework
version: v1
`,
},
{
name: "success - stdout",
cfg: &mocks.Configuration{
CtrlClientObjects: []runtime.Object{mockFramework},
DynamicClientObjects: []runtime.Object{},
},
options: frameworkExportOptions{frameworkName: "myframework"},
expected: `appQuotaLimit: 1
ingressController:
className: traefik
clusterIssuer: letsencrypt
serviceEndpoint: 10.10.20.30
type: traefik
name: myframework
namespace: ketch-myframework
version: v1
`,
},
{
Expand All @@ -72,16 +91,21 @@ version: v1
if tt.before != nil {
tt.before()
}
err := exportFramework(context.Background(), tt.cfg, tt.options)
buf := &bytes.Buffer{}
err := exportFramework(context.Background(), tt.cfg, tt.options, buf)
if tt.err != nil {
require.Equal(t, tt.err, err)
return
} else {
require.Nil(t, err)
}
data, err := os.ReadFile(tt.options.filename)
require.Nil(t, err)
require.Equal(t, tt.expected, string(data))
if tt.options.filename != "" {
data, err := os.ReadFile(tt.options.filename)
require.Nil(t, err)
require.Equal(t, tt.expected, string(data))
} else {
require.Equal(t, tt.expected, buf.String())
}
})
}
}
2 changes: 1 addition & 1 deletion internal/deploy/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
// Application represents the fields in an application.yaml file that will be
// transitioned to a ChangeSet.
type Application struct {
Version *string `json:"version"`
Version *string `json:"version,omitempty"`
Type *string `json:"type"`
Name *string `json:"name"`
Image *string `json:"image,omitempty"`
Expand Down

0 comments on commit c5d14ee

Please sign in to comment.