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

Export defaults to stdout + cleanup #118

Merged
merged 1 commit into from
Jul 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cli_tests/app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ EOF
}

@test "framework export" {
run $KETCH framework export "$FRAMEWORK"
run $KETCH framework export "$FRAMEWORK" -f framework.yaml
result=$(cat framework.yaml)
echo "RECEIVED:" $result
[[ $result =~ "name: $FRAMEWORK" ]]
Expand Down Expand Up @@ -171,13 +171,13 @@ EOF
}

@test "app export" {
run $KETCH app export "$APP_NAME"
run $KETCH app export "$APP_NAME" -f app.yaml
result=$(cat app.yaml)
echo "RECEIVED:" $result
[[ $result =~ "name: $APP_NAME" ]]
[[ $result =~ "type: Application" ]]
[[ $result =~ "framework: $FRAMEWORK" ]]
rm -f framework.yaml
rm -f app.yaml
}

@test "app stop" {
Expand Down
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