From 3ec62b1c8d8349a35db03e7c18922aaa94a68134 Mon Sep 17 00:00:00 2001 From: Janelle Tavares Date: Wed, 3 Aug 2022 02:25:01 -0700 Subject: [PATCH] Simply apps describe command and add apps log command (#386) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Collapse apps describe command with the extended flag and create separate logs command * chore: Use upstream version of meroxa-go * fix: code using latest meroxa-go * chore: update docs * fix: tests * refactor: display functions and tests I noticed the display and tests file were getting very big, and I decided to refactor this pkg. This was will become easier to spot those new functions that are not being tested (I spotted some doing this refactor). * test: AppLogsTable and change output Certain bits are shown depending on its content Co-authored-by: Raúl Barroso --- cmd/meroxa/root/apps/apps.go | 1 + cmd/meroxa/root/apps/describe.go | 83 +- cmd/meroxa/root/apps/describe_test.go | 93 +- cmd/meroxa/root/apps/list.go | 7 +- cmd/meroxa/root/apps/list_test.go | 7 +- cmd/meroxa/root/apps/logs.go | 147 +++ cmd/meroxa/root/apps/logs_test.go | 161 +++ cmd/meroxa/root/builds/describe.go | 7 +- cmd/meroxa/root/builds/describe_test.go | 6 +- cmd/meroxa/root/builds/logs.go | 2 +- cmd/meroxa/root/connectors/describe.go | 4 +- cmd/meroxa/root/connectors/describe_test.go | 4 +- cmd/meroxa/root/connectors/list.go | 5 +- cmd/meroxa/root/connectors/list_test.go | 4 +- cmd/meroxa/root/endpoints/describe.go | 5 +- cmd/meroxa/root/endpoints/describe_test.go | 4 +- cmd/meroxa/root/endpoints/list.go | 5 +- cmd/meroxa/root/endpoints/list_test.go | 4 +- cmd/meroxa/root/environments/create.go | 5 +- cmd/meroxa/root/environments/describe.go | 4 +- cmd/meroxa/root/environments/describe_test.go | 6 +- cmd/meroxa/root/environments/list.go | 5 +- cmd/meroxa/root/environments/list_test.go | 5 +- cmd/meroxa/root/environments/repair.go | 5 +- cmd/meroxa/root/environments/update.go | 5 +- cmd/meroxa/root/functions/describe.go | 5 +- cmd/meroxa/root/functions/list.go | 5 +- cmd/meroxa/root/pipelines/describe.go | 5 +- cmd/meroxa/root/pipelines/describe_test.go | 4 +- cmd/meroxa/root/pipelines/list.go | 5 +- cmd/meroxa/root/pipelines/list_test.go | 5 +- cmd/meroxa/root/resources/describe.go | 5 +- cmd/meroxa/root/resources/describe_test.go | 4 +- cmd/meroxa/root/resources/list.go | 7 +- cmd/meroxa/root/resources/list_test.go | 6 +- cmd/meroxa/root/transforms/list.go | 5 +- cmd/meroxa/root/transforms/list_test.go | 4 +- docs/cmd/md/meroxa_apps.md | 1 + docs/cmd/md/meroxa_apps_describe.md | 3 +- docs/cmd/md/meroxa_apps_logs.md | 33 + docs/cmd/www/meroxa-apps-describe.md | 3 +- docs/cmd/www/meroxa-apps-logs.md | 40 + docs/cmd/www/meroxa-apps.md | 1 + etc/completion/meroxa.completion.sh | 34 +- etc/man/man1/meroxa-api.1 | 2 +- etc/man/man1/meroxa-apps-deploy.1 | 2 +- etc/man/man1/meroxa-apps-describe.1 | 6 +- etc/man/man1/meroxa-apps-init.1 | 2 +- etc/man/man1/meroxa-apps-list.1 | 2 +- etc/man/man1/meroxa-apps-logs.1 | 56 + etc/man/man1/meroxa-apps-remove.1 | 2 +- etc/man/man1/meroxa-apps-run.1 | 2 +- etc/man/man1/meroxa-apps.1 | 4 +- etc/man/man1/meroxa-auth-login.1 | 2 +- etc/man/man1/meroxa-auth-logout.1 | 2 +- etc/man/man1/meroxa-auth-whoami.1 | 2 +- etc/man/man1/meroxa-auth.1 | 2 +- etc/man/man1/meroxa-billing.1 | 2 +- etc/man/man1/meroxa-builds-describe.1 | 2 +- etc/man/man1/meroxa-builds-logs.1 | 2 +- etc/man/man1/meroxa-builds.1 | 2 +- etc/man/man1/meroxa-completion.1 | 2 +- etc/man/man1/meroxa-config-describe.1 | 2 +- etc/man/man1/meroxa-config-set.1 | 2 +- etc/man/man1/meroxa-config.1 | 2 +- etc/man/man1/meroxa-endpoints-create.1 | 2 +- etc/man/man1/meroxa-endpoints-describe.1 | 2 +- etc/man/man1/meroxa-endpoints-list.1 | 2 +- etc/man/man1/meroxa-endpoints-remove.1 | 2 +- etc/man/man1/meroxa-endpoints.1 | 2 +- etc/man/man1/meroxa-environments-create.1 | 2 +- etc/man/man1/meroxa-environments-describe.1 | 2 +- etc/man/man1/meroxa-environments-list.1 | 2 +- etc/man/man1/meroxa-environments-remove.1 | 2 +- etc/man/man1/meroxa-environments-repair.1 | 2 +- etc/man/man1/meroxa-environments-update.1 | 2 +- etc/man/man1/meroxa-environments.1 | 2 +- etc/man/man1/meroxa-login.1 | 2 +- etc/man/man1/meroxa-logout.1 | 2 +- etc/man/man1/meroxa-open-billing.1 | 2 +- etc/man/man1/meroxa-open.1 | 2 +- etc/man/man1/meroxa-resources-create.1 | 2 +- etc/man/man1/meroxa-resources-describe.1 | 2 +- etc/man/man1/meroxa-resources-list.1 | 2 +- etc/man/man1/meroxa-resources-remove.1 | 2 +- .../man1/meroxa-resources-rotate-tunnel-key.1 | 2 +- etc/man/man1/meroxa-resources-update.1 | 2 +- etc/man/man1/meroxa-resources-validate.1 | 2 +- etc/man/man1/meroxa-resources.1 | 2 +- etc/man/man1/meroxa-transforms-list.1 | 2 +- etc/man/man1/meroxa-transforms.1 | 2 +- etc/man/man1/meroxa-version.1 | 2 +- etc/man/man1/meroxa-whoami.1 | 2 +- etc/man/man1/meroxa.1 | 2 +- go.mod | 4 +- go.sum | 6 +- utils/display.go | 1054 ----------------- utils/display/apps.go | 140 +++ utils/display/apps_test.go | 64 + utils/display/builds.go | 37 + utils/display/connectors.go | 150 +++ utils/display/connectors_test.go | 207 ++++ utils/display/display.go | 11 + utils/display/display_test.go | 47 + utils/display/endpoints.go | 58 + utils/display/environments.go | 225 ++++ utils/display/environments_test.go | 158 +++ utils/display/functions.go | 120 ++ utils/display/pipelines.go | 98 ++ utils/display/pipelines_test.go | 167 +++ utils/display/resources.go | 185 +++ utils/display/resources_test.go | 154 +++ utils/display/transforms.go | 51 + utils/display_test.go | 692 ----------- .../meroxa-go/pkg/meroxa/application.go | 37 +- vendor/modules.txt | 5 +- 116 files changed, 2596 insertions(+), 1993 deletions(-) create mode 100644 cmd/meroxa/root/apps/logs.go create mode 100644 cmd/meroxa/root/apps/logs_test.go create mode 100644 docs/cmd/md/meroxa_apps_logs.md create mode 100644 docs/cmd/www/meroxa-apps-logs.md create mode 100644 etc/man/man1/meroxa-apps-logs.1 delete mode 100644 utils/display.go create mode 100644 utils/display/apps.go create mode 100644 utils/display/apps_test.go create mode 100644 utils/display/builds.go create mode 100644 utils/display/connectors.go create mode 100644 utils/display/connectors_test.go create mode 100644 utils/display/display.go create mode 100644 utils/display/display_test.go create mode 100644 utils/display/endpoints.go create mode 100644 utils/display/environments.go create mode 100644 utils/display/environments_test.go create mode 100644 utils/display/functions.go create mode 100644 utils/display/pipelines.go create mode 100644 utils/display/pipelines_test.go create mode 100644 utils/display/resources.go create mode 100644 utils/display/resources_test.go create mode 100644 utils/display/transforms.go delete mode 100644 utils/display_test.go diff --git a/cmd/meroxa/root/apps/apps.go b/cmd/meroxa/root/apps/apps.go index 15f2362fe..a572ef29c 100644 --- a/cmd/meroxa/root/apps/apps.go +++ b/cmd/meroxa/root/apps/apps.go @@ -60,6 +60,7 @@ func (*Apps) SubCommands() []*cobra.Command { builder.BuildCobraCommand(&Describe{}), builder.BuildCobraCommand(&Init{}), builder.BuildCobraCommand(&List{}), + builder.BuildCobraCommand(&Logs{}), builder.BuildCobraCommand(&Remove{}), builder.BuildCobraCommand(&Run{}), } diff --git a/cmd/meroxa/root/apps/describe.go b/cmd/meroxa/root/apps/describe.go index 57acc2b97..7a9b3f7df 100644 --- a/cmd/meroxa/root/apps/describe.go +++ b/cmd/meroxa/root/apps/describe.go @@ -1,5 +1,5 @@ /* -Copyright © 2021 Meroxa Inc +Copyright © 2022 Meroxa Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,21 +17,19 @@ limitations under the License. package apps import ( - "bytes" "context" "errors" - "net/http" + + "github.com/meroxa/cli/utils/display" "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) var ( _ builder.CommandWithDocs = (*Describe)(nil) _ builder.CommandWithArgs = (*Describe)(nil) - _ builder.CommandWithFlags = (*Describe)(nil) _ builder.CommandWithClient = (*Describe)(nil) _ builder.CommandWithLogger = (*Describe)(nil) _ builder.CommandWithExecute = (*Describe)(nil) @@ -39,7 +37,6 @@ var ( type describeApplicationClient interface { GetApplication(ctx context.Context, nameOrUUID string) (*meroxa.Application, error) - GetFunctionLogs(ctx context.Context, nameOrUUID string) (*http.Response, error) GetResourceByNameOrID(ctx context.Context, nameOrID string) (*meroxa.Resource, error) GetConnectorByNameOrID(ctx context.Context, nameOrID string) (*meroxa.Connector, error) GetFunction(ctx context.Context, nameOrUUID string) (*meroxa.Function, error) @@ -52,14 +49,6 @@ type Describe struct { args struct { NameOrUUID string } - - flags struct { - Extended bool `long:"extended" usage:"whether to show additional details about the Turbine Data Application"` - } -} - -func (d *Describe) Flags() []builder.Flag { - return builder.BuildFlags(&d.flags) } func (d *Describe) Usage() string { @@ -81,53 +70,35 @@ func (d *Describe) Execute(ctx context.Context) error { return err } - if d.flags.Extended { - resources := make([]*meroxa.Resource, 0) - connectors := make(map[string]*meroxa.Connector) - functions := make([]*meroxa.Function, 0) - - for _, rr := range app.Resources { - resource, err := d.client.GetResourceByNameOrID(ctx, rr.Name.String) - if err != nil { - return err - } - resources = append(resources, resource) + resources := make([]*meroxa.Resource, 0) + connectors := make([]*meroxa.Connector, 0) + functions := make([]*meroxa.Function, 0) + + for _, rr := range app.Resources { + resource, err := d.client.GetResourceByNameOrID(ctx, rr.Name.String) + if err != nil { + return err } - for _, cc := range app.Connectors { - connector, err := d.client.GetConnectorByNameOrID(ctx, cc.Name.String) - if err != nil { - return err - } - connectors[connector.ResourceName] = connector + resources = append(resources, resource) + } + for _, cc := range app.Connectors { + connector, err := d.client.GetConnectorByNameOrID(ctx, cc.Name.String) + if err != nil { + return err } - for _, ff := range app.Functions { - function, err := d.client.GetFunction(ctx, ff.UUID.String) - if err != nil { - return err - } - - // Include logs - resp, err := d.client.GetFunctionLogs(ctx, ff.Name.String) - if err != nil { - return err - } - - buf := new(bytes.Buffer) - _, err = buf.ReadFrom(resp.Body) - if err != nil { - return err - } - - function.Logs = buf.String() - - functions = append(functions, function) + connectors = append(connectors, connector) + } + for _, ff := range app.Functions { + function, err := d.client.GetFunction(ctx, ff.Name.String) + if err != nil { + return err } - output = utils.AppExtendedTable(app, resources, connectors, functions) - } else { - output = utils.AppTable(app) + functions = append(functions, function) } + output = display.AppTable(app, resources, connectors, functions) + d.logger.Info(ctx, output) d.logger.JSON(ctx, app) @@ -144,7 +115,7 @@ func (d *Describe) Logger(logger log.Logger) { func (d *Describe) ParseArgs(args []string) error { if len(args) < 1 { - return errors.New("requires app name") + return errors.New("requires app name or UUID") } d.args.NameOrUUID = args[0] diff --git a/cmd/meroxa/root/apps/describe_test.go b/cmd/meroxa/root/apps/describe_test.go index 232573d9f..fab742ba2 100644 --- a/cmd/meroxa/root/apps/describe_test.go +++ b/cmd/meroxa/root/apps/describe_test.go @@ -1,5 +1,5 @@ /* -Copyright © 2021 Meroxa Inc +Copyright © 2022 Meroxa Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,6 +24,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/volatiletech/null/v8" "github.com/golang/mock/gomock" @@ -39,7 +41,7 @@ func TestDescribeApplicationArgs(t *testing.T) { err error name string }{ - {args: nil, err: errors.New("requires app name"), name: ""}, + {args: nil, err: errors.New("requires app name or UUID"), name: ""}, {args: []string{"ApplicationName"}, err: nil, name: "ApplicationName"}, } @@ -68,66 +70,53 @@ func TestDescribeApplicationExecution(t *testing.T) { a := utils.GenerateApplication("") a.Name = appName - client. - EXPECT(). - GetApplication( - ctx, - a.Name, - ). - Return(&a, nil) - - dc := &Describe{ - client: client, - logger: logger, + a.Resources = []meroxa.ApplicationResource{ + { + EntityIdentifier: meroxa.EntityIdentifier{ + Name: null.StringFrom("res1"), + }, + Collection: meroxa.ResourceCollection{ + Name: null.StringFrom("res1"), + Source: null.StringFrom("source"), + }, + }, + { + EntityIdentifier: meroxa.EntityIdentifier{ + Name: null.StringFrom("res2"), + }, + Collection: meroxa.ResourceCollection{ + Name: null.StringFrom("res2"), + Destination: null.StringFrom("destination"), + }, + }, } - dc.args.NameOrUUID = a.Name - - err := dc.Execute(ctx) - if err != nil { - t.Fatalf("not expected error, got %q", err.Error()) + resources := []*meroxa.Resource{ + {Name: "res1", UUID: "abc-def", Type: meroxa.ResourceTypePostgres}, + {Name: "res2", UUID: "abc-def", Type: meroxa.ResourceTypeBigquery}, } - gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.AppTable(&a) - - if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { - t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) + a.Connectors = []meroxa.EntityIdentifier{ + {Name: null.StringFrom("conn1")}, + {Name: null.StringFrom("conn2")}, } - - gotJSONOutput := logger.JSONOutput() - var gotApp meroxa.Application - err = json.Unmarshal([]byte(gotJSONOutput), &gotApp) - if err != nil { - t.Fatalf("not expected error, got %q", err.Error()) + connectors := []*meroxa.Connector{ + {Name: "conn1", ResourceName: "res1", Type: meroxa.ConnectorTypeSource, State: meroxa.ConnectorStateRunning}, + {Name: "conn2", ResourceName: "res2", Type: meroxa.ConnectorTypeDestination, State: meroxa.ConnectorStateRunning}, } - if !reflect.DeepEqual(gotApp, a) { - t.Fatalf("expected \"%v\", got \"%v\"", a, gotApp) + functions := []*meroxa.Function{ + {Name: "fun1", UUID: "abc-def", Status: meroxa.FunctionStatus{State: "running"}}, } -} - -func TestDescribeApplicationExecutionWithFunctions(t *testing.T) { - ctx := context.Background() - ctrl := gomock.NewController(t) - client := mock.NewMockClient(ctrl) - logger := log.NewTestLogger() - - appName := "my-app-with-funcs" - - a := utils.GenerateApplication("") - a.Name = appName a.Functions = []meroxa.EntityIdentifier{ {Name: null.StringFrom("fun1")}, - {Name: null.StringFrom("fun2")}, } - client. - EXPECT(). - GetApplication( - ctx, - a.Name, - ). - Return(&a, nil) + client.EXPECT().GetApplication(ctx, a.Name).Return(&a, nil) + client.EXPECT().GetResourceByNameOrID(ctx, "res1").Return(resources[0], nil) + client.EXPECT().GetResourceByNameOrID(ctx, "res2").Return(resources[1], nil) + client.EXPECT().GetConnectorByNameOrID(ctx, "conn1").Return(connectors[0], nil) + client.EXPECT().GetConnectorByNameOrID(ctx, "conn2").Return(connectors[1], nil) + client.EXPECT().GetFunction(ctx, "fun1").Return(functions[0], nil) dc := &Describe{ client: client, @@ -141,7 +130,7 @@ func TestDescribeApplicationExecutionWithFunctions(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.AppTable(&a) + wantLeveledOutput := display.AppTable(&a, resources, connectors, functions) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/apps/list.go b/cmd/meroxa/root/apps/list.go index 424c53e7f..a11c7b5de 100644 --- a/cmd/meroxa/root/apps/list.go +++ b/cmd/meroxa/root/apps/list.go @@ -1,5 +1,5 @@ /* -Copyright © 2021 Meroxa Inc +Copyright © 2022 Meroxa Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,9 +19,10 @@ package apps import ( "context" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -67,7 +68,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, apps) - l.logger.Info(ctx, utils.AppsTable(apps, l.hideHeaders)) + l.logger.Info(ctx, display.AppsTable(apps, l.hideHeaders)) return nil } diff --git a/cmd/meroxa/root/apps/list_test.go b/cmd/meroxa/root/apps/list_test.go index 2bc815238..df4755256 100644 --- a/cmd/meroxa/root/apps/list_test.go +++ b/cmd/meroxa/root/apps/list_test.go @@ -1,5 +1,5 @@ /* -Copyright © 2021 Meroxa Inc +Copyright © 2022 Meroxa Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,9 +23,10 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" "github.com/meroxa/meroxa-go/pkg/mock" ) @@ -62,7 +63,7 @@ func TestListAppsExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.AppsTable(apps, false) + wantLeveledOutput := display.AppsTable(apps, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/apps/logs.go b/cmd/meroxa/root/apps/logs.go new file mode 100644 index 000000000..6e56b8415 --- /dev/null +++ b/cmd/meroxa/root/apps/logs.go @@ -0,0 +1,147 @@ +/* +Copyright © 2022 Meroxa Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apps + +import ( + "bytes" + "context" + "errors" + "net/http" + + "github.com/meroxa/cli/utils/display" + + "github.com/meroxa/cli/cmd/meroxa/builder" + "github.com/meroxa/cli/log" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +var ( + _ builder.CommandWithAliases = (*Logs)(nil) + _ builder.CommandWithDocs = (*Logs)(nil) + _ builder.CommandWithArgs = (*Logs)(nil) + _ builder.CommandWithClient = (*Logs)(nil) + _ builder.CommandWithLogger = (*Logs)(nil) + _ builder.CommandWithExecute = (*Logs)(nil) +) + +type Logs struct { + client applicationLogsClient + logger log.Logger + + args struct { + NameOrUUID string + } +} + +type applicationLogsClient interface { + GetApplication(ctx context.Context, nameOrUUID string) (*meroxa.Application, error) + GetConnectorByNameOrID(ctx context.Context, nameOrID string) (*meroxa.Connector, error) + GetConnectorLogs(ctx context.Context, nameOrID string) (*http.Response, error) + GetFunction(ctx context.Context, nameOrUUID string) (*meroxa.Function, error) + GetFunctionLogs(ctx context.Context, nameOrUUID string) (*http.Response, error) + GetResourceByNameOrID(ctx context.Context, nameOrID string) (*meroxa.Resource, error) +} + +func (*Logs) Aliases() []string { + return []string{"log"} +} + +func (l *Logs) Usage() string { + return "logs [NAMEorUUID]" +} + +func (l *Logs) Docs() builder.Docs { + return builder.Docs{ + Short: "View relevant logs to the state of the given Turbine Data Application", + Example: "meroxa apps logs my-turbine-application", + Beta: true, + } +} + +func (l *Logs) Execute(ctx context.Context) error { + app, err := l.client.GetApplication(ctx, l.args.NameOrUUID) + if err != nil { + return err + } + + connectors := make([]*display.AppExtendedConnector, 0) + functions := make([]*meroxa.Function, 0) + + resources := app.Resources + for _, cc := range app.Connectors { + connector, err := l.client.GetConnectorByNameOrID(ctx, cc.Name.String) + if err != nil { + return err + } + + resp, err := l.client.GetConnectorLogs(ctx, connector.Name) + if err != nil { + return err + } + + buf := new(bytes.Buffer) + _, err = buf.ReadFrom(resp.Body) + if err != nil { + return err + } + + connectors = append(connectors, &display.AppExtendedConnector{Connector: connector, Logs: buf.String()}) + } + for _, ff := range app.Functions { + function, err := l.client.GetFunction(ctx, ff.Name.String) + if err != nil { + return err + } + + resp, err := l.client.GetFunctionLogs(ctx, ff.Name.String) + if err != nil { + return err + } + + buf := new(bytes.Buffer) + _, err = buf.ReadFrom(resp.Body) + if err != nil { + return err + } + + function.Logs = buf.String() + functions = append(functions, function) + } + output := display.AppLogsTable(resources, connectors, functions) + + l.logger.Info(ctx, output) + l.logger.JSON(ctx, app) + + return nil +} + +func (l *Logs) Client(client meroxa.Client) { + l.client = client +} + +func (l *Logs) Logger(logger log.Logger) { + l.logger = logger +} + +func (l *Logs) ParseArgs(args []string) error { + if len(args) < 1 { + return errors.New("requires app name or UUID") + } + + l.args.NameOrUUID = args[0] + return nil +} diff --git a/cmd/meroxa/root/apps/logs_test.go b/cmd/meroxa/root/apps/logs_test.go new file mode 100644 index 000000000..4e1c5c148 --- /dev/null +++ b/cmd/meroxa/root/apps/logs_test.go @@ -0,0 +1,161 @@ +/* +Copyright © 2022 Meroxa Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apps + +import ( + "context" + "encoding/json" + "errors" + "io" + "net/http" + "reflect" + "strings" + "testing" + + "github.com/meroxa/cli/utils/display" + + "github.com/golang/mock/gomock" + "github.com/google/go-cmp/cmp" + "github.com/volatiletech/null/v8" + + "github.com/meroxa/cli/log" + "github.com/meroxa/cli/utils" + "github.com/meroxa/meroxa-go/pkg/meroxa" + "github.com/meroxa/meroxa-go/pkg/mock" +) + +func TestApplicationLogsArgs(t *testing.T) { + tests := []struct { + args []string + err error + name string + }{ + {args: nil, err: errors.New("requires app name or UUID"), name: ""}, + {args: []string{"ApplicationName"}, err: nil, name: "ApplicationName"}, + } + + for _, tt := range tests { + ar := &Logs{} + err := ar.ParseArgs(tt.args) + + if err != nil && tt.err.Error() != err.Error() { + t.Fatalf("expected \"%s\" got \"%s\"", tt.err, err) + } + + if tt.name != ar.args.NameOrUUID { + t.Fatalf("expected \"%s\" got \"%s\"", tt.name, ar.args.NameOrUUID) + } + } +} + +func TestApplicationLogsExecution(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + client := mock.NewMockClient(ctrl) + logger := log.NewTestLogger() + + appName := "my-app-with-funcs" + log := "hello world" + res1 := &http.Response{ + Body: io.NopCloser(strings.NewReader(log)), + } + res2 := &http.Response{ + Body: io.NopCloser(strings.NewReader(log)), + } + res3 := &http.Response{ + Body: io.NopCloser(strings.NewReader(log)), + } + + a := utils.GenerateApplication("") + a.Name = appName + + a.Resources = []meroxa.ApplicationResource{ + { + EntityIdentifier: meroxa.EntityIdentifier{Name: null.StringFrom("res1")}, + Collection: meroxa.ResourceCollection{ + Name: null.StringFrom("res1"), + Source: null.StringFrom("source"), + }, + }, + { + EntityIdentifier: meroxa.EntityIdentifier{Name: null.StringFrom("res2")}, + Collection: meroxa.ResourceCollection{ + Name: null.StringFrom("res2"), + Destination: null.StringFrom("destination"), + }, + }, + } + + a.Connectors = []meroxa.EntityIdentifier{ + {Name: null.StringFrom("conn1")}, + {Name: null.StringFrom("conn2")}, + } + connectors := []*display.AppExtendedConnector{ + {Connector: &meroxa.Connector{ + Name: "conn1", ResourceName: "res1", Type: meroxa.ConnectorTypeSource, State: meroxa.ConnectorStateRunning}, + Logs: log}, + {Connector: &meroxa.Connector{ + Name: "conn2", ResourceName: "res2", Type: meroxa.ConnectorTypeDestination, State: meroxa.ConnectorStateRunning}, + Logs: log}, + } + + functions := []*meroxa.Function{ + {Name: "fun1", UUID: "abc-def", Status: meroxa.FunctionStatus{State: "running"}, Logs: log}, + } + a.Functions = []meroxa.EntityIdentifier{ + {Name: null.StringFrom("fun1")}, + } + + client.EXPECT().GetApplication(ctx, a.Name).Return(&a, nil) + client.EXPECT().GetConnectorByNameOrID(ctx, "conn1"). + Return(&meroxa.Connector{Name: "conn1", ResourceName: "res1"}, nil) + client.EXPECT().GetConnectorLogs(ctx, "conn1").Return(res1, nil) + client.EXPECT().GetConnectorByNameOrID(ctx, "conn2"). + Return(&meroxa.Connector{Name: "conn2", ResourceName: "res2"}, nil) + client.EXPECT().GetConnectorLogs(ctx, "conn2").Return(res2, nil) + client.EXPECT().GetFunction(ctx, "fun1").Return(functions[0], nil) + client.EXPECT().GetFunctionLogs(ctx, "fun1").Return(res3, nil) + + dc := &Logs{ + client: client, + logger: logger, + } + dc.args.NameOrUUID = a.Name + + err := dc.Execute(ctx) + if err != nil { + t.Fatalf("not expected error, got %q", err.Error()) + } + + gotLeveledOutput := logger.LeveledOutput() + wantLeveledOutput := display.AppLogsTable(a.Resources, connectors, functions) + + if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { + t.Fatalf(cmp.Diff(wantLeveledOutput, gotLeveledOutput)) + } + + gotJSONOutput := logger.JSONOutput() + var gotApp meroxa.Application + err = json.Unmarshal([]byte(gotJSONOutput), &gotApp) + if err != nil { + t.Fatalf("not expected error, got %q", err.Error()) + } + + if !reflect.DeepEqual(gotApp, a) { + t.Fatalf(cmp.Diff(a, gotApp)) + } +} diff --git a/cmd/meroxa/root/builds/describe.go b/cmd/meroxa/root/builds/describe.go index 22aefa2f9..da1e6e061 100644 --- a/cmd/meroxa/root/builds/describe.go +++ b/cmd/meroxa/root/builds/describe.go @@ -1,5 +1,5 @@ /* -Copyright © 2021 Meroxa Inc +Copyright © 2022 Meroxa Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,9 +20,10 @@ import ( "context" "errors" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -64,7 +65,7 @@ func (d *Describe) Execute(ctx context.Context) error { return err } - d.logger.Info(ctx, utils.BuildTable(build)) + d.logger.Info(ctx, display.BuildTable(build)) d.logger.JSON(ctx, build) return nil diff --git a/cmd/meroxa/root/builds/describe_test.go b/cmd/meroxa/root/builds/describe_test.go index f87ef90d5..2c68b549c 100644 --- a/cmd/meroxa/root/builds/describe_test.go +++ b/cmd/meroxa/root/builds/describe_test.go @@ -1,5 +1,5 @@ /* -Copyright © 2021 Meroxa Inc +Copyright © 2022 Meroxa Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,6 +24,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" "github.com/meroxa/cli/utils" @@ -83,7 +85,7 @@ func TestDescribeBuildsExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.BuildTable(&a) + wantLeveledOutput := display.BuildTable(&a) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/builds/logs.go b/cmd/meroxa/root/builds/logs.go index 11f4e6ec1..549290510 100644 --- a/cmd/meroxa/root/builds/logs.go +++ b/cmd/meroxa/root/builds/logs.go @@ -1,5 +1,5 @@ /* -Copyright © 2021 Meroxa Inc +Copyright © 2022 Meroxa Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/meroxa/root/connectors/describe.go b/cmd/meroxa/root/connectors/describe.go index fe7e2a3e9..0034a8ae6 100644 --- a/cmd/meroxa/root/connectors/describe.go +++ b/cmd/meroxa/root/connectors/describe.go @@ -20,7 +20,7 @@ import ( "context" "errors" - "github.com/meroxa/cli/utils" + "github.com/meroxa/cli/utils/display" "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" @@ -65,7 +65,7 @@ func (d *Describe) Execute(ctx context.Context) error { return err } - d.logger.Info(ctx, utils.ConnectorTable(connector)) + d.logger.Info(ctx, display.ConnectorTable(connector)) d.logger.JSON(ctx, connector) return nil diff --git a/cmd/meroxa/root/connectors/describe_test.go b/cmd/meroxa/root/connectors/describe_test.go index e6740e210..faad6b1c4 100644 --- a/cmd/meroxa/root/connectors/describe_test.go +++ b/cmd/meroxa/root/connectors/describe_test.go @@ -24,6 +24,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/meroxa-go/pkg/mock" "github.com/golang/mock/gomock" @@ -87,7 +89,7 @@ func TestDescribeConnectorExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.ConnectorTable(&c) + wantLeveledOutput := display.ConnectorTable(&c) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/connectors/list.go b/cmd/meroxa/root/connectors/list.go index 2f8f10029..c3617ff89 100644 --- a/cmd/meroxa/root/connectors/list.go +++ b/cmd/meroxa/root/connectors/list.go @@ -19,9 +19,10 @@ package connectors import ( "context" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -86,7 +87,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, connectors) - l.logger.Info(ctx, utils.ConnectorsTable(connectors, l.hideHeaders)) + l.logger.Info(ctx, display.ConnectorsTable(connectors, l.hideHeaders)) return nil } diff --git a/cmd/meroxa/root/connectors/list_test.go b/cmd/meroxa/root/connectors/list_test.go index 0e32322ba..9f5d57cc9 100644 --- a/cmd/meroxa/root/connectors/list_test.go +++ b/cmd/meroxa/root/connectors/list_test.go @@ -23,6 +23,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/log" "github.com/meroxa/cli/cmd/meroxa/builder" @@ -100,7 +102,7 @@ func TestListConnectorsExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.ConnectorsTable(connectors, false) + wantLeveledOutput := display.ConnectorsTable(connectors, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/endpoints/describe.go b/cmd/meroxa/root/endpoints/describe.go index fad71f2a3..5b9b6a82b 100644 --- a/cmd/meroxa/root/endpoints/describe.go +++ b/cmd/meroxa/root/endpoints/describe.go @@ -20,9 +20,10 @@ import ( "context" "errors" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -63,7 +64,7 @@ func (d *Describe) Execute(ctx context.Context) error { return err } - d.logger.Info(ctx, utils.EndpointsTable([]meroxa.Endpoint{*endpoint}, false)) + d.logger.Info(ctx, display.EndpointsTable([]meroxa.Endpoint{*endpoint}, false)) d.logger.JSON(ctx, endpoint) return nil diff --git a/cmd/meroxa/root/endpoints/describe_test.go b/cmd/meroxa/root/endpoints/describe_test.go index 26a7704e6..d0592e3d6 100644 --- a/cmd/meroxa/root/endpoints/describe_test.go +++ b/cmd/meroxa/root/endpoints/describe_test.go @@ -24,6 +24,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" "github.com/meroxa/cli/utils" @@ -82,7 +84,7 @@ func TestDescribeConnectorExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.EndpointsTable([]meroxa.Endpoint{e}, false) + wantLeveledOutput := display.EndpointsTable([]meroxa.Endpoint{e}, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/endpoints/list.go b/cmd/meroxa/root/endpoints/list.go index 97fc54d84..063dca808 100644 --- a/cmd/meroxa/root/endpoints/list.go +++ b/cmd/meroxa/root/endpoints/list.go @@ -19,9 +19,10 @@ package endpoints import ( "context" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -66,7 +67,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, endpoints) - l.logger.Info(ctx, utils.EndpointsTable(endpoints, l.hideHeaders)) + l.logger.Info(ctx, display.EndpointsTable(endpoints, l.hideHeaders)) return nil } diff --git a/cmd/meroxa/root/endpoints/list_test.go b/cmd/meroxa/root/endpoints/list_test.go index bfbad6a08..d3a021c0a 100644 --- a/cmd/meroxa/root/endpoints/list_test.go +++ b/cmd/meroxa/root/endpoints/list_test.go @@ -23,6 +23,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" "github.com/meroxa/cli/utils" @@ -61,7 +63,7 @@ func TestListConnectorsExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.EndpointsTable(endpoints, false) + wantLeveledOutput := display.EndpointsTable(endpoints, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/environments/create.go b/cmd/meroxa/root/environments/create.go index 2fbee1241..14aa361a7 100644 --- a/cmd/meroxa/root/environments/create.go +++ b/cmd/meroxa/root/environments/create.go @@ -19,11 +19,12 @@ import ( "fmt" "strings" + "github.com/meroxa/cli/utils/display" + "github.com/manifoldco/promptui" "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -134,7 +135,7 @@ func (c *Create) Execute(ctx context.Context) error { } if environment.Status.State != meroxa.EnvironmentStatePreflightSuccess { - details := utils.EnvironmentPreflightTable(environment) + details := display.EnvironmentPreflightTable(environment) c.logger.Errorf(ctx, "Environment %q could not be provisioned because it failed the preflight checks\n%s\n", environment.Name, diff --git a/cmd/meroxa/root/environments/describe.go b/cmd/meroxa/root/environments/describe.go index 64716707a..234fe61c9 100644 --- a/cmd/meroxa/root/environments/describe.go +++ b/cmd/meroxa/root/environments/describe.go @@ -20,7 +20,7 @@ import ( "context" "errors" - "github.com/meroxa/cli/utils" + "github.com/meroxa/cli/utils/display" "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" @@ -64,7 +64,7 @@ func (d *Describe) Execute(ctx context.Context) error { return err } - d.logger.Info(ctx, utils.EnvironmentTable(environment)) + d.logger.Info(ctx, display.EnvironmentTable(environment)) d.logger.JSON(ctx, environment) return nil diff --git a/cmd/meroxa/root/environments/describe_test.go b/cmd/meroxa/root/environments/describe_test.go index baf25d5e1..641133566 100644 --- a/cmd/meroxa/root/environments/describe_test.go +++ b/cmd/meroxa/root/environments/describe_test.go @@ -21,6 +21,8 @@ import ( "encoding/json" "errors" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" "github.com/meroxa/cli/utils" @@ -86,7 +88,7 @@ func TestDescribeEnvironmentExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.EnvironmentTable(&e) + wantLeveledOutput := display.EnvironmentTable(&e) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) @@ -134,7 +136,7 @@ func TestDescribeEnvironmentExecutionBadEnv(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.EnvironmentTable(&e) + wantLeveledOutput := display.EnvironmentTable(&e) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/environments/list.go b/cmd/meroxa/root/environments/list.go index 840b2021c..f96033850 100644 --- a/cmd/meroxa/root/environments/list.go +++ b/cmd/meroxa/root/environments/list.go @@ -19,9 +19,10 @@ package environments import ( "context" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -66,7 +67,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, environments) - l.logger.Info(ctx, utils.EnvironmentsTable(environments, l.hideHeaders)) + l.logger.Info(ctx, display.EnvironmentsTable(environments, l.hideHeaders)) return nil } diff --git a/cmd/meroxa/root/environments/list_test.go b/cmd/meroxa/root/environments/list_test.go index 8baee340a..1925b8b5d 100644 --- a/cmd/meroxa/root/environments/list_test.go +++ b/cmd/meroxa/root/environments/list_test.go @@ -23,9 +23,10 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" "github.com/meroxa/meroxa-go/pkg/mock" ) @@ -64,7 +65,7 @@ func TestListEnvironmentsExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.EnvironmentsTable(environments, false) + wantLeveledOutput := display.EnvironmentsTable(environments, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/environments/repair.go b/cmd/meroxa/root/environments/repair.go index eb5b49cd5..9bfb7c22c 100644 --- a/cmd/meroxa/root/environments/repair.go +++ b/cmd/meroxa/root/environments/repair.go @@ -17,9 +17,10 @@ import ( "context" "errors" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -78,7 +79,7 @@ func (r *Repair) Execute(ctx context.Context) error { } if environment.Status.State != meroxa.EnvironmentStatePreflightSuccess { - details := utils.EnvironmentPreflightTable(environment) + details := display.EnvironmentPreflightTable(environment) r.logger.Errorf(ctx, "Environment %q could not be repaired because it failed the preflight checks\n%s\n", environment.Name, diff --git a/cmd/meroxa/root/environments/update.go b/cmd/meroxa/root/environments/update.go index c1b35a562..e74fbd8ae 100644 --- a/cmd/meroxa/root/environments/update.go +++ b/cmd/meroxa/root/environments/update.go @@ -20,11 +20,12 @@ import ( "context" "fmt" + "github.com/meroxa/cli/utils/display" + "github.com/manifoldco/promptui" "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -112,7 +113,7 @@ func (c *Update) Execute(ctx context.Context) error { } if environment.Status.State != meroxa.EnvironmentStatePreflightSuccess { - details := utils.EnvironmentPreflightTable(environment) + details := display.EnvironmentPreflightTable(environment) c.logger.Errorf(ctx, "Environment %q could not be updated because it failed the preflight checks\n%s\n", environment.Name, diff --git a/cmd/meroxa/root/functions/describe.go b/cmd/meroxa/root/functions/describe.go index d0c201bd3..6320d3707 100644 --- a/cmd/meroxa/root/functions/describe.go +++ b/cmd/meroxa/root/functions/describe.go @@ -4,9 +4,10 @@ import ( "context" "errors" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -47,7 +48,7 @@ func (d *Describe) Execute(ctx context.Context) error { return err } - d.logger.Info(ctx, utils.FunctionTable(fun)) + d.logger.Info(ctx, display.FunctionTable(fun)) d.logger.JSON(ctx, fun) return nil diff --git a/cmd/meroxa/root/functions/list.go b/cmd/meroxa/root/functions/list.go index 835010f97..1c95dc30b 100644 --- a/cmd/meroxa/root/functions/list.go +++ b/cmd/meroxa/root/functions/list.go @@ -3,9 +3,10 @@ package functions import ( "context" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -35,7 +36,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, funs) - l.logger.Info(ctx, utils.FunctionsTable(funs, l.hideHeaders)) + l.logger.Info(ctx, display.FunctionsTable(funs, l.hideHeaders)) return nil } diff --git a/cmd/meroxa/root/pipelines/describe.go b/cmd/meroxa/root/pipelines/describe.go index 71b336b56..09d35f022 100644 --- a/cmd/meroxa/root/pipelines/describe.go +++ b/cmd/meroxa/root/pipelines/describe.go @@ -20,9 +20,10 @@ import ( "context" "errors" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -64,7 +65,7 @@ func (d *Describe) Execute(ctx context.Context) error { return err } - d.logger.Info(ctx, utils.PipelineTable(p)) + d.logger.Info(ctx, display.PipelineTable(p)) d.logger.JSON(ctx, p) diff --git a/cmd/meroxa/root/pipelines/describe_test.go b/cmd/meroxa/root/pipelines/describe_test.go index c6576e741..169171954 100644 --- a/cmd/meroxa/root/pipelines/describe_test.go +++ b/cmd/meroxa/root/pipelines/describe_test.go @@ -24,6 +24,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" "github.com/meroxa/cli/utils" @@ -82,7 +84,7 @@ func TestDescribePipelineExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.PipelineTable(&p) + wantLeveledOutput := display.PipelineTable(&p) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/pipelines/list.go b/cmd/meroxa/root/pipelines/list.go index 0079a0e94..42ba997aa 100644 --- a/cmd/meroxa/root/pipelines/list.go +++ b/cmd/meroxa/root/pipelines/list.go @@ -19,9 +19,10 @@ package pipelines import ( "context" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -67,7 +68,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, pipelines) - l.logger.Info(ctx, utils.PipelinesTable(pipelines, l.hideHeaders)) + l.logger.Info(ctx, display.PipelinesTable(pipelines, l.hideHeaders)) return nil } diff --git a/cmd/meroxa/root/pipelines/list_test.go b/cmd/meroxa/root/pipelines/list_test.go index d94fd0675..1d014182d 100644 --- a/cmd/meroxa/root/pipelines/list_test.go +++ b/cmd/meroxa/root/pipelines/list_test.go @@ -23,9 +23,10 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" "github.com/meroxa/meroxa-go/pkg/mock" ) @@ -63,7 +64,7 @@ func TestListPipelinesExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.PipelinesTable(pipelines, false) + wantLeveledOutput := display.PipelinesTable(pipelines, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/resources/describe.go b/cmd/meroxa/root/resources/describe.go index dd9b3e250..a7fc2d70c 100644 --- a/cmd/meroxa/root/resources/describe.go +++ b/cmd/meroxa/root/resources/describe.go @@ -20,9 +20,10 @@ import ( "context" "errors" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -63,7 +64,7 @@ func (d *Describe) Execute(ctx context.Context) error { return err } - d.logger.Info(ctx, utils.ResourceTable(resource)) + d.logger.Info(ctx, display.ResourceTable(resource)) if tun := resource.SSHTunnel; tun != nil { nextSteps := "\nPaste the following public key on your host:" diff --git a/cmd/meroxa/root/resources/describe_test.go b/cmd/meroxa/root/resources/describe_test.go index 98e4c4843..db4852b51 100644 --- a/cmd/meroxa/root/resources/describe_test.go +++ b/cmd/meroxa/root/resources/describe_test.go @@ -24,6 +24,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" "github.com/meroxa/cli/utils" @@ -82,7 +84,7 @@ func TestDescribeResourceExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.ResourceTable(&r) + wantLeveledOutput := display.ResourceTable(&r) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/resources/list.go b/cmd/meroxa/root/resources/list.go index 3577ddda2..9a468079d 100644 --- a/cmd/meroxa/root/resources/list.go +++ b/cmd/meroxa/root/resources/list.go @@ -19,9 +19,10 @@ package resources import ( "context" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -87,7 +88,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, rTypes) - l.logger.Info(ctx, utils.ResourceTypesTable(rTypes, l.hideHeaders)) + l.logger.Info(ctx, display.ResourceTypesTable(rTypes, l.hideHeaders)) return nil } @@ -98,7 +99,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, resources) - l.logger.Info(ctx, utils.ResourcesTable(resources, l.hideHeaders)) + l.logger.Info(ctx, display.ResourcesTable(resources, l.hideHeaders)) return nil } diff --git a/cmd/meroxa/root/resources/list_test.go b/cmd/meroxa/root/resources/list_test.go index 95ae2ccae..e9ee00f40 100644 --- a/cmd/meroxa/root/resources/list_test.go +++ b/cmd/meroxa/root/resources/list_test.go @@ -23,6 +23,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/golang/mock/gomock" @@ -96,7 +98,7 @@ func TestListResourcesExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.ResourcesTable(resources, false) + wantLeveledOutput := display.ResourcesTable(resources, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) @@ -158,7 +160,7 @@ func TestListResourceTypesExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.ResourceTypesTable(types, false) + wantLeveledOutput := display.ResourceTypesTable(types, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/cmd/meroxa/root/transforms/list.go b/cmd/meroxa/root/transforms/list.go index b39ff24b7..4caf303d9 100644 --- a/cmd/meroxa/root/transforms/list.go +++ b/cmd/meroxa/root/transforms/list.go @@ -19,9 +19,10 @@ package transforms import ( "context" + "github.com/meroxa/cli/utils/display" + "github.com/meroxa/cli/cmd/meroxa/builder" "github.com/meroxa/cli/log" - "github.com/meroxa/cli/utils" "github.com/meroxa/meroxa-go/pkg/meroxa" ) @@ -66,7 +67,7 @@ func (l *List) Execute(ctx context.Context) error { } l.logger.JSON(ctx, transforms) - l.logger.Info(ctx, utils.TransformsTable(transforms, l.hideHeaders)) + l.logger.Info(ctx, display.TransformsTable(transforms, l.hideHeaders)) return nil } diff --git a/cmd/meroxa/root/transforms/list_test.go b/cmd/meroxa/root/transforms/list_test.go index 1be697fd5..c79d7d6fa 100644 --- a/cmd/meroxa/root/transforms/list_test.go +++ b/cmd/meroxa/root/transforms/list_test.go @@ -23,6 +23,8 @@ import ( "strings" "testing" + "github.com/meroxa/cli/utils/display" + "github.com/golang/mock/gomock" "github.com/meroxa/cli/log" "github.com/meroxa/cli/utils" @@ -61,7 +63,7 @@ func TestListTransformsExecution(t *testing.T) { } gotLeveledOutput := logger.LeveledOutput() - wantLeveledOutput := utils.TransformsTable(transforms, false) + wantLeveledOutput := display.TransformsTable(transforms, false) if !strings.Contains(gotLeveledOutput, wantLeveledOutput) { t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput) diff --git a/docs/cmd/md/meroxa_apps.md b/docs/cmd/md/meroxa_apps.md index c0b3274f3..593eeddf7 100644 --- a/docs/cmd/md/meroxa_apps.md +++ b/docs/cmd/md/meroxa_apps.md @@ -24,6 +24,7 @@ Manage Turbine Data Applications (Beta) * [meroxa apps describe](meroxa_apps_describe.md) - Describe a Turbine Data Application (Beta) * [meroxa apps init](meroxa_apps_init.md) - Initialize a Turbine Data Application (Beta) * [meroxa apps list](meroxa_apps_list.md) - List Turbine Data Applications (Beta) +* [meroxa apps logs](meroxa_apps_logs.md) - View relevant logs to the state of the given Turbine Data Application (Beta) * [meroxa apps remove](meroxa_apps_remove.md) - Removes a Turbine Data Application (Beta) * [meroxa apps run](meroxa_apps_run.md) - Execute a Turbine Data Application locally (Beta) diff --git a/docs/cmd/md/meroxa_apps_describe.md b/docs/cmd/md/meroxa_apps_describe.md index 24c8e6864..43dfaaed5 100644 --- a/docs/cmd/md/meroxa_apps_describe.md +++ b/docs/cmd/md/meroxa_apps_describe.md @@ -9,8 +9,7 @@ meroxa apps describe [NAMEorUUID] [flags] ### Options ``` - --extended whether to show additional details about the Turbine Data Application - -h, --help help for describe + -h, --help help for describe ``` ### Options inherited from parent commands diff --git a/docs/cmd/md/meroxa_apps_logs.md b/docs/cmd/md/meroxa_apps_logs.md new file mode 100644 index 000000000..58f0fd89c --- /dev/null +++ b/docs/cmd/md/meroxa_apps_logs.md @@ -0,0 +1,33 @@ +## meroxa apps logs + +View relevant logs to the state of the given Turbine Data Application (Beta) + +``` +meroxa apps logs [NAMEorUUID] [flags] +``` + +### Examples + +``` +meroxa apps logs my-turbine-application +``` + +### Options + +``` + -h, --help help for logs +``` + +### Options inherited from parent commands + +``` + --cli-config-file string meroxa configuration file + --debug display any debugging information + --json output json + --timeout duration set the duration of the client timeout in seconds (default 10s) +``` + +### SEE ALSO + +* [meroxa apps](meroxa_apps.md) - Manage Turbine Data Applications (Beta) + diff --git a/docs/cmd/www/meroxa-apps-describe.md b/docs/cmd/www/meroxa-apps-describe.md index e975d7f43..9e4ddc3cf 100644 --- a/docs/cmd/www/meroxa-apps-describe.md +++ b/docs/cmd/www/meroxa-apps-describe.md @@ -16,8 +16,7 @@ meroxa apps describe [NAMEorUUID] [flags] ### Options ``` - --extended whether to show additional details about the Turbine Data Application - -h, --help help for describe + -h, --help help for describe ``` ### Options inherited from parent commands diff --git a/docs/cmd/www/meroxa-apps-logs.md b/docs/cmd/www/meroxa-apps-logs.md new file mode 100644 index 000000000..37b40d5c4 --- /dev/null +++ b/docs/cmd/www/meroxa-apps-logs.md @@ -0,0 +1,40 @@ +--- +createdAt: +updatedAt: +title: "meroxa apps logs" +slug: meroxa-apps-logs +url: /cli/cmd/meroxa-apps-logs/ +--- +## meroxa apps logs + +View relevant logs to the state of the given Turbine Data Application (Beta) + +``` +meroxa apps logs [NAMEorUUID] [flags] +``` + +### Examples + +``` +meroxa apps logs my-turbine-application +``` + +### Options + +``` + -h, --help help for logs +``` + +### Options inherited from parent commands + +``` + --cli-config-file string meroxa configuration file + --debug display any debugging information + --json output json + --timeout duration set the duration of the client timeout in seconds (default 10s) +``` + +### SEE ALSO + +* [meroxa apps](/cli/cmd/meroxa-apps/) - Manage Turbine Data Applications (Beta) + diff --git a/docs/cmd/www/meroxa-apps.md b/docs/cmd/www/meroxa-apps.md index b07f8fcd1..194f20f1f 100644 --- a/docs/cmd/www/meroxa-apps.md +++ b/docs/cmd/www/meroxa-apps.md @@ -31,6 +31,7 @@ Manage Turbine Data Applications (Beta) * [meroxa apps describe](/cli/cmd/meroxa-apps-describe/) - Describe a Turbine Data Application (Beta) * [meroxa apps init](/cli/cmd/meroxa-apps-init/) - Initialize a Turbine Data Application (Beta) * [meroxa apps list](/cli/cmd/meroxa-apps-list/) - List Turbine Data Applications (Beta) +* [meroxa apps logs](/cli/cmd/meroxa-apps-logs/) - View relevant logs to the state of the given Turbine Data Application (Beta) * [meroxa apps remove](/cli/cmd/meroxa-apps-remove/) - Removes a Turbine Data Application (Beta) * [meroxa apps run](/cli/cmd/meroxa-apps-run/) - Execute a Turbine Data Application locally (Beta) diff --git a/etc/completion/meroxa.completion.sh b/etc/completion/meroxa.completion.sh index 66d9e19d2..4f29b8237 100644 --- a/etc/completion/meroxa.completion.sh +++ b/etc/completion/meroxa.completion.sh @@ -425,7 +425,6 @@ _meroxa_apps_describe() flags_with_completion=() flags_completion=() - flags+=("--extended") flags+=("--help") flags+=("-h") flags+=("--cli-config-file=") @@ -533,6 +532,34 @@ _meroxa_apps_list() noun_aliases=() } +_meroxa_apps_logs() +{ + last_command="meroxa_apps_logs" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--help") + flags+=("-h") + flags+=("--cli-config-file=") + two_word_flags+=("--cli-config-file") + flags+=("--debug") + flags+=("--json") + flags+=("--timeout=") + two_word_flags+=("--timeout") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _meroxa_apps_remove() { last_command="meroxa_apps_remove" @@ -612,6 +639,11 @@ _meroxa_apps() command_aliases+=("ls") aliashash["ls"]="list" fi + commands+=("logs") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("log") + aliashash["log"]="logs" + fi commands+=("remove") if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then command_aliases+=("delete") diff --git a/etc/man/man1/meroxa-api.1 b/etc/man/man1/meroxa-api.1 index 874b212ae..b891643e0 100644 --- a/etc/man/man1/meroxa-api.1 +++ b/etc/man/man1/meroxa-api.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-apps-deploy.1 b/etc/man/man1/meroxa-apps-deploy.1 index fdcffb731..9d00e1660 100644 --- a/etc/man/man1/meroxa-apps-deploy.1 +++ b/etc/man/man1/meroxa-apps-deploy.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-apps-describe.1 b/etc/man/man1/meroxa-apps-describe.1 index 0ff970779..00b567676 100644 --- a/etc/man/man1/meroxa-apps-describe.1 +++ b/etc/man/man1/meroxa-apps-describe.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP @@ -17,10 +17,6 @@ Describe a Turbine Data Application (Beta) .SH OPTIONS -.PP -\fB\-\-extended\fP[=false] - whether to show additional details about the Turbine Data Application - .PP \fB\-h\fP, \fB\-\-help\fP[=false] help for describe diff --git a/etc/man/man1/meroxa-apps-init.1 b/etc/man/man1/meroxa-apps-init.1 index ae2b2728f..56e350886 100644 --- a/etc/man/man1/meroxa-apps-init.1 +++ b/etc/man/man1/meroxa-apps-init.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-apps-list.1 b/etc/man/man1/meroxa-apps-list.1 index 4bac3f899..d0fe40b6a 100644 --- a/etc/man/man1/meroxa-apps-list.1 +++ b/etc/man/man1/meroxa-apps-list.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-apps-logs.1 b/etc/man/man1/meroxa-apps-logs.1 new file mode 100644 index 000000000..c9ba0c104 --- /dev/null +++ b/etc/man/man1/meroxa-apps-logs.1 @@ -0,0 +1,56 @@ +.nh +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" + +.SH NAME +.PP +meroxa\-apps\-logs \- View relevant logs to the state of the given Turbine Data Application (Beta) + + +.SH SYNOPSIS +.PP +\fBmeroxa apps logs [NAMEorUUID] [flags]\fP + + +.SH DESCRIPTION +.PP +View relevant logs to the state of the given Turbine Data Application (Beta) + + +.SH OPTIONS +.PP +\fB\-h\fP, \fB\-\-help\fP[=false] + help for logs + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-cli\-config\-file\fP="" + meroxa configuration file + +.PP +\fB\-\-debug\fP[=false] + display any debugging information + +.PP +\fB\-\-json\fP[=false] + output json + +.PP +\fB\-\-timeout\fP=10s + set the duration of the client timeout in seconds + + +.SH EXAMPLE +.PP +.RS + +.nf +meroxa apps logs my\-turbine\-application + +.fi +.RE + + +.SH SEE ALSO +.PP +\fBmeroxa\-apps(1)\fP diff --git a/etc/man/man1/meroxa-apps-remove.1 b/etc/man/man1/meroxa-apps-remove.1 index 7502601e9..8216625ff 100644 --- a/etc/man/man1/meroxa-apps-remove.1 +++ b/etc/man/man1/meroxa-apps-remove.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-apps-run.1 b/etc/man/man1/meroxa-apps-run.1 index 2e386fd25..8f86c9550 100644 --- a/etc/man/man1/meroxa-apps-run.1 +++ b/etc/man/man1/meroxa-apps-run.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-apps.1 b/etc/man/man1/meroxa-apps.1 index 1581ed816..90b3abc55 100644 --- a/etc/man/man1/meroxa-apps.1 +++ b/etc/man/man1/meroxa-apps.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP @@ -42,4 +42,4 @@ Manage Turbine Data Applications (Beta) .SH SEE ALSO .PP -\fBmeroxa(1)\fP, \fBmeroxa\-apps\-deploy(1)\fP, \fBmeroxa\-apps\-describe(1)\fP, \fBmeroxa\-apps\-init(1)\fP, \fBmeroxa\-apps\-list(1)\fP, \fBmeroxa\-apps\-remove(1)\fP, \fBmeroxa\-apps\-run(1)\fP +\fBmeroxa(1)\fP, \fBmeroxa\-apps\-deploy(1)\fP, \fBmeroxa\-apps\-describe(1)\fP, \fBmeroxa\-apps\-init(1)\fP, \fBmeroxa\-apps\-list(1)\fP, \fBmeroxa\-apps\-logs(1)\fP, \fBmeroxa\-apps\-remove(1)\fP, \fBmeroxa\-apps\-run(1)\fP diff --git a/etc/man/man1/meroxa-auth-login.1 b/etc/man/man1/meroxa-auth-login.1 index e4601c33e..329ef1eba 100644 --- a/etc/man/man1/meroxa-auth-login.1 +++ b/etc/man/man1/meroxa-auth-login.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-auth-logout.1 b/etc/man/man1/meroxa-auth-logout.1 index 4eb19557e..0e6a32017 100644 --- a/etc/man/man1/meroxa-auth-logout.1 +++ b/etc/man/man1/meroxa-auth-logout.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-auth-whoami.1 b/etc/man/man1/meroxa-auth-whoami.1 index bce8e1031..c44bb9386 100644 --- a/etc/man/man1/meroxa-auth-whoami.1 +++ b/etc/man/man1/meroxa-auth-whoami.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-auth.1 b/etc/man/man1/meroxa-auth.1 index 9bea7be18..abc17a406 100644 --- a/etc/man/man1/meroxa-auth.1 +++ b/etc/man/man1/meroxa-auth.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-billing.1 b/etc/man/man1/meroxa-billing.1 index 399c62566..a5f5da7b7 100644 --- a/etc/man/man1/meroxa-billing.1 +++ b/etc/man/man1/meroxa-billing.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-builds-describe.1 b/etc/man/man1/meroxa-builds-describe.1 index c020f3450..3e1d39f55 100644 --- a/etc/man/man1/meroxa-builds-describe.1 +++ b/etc/man/man1/meroxa-builds-describe.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-builds-logs.1 b/etc/man/man1/meroxa-builds-logs.1 index d32e2247a..0dfb62cdb 100644 --- a/etc/man/man1/meroxa-builds-logs.1 +++ b/etc/man/man1/meroxa-builds-logs.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-builds.1 b/etc/man/man1/meroxa-builds.1 index dee95e4c0..8c6b8ce0f 100644 --- a/etc/man/man1/meroxa-builds.1 +++ b/etc/man/man1/meroxa-builds.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-completion.1 b/etc/man/man1/meroxa-completion.1 index f453dc176..e99f46d15 100644 --- a/etc/man/man1/meroxa-completion.1 +++ b/etc/man/man1/meroxa-completion.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-config-describe.1 b/etc/man/man1/meroxa-config-describe.1 index d25aa6a2b..de22a38b8 100644 --- a/etc/man/man1/meroxa-config-describe.1 +++ b/etc/man/man1/meroxa-config-describe.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-config-set.1 b/etc/man/man1/meroxa-config-set.1 index fc74acc42..2ad64016d 100644 --- a/etc/man/man1/meroxa-config-set.1 +++ b/etc/man/man1/meroxa-config-set.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-config.1 b/etc/man/man1/meroxa-config.1 index 563295fc2..0fba8924c 100644 --- a/etc/man/man1/meroxa-config.1 +++ b/etc/man/man1/meroxa-config.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-endpoints-create.1 b/etc/man/man1/meroxa-endpoints-create.1 index 789867288..d8952b4a9 100644 --- a/etc/man/man1/meroxa-endpoints-create.1 +++ b/etc/man/man1/meroxa-endpoints-create.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-endpoints-describe.1 b/etc/man/man1/meroxa-endpoints-describe.1 index c38aff0f4..5bed3b955 100644 --- a/etc/man/man1/meroxa-endpoints-describe.1 +++ b/etc/man/man1/meroxa-endpoints-describe.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-endpoints-list.1 b/etc/man/man1/meroxa-endpoints-list.1 index 8ec3133e2..0e850ddb4 100644 --- a/etc/man/man1/meroxa-endpoints-list.1 +++ b/etc/man/man1/meroxa-endpoints-list.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-endpoints-remove.1 b/etc/man/man1/meroxa-endpoints-remove.1 index 4fb49391f..629430973 100644 --- a/etc/man/man1/meroxa-endpoints-remove.1 +++ b/etc/man/man1/meroxa-endpoints-remove.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-endpoints.1 b/etc/man/man1/meroxa-endpoints.1 index cad182d0e..3cc7ad1d6 100644 --- a/etc/man/man1/meroxa-endpoints.1 +++ b/etc/man/man1/meroxa-endpoints.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-environments-create.1 b/etc/man/man1/meroxa-environments-create.1 index a81d8453b..42724ef96 100644 --- a/etc/man/man1/meroxa-environments-create.1 +++ b/etc/man/man1/meroxa-environments-create.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-environments-describe.1 b/etc/man/man1/meroxa-environments-describe.1 index 15eb7933a..8231bcfed 100644 --- a/etc/man/man1/meroxa-environments-describe.1 +++ b/etc/man/man1/meroxa-environments-describe.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-environments-list.1 b/etc/man/man1/meroxa-environments-list.1 index d0c867e22..57d7b5b07 100644 --- a/etc/man/man1/meroxa-environments-list.1 +++ b/etc/man/man1/meroxa-environments-list.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-environments-remove.1 b/etc/man/man1/meroxa-environments-remove.1 index 23c06dd77..85ae840d1 100644 --- a/etc/man/man1/meroxa-environments-remove.1 +++ b/etc/man/man1/meroxa-environments-remove.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-environments-repair.1 b/etc/man/man1/meroxa-environments-repair.1 index 181b0cbc4..6793da86b 100644 --- a/etc/man/man1/meroxa-environments-repair.1 +++ b/etc/man/man1/meroxa-environments-repair.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-environments-update.1 b/etc/man/man1/meroxa-environments-update.1 index 966e23afa..eb6638403 100644 --- a/etc/man/man1/meroxa-environments-update.1 +++ b/etc/man/man1/meroxa-environments-update.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-environments.1 b/etc/man/man1/meroxa-environments.1 index 3ce7e8b77..d64af7ff2 100644 --- a/etc/man/man1/meroxa-environments.1 +++ b/etc/man/man1/meroxa-environments.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-login.1 b/etc/man/man1/meroxa-login.1 index 0d7a47073..247fb4a30 100644 --- a/etc/man/man1/meroxa-login.1 +++ b/etc/man/man1/meroxa-login.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-logout.1 b/etc/man/man1/meroxa-logout.1 index 7f7495682..214b2d928 100644 --- a/etc/man/man1/meroxa-logout.1 +++ b/etc/man/man1/meroxa-logout.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-open-billing.1 b/etc/man/man1/meroxa-open-billing.1 index 12c113a3b..d8627b17d 100644 --- a/etc/man/man1/meroxa-open-billing.1 +++ b/etc/man/man1/meroxa-open-billing.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-open.1 b/etc/man/man1/meroxa-open.1 index 0997471a4..80c9d740a 100644 --- a/etc/man/man1/meroxa-open.1 +++ b/etc/man/man1/meroxa-open.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-resources-create.1 b/etc/man/man1/meroxa-resources-create.1 index 28c0731f0..72bc5648a 100644 --- a/etc/man/man1/meroxa-resources-create.1 +++ b/etc/man/man1/meroxa-resources-create.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-resources-describe.1 b/etc/man/man1/meroxa-resources-describe.1 index ea22e585a..1a7c1459d 100644 --- a/etc/man/man1/meroxa-resources-describe.1 +++ b/etc/man/man1/meroxa-resources-describe.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-resources-list.1 b/etc/man/man1/meroxa-resources-list.1 index 55a54db9d..8df1e2eb4 100644 --- a/etc/man/man1/meroxa-resources-list.1 +++ b/etc/man/man1/meroxa-resources-list.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-resources-remove.1 b/etc/man/man1/meroxa-resources-remove.1 index 9b41182c8..9b33029fc 100644 --- a/etc/man/man1/meroxa-resources-remove.1 +++ b/etc/man/man1/meroxa-resources-remove.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-resources-rotate-tunnel-key.1 b/etc/man/man1/meroxa-resources-rotate-tunnel-key.1 index a86dad596..47f4e29c2 100644 --- a/etc/man/man1/meroxa-resources-rotate-tunnel-key.1 +++ b/etc/man/man1/meroxa-resources-rotate-tunnel-key.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-resources-update.1 b/etc/man/man1/meroxa-resources-update.1 index ba5c0a4e2..25918ade9 100644 --- a/etc/man/man1/meroxa-resources-update.1 +++ b/etc/man/man1/meroxa-resources-update.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-resources-validate.1 b/etc/man/man1/meroxa-resources-validate.1 index 2f9ec7f05..4ef07d033 100644 --- a/etc/man/man1/meroxa-resources-validate.1 +++ b/etc/man/man1/meroxa-resources-validate.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-resources.1 b/etc/man/man1/meroxa-resources.1 index b18e2281b..b7b667088 100644 --- a/etc/man/man1/meroxa-resources.1 +++ b/etc/man/man1/meroxa-resources.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-transforms-list.1 b/etc/man/man1/meroxa-transforms-list.1 index 186f1ed35..8bd03d484 100644 --- a/etc/man/man1/meroxa-transforms-list.1 +++ b/etc/man/man1/meroxa-transforms-list.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-transforms.1 b/etc/man/man1/meroxa-transforms.1 index d54ccc29c..d6e0e70cf 100644 --- a/etc/man/man1/meroxa-transforms.1 +++ b/etc/man/man1/meroxa-transforms.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-version.1 b/etc/man/man1/meroxa-version.1 index 2c1653b2f..3eda7b7e3 100644 --- a/etc/man/man1/meroxa-version.1 +++ b/etc/man/man1/meroxa-version.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa-whoami.1 b/etc/man/man1/meroxa-whoami.1 index ca331e20b..b1b03f7c5 100644 --- a/etc/man/man1/meroxa-whoami.1 +++ b/etc/man/man1/meroxa-whoami.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/etc/man/man1/meroxa.1 b/etc/man/man1/meroxa.1 index 906fc7df4..05aa1114e 100644 --- a/etc/man/man1/meroxa.1 +++ b/etc/man/man1/meroxa.1 @@ -1,5 +1,5 @@ .nh -.TH "Meroxa" "1" "Jun 2022" "Meroxa CLI " "Meroxa Manual" +.TH "Meroxa" "1" "Aug 2022" "Meroxa CLI " "Meroxa Manual" .SH NAME .PP diff --git a/go.mod b/go.mod index a8d8914f3..b4f780f37 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/manifoldco/promptui v0.8.0 github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-runewidth v0.0.10 // indirect - github.com/meroxa/meroxa-go v0.0.0-20220711165903-c09da3162930 + github.com/meroxa/meroxa-go v0.0.0-20220802095537-beb01d916646 github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 github.com/rivo/uniseg v0.2.0 // indirect @@ -97,5 +97,3 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace github.com/meroxa/turbine-go => ../turbine-go diff --git a/go.sum b/go.sum index ba2c43bce..8a671f00f 100644 --- a/go.sum +++ b/go.sum @@ -563,8 +563,10 @@ github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lL github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/meroxa/meroxa-go v0.0.0-20220711165903-c09da3162930 h1:K2XpGYdkvI3J03JX7+9f2U3QspZgMr+tUgg2phkwLJI= -github.com/meroxa/meroxa-go v0.0.0-20220711165903-c09da3162930/go.mod h1:qczCsZeXwn2R+JeEVjPkgtIMGROQ1Si8ox+OC2nfOYg= +github.com/meroxa/meroxa-go v0.0.0-20220802095537-beb01d916646 h1:HG42GPLNMo8dwkiRaqU9WtAQbxn1gcWMGl4RnqQRIso= +github.com/meroxa/meroxa-go v0.0.0-20220802095537-beb01d916646/go.mod h1:qczCsZeXwn2R+JeEVjPkgtIMGROQ1Si8ox+OC2nfOYg= +github.com/meroxa/turbine-go v0.0.0-20220720222241-fb02bcb83a88 h1:b8G0ZKrNERi5qc/SBeHmoZF/9YKutMXevUPzOFYb4SU= +github.com/meroxa/turbine-go v0.0.0-20220720222241-fb02bcb83a88/go.mod h1:x6qIhTUBt8961KrUUioSTd1sCsRKMBvZ3LSS2BDUhJo= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= diff --git a/utils/display.go b/utils/display.go deleted file mode 100644 index 12b43789a..000000000 --- a/utils/display.go +++ /dev/null @@ -1,1054 +0,0 @@ -package utils - -import ( - "encoding/json" - "fmt" - "net/url" - "strconv" - "strings" - - "github.com/alexeyco/simpletable" - "github.com/meroxa/meroxa-go/pkg/meroxa" -) - -func EndpointsTable(ends []meroxa.Endpoint, hideHeaders bool) string { - if len(ends) == 0 { - return "" - } - - table := simpletable.New() - - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "NAME"}, - {Align: simpletable.AlignCenter, Text: "PROTOCOL"}, - {Align: simpletable.AlignCenter, Text: "STREAM"}, - {Align: simpletable.AlignCenter, Text: "URL"}, - {Align: simpletable.AlignCenter, Text: "READY"}, - }, - } - } - - for _, end := range ends { - var u string - switch end.Protocol { - case meroxa.EndpointProtocolHttp: - host, err := url.ParseRequestURI(end.Host) - if err != nil { - continue - } - host.User = url.UserPassword(end.BasicAuthUsername, end.BasicAuthPassword) - u = host.String() - case meroxa.EndpointProtocolGrpc: - u = fmt.Sprintf("host=%s username=%s password=%s", end.Host, end.BasicAuthUsername, end.BasicAuthPassword) - } - - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: end.Name}, - {Text: string(end.Protocol)}, - {Text: end.Stream}, - {Text: u}, - {Text: strconv.FormatBool(end.Ready)}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - table.SetStyle(simpletable.StyleCompact) - - return table.String() -} - -func ResourceTable(res *meroxa.Resource) string { - tunnel := "N/A" - if res.SSHTunnel != nil { - tunnel = "SSH" - } - - mainTable := simpletable.New() - mainTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: "UUID:"}, - {Text: res.UUID}, - }, - { - {Align: simpletable.AlignRight, Text: "Name:"}, - {Text: res.Name}, - }, - { - {Align: simpletable.AlignRight, Text: "Type:"}, - {Text: string(res.Type)}, - }, - { - {Align: simpletable.AlignRight, Text: "URL:"}, - {Text: res.URL}, - }, - { - {Align: simpletable.AlignRight, Text: "Tunnel:"}, - {Text: tunnel}, - }, - { - {Align: simpletable.AlignRight, Text: "State:"}, - {Text: string(res.Status.State)}, - }, - } - - if res.Status.Details != "" { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "State details:"}, - {Text: res.Status.Details}, - }) - } - - if res.Environment != nil { - if res.Environment.UUID.Valid { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment UUID:"}, - {Text: res.Environment.UUID.String}, - }) - } - - if res.Environment.Name.Valid { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment Name:"}, - {Text: res.Environment.Name.String}, - }) - } - } else { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment Name:"}, - {Text: string(meroxa.EnvironmentTypeCommon)}, - }) - } - - mainTable.SetStyle(simpletable.StyleCompact) - - return mainTable.String() -} - -func PipelineTable(p *meroxa.Pipeline) string { - mainTable := simpletable.New() - mainTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: "UUID:"}, - {Text: p.UUID}, - }, - { - {Align: simpletable.AlignRight, Text: "Name:"}, - {Text: p.Name}, - }, - } - - if p.Environment != nil { - if p.Environment.UUID.Valid { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment UUID:"}, - {Text: p.Environment.UUID.String}, - }) - } - if p.Environment.Name.Valid { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment Name:"}, - {Text: p.Environment.Name.String}, - }) - } - } else { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment Name:"}, - {Text: string(meroxa.EnvironmentTypeCommon)}, - }) - } - - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "State:"}, - {Text: string(p.State)}, - }) - - mainTable.SetStyle(simpletable.StyleCompact) - - return mainTable.String() -} - -func PrintPipelineTable(pipeline *meroxa.Pipeline) { - fmt.Println(PipelineTable(pipeline)) -} - -func ResourcesTable(resources []*meroxa.Resource, hideHeaders bool) string { - if len(resources) != 0 { - table := simpletable.New() - - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "UUID"}, - {Align: simpletable.AlignCenter, Text: "NAME"}, - {Align: simpletable.AlignCenter, Text: "TYPE"}, - {Align: simpletable.AlignCenter, Text: "ENVIRONMENT"}, - {Align: simpletable.AlignCenter, Text: "URL"}, - {Align: simpletable.AlignCenter, Text: "TUNNEL"}, - {Align: simpletable.AlignCenter, Text: "STATE"}, - }, - } - } - - for _, res := range resources { - tunnel := "N/A" - if res.SSHTunnel != nil { - tunnel = "SSH" - } - - var env string - - if res.Environment != nil && res.Environment.Name.Valid { - env = res.Environment.Name.String - } else { - env = string(meroxa.EnvironmentTypeCommon) - } - - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: res.UUID}, - {Text: res.Name}, - {Text: string(res.Type)}, - {Text: env}, - {Text: res.URL}, - {Align: simpletable.AlignCenter, Text: tunnel}, - {Align: simpletable.AlignCenter, Text: string(res.Status.State)}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - table.SetStyle(simpletable.StyleCompact) - return table.String() - } - - return "" -} - -func PrintResourcesTable(resources []*meroxa.Resource, hideHeaders bool) { - fmt.Println(ResourcesTable(resources, hideHeaders)) -} - -func TransformsTable(transforms []*meroxa.Transform, hideHeaders bool) string { - if len(transforms) != 0 { - table := simpletable.New() - - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "NAME"}, - {Align: simpletable.AlignCenter, Text: "TYPE"}, - {Align: simpletable.AlignCenter, Text: "REQUIRED"}, - {Align: simpletable.AlignCenter, Text: "DESCRIPTION"}, - {Align: simpletable.AlignCenter, Text: "PROPERTIES"}, - }, - } - } - - for _, res := range transforms { - r := []*simpletable.Cell{ - {Text: res.Name}, - {Text: res.Type}, - {Text: strconv.FormatBool(res.Required)}, - {Text: truncateString(res.Description, 151)}, // nolint:gomnd - } - - var properties []string - for _, p := range res.Properties { - properties = append(properties, p.Name) - } - var cell = &simpletable.Cell{ - Text: strings.Join(properties, ","), - } - - r = append(r, cell) - table.Body.Cells = append(table.Body.Cells, r) - } - table.SetStyle(simpletable.StyleCompact) - return table.String() - } - - return "" -} - -func ConnectorTable(connector *meroxa.Connector) string { - mainTable := simpletable.New() - mainTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: "UUID:"}, - {Text: connector.UUID}, - }, - { - {Align: simpletable.AlignRight, Text: "Name:"}, - {Text: connector.Name}, - }, - { - {Align: simpletable.AlignRight, Text: "Type:"}, - {Text: string(connector.Type)}, - }, - { - {Align: simpletable.AlignRight, Text: "Streams:"}, - {Text: formatStreams(connector.Streams)}, - }, - { - {Align: simpletable.AlignRight, Text: "State:"}, - {Text: string(connector.State)}, - }, - { - {Align: simpletable.AlignRight, Text: "Pipeline:"}, - {Text: connector.PipelineName}, - }, - } - - if connector.Trace != "" { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Trace:"}, - {Text: connector.Trace}, - }) - } - if connector.Environment != nil { - if connector.Environment.UUID.Valid { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment UUID:"}, - {Text: connector.Environment.UUID.String}, - }) - } - if connector.Environment.Name.Valid { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment Name:"}, - {Text: connector.Environment.Name.String}, - }) - } - } else { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment Name:"}, - {Text: string(meroxa.EnvironmentTypeCommon)}, - }) - } - - mainTable.SetStyle(simpletable.StyleCompact) - - return mainTable.String() -} - -func ConnectorsTable(connectors []*meroxa.Connector, hideHeaders bool) string { - if len(connectors) != 0 { - table := simpletable.New() - - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "UUID"}, - {Align: simpletable.AlignCenter, Text: "NAME"}, - {Align: simpletable.AlignCenter, Text: "TYPE"}, - {Align: simpletable.AlignCenter, Text: "STREAMS"}, - {Align: simpletable.AlignCenter, Text: "STATE"}, - {Align: simpletable.AlignCenter, Text: "PIPELINE"}, - {Align: simpletable.AlignCenter, Text: "ENVIRONMENT"}, - }, - } - } - - for _, conn := range connectors { - var env string - - if conn.Environment != nil && conn.Environment.Name.Valid { - env = conn.Environment.Name.String - } else { - env = string(meroxa.EnvironmentTypeCommon) - } - - streamStr := formatStreams(conn.Streams) - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: conn.UUID}, - {Text: conn.Name}, - {Text: string(conn.Type)}, - {Text: streamStr}, - {Text: string(conn.State)}, - {Text: conn.PipelineName}, - {Text: env}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - table.SetStyle(simpletable.StyleCompact) - return table.String() - } - - return "" -} - -func formatStreams(ss map[string]interface{}) string { - var streamStr string - - if streamInput, ok := ss["input"]; ok { - streamStr += "(input) " - - streamInterface := streamInput.([]interface{}) - for i, v := range streamInterface { - streamStr += fmt.Sprintf("%v", v) - - if i < len(streamInterface)-1 { - streamStr += ", " - } - } - } - - if streamOutput, ok := ss["output"]; ok { - streamStr += "(output) " - - streamInterface := streamOutput.([]interface{}) - for i, v := range streamInterface { - streamStr += fmt.Sprintf("%v", v) - - if i < len(streamInterface)-1 { - streamStr += ", " - } - } - } - return streamStr -} - -func PrintConnectorsTable(connectors []*meroxa.Connector, hideHeaders bool) { - fmt.Println(ConnectorsTable(connectors, hideHeaders)) -} - -func ResourceTypesTable(types []string, hideHeaders bool) string { - table := simpletable.New() - - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "TYPES"}, - }, - } - } - - for _, t := range types { - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: t}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - table.SetStyle(simpletable.StyleCompact) - return table.String() -} - -func PrintResourceTypesTable(types []string, hideHeaders bool) { - fmt.Println(ResourceTypesTable(types, hideHeaders)) -} - -func PipelinesTable(pipelines []*meroxa.Pipeline, hideHeaders bool) string { - if len(pipelines) != 0 { - table := simpletable.New() - - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "UUID"}, - {Align: simpletable.AlignCenter, Text: "NAME"}, - {Align: simpletable.AlignCenter, Text: "ENVIRONMENT"}, - {Align: simpletable.AlignCenter, Text: "STATE"}, - }, - } - } - - for _, p := range pipelines { - var env string - - if p.Environment != nil && p.Environment.Name.Valid { - env = p.Environment.Name.String - } else { - env = string(meroxa.EnvironmentTypeCommon) - } - - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: p.UUID}, - {Align: simpletable.AlignCenter, Text: p.Name}, - {Align: simpletable.AlignCenter, Text: env}, - {Align: simpletable.AlignCenter, Text: string(p.State)}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - table.SetStyle(simpletable.StyleCompact) - return table.String() - } - return "" -} - -func PrintPipelinesTable(pipelines []*meroxa.Pipeline, hideHeaders bool) { - fmt.Println(PipelinesTable(pipelines, hideHeaders)) -} - -func FunctionsTable(funs []*meroxa.Function, hideHeaders bool) string { - if len(funs) == 0 { - return "" - } - - table := simpletable.New() - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "UUID"}, - {Align: simpletable.AlignCenter, Text: "NAME"}, - {Align: simpletable.AlignCenter, Text: "INPUT STREAM"}, - {Align: simpletable.AlignCenter, Text: "OUTPUT STREAM"}, - {Align: simpletable.AlignCenter, Text: "STATE"}, - {Align: simpletable.AlignCenter, Text: "PIPELINE"}, - }, - } - } - - for _, p := range funs { - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: p.UUID}, - {Align: simpletable.AlignCenter, Text: p.Name}, - {Align: simpletable.AlignCenter, Text: p.InputStream}, - {Align: simpletable.AlignCenter, Text: p.OutputStream}, - {Align: simpletable.AlignCenter, Text: p.Status.State}, - {Align: simpletable.AlignCenter, Text: p.Pipeline.Name}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - - table.SetStyle(simpletable.StyleCompact) - return table.String() -} - -func FunctionTable(fun *meroxa.Function) string { - envVars := []string{} - for k, v := range fun.EnvVars { - envVars = append(envVars, fmt.Sprintf("%s=%s", k, v)) - } - - mainTable := simpletable.New() - mainTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: "UUID:"}, - {Text: fun.UUID}, - }, - { - {Align: simpletable.AlignRight, Text: "Name:"}, - {Text: fun.Name}, - }, - { - {Align: simpletable.AlignRight, Text: "Input Stream:"}, - {Text: fun.InputStream}, - }, - { - {Align: simpletable.AlignRight, Text: "Output Stream:"}, - {Text: fun.OutputStream}, - }, - { - {Align: simpletable.AlignRight, Text: "Image:"}, - {Text: fun.Image}, - }, - { - {Align: simpletable.AlignRight, Text: "Command:"}, - {Text: strings.Join(fun.Command, " ")}, - }, - { - {Align: simpletable.AlignRight, Text: "Arguments:"}, - {Text: strings.Join(fun.Args, " ")}, - }, - { - {Align: simpletable.AlignRight, Text: "Environment Variables:"}, - {Text: strings.Join(envVars, "\n")}, - }, - { - {Align: simpletable.AlignRight, Text: "Pipeline:"}, - {Text: fun.Pipeline.Name}, - }, - { - {Align: simpletable.AlignRight, Text: "State:"}, - {Text: fun.Status.State}, - }, - } - mainTable.SetStyle(simpletable.StyleCompact) - table := mainTable.String() - - details := fun.Status.Details - if details == "" { - return table - } - - return fmt.Sprintf("%s\n\n%s", table, details) -} - -func EnvironmentsTable(environments []*meroxa.Environment, hideHeaders bool) string { - if len(environments) != 0 { - table := simpletable.New() - - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "UUID"}, - {Align: simpletable.AlignCenter, Text: "NAME"}, - {Align: simpletable.AlignCenter, Text: "TYPE"}, - {Align: simpletable.AlignCenter, Text: "PROVIDER"}, - {Align: simpletable.AlignCenter, Text: "REGION"}, - {Align: simpletable.AlignCenter, Text: "STATE"}, - }, - } - } - - for _, p := range environments { - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: p.UUID}, - {Align: simpletable.AlignCenter, Text: p.Name}, - {Align: simpletable.AlignCenter, Text: string(p.Type)}, - {Align: simpletable.AlignCenter, Text: string(p.Provider)}, - {Align: simpletable.AlignCenter, Text: string(p.Region)}, - {Align: simpletable.AlignCenter, Text: string(p.Status.State)}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - table.SetStyle(simpletable.StyleCompact) - return table.String() - } - return "" -} - -// nolint:funlen -func EnvironmentTable(environment *meroxa.Environment) string { - mainTable := simpletable.New() - - mainTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: "UUID:"}, - {Text: environment.UUID}, - }, - { - {Align: simpletable.AlignRight, Text: "Name:"}, - {Text: environment.Name}, - }, - { - {Align: simpletable.AlignRight, Text: "Provider:"}, - {Text: string(environment.Provider)}, - }, - { - {Align: simpletable.AlignRight, Text: "Region:"}, - {Text: string(environment.Region)}, - }, - { - {Align: simpletable.AlignRight, Text: "Type:"}, - {Text: string(environment.Type)}, - }, - - { - {Align: simpletable.AlignRight, Text: "Created At:"}, - {Text: environment.CreatedAt.String()}, - }, - { - {Align: simpletable.AlignRight, Text: "Updated At:"}, - {Text: environment.UpdatedAt.String()}, - }, - { - {Align: simpletable.AlignRight, Text: "Environment Status:"}, - {Text: string(environment.Status.State)}, - }, - } - - if environment.Status.Details != "" { - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Environment Status Details:"}, - {Text: string(environment.Status.State)}, - } - mainTable.Body.Cells = append(mainTable.Body.Cells, r) - } - - mainTable.SetStyle(simpletable.StyleCompact) - str := mainTable.String() - - if environment.Status.PreflightDetails != nil { - preflightTable := simpletable.New() - preflightTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: " Preflight Checks:"}, - {Text: ""}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS EC2 Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.EC2, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS EKS Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.EKS, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS IAM Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.IAM, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS KMS Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.KMS, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS MKS Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.MSK, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS S3 Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.S3, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS ServiceQuotas Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.ServiceQuotas, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS CloudFormation Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.Cloudformation, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS Cloudwatch Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.Cloudwatch, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS EIP Limits Status:"}, - {Text: environment.Status.PreflightDetails.PreflightLimits.EIP}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS NAT Limits Status:"}, - {Text: environment.Status.PreflightDetails.PreflightLimits.NAT}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS VPC Limits Status:"}, - {Text: environment.Status.PreflightDetails.PreflightLimits.VPC}, - }, - } - preflightTable.SetStyle(simpletable.StyleCompact) - str += "\n" + preflightTable.String() - } - - return str -} - -func EnvironmentPreflightTable(environment *meroxa.Environment) string { - if environment.Status.PreflightDetails != nil { - preflightTable := simpletable.New() - preflightTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: " Preflight Checks:"}, - {Text: ""}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS EC2 Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.EC2, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS EKS Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.EKS, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS IAM Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.IAM, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS KMS Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.KMS, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS MKS Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.MSK, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS S3 Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.S3, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS ServiceQuotas Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.ServiceQuotas, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS CloudFormation Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.Cloudformation, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS Cloudwatch Permissions Status:"}, - {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.Cloudwatch, " ; ")}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS EIP Limits Status:"}, - {Text: environment.Status.PreflightDetails.PreflightLimits.EIP}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS NAT Limits Status:"}, - {Text: environment.Status.PreflightDetails.PreflightLimits.NAT}, - }, - { - {Align: simpletable.AlignRight, Text: "AWS VPC Limits Status:"}, - {Text: environment.Status.PreflightDetails.PreflightLimits.VPC}, - }, - } - preflightTable.SetStyle(simpletable.StyleCompact) - return preflightTable.String() - } - return "" -} - -func PrintEnvironmentsTable(environments []*meroxa.Environment, hideHeaders bool) { - fmt.Println(EnvironmentsTable(environments, hideHeaders)) -} - -func AppsTable(apps []*meroxa.Application, hideHeaders bool) string { - if len(apps) == 0 { - return "" - } - - table := simpletable.New() - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "UUID"}, - {Align: simpletable.AlignCenter, Text: "NAME"}, - {Align: simpletable.AlignCenter, Text: "LANGUAGE"}, - {Align: simpletable.AlignCenter, Text: "GIT SHA"}, - {Align: simpletable.AlignCenter, Text: "STATE"}, - }, - } - } - - for _, app := range apps { - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: app.UUID}, - {Align: simpletable.AlignCenter, Text: app.Name}, - {Align: simpletable.AlignCenter, Text: app.Language}, - {Align: simpletable.AlignCenter, Text: app.GitSha}, - {Align: simpletable.AlignCenter, Text: string(app.Status.State)}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - - table.SetStyle(simpletable.StyleCompact) - return table.String() -} - -func PrintAppsTable(apps []*meroxa.Application, hideHeaders bool) { - fmt.Println(AppsTable(apps, hideHeaders)) -} - -func AppTable(app *meroxa.Application) string { - mainTable := simpletable.New() - mainTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: "UUID:"}, - {Text: app.UUID}, - }, - { - {Align: simpletable.AlignRight, Text: "Name:"}, - {Text: app.Name}, - }, - { - {Align: simpletable.AlignRight, Text: "Language:"}, - {Text: app.Language}, - }, - { - {Align: simpletable.AlignRight, Text: "Git SHA:"}, - {Text: strings.TrimSpace(app.GitSha)}, - }, - { - {Align: simpletable.AlignRight, Text: "Created At:"}, - {Text: app.CreatedAt.String()}, - }, - { - {Align: simpletable.AlignRight, Text: "Updated At:"}, - {Text: app.UpdatedAt.String()}, - }, - { - {Align: simpletable.AlignRight, Text: "State:"}, - {Text: string(app.Status.State)}, - }, - } - - details := app.Status.Details - if details != "" { - mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "State details:"}, - {Text: details}, - }) - } - - mainTable.SetStyle(simpletable.StyleCompact) - return mainTable.String() -} - -func AppExtendedTable(app *meroxa.Application, resources []*meroxa.Resource, connectors map[string]*meroxa.Connector, - functions []*meroxa.Function) string { - mainTable := simpletable.New() - mainTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: "UUID:"}, - {Text: app.UUID}, - }, - { - {Align: simpletable.AlignRight, Text: "Name:"}, - {Text: app.Name}, - }, - { - {Align: simpletable.AlignRight, Text: "Language:"}, - {Text: app.Language}, - }, - { - {Align: simpletable.AlignRight, Text: "Git SHA:"}, - {Text: strings.TrimSpace(app.GitSha)}, - }, - { - {Align: simpletable.AlignRight, Text: "Created At:"}, - {Text: app.CreatedAt.String()}, - }, - { - {Align: simpletable.AlignRight, Text: "Updated At:"}, - {Text: app.UpdatedAt.String()}, - }, - { - {Align: simpletable.AlignRight, Text: "State:"}, - {Text: string(app.Status.State)}, - }, - } - mainTable.SetStyle(simpletable.StyleCompact) - output := mainTable.String() - - subTable := extendedResourcesTable(resources, connectors) - if subTable != "" { - output += "\n" + subTable - } - subTable = extendedFunctionsTable(functions) - if subTable != "" { - output += "\n" + subTable - } - return output -} - -func extendedResourcesTable(resources []*meroxa.Resource, connectors map[string]*meroxa.Connector) string { - if len(resources) == 0 { - return "" - } - subTable := "\tResources\n" - - for _, r := range resources { - c, ok := connectors[r.Name] - if !ok { - panic("internal error") - } - - subTable += fmt.Sprintf("\t %s\n", r.Name) - subTable += fmt.Sprintf("\t\t%5s: %s\n", "UUID", r.UUID) - subTable += fmt.Sprintf("\t\t%5s: %s\n", "Type", string(r.Type)) - subTable += fmt.Sprintf("\t\t%5s: %s\n", "State", string(c.State)) - subTable += fmt.Sprintf("\t\t%5s: %s\n", "As", string(c.Type)) - - if c.Trace != "" { - subTable += fmt.Sprintf("\t\t%5s: %s\n", "Trace", c.Trace) - } - } - - return subTable -} - -func extendedFunctionsTable(functions []*meroxa.Function) string { - if len(functions) == 0 { - return "" - } - subTable := "\tFunctions\n" - - for _, f := range functions { - subTable += fmt.Sprintf("\t %s\n", f.Name) - subTable += fmt.Sprintf("\t\t%5s: %s\n", "UUID", f.UUID) - subTable += fmt.Sprintf("\t\t%5s: %s\n", "State", f.Status.State) - - if f.Logs != "" { - subTable += fmt.Sprintf("\t\t%5s: %s\n", "Logs", f.Logs) - } - } - - return subTable -} - -// BuildsTable displays multiple build records for future listing per app. -func BuildsTable(builds []*meroxa.Build, hideHeaders bool) string { - if len(builds) == 0 { - return "" - } - - table := simpletable.New() - if !hideHeaders { - table.Header = &simpletable.Header{ - Cells: []*simpletable.Cell{ - {Align: simpletable.AlignCenter, Text: "UUID"}, - {Align: simpletable.AlignCenter, Text: "STATE"}, - {Align: simpletable.AlignCenter, Text: "CREATED AT"}, - {Align: simpletable.AlignCenter, Text: "UPDATED AT"}, - }, - } - } - - for _, p := range builds { - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: p.Uuid}, - {Align: simpletable.AlignCenter, Text: p.Status.State}, - {Align: simpletable.AlignCenter, Text: p.CreatedAt}, - {Align: simpletable.AlignCenter, Text: p.UpdatedAt}, - } - - table.Body.Cells = append(table.Body.Cells, r) - } - - table.SetStyle(simpletable.StyleCompact) - return table.String() -} - -func BuildTable(build *meroxa.Build) string { - mainTable := simpletable.New() - mainTable.Body.Cells = [][]*simpletable.Cell{ - { - {Align: simpletable.AlignRight, Text: "UUID:"}, - {Text: build.Uuid}, - }, - { - {Align: simpletable.AlignRight, Text: "Created At:"}, - {Text: build.CreatedAt}, - }, - { - {Align: simpletable.AlignRight, Text: "Updated At:"}, - {Text: build.UpdatedAt}, - }, - { - {Align: simpletable.AlignRight, Text: "State:"}, - {Text: build.Status.State}, - }, - } - if build.Status.Details != "" { - r := []*simpletable.Cell{ - {Align: simpletable.AlignRight, Text: "Status Details:"}, - {Text: build.Status.Details}, - } - mainTable.Body.Cells = append(mainTable.Body.Cells, r) - } - mainTable.SetStyle(simpletable.StyleCompact) - return mainTable.String() -} - -func truncateString(oldString string, l int) string { - str := oldString - - if len(oldString) > l { - str = oldString[:l] + "..." - } - - return str -} - -func PrettyString(a interface{}) (string, error) { - j, err := json.MarshalIndent(a, "", " ") - if err != nil { - return "", err - } - if string(j) == "null" { - return "", fmt.Errorf("unsuccessful marshal indent") - } - return string(j), nil -} diff --git a/utils/display/apps.go b/utils/display/apps.go new file mode 100644 index 000000000..d563f271f --- /dev/null +++ b/utils/display/apps.go @@ -0,0 +1,140 @@ +package display + +import ( + "fmt" + "strings" + + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +type AppExtendedConnector struct { + Connector *meroxa.Connector + Logs string +} + +func AppsTable(apps []*meroxa.Application, hideHeaders bool) string { + if len(apps) == 0 { + return "" + } + + table := simpletable.New() + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "UUID"}, + {Align: simpletable.AlignCenter, Text: "NAME"}, + {Align: simpletable.AlignCenter, Text: "LANGUAGE"}, + {Align: simpletable.AlignCenter, Text: "GIT SHA"}, + {Align: simpletable.AlignCenter, Text: "STATE"}, + }, + } + } + + for _, app := range apps { + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: app.UUID}, + {Align: simpletable.AlignCenter, Text: app.Name}, + {Align: simpletable.AlignCenter, Text: app.Language}, + {Align: simpletable.AlignCenter, Text: app.GitSha}, + {Align: simpletable.AlignCenter, Text: string(app.Status.State)}, + } + + table.Body.Cells = append(table.Body.Cells, r) + } + + table.SetStyle(simpletable.StyleCompact) + return table.String() +} + +func AppTable(app *meroxa.Application, resources []*meroxa.Resource, connectors []*meroxa.Connector, + functions []*meroxa.Function) string { + mainTable := simpletable.New() + mainTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: "UUID:"}, + {Text: app.UUID}, + }, + { + {Align: simpletable.AlignRight, Text: "Name:"}, + {Text: app.Name}, + }, + { + {Align: simpletable.AlignRight, Text: "Language:"}, + {Text: app.Language}, + }, + { + {Align: simpletable.AlignRight, Text: "Git SHA:"}, + {Text: strings.TrimSpace(app.GitSha)}, + }, + { + {Align: simpletable.AlignRight, Text: "Created At:"}, + {Text: app.CreatedAt.String()}, + }, + { + {Align: simpletable.AlignRight, Text: "Updated At:"}, + {Text: app.UpdatedAt.String()}, + }, + { + {Align: simpletable.AlignRight, Text: "State:"}, + {Text: string(app.Status.State)}, + }, + } + mainTable.SetStyle(simpletable.StyleCompact) + output := mainTable.String() + + subTable := extendedResourcesTable(resources, connectors) + if subTable != "" { + output += "\n" + subTable + } + subTable = extendedFunctionsTable(functions) + if subTable != "" { + output += "\n" + subTable + } + return output +} + +func AppLogsTable(resources []meroxa.ApplicationResource, connectors []*AppExtendedConnector, functions []*meroxa.Function) string { + var r meroxa.ApplicationResource + var subTable string + + for _, c := range connectors { + found := false + for _, resource := range resources { + if resource.Name.String == c.Connector.ResourceName { + r = resource + found = true + break + } + } + if !found { + panic("internal error") + } + + // Only show information if there are logs or a trace available + if c.Logs != "" || c.Connector.Trace != "" { + if r.Collection.Source.String != "" { + subTable += fmt.Sprintf("\n%s (source)", r.Name.String) + } + if r.Collection.Destination.String != "" { + subTable += fmt.Sprintf("\n%s (destination)", r.Name.String) + } + } + + if c.Logs != "" { + subTable += fmt.Sprintf("\n\t%s\n", c.Logs) + } + + if c.Connector.Trace != "" { + subTable += fmt.Sprintf("\n\t%s\n", c.Connector.Trace) + } + } + + for _, f := range functions { + if f.Logs != "" { + subTable += fmt.Sprintf("\n%s (function)\n\t%s\n", r.Name.String, f.Logs) + } + } + + return subTable +} diff --git a/utils/display/apps_test.go b/utils/display/apps_test.go new file mode 100644 index 000000000..a60289053 --- /dev/null +++ b/utils/display/apps_test.go @@ -0,0 +1,64 @@ +package display + +import ( + "fmt" + "strings" + "testing" + + "github.com/meroxa/meroxa-go/pkg/meroxa" + "github.com/volatiletech/null/v8" + + "github.com/meroxa/cli/utils" +) + +func TestAppLogsTable(t *testing.T) { + app := utils.GenerateApplication("") + res1 := "res1" + res2 := "res2" + + app.Resources = []meroxa.ApplicationResource{ + { + EntityIdentifier: meroxa.EntityIdentifier{Name: null.StringFrom(res1)}, + Collection: meroxa.ResourceCollection{ + Name: null.StringFrom(res1), + Source: null.StringFrom("source"), + }, + }, + { + EntityIdentifier: meroxa.EntityIdentifier{Name: null.StringFrom(res2)}, + Collection: meroxa.ResourceCollection{ + Name: null.StringFrom(res2), + Destination: null.StringFrom("destination"), + }, + }, + } + + log := "custom log" + + connectors := []*AppExtendedConnector{ + {Connector: &meroxa.Connector{ + Name: "conn1", ResourceName: res1, Type: meroxa.ConnectorTypeSource, State: meroxa.ConnectorStateRunning}, + Logs: log}, + {Connector: &meroxa.Connector{ + Name: "conn2", ResourceName: res2, Type: meroxa.ConnectorTypeDestination, State: meroxa.ConnectorStateRunning}, + Logs: log}, + } + + functions := []*meroxa.Function{ + {Name: "fun1", UUID: "abc-def", Status: meroxa.FunctionStatus{State: "running"}, Logs: log}, + } + + out := AppLogsTable(app.Resources, connectors, functions) + + if !strings.Contains(out, "custom log") { + t.Errorf("expected %q to be shown", log) + } + + if !strings.Contains(out, fmt.Sprintf("%s (source)", res1)) { + t.Errorf("expected %q to be shown as a source", res1) + } + + if !strings.Contains(out, fmt.Sprintf("%s (destination)", res2)) { + t.Errorf("expected %q to be shown as a destination", res2) + } +} diff --git a/utils/display/builds.go b/utils/display/builds.go new file mode 100644 index 000000000..15eb59ebc --- /dev/null +++ b/utils/display/builds.go @@ -0,0 +1,37 @@ +package display + +import ( + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func BuildTable(build *meroxa.Build) string { + mainTable := simpletable.New() + mainTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: "UUID:"}, + {Text: build.Uuid}, + }, + { + {Align: simpletable.AlignRight, Text: "Created At:"}, + {Text: build.CreatedAt}, + }, + { + {Align: simpletable.AlignRight, Text: "Updated At:"}, + {Text: build.UpdatedAt}, + }, + { + {Align: simpletable.AlignRight, Text: "State:"}, + {Text: build.Status.State}, + }, + } + if build.Status.Details != "" { + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Status Details:"}, + {Text: build.Status.Details}, + } + mainTable.Body.Cells = append(mainTable.Body.Cells, r) + } + mainTable.SetStyle(simpletable.StyleCompact) + return mainTable.String() +} diff --git a/utils/display/connectors.go b/utils/display/connectors.go new file mode 100644 index 000000000..de7d658d5 --- /dev/null +++ b/utils/display/connectors.go @@ -0,0 +1,150 @@ +package display + +import ( + "fmt" + + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func formatStreams(ss map[string]interface{}) string { + var streamStr string + + if streamInput, ok := ss["input"]; ok { + streamStr += "(input) " + + streamInterface := streamInput.([]interface{}) + for i, v := range streamInterface { + streamStr += fmt.Sprintf("%v", v) + + if i < len(streamInterface)-1 { + streamStr += ", " + } + } + } + + if streamOutput, ok := ss["output"]; ok { + streamStr += "(output) " + + streamInterface := streamOutput.([]interface{}) + for i, v := range streamInterface { + streamStr += fmt.Sprintf("%v", v) + + if i < len(streamInterface)-1 { + streamStr += ", " + } + } + } + return streamStr +} + +func ConnectorTable(connector *meroxa.Connector) string { + mainTable := simpletable.New() + mainTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: "UUID:"}, + {Text: connector.UUID}, + }, + { + {Align: simpletable.AlignRight, Text: "Name:"}, + {Text: connector.Name}, + }, + { + {Align: simpletable.AlignRight, Text: "Type:"}, + {Text: string(connector.Type)}, + }, + { + {Align: simpletable.AlignRight, Text: "Streams:"}, + {Text: formatStreams(connector.Streams)}, + }, + { + {Align: simpletable.AlignRight, Text: "State:"}, + {Text: string(connector.State)}, + }, + { + {Align: simpletable.AlignRight, Text: "Pipeline:"}, + {Text: connector.PipelineName}, + }, + } + + if connector.Trace != "" { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Trace:"}, + {Text: connector.Trace}, + }) + } + if connector.Environment != nil { + if connector.Environment.UUID.Valid { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment UUID:"}, + {Text: connector.Environment.UUID.String}, + }) + } + if connector.Environment.Name.Valid { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment Name:"}, + {Text: connector.Environment.Name.String}, + }) + } + } else { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment Name:"}, + {Text: string(meroxa.EnvironmentTypeCommon)}, + }) + } + + mainTable.SetStyle(simpletable.StyleCompact) + + return mainTable.String() +} + +func ConnectorsTable(connectors []*meroxa.Connector, hideHeaders bool) string { + if len(connectors) != 0 { + table := simpletable.New() + + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "UUID"}, + {Align: simpletable.AlignCenter, Text: "NAME"}, + {Align: simpletable.AlignCenter, Text: "TYPE"}, + {Align: simpletable.AlignCenter, Text: "STREAMS"}, + {Align: simpletable.AlignCenter, Text: "STATE"}, + {Align: simpletable.AlignCenter, Text: "PIPELINE"}, + {Align: simpletable.AlignCenter, Text: "ENVIRONMENT"}, + }, + } + } + + for _, conn := range connectors { + var env string + + if conn.Environment != nil && conn.Environment.Name.Valid { + env = conn.Environment.Name.String + } else { + env = string(meroxa.EnvironmentTypeCommon) + } + + streamStr := formatStreams(conn.Streams) + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: conn.UUID}, + {Text: conn.Name}, + {Text: string(conn.Type)}, + {Text: streamStr}, + {Text: string(conn.State)}, + {Text: conn.PipelineName}, + {Text: env}, + } + + table.Body.Cells = append(table.Body.Cells, r) + } + table.SetStyle(simpletable.StyleCompact) + return table.String() + } + + return "" +} + +func PrintConnectorsTable(connectors []*meroxa.Connector, hideHeaders bool) { + fmt.Println(ConnectorsTable(connectors, hideHeaders)) +} diff --git a/utils/display/connectors_test.go b/utils/display/connectors_test.go new file mode 100644 index 000000000..5ee584fba --- /dev/null +++ b/utils/display/connectors_test.go @@ -0,0 +1,207 @@ +package display + +import ( + "fmt" + "strings" + "testing" + + "github.com/meroxa/cli/utils" + "github.com/meroxa/meroxa-go/pkg/meroxa" + "github.com/volatiletech/null/v8" +) + +func TestConnectorRunningTable(t *testing.T) { + connector := &meroxa.Connector{ + UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", + Type: "jdbc", + Name: "base", + Configuration: nil, + Metadata: nil, + Streams: map[string]interface{}{ + "dynamic": "false", + "output": []interface{}{"output-foo", "output-bar"}, + }, + State: "running", + Trace: "", + PipelineName: "pipeline-1", + Environment: &meroxa.EntityIdentifier{Name: null.StringFrom("my-env")}, + } + failedConnector := &meroxa.Connector{} + deepCopy(connector, failedConnector) + failedConnector.State = "failed" + failedConnector.Trace = "exception goes here" + + tests := map[string]*meroxa.Connector{ + "running": connector, + "failed": failedConnector, + } + + tableHeaders := []string{"UUID", "ID", "Name", "Type", "Streams", "State", "Pipeline", "Environment"} + + for name, connector := range tests { + t.Run(name, func(t *testing.T) { + out := utils.CaptureOutput(func() { + fmt.Println(ConnectorTable(connector)) + }) + + for _, header := range tableHeaders { + if !strings.Contains(out, header) { + t.Errorf("%s header is missing", header) + } + } + + switch name { + case "running": + if !strings.Contains(out, connector.UUID) { + t.Errorf("%s, not found", connector.UUID) + } + if !strings.Contains(out, connector.Name) { + t.Errorf("%s, not found", connector.Name) + } + if !strings.Contains(out, connector.UUID) { + t.Errorf("%s, not found", connector.UUID) + } + case "failed": + if !strings.Contains(out, connector.UUID) { + t.Errorf("%s, not found", connector.UUID) + } + if !strings.Contains(out, connector.Name) { + t.Errorf("%s, not found", connector.Name) + } + if !strings.Contains(out, connector.UUID) { + t.Errorf("%s, not found", connector.UUID) + } + if !strings.Contains(out, connector.Trace) { + t.Errorf("%s, not found", connector.Trace) + } + } + fmt.Println(out) + }) + } +} + +func TestConnectorsTable(t *testing.T) { + connectionIDAlign := &meroxa.Connector{} + connectionInputOutput := &meroxa.Connector{} + connection := &meroxa.Connector{ + UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", + Type: "jdbc", + Name: "base", + Configuration: nil, + Metadata: nil, + Streams: map[string]interface{}{ + "dynamic": "false", + "output": []interface{}{"output-foo", "output-bar"}, + }, + State: "running", + Trace: "", + PipelineName: "pipeline-1", + Environment: &meroxa.EntityIdentifier{UUID: null.StringFrom("2c5326ac-041f-4679-b446-d6d95b91f497")}, + } + + deepCopy(connection, connectionIDAlign) + connectionIDAlign.Name = "id-alignment" + connectionIDAlign.UUID = "1000" + + deepCopy(connection, connectionInputOutput) + connectionInputOutput.Name = "input-output" + connectionInputOutput.Streams = map[string]interface{}{ + "dynamic": "true", + "input": []interface{}{"input-foo", "input-bar"}, + "output": []interface{}{"output-foo", "output-bar"}, + } + + tests := map[string][]*meroxa.Connector{ + "Base": {connection}, + "ID_Alignment": {connection, connectionIDAlign}, + "Input_Output": {connection, connectionInputOutput}, + } + + tableHeaders := []string{"UUID", "ID", "NAME", "TYPE", "STREAMS", "STATE", "PIPELINE", "ENVIRONMENT"} + + for name, connections := range tests { + t.Run(name, func(t *testing.T) { + out := utils.CaptureOutput(func() { + PrintConnectorsTable(connections, false) + }) + + for _, header := range tableHeaders { + if !strings.Contains(out, header) { + t.Errorf("%s header is missing", header) + } + } + + switch name { + case "Base": + if !strings.Contains(out, connection.UUID) { + t.Errorf("%s, not found", connection.UUID) + } + if !strings.Contains(out, connection.Name) { + t.Errorf("%s, not found", connection.Name) + } + if !strings.Contains(out, connection.UUID) { + t.Errorf("%s, not found", connection.UUID) + } + case "ID_Alignment": + if !strings.Contains(out, connectionIDAlign.Name) { + t.Errorf("%s, not found", connectionIDAlign.Name) + } + if !strings.Contains(out, connectionIDAlign.UUID) { + t.Errorf("%s, not found", connectionIDAlign.UUID) + } + case "Input_Output": + if !strings.Contains(out, connectionInputOutput.Name) { + t.Errorf("%s, not found", connection.Name) + } + if !strings.Contains(out, "input-foo") { + t.Errorf("%s, not found", "input-foo") + } + if !strings.Contains(out, "output-foo") { + t.Errorf("%s, not found", "output-foo") + } + } + fmt.Println(out) + }) + } +} + +func TestConnectorsTableWithoutHeaders(t *testing.T) { + connection := &meroxa.Connector{ + UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", + Type: "jdbc", + Name: "base", + Configuration: nil, + Metadata: nil, + Streams: map[string]interface{}{ + "dynamic": "false", + "output": []interface{}{"output-foo", "output-bar"}, + }, + State: "running", + Trace: "", + PipelineName: "pipeline-1", + } + + tableHeaders := []string{"UUID", "ID", "NAME", "TYPE", "STREAMS", "STATE", "PIPELINE", "ENVIRONMENT"} + + var connections []*meroxa.Connector + connections = append(connections, connection) + + out := utils.CaptureOutput(func() { + PrintConnectorsTable(connections, true) + }) + + for _, header := range tableHeaders { + if strings.Contains(out, header) { + t.Errorf("%s header should not be displayed", header) + } + } + if !strings.Contains(out, connection.UUID) { + t.Errorf("%s, not found", connection.UUID) + } + if !strings.Contains(out, connection.Name) { + t.Errorf("%s, not found", connection.Name) + } + if !strings.Contains(out, connection.UUID) { + t.Errorf("%s, not found", connection.UUID) + } +} diff --git a/utils/display/display.go b/utils/display/display.go new file mode 100644 index 000000000..fad094844 --- /dev/null +++ b/utils/display/display.go @@ -0,0 +1,11 @@ +package display + +func truncateString(oldString string, l int) string { + str := oldString + + if len(oldString) > l { + str = oldString[:l] + "..." + } + + return str +} diff --git a/utils/display/display_test.go b/utils/display/display_test.go new file mode 100644 index 000000000..63f8d89aa --- /dev/null +++ b/utils/display/display_test.go @@ -0,0 +1,47 @@ +package display + +import ( + "testing" + + "github.com/meroxa/cli/utils" + + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func TestEmptyTables(t *testing.T) { + var emptyResourcesList []*meroxa.Resource + out := utils.CaptureOutput(func() { + PrintResourcesTable(emptyResourcesList, true) + }) + + if out != "\n" { + t.Errorf("Output for resources should be blank") + } + + var emptyConnectorsList []*meroxa.Connector + out = utils.CaptureOutput(func() { + PrintConnectorsTable(emptyConnectorsList, true) + }) + + if out != "\n" { + t.Errorf("Output for connectors should be blank") + } + + var emptyPipelinesList []*meroxa.Pipeline + out = utils.CaptureOutput(func() { + PrintPipelinesTable(emptyPipelinesList, true) + }) + + if out != "\n" { + t.Errorf("Output for pipelines should be blank") + } + + var emptyEnvironmentsList []*meroxa.Environment + out = utils.CaptureOutput(func() { + PrintEnvironmentsTable(emptyEnvironmentsList, true) + }) + + if out != "\n" { + t.Errorf("Output for pipelines should be blank") + } +} diff --git a/utils/display/endpoints.go b/utils/display/endpoints.go new file mode 100644 index 000000000..ebef4fce7 --- /dev/null +++ b/utils/display/endpoints.go @@ -0,0 +1,58 @@ +package display + +import ( + "fmt" + "net/url" + "strconv" + + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func EndpointsTable(ends []meroxa.Endpoint, hideHeaders bool) string { + if len(ends) == 0 { + return "" + } + + table := simpletable.New() + + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "NAME"}, + {Align: simpletable.AlignCenter, Text: "PROTOCOL"}, + {Align: simpletable.AlignCenter, Text: "STREAM"}, + {Align: simpletable.AlignCenter, Text: "URL"}, + {Align: simpletable.AlignCenter, Text: "READY"}, + }, + } + } + + for _, end := range ends { + var u string + switch end.Protocol { + case meroxa.EndpointProtocolHttp: + host, err := url.ParseRequestURI(end.Host) + if err != nil { + continue + } + host.User = url.UserPassword(end.BasicAuthUsername, end.BasicAuthPassword) + u = host.String() + case meroxa.EndpointProtocolGrpc: + u = fmt.Sprintf("host=%s username=%s password=%s", end.Host, end.BasicAuthUsername, end.BasicAuthPassword) + } + + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: end.Name}, + {Text: string(end.Protocol)}, + {Text: end.Stream}, + {Text: u}, + {Text: strconv.FormatBool(end.Ready)}, + } + + table.Body.Cells = append(table.Body.Cells, r) + } + table.SetStyle(simpletable.StyleCompact) + + return table.String() +} diff --git a/utils/display/environments.go b/utils/display/environments.go new file mode 100644 index 000000000..8a92303c7 --- /dev/null +++ b/utils/display/environments.go @@ -0,0 +1,225 @@ +package display + +import ( + "fmt" + "strings" + + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func EnvironmentsTable(environments []*meroxa.Environment, hideHeaders bool) string { + if len(environments) != 0 { + table := simpletable.New() + + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "UUID"}, + {Align: simpletable.AlignCenter, Text: "NAME"}, + {Align: simpletable.AlignCenter, Text: "TYPE"}, + {Align: simpletable.AlignCenter, Text: "PROVIDER"}, + {Align: simpletable.AlignCenter, Text: "REGION"}, + {Align: simpletable.AlignCenter, Text: "STATE"}, + }, + } + } + + for _, p := range environments { + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: p.UUID}, + {Align: simpletable.AlignCenter, Text: p.Name}, + {Align: simpletable.AlignCenter, Text: string(p.Type)}, + {Align: simpletable.AlignCenter, Text: string(p.Provider)}, + {Align: simpletable.AlignCenter, Text: string(p.Region)}, + {Align: simpletable.AlignCenter, Text: string(p.Status.State)}, + } + + table.Body.Cells = append(table.Body.Cells, r) + } + table.SetStyle(simpletable.StyleCompact) + return table.String() + } + return "" +} + +// nolint:funlen +func EnvironmentTable(environment *meroxa.Environment) string { + mainTable := simpletable.New() + + mainTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: "UUID:"}, + {Text: environment.UUID}, + }, + { + {Align: simpletable.AlignRight, Text: "Name:"}, + {Text: environment.Name}, + }, + { + {Align: simpletable.AlignRight, Text: "Provider:"}, + {Text: string(environment.Provider)}, + }, + { + {Align: simpletable.AlignRight, Text: "Region:"}, + {Text: string(environment.Region)}, + }, + { + {Align: simpletable.AlignRight, Text: "Type:"}, + {Text: string(environment.Type)}, + }, + + { + {Align: simpletable.AlignRight, Text: "Created At:"}, + {Text: environment.CreatedAt.String()}, + }, + { + {Align: simpletable.AlignRight, Text: "Updated At:"}, + {Text: environment.UpdatedAt.String()}, + }, + { + {Align: simpletable.AlignRight, Text: "Environment Status:"}, + {Text: string(environment.Status.State)}, + }, + } + + if environment.Status.Details != "" { + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment Status Details:"}, + {Text: string(environment.Status.State)}, + } + mainTable.Body.Cells = append(mainTable.Body.Cells, r) + } + + mainTable.SetStyle(simpletable.StyleCompact) + str := mainTable.String() + + if environment.Status.PreflightDetails != nil { + preflightTable := simpletable.New() + preflightTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: " Preflight Checks:"}, + {Text: ""}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS EC2 Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.EC2, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS EKS Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.EKS, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS IAM Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.IAM, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS KMS Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.KMS, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS MKS Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.MSK, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS S3 Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.S3, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS ServiceQuotas Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.ServiceQuotas, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS CloudFormation Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.Cloudformation, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS Cloudwatch Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.Cloudwatch, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS EIP Limits Status:"}, + {Text: environment.Status.PreflightDetails.PreflightLimits.EIP}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS NAT Limits Status:"}, + {Text: environment.Status.PreflightDetails.PreflightLimits.NAT}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS VPC Limits Status:"}, + {Text: environment.Status.PreflightDetails.PreflightLimits.VPC}, + }, + } + preflightTable.SetStyle(simpletable.StyleCompact) + str += "\n" + preflightTable.String() + } + + return str +} + +func EnvironmentPreflightTable(environment *meroxa.Environment) string { + if environment.Status.PreflightDetails != nil { + preflightTable := simpletable.New() + preflightTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: " Preflight Checks:"}, + {Text: ""}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS EC2 Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.EC2, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS EKS Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.EKS, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS IAM Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.IAM, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS KMS Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.KMS, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS MKS Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.MSK, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS S3 Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.S3, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS ServiceQuotas Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.ServiceQuotas, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS CloudFormation Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.Cloudformation, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS Cloudwatch Permissions Status:"}, + {Text: strings.Join(environment.Status.PreflightDetails.PreflightPermissions.Cloudwatch, " ; ")}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS EIP Limits Status:"}, + {Text: environment.Status.PreflightDetails.PreflightLimits.EIP}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS NAT Limits Status:"}, + {Text: environment.Status.PreflightDetails.PreflightLimits.NAT}, + }, + { + {Align: simpletable.AlignRight, Text: "AWS VPC Limits Status:"}, + {Text: environment.Status.PreflightDetails.PreflightLimits.VPC}, + }, + } + preflightTable.SetStyle(simpletable.StyleCompact) + return preflightTable.String() + } + return "" +} + +func PrintEnvironmentsTable(environments []*meroxa.Environment, hideHeaders bool) { + fmt.Println(EnvironmentsTable(environments, hideHeaders)) +} diff --git a/utils/display/environments_test.go b/utils/display/environments_test.go new file mode 100644 index 000000000..58c880624 --- /dev/null +++ b/utils/display/environments_test.go @@ -0,0 +1,158 @@ +package display + +import ( + "encoding/json" + "fmt" + "strings" + "testing" + + "github.com/meroxa/cli/utils" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func TestEnvironmentsTable(t *testing.T) { + e := &meroxa.Environment{ + Type: meroxa.EnvironmentTypePrivate, + Name: "environment-1234", + Provider: meroxa.EnvironmentProviderAws, + Region: meroxa.EnvironmentRegionUsEast1, + Status: meroxa.EnvironmentViewStatus{State: meroxa.EnvironmentStateReady}, + UUID: "531428f7-4e86-4094-8514-d397d49026f7", + } + + tests := map[string][]*meroxa.Environment{ + "Base": {e}, + } + + tableHeaders := []string{"ID", "NAME", "TYPE", "PROVIDER", "REGION", "STATE"} + + for name, environments := range tests { + t.Run(name, func(t *testing.T) { + out := utils.CaptureOutput(func() { + PrintEnvironmentsTable(environments, false) + }) + + for _, header := range tableHeaders { + if !strings.Contains(out, header) { + t.Errorf("%s header is missing", header) + } + } + + if !strings.Contains(out, e.UUID) { + t.Errorf("%s, not found", e.UUID) + } + if !strings.Contains(out, e.Name) { + t.Errorf("%s, not found", e.Name) + } + if !strings.Contains(out, string(e.Type)) { + t.Errorf("%s, not found", e.Type) + } + if !strings.Contains(out, string(e.Region)) { + t.Errorf("%s, not found", e.Region) + } + if !strings.Contains(out, string(e.Status.State)) { + t.Errorf("%s, not found", e.Status.State) + } + if !strings.Contains(out, e.UUID) { + t.Errorf("%s, not found", e.UUID) + } + + fmt.Println(out) + }) + } +} + +func TestEnvironmentsTablePreflightFailed(t *testing.T) { + e := utils.GenerateEnvironmentFailed("environment-preflight-failed") + + tests := map[string][]*meroxa.Environment{ + "Base": {&e}, + } + + tableHeaders := []string{"ID", "NAME", "TYPE", "PROVIDER", "REGION", "STATE"} + + for name, environments := range tests { + t.Run(name, func(t *testing.T) { + out := utils.CaptureOutput(func() { + PrintEnvironmentsTable(environments, false) + }) + + for _, header := range tableHeaders { + if !strings.Contains(out, header) { + t.Errorf("%s header is missing", header) + } + } + + if !strings.Contains(out, e.UUID) { + t.Errorf("%s, not found", e.UUID) + } + if !strings.Contains(out, e.Name) { + t.Errorf("%s, not found", e.Name) + } + if !strings.Contains(out, string(e.Type)) { + t.Errorf("%s, not found", e.Type) + } + if !strings.Contains(out, string(e.Region)) { + t.Errorf("%s, not found", e.Region) + } + if !strings.Contains(out, string(e.Status.State)) { + t.Errorf("%s, not found", e.Status.State) + } + if !strings.Contains(out, e.UUID) { + t.Errorf("%s, not found", e.UUID) + } + + fmt.Println(out) + }) + } +} + +func TestEnvironmentsTableWithoutHeaders(t *testing.T) { + e := &meroxa.Environment{ + Type: meroxa.EnvironmentTypePrivate, + Name: "environment-1234", + Provider: meroxa.EnvironmentProviderAws, + Region: meroxa.EnvironmentRegionUsEast1, + Status: meroxa.EnvironmentViewStatus{State: meroxa.EnvironmentStateReady}, + UUID: "531428f7-4e86-4094-8514-d397d49026f7", + } + + var environments []*meroxa.Environment + tableHeaders := []string{"ID", "NAME", "TYPE", "PROVIDER", "REGION", "STATE"} + + environments = append(environments, e) + + out := utils.CaptureOutput(func() { + PrintEnvironmentsTable(environments, true) + }) + + for _, header := range tableHeaders { + if strings.Contains(out, header) { + t.Errorf("%s header should not be displayed", header) + } + } + + if !strings.Contains(out, e.UUID) { + t.Errorf("%s, not found", e.UUID) + } + if !strings.Contains(out, e.Name) { + t.Errorf("%s, not found", e.Name) + } + if !strings.Contains(out, string(e.Type)) { + t.Errorf("%s, not found", e.Type) + } + if !strings.Contains(out, string(e.Region)) { + t.Errorf("%s, not found", e.Region) + } + if !strings.Contains(out, string(e.Status.State)) { + t.Errorf("%s, not found", e.Status.State) + } + if !strings.Contains(out, e.UUID) { + t.Errorf("%s, not found", e.UUID) + } +} + +func deepCopy(a, b interface{}) { + byt, _ := json.Marshal(a) + _ = json.Unmarshal(byt, b) +} diff --git a/utils/display/functions.go b/utils/display/functions.go new file mode 100644 index 000000000..08a4f714f --- /dev/null +++ b/utils/display/functions.go @@ -0,0 +1,120 @@ +package display + +import ( + "fmt" + "strings" + + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func FunctionsTable(funs []*meroxa.Function, hideHeaders bool) string { + if len(funs) == 0 { + return "" + } + + table := simpletable.New() + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "UUID"}, + {Align: simpletable.AlignCenter, Text: "NAME"}, + {Align: simpletable.AlignCenter, Text: "INPUT STREAM"}, + {Align: simpletable.AlignCenter, Text: "OUTPUT STREAM"}, + {Align: simpletable.AlignCenter, Text: "STATE"}, + {Align: simpletable.AlignCenter, Text: "PIPELINE"}, + }, + } + } + + for _, p := range funs { + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: p.UUID}, + {Align: simpletable.AlignCenter, Text: p.Name}, + {Align: simpletable.AlignCenter, Text: p.InputStream}, + {Align: simpletable.AlignCenter, Text: p.OutputStream}, + {Align: simpletable.AlignCenter, Text: p.Status.State}, + {Align: simpletable.AlignCenter, Text: p.Pipeline.Name}, + } + + table.Body.Cells = append(table.Body.Cells, r) + } + + table.SetStyle(simpletable.StyleCompact) + return table.String() +} + +func FunctionTable(fun *meroxa.Function) string { + envVars := []string{} + for k, v := range fun.EnvVars { + envVars = append(envVars, fmt.Sprintf("%s=%s", k, v)) + } + + mainTable := simpletable.New() + mainTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: "UUID:"}, + {Text: fun.UUID}, + }, + { + {Align: simpletable.AlignRight, Text: "Name:"}, + {Text: fun.Name}, + }, + { + {Align: simpletable.AlignRight, Text: "Input Stream:"}, + {Text: fun.InputStream}, + }, + { + {Align: simpletable.AlignRight, Text: "Output Stream:"}, + {Text: fun.OutputStream}, + }, + { + {Align: simpletable.AlignRight, Text: "Image:"}, + {Text: fun.Image}, + }, + { + {Align: simpletable.AlignRight, Text: "Command:"}, + {Text: strings.Join(fun.Command, " ")}, + }, + { + {Align: simpletable.AlignRight, Text: "Arguments:"}, + {Text: strings.Join(fun.Args, " ")}, + }, + { + {Align: simpletable.AlignRight, Text: "Environment Variables:"}, + {Text: strings.Join(envVars, "\n")}, + }, + { + {Align: simpletable.AlignRight, Text: "Pipeline:"}, + {Text: fun.Pipeline.Name}, + }, + { + {Align: simpletable.AlignRight, Text: "State:"}, + {Text: fun.Status.State}, + }, + } + mainTable.SetStyle(simpletable.StyleCompact) + table := mainTable.String() + + details := fun.Status.Details + if details == "" { + return table + } + + return fmt.Sprintf("%s\n\n%s", table, details) +} + +func extendedFunctionsTable(functions []*meroxa.Function) string { + if len(functions) == 0 { + return "" + } + subTable := "\tFunctions\n" + + for _, f := range functions { + subTable += fmt.Sprintf("\t %s\n", f.Name) + subTable += fmt.Sprintf("\t\t%5s: %s\n", "UUID", f.UUID) + subTable += fmt.Sprintf("\t\t%5s: %s\n", "State", f.Status.State) + } + + return subTable +} diff --git a/utils/display/pipelines.go b/utils/display/pipelines.go new file mode 100644 index 000000000..67c7bbb31 --- /dev/null +++ b/utils/display/pipelines.go @@ -0,0 +1,98 @@ +package display + +import ( + "fmt" + + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func PipelineTable(p *meroxa.Pipeline) string { + mainTable := simpletable.New() + mainTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: "UUID:"}, + {Text: p.UUID}, + }, + { + {Align: simpletable.AlignRight, Text: "Name:"}, + {Text: p.Name}, + }, + } + + if p.Environment != nil { + if p.Environment.UUID.Valid { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment UUID:"}, + {Text: p.Environment.UUID.String}, + }) + } + if p.Environment.Name.Valid { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment Name:"}, + {Text: p.Environment.Name.String}, + }) + } + } else { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment Name:"}, + {Text: string(meroxa.EnvironmentTypeCommon)}, + }) + } + + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "State:"}, + {Text: string(p.State)}, + }) + + mainTable.SetStyle(simpletable.StyleCompact) + + return mainTable.String() +} + +func PrintPipelineTable(pipeline *meroxa.Pipeline) { + fmt.Println(PipelineTable(pipeline)) +} + +func PipelinesTable(pipelines []*meroxa.Pipeline, hideHeaders bool) string { + if len(pipelines) != 0 { + table := simpletable.New() + + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "UUID"}, + {Align: simpletable.AlignCenter, Text: "NAME"}, + {Align: simpletable.AlignCenter, Text: "ENVIRONMENT"}, + {Align: simpletable.AlignCenter, Text: "STATE"}, + }, + } + } + + for _, p := range pipelines { + var env string + + if p.Environment != nil && p.Environment.Name.Valid { + env = p.Environment.Name.String + } else { + env = string(meroxa.EnvironmentTypeCommon) + } + + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: p.UUID}, + {Align: simpletable.AlignCenter, Text: p.Name}, + {Align: simpletable.AlignCenter, Text: env}, + {Align: simpletable.AlignCenter, Text: string(p.State)}, + } + + table.Body.Cells = append(table.Body.Cells, r) + } + table.SetStyle(simpletable.StyleCompact) + return table.String() + } + return "" +} + +func PrintPipelinesTable(pipelines []*meroxa.Pipeline, hideHeaders bool) { + fmt.Println(PipelinesTable(pipelines, hideHeaders)) +} diff --git a/utils/display/pipelines_test.go b/utils/display/pipelines_test.go new file mode 100644 index 000000000..b0a319f35 --- /dev/null +++ b/utils/display/pipelines_test.go @@ -0,0 +1,167 @@ +package display + +import ( + "fmt" + "strings" + "testing" + + "github.com/meroxa/cli/utils" + "github.com/meroxa/meroxa-go/pkg/meroxa" + "github.com/volatiletech/null/v8" +) + +func TestPipelinesTable(t *testing.T) { + pipelineIDAlign := &meroxa.Pipeline{} + pipelineWithEnv := &meroxa.Pipeline{} + + pipelineBase := &meroxa.Pipeline{ + UUID: "6f380820-dfed-4a69-b708-10d134866a35", + Name: "pipeline-base", + } + deepCopy(pipelineBase, pipelineIDAlign) + pipelineIDAlign.UUID = "0e1d29b9-2e62-4cc2-a49d-126f2e1b15ef" + pipelineIDAlign.Name = "pipeline-align" + + deepCopy(pipelineBase, pipelineWithEnv) + pipelineWithEnv.UUID = "038de172-c4b0-49d8-a1d9-26fbeaa2f726" + pipelineWithEnv.Environment = &meroxa.EntityIdentifier{ + UUID: null.StringFrom("e56b1b2e-b6d7-455d-887e-84a0823d84a8"), + Name: null.StringFrom("my-environment"), + } + + tests := map[string][]*meroxa.Pipeline{ + "Base": {pipelineBase}, + "ID_Alignment": {pipelineBase, pipelineIDAlign}, + "With_Environment": {pipelineBase, pipelineIDAlign, pipelineWithEnv}, + } + + tableHeaders := []string{"UUID", "ID", "NAME", "ENVIRONMENT", "STATE"} + + for name, pipelines := range tests { + t.Run(name, func(t *testing.T) { + out := utils.CaptureOutput(func() { + PrintPipelinesTable(pipelines, false) + }) + + for _, header := range tableHeaders { + if !strings.Contains(out, header) { + t.Errorf("%s header is missing", header) + } + } + + switch name { + case "Base": + if !strings.Contains(out, pipelineBase.Name) { + t.Errorf("%s, not found", pipelineBase.Name) + } + if !strings.Contains(out, pipelineBase.UUID) { + t.Errorf("%s, not found", pipelineBase.UUID) + } + if !strings.Contains(out, string(meroxa.EnvironmentTypeCommon)) { + t.Errorf("environment should be %s", string(meroxa.EnvironmentTypeCommon)) + } + case "ID_Alignment": + if !strings.Contains(out, pipelineIDAlign.Name) { + t.Errorf("%s, not found", pipelineIDAlign.Name) + } + if !strings.Contains(out, pipelineIDAlign.UUID) { + t.Errorf("%s, not found", pipelineIDAlign.UUID) + } + case "With_Environment": + if !strings.Contains(out, pipelineWithEnv.Environment.Name.String) { + t.Errorf("expected environment name to be %q", pipelineWithEnv.Environment.Name.String) + } + } + + fmt.Println(out) + }) + } +} + +func TestPipelineTable(t *testing.T) { + pipelineWithEnv := &meroxa.Pipeline{} + + pipelineBase := &meroxa.Pipeline{ + UUID: "6f380820-dfed-4a69-b708-10d134866a35", + Name: "pipeline-base", + } + + deepCopy(pipelineBase, pipelineWithEnv) + pipelineWithEnv.UUID = "038de172-c4b0-49d8-a1d9-26fbeaa2f726" + pipelineWithEnv.Environment = &meroxa.EntityIdentifier{ + UUID: null.StringFrom("e56b1b2e-b6d7-455d-887e-84a0823d84a8"), + Name: null.StringFrom("my-environment"), + } + + tests := map[string]*meroxa.Pipeline{ + "Base": pipelineBase, + "With_Environment": pipelineWithEnv, + } + + tableHeaders := []string{"UUID", "ID", "Name", "State"} + var envHeader = "Environment Name" + + for name, p := range tests { + t.Run(name, func(t *testing.T) { + out := utils.CaptureOutput(func() { + PrintPipelineTable(p) + }) + + for _, header := range tableHeaders { + if !strings.Contains(out, header) { + t.Errorf("%q header is missing", header) + } + } + + switch name { + case "Base": + if !strings.Contains(out, pipelineBase.Name) { + t.Errorf("%s, not found", pipelineBase.Name) + } + if !strings.Contains(out, pipelineBase.UUID) { + t.Errorf("%s, not found", pipelineBase.UUID) + } + if !strings.Contains(out, pipelineBase.UUID) { + t.Errorf("%s, not found", pipelineBase.UUID) + } + if !strings.Contains(out, envHeader) { + t.Errorf("%q not found", envHeader) + } + case "With_Environment": + if !strings.Contains(out, pipelineWithEnv.Environment.UUID.String) { + t.Errorf("expected environment UUID to be %q", pipelineWithEnv.Environment.UUID.String) + } + } + fmt.Println(out) + }) + } +} + +func TestPipelinesTableWithoutHeaders(t *testing.T) { + pipeline := &meroxa.Pipeline{ + UUID: "6f380820-dfed-4a69-b708-10d134866a35", + Name: "pipeline-base", + } + + var pipelines []*meroxa.Pipeline + tableHeaders := []string{"ID", "NAME", "STATE"} + + pipelines = append(pipelines, pipeline) + + out := utils.CaptureOutput(func() { + PrintPipelinesTable(pipelines, true) + }) + + for _, header := range tableHeaders { + if strings.Contains(out, header) { + t.Errorf("%s header should not be displayed", header) + } + } + + if !strings.Contains(out, pipeline.Name) { + t.Errorf("%s, not found", pipeline.Name) + } + if !strings.Contains(out, pipeline.UUID) { + t.Errorf("%s, not found", pipeline.UUID) + } +} diff --git a/utils/display/resources.go b/utils/display/resources.go new file mode 100644 index 000000000..b2e5570d3 --- /dev/null +++ b/utils/display/resources.go @@ -0,0 +1,185 @@ +package display + +import ( + "fmt" + + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func ResourceTable(res *meroxa.Resource) string { + tunnel := "N/A" + if res.SSHTunnel != nil { + tunnel = "SSH" + } + + mainTable := simpletable.New() + mainTable.Body.Cells = [][]*simpletable.Cell{ + { + {Align: simpletable.AlignRight, Text: "UUID:"}, + {Text: res.UUID}, + }, + { + {Align: simpletable.AlignRight, Text: "Name:"}, + {Text: res.Name}, + }, + { + {Align: simpletable.AlignRight, Text: "Type:"}, + {Text: string(res.Type)}, + }, + { + {Align: simpletable.AlignRight, Text: "URL:"}, + {Text: res.URL}, + }, + { + {Align: simpletable.AlignRight, Text: "Tunnel:"}, + {Text: tunnel}, + }, + { + {Align: simpletable.AlignRight, Text: "State:"}, + {Text: string(res.Status.State)}, + }, + } + + if res.Status.Details != "" { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "State details:"}, + {Text: res.Status.Details}, + }) + } + + if res.Environment != nil { + if res.Environment.UUID.Valid { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment UUID:"}, + {Text: res.Environment.UUID.String}, + }) + } + + if res.Environment.Name.Valid { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment Name:"}, + {Text: res.Environment.Name.String}, + }) + } + } else { + mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: "Environment Name:"}, + {Text: string(meroxa.EnvironmentTypeCommon)}, + }) + } + + mainTable.SetStyle(simpletable.StyleCompact) + + return mainTable.String() +} + +func ResourcesTable(resources []*meroxa.Resource, hideHeaders bool) string { + if len(resources) != 0 { + table := simpletable.New() + + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "UUID"}, + {Align: simpletable.AlignCenter, Text: "NAME"}, + {Align: simpletable.AlignCenter, Text: "TYPE"}, + {Align: simpletable.AlignCenter, Text: "ENVIRONMENT"}, + {Align: simpletable.AlignCenter, Text: "URL"}, + {Align: simpletable.AlignCenter, Text: "TUNNEL"}, + {Align: simpletable.AlignCenter, Text: "STATE"}, + }, + } + } + + for _, res := range resources { + tunnel := "N/A" + if res.SSHTunnel != nil { + tunnel = "SSH" + } + + var env string + + if res.Environment != nil && res.Environment.Name.Valid { + env = res.Environment.Name.String + } else { + env = string(meroxa.EnvironmentTypeCommon) + } + + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: res.UUID}, + {Text: res.Name}, + {Text: string(res.Type)}, + {Text: env}, + {Text: res.URL}, + {Align: simpletable.AlignCenter, Text: tunnel}, + {Align: simpletable.AlignCenter, Text: string(res.Status.State)}, + } + + table.Body.Cells = append(table.Body.Cells, r) + } + table.SetStyle(simpletable.StyleCompact) + return table.String() + } + + return "" +} + +func PrintResourcesTable(resources []*meroxa.Resource, hideHeaders bool) { + fmt.Println(ResourcesTable(resources, hideHeaders)) +} + +func ResourceTypesTable(types []string, hideHeaders bool) string { + table := simpletable.New() + + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "TYPES"}, + }, + } + } + + for _, t := range types { + r := []*simpletable.Cell{ + {Align: simpletable.AlignRight, Text: t}, + } + + table.Body.Cells = append(table.Body.Cells, r) + } + table.SetStyle(simpletable.StyleCompact) + return table.String() +} + +func PrintResourceTypesTable(types []string, hideHeaders bool) { + fmt.Println(ResourceTypesTable(types, hideHeaders)) +} + +func extendedResourcesTable(resources []*meroxa.Resource, connectors []*meroxa.Connector) string { + if len(resources) == 0 { + return "" + } + subTable := "\tResources\n" + + var r *meroxa.Resource + for _, c := range connectors { + found := false + for _, resource := range resources { + if resource.Name == c.ResourceName { + r = resource + found = true + break + } + } + if !found { + panic("internal error") + } + + subTable += fmt.Sprintf("\t %s (%s)\n", r.Name, string(c.Type)) + subTable += fmt.Sprintf("\t\t%5s: %s\n", "UUID", r.UUID) + subTable += fmt.Sprintf("\t\t%5s: %s\n", "Type", string(r.Type)) + subTable += fmt.Sprintf("\t\t%5s: %s\n", "State", string(c.State)) + } + + return subTable +} diff --git a/utils/display/resources_test.go b/utils/display/resources_test.go new file mode 100644 index 000000000..3c367b2f6 --- /dev/null +++ b/utils/display/resources_test.go @@ -0,0 +1,154 @@ +package display + +import ( + "fmt" + "strings" + "testing" + + "github.com/meroxa/cli/utils" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func TestResourcesTable(t *testing.T) { + resource := &meroxa.Resource{ + UUID: "1dc8c9c6-d1d3-4b41-8f16-08302e87fc7b", + Type: "jdbc", + Name: "my-db-jdbc-source", + URL: "postgres://display.test.us-east-1.rds.amazonaws.com:5432/display", + Credentials: nil, + Metadata: nil, + Status: meroxa.ResourceStatus{ + State: "error", + }, + } + resIDAlign := &meroxa.Resource{ + UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", + Type: "jdbc", + Name: "my-db-jdbc-source", + URL: "postgres://display.test.us-east-1.rds.amazonaws.com:5432/display", + Credentials: nil, + Metadata: nil, + Status: meroxa.ResourceStatus{ + State: "ready", + }, + } + + tests := map[string][]*meroxa.Resource{ + "Base": {resource}, + "ID_Alignment": {resource, resIDAlign}, + } + + tableHeaders := []string{"ID", "NAME", "TYPE", "ENVIRONMENT", "URL", "TUNNEL", "STATE"} + + for name, resources := range tests { + t.Run(name, func(t *testing.T) { + out := utils.CaptureOutput(func() { + PrintResourcesTable(resources, false) + }) + + for _, header := range tableHeaders { + if !strings.Contains(out, header) { + t.Errorf("%s header is missing", header) + } + } + + switch name { + case "Base": + if !strings.Contains(out, resource.Name) { + t.Errorf("%s, not found", resource.Name) + } + if !strings.Contains(out, resource.UUID) { + t.Errorf("%s, not found", resource.UUID) + } + if !strings.Contains(out, string(resource.Status.State)) { + t.Errorf("state %s, not found", resource.Status.State) + } + case "ID_Alignment": + if !strings.Contains(out, resIDAlign.Name) { + t.Errorf("%s, not found", resIDAlign.Name) + } + if !strings.Contains(out, resIDAlign.UUID) { + t.Errorf("%s, not found", resIDAlign.UUID) + } + if !strings.Contains(out, string(resIDAlign.Status.State)) { + t.Errorf("state %s, not found", resource.Status.State) + } + } + fmt.Println(out) + }) + } +} + +func TestResourcesTableWithoutHeaders(t *testing.T) { + resource := &meroxa.Resource{ + UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", + Type: "jdbc", + Name: "my-db-jdbc-source", + URL: "postgres://display.test.us-east-1.rds.amazonaws.com:5432/display", + Credentials: nil, + Metadata: nil, + Status: meroxa.ResourceStatus{ + State: "error", + }, + } + + var resources []*meroxa.Resource + resources = append(resources, resource) + + tableHeaders := []string{"ID", "NAME", "TYPE", "URL", "TUNNEL", "STATE"} + + out := utils.CaptureOutput(func() { + PrintResourcesTable(resources, true) + }) + + for _, header := range tableHeaders { + if strings.Contains(out, header) { + t.Errorf("%s header should not be displayed", header) + } + } + + if !strings.Contains(out, resource.Name) { + t.Errorf("%s, not found", resource.Name) + } + if !strings.Contains(out, resource.UUID) { + t.Errorf("%s, not found", resource.UUID) + } + if !strings.Contains(out, string(resource.Status.State)) { + t.Errorf("state %s, not found", resource.Status.State) + } +} + +func TestResourceTypesTable(t *testing.T) { + types := []string{"postgres", "s3", "redshift", "mysql", "jdbc", "url", "mongodb"} + + out := utils.CaptureOutput(func() { + PrintResourceTypesTable(types, false) + }) + + if !strings.Contains(out, "TYPES") { + t.Errorf("table headers is missing") + } + + for _, rType := range types { + if !strings.Contains(out, rType) { + t.Errorf("%s, not found", rType) + } + } +} + +func TestResourceTypesTableWithoutHeaders(t *testing.T) { + types := []string{"postgres", "s3", "redshift", "mysql", "jdbc", "url", "mongodb"} + out := utils.CaptureOutput(func() { + PrintResourceTypesTable(types, true) + }) + + if strings.Contains(out, "TYPES") { + t.Errorf("table header should not be displayed") + } + + for _, rType := range types { + if !strings.Contains(out, rType) { + t.Errorf("%s, not found", rType) + } + } +} diff --git a/utils/display/transforms.go b/utils/display/transforms.go new file mode 100644 index 000000000..9bb60b99a --- /dev/null +++ b/utils/display/transforms.go @@ -0,0 +1,51 @@ +package display + +import ( + "strconv" + "strings" + + "github.com/alexeyco/simpletable" + "github.com/meroxa/meroxa-go/pkg/meroxa" +) + +func TransformsTable(transforms []*meroxa.Transform, hideHeaders bool) string { + if len(transforms) != 0 { + table := simpletable.New() + + if !hideHeaders { + table.Header = &simpletable.Header{ + Cells: []*simpletable.Cell{ + {Align: simpletable.AlignCenter, Text: "NAME"}, + {Align: simpletable.AlignCenter, Text: "TYPE"}, + {Align: simpletable.AlignCenter, Text: "REQUIRED"}, + {Align: simpletable.AlignCenter, Text: "DESCRIPTION"}, + {Align: simpletable.AlignCenter, Text: "PROPERTIES"}, + }, + } + } + + for _, res := range transforms { + r := []*simpletable.Cell{ + {Text: res.Name}, + {Text: res.Type}, + {Text: strconv.FormatBool(res.Required)}, + {Text: truncateString(res.Description, 151)}, // nolint:gomnd + } + + var properties []string + for _, p := range res.Properties { + properties = append(properties, p.Name) + } + var cell = &simpletable.Cell{ + Text: strings.Join(properties, ","), + } + + r = append(r, cell) + table.Body.Cells = append(table.Body.Cells, r) + } + table.SetStyle(simpletable.StyleCompact) + return table.String() + } + + return "" +} diff --git a/utils/display_test.go b/utils/display_test.go deleted file mode 100644 index 316c24958..000000000 --- a/utils/display_test.go +++ /dev/null @@ -1,692 +0,0 @@ -package utils - -import ( - "encoding/json" - "fmt" - "strings" - "testing" - - "github.com/volatiletech/null/v8" - - "github.com/meroxa/meroxa-go/pkg/meroxa" -) - -func TestResourcesTable(t *testing.T) { - resource := &meroxa.Resource{ - UUID: "1dc8c9c6-d1d3-4b41-8f16-08302e87fc7b", - Type: "jdbc", - Name: "my-db-jdbc-source", - URL: "postgres://display.test.us-east-1.rds.amazonaws.com:5432/display", - Credentials: nil, - Metadata: nil, - Status: meroxa.ResourceStatus{ - State: "error", - }, - } - resIDAlign := &meroxa.Resource{ - UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", - Type: "jdbc", - Name: "my-db-jdbc-source", - URL: "postgres://display.test.us-east-1.rds.amazonaws.com:5432/display", - Credentials: nil, - Metadata: nil, - Status: meroxa.ResourceStatus{ - State: "ready", - }, - } - - tests := map[string][]*meroxa.Resource{ - "Base": {resource}, - "ID_Alignment": {resource, resIDAlign}, - } - - tableHeaders := []string{"ID", "NAME", "TYPE", "ENVIRONMENT", "URL", "TUNNEL", "STATE"} - - for name, resources := range tests { - t.Run(name, func(t *testing.T) { - out := CaptureOutput(func() { - PrintResourcesTable(resources, false) - }) - - for _, header := range tableHeaders { - if !strings.Contains(out, header) { - t.Errorf("%s header is missing", header) - } - } - - switch name { - case "Base": - if !strings.Contains(out, resource.Name) { - t.Errorf("%s, not found", resource.Name) - } - if !strings.Contains(out, resource.UUID) { - t.Errorf("%s, not found", resource.UUID) - } - if !strings.Contains(out, string(resource.Status.State)) { - t.Errorf("state %s, not found", resource.Status.State) - } - case "ID_Alignment": - if !strings.Contains(out, resIDAlign.Name) { - t.Errorf("%s, not found", resIDAlign.Name) - } - if !strings.Contains(out, resIDAlign.UUID) { - t.Errorf("%s, not found", resIDAlign.UUID) - } - if !strings.Contains(out, string(resIDAlign.Status.State)) { - t.Errorf("state %s, not found", resource.Status.State) - } - } - fmt.Println(out) - }) - } -} - -func TestResourcesTableWithoutHeaders(t *testing.T) { - resource := &meroxa.Resource{ - UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", - Type: "jdbc", - Name: "my-db-jdbc-source", - URL: "postgres://display.test.us-east-1.rds.amazonaws.com:5432/display", - Credentials: nil, - Metadata: nil, - Status: meroxa.ResourceStatus{ - State: "error", - }, - } - - var resources []*meroxa.Resource - resources = append(resources, resource) - - tableHeaders := []string{"ID", "NAME", "TYPE", "URL", "TUNNEL", "STATE"} - - out := CaptureOutput(func() { - PrintResourcesTable(resources, true) - }) - - for _, header := range tableHeaders { - if strings.Contains(out, header) { - t.Errorf("%s header should not be displayed", header) - } - } - - if !strings.Contains(out, resource.Name) { - t.Errorf("%s, not found", resource.Name) - } - if !strings.Contains(out, resource.UUID) { - t.Errorf("%s, not found", resource.UUID) - } - if !strings.Contains(out, string(resource.Status.State)) { - t.Errorf("state %s, not found", resource.Status.State) - } -} - -func TestEmptyTables(t *testing.T) { - var emptyResourcesList []*meroxa.Resource - out := CaptureOutput(func() { - PrintResourcesTable(emptyResourcesList, true) - }) - - if out != "\n" { - t.Errorf("Output for resources should be blank") - } - - var emptyConnectorsList []*meroxa.Connector - out = CaptureOutput(func() { - PrintConnectorsTable(emptyConnectorsList, true) - }) - - if out != "\n" { - t.Errorf("Output for connectors should be blank") - } - - var emptyPipelinesList []*meroxa.Pipeline - out = CaptureOutput(func() { - PrintPipelinesTable(emptyPipelinesList, true) - }) - - if out != "\n" { - t.Errorf("Output for pipelines should be blank") - } - - var emptyEnvironmentsList []*meroxa.Environment - out = CaptureOutput(func() { - PrintEnvironmentsTable(emptyEnvironmentsList, true) - }) - - if out != "\n" { - t.Errorf("Output for pipelines should be blank") - } -} -func TestResourceTypesTable(t *testing.T) { - types := []string{"postgres", "s3", "redshift", "mysql", "jdbc", "url", "mongodb"} - - out := CaptureOutput(func() { - PrintResourceTypesTable(types, false) - }) - - if !strings.Contains(out, "TYPES") { - t.Errorf("table headers is missing") - } - - for _, rType := range types { - if !strings.Contains(out, rType) { - t.Errorf("%s, not found", rType) - } - } -} - -func TestResourceTypesTableWithoutHeaders(t *testing.T) { - types := []string{"postgres", "s3", "redshift", "mysql", "jdbc", "url", "mongodb"} - out := CaptureOutput(func() { - PrintResourceTypesTable(types, true) - }) - - if strings.Contains(out, "TYPES") { - t.Errorf("table header should not be displayed") - } - - for _, rType := range types { - if !strings.Contains(out, rType) { - t.Errorf("%s, not found", rType) - } - } -} - -func TestConnectorRunningTable(t *testing.T) { - connector := &meroxa.Connector{ - UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", - Type: "jdbc", - Name: "base", - Configuration: nil, - Metadata: nil, - Streams: map[string]interface{}{ - "dynamic": "false", - "output": []interface{}{"output-foo", "output-bar"}, - }, - State: "running", - Trace: "", - PipelineName: "pipeline-1", - Environment: &meroxa.EntityIdentifier{Name: null.StringFrom("my-env")}, - } - failedConnector := &meroxa.Connector{} - deepCopy(connector, failedConnector) - failedConnector.State = "failed" - failedConnector.Trace = "exception goes here" - - tests := map[string]*meroxa.Connector{ - "running": connector, - "failed": failedConnector, - } - - tableHeaders := []string{"UUID", "ID", "Name", "Type", "Streams", "State", "Pipeline", "Environment"} - - for name, connector := range tests { - t.Run(name, func(t *testing.T) { - out := CaptureOutput(func() { - fmt.Println(ConnectorTable(connector)) - }) - - for _, header := range tableHeaders { - if !strings.Contains(out, header) { - t.Errorf("%s header is missing", header) - } - } - - switch name { - case "running": - if !strings.Contains(out, connector.UUID) { - t.Errorf("%s, not found", connector.UUID) - } - if !strings.Contains(out, connector.Name) { - t.Errorf("%s, not found", connector.Name) - } - if !strings.Contains(out, connector.UUID) { - t.Errorf("%s, not found", connector.UUID) - } - case "failed": - if !strings.Contains(out, connector.UUID) { - t.Errorf("%s, not found", connector.UUID) - } - if !strings.Contains(out, connector.Name) { - t.Errorf("%s, not found", connector.Name) - } - if !strings.Contains(out, connector.UUID) { - t.Errorf("%s, not found", connector.UUID) - } - if !strings.Contains(out, connector.Trace) { - t.Errorf("%s, not found", connector.Trace) - } - } - fmt.Println(out) - }) - } -} - -func TestConnectorsTable(t *testing.T) { - connectionIDAlign := &meroxa.Connector{} - connectionInputOutput := &meroxa.Connector{} - connection := &meroxa.Connector{ - UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", - Type: "jdbc", - Name: "base", - Configuration: nil, - Metadata: nil, - Streams: map[string]interface{}{ - "dynamic": "false", - "output": []interface{}{"output-foo", "output-bar"}, - }, - State: "running", - Trace: "", - PipelineName: "pipeline-1", - Environment: &meroxa.EntityIdentifier{UUID: null.StringFrom("2c5326ac-041f-4679-b446-d6d95b91f497")}, - } - - deepCopy(connection, connectionIDAlign) - connectionIDAlign.Name = "id-alignment" - connectionIDAlign.UUID = "1000" - - deepCopy(connection, connectionInputOutput) - connectionInputOutput.Name = "input-output" - connectionInputOutput.Streams = map[string]interface{}{ - "dynamic": "true", - "input": []interface{}{"input-foo", "input-bar"}, - "output": []interface{}{"output-foo", "output-bar"}, - } - - tests := map[string][]*meroxa.Connector{ - "Base": {connection}, - "ID_Alignment": {connection, connectionIDAlign}, - "Input_Output": {connection, connectionInputOutput}, - } - - tableHeaders := []string{"UUID", "ID", "NAME", "TYPE", "STREAMS", "STATE", "PIPELINE", "ENVIRONMENT"} - - for name, connections := range tests { - t.Run(name, func(t *testing.T) { - out := CaptureOutput(func() { - PrintConnectorsTable(connections, false) - }) - - for _, header := range tableHeaders { - if !strings.Contains(out, header) { - t.Errorf("%s header is missing", header) - } - } - - switch name { - case "Base": - if !strings.Contains(out, connection.UUID) { - t.Errorf("%s, not found", connection.UUID) - } - if !strings.Contains(out, connection.Name) { - t.Errorf("%s, not found", connection.Name) - } - if !strings.Contains(out, connection.UUID) { - t.Errorf("%s, not found", connection.UUID) - } - case "ID_Alignment": - if !strings.Contains(out, connectionIDAlign.Name) { - t.Errorf("%s, not found", connectionIDAlign.Name) - } - if !strings.Contains(out, connectionIDAlign.UUID) { - t.Errorf("%s, not found", connectionIDAlign.UUID) - } - case "Input_Output": - if !strings.Contains(out, connectionInputOutput.Name) { - t.Errorf("%s, not found", connection.Name) - } - if !strings.Contains(out, "input-foo") { - t.Errorf("%s, not found", "input-foo") - } - if !strings.Contains(out, "output-foo") { - t.Errorf("%s, not found", "output-foo") - } - } - fmt.Println(out) - }) - } -} - -func TestConnectorsTableWithoutHeaders(t *testing.T) { - connection := &meroxa.Connector{ - UUID: "9483768f-c384-4b4a-96bf-b80a79a23b5c", - Type: "jdbc", - Name: "base", - Configuration: nil, - Metadata: nil, - Streams: map[string]interface{}{ - "dynamic": "false", - "output": []interface{}{"output-foo", "output-bar"}, - }, - State: "running", - Trace: "", - PipelineName: "pipeline-1", - } - - tableHeaders := []string{"UUID", "ID", "NAME", "TYPE", "STREAMS", "STATE", "PIPELINE", "ENVIRONMENT"} - - var connections []*meroxa.Connector - connections = append(connections, connection) - - out := CaptureOutput(func() { - PrintConnectorsTable(connections, true) - }) - - for _, header := range tableHeaders { - if strings.Contains(out, header) { - t.Errorf("%s header should not be displayed", header) - } - } - if !strings.Contains(out, connection.UUID) { - t.Errorf("%s, not found", connection.UUID) - } - if !strings.Contains(out, connection.Name) { - t.Errorf("%s, not found", connection.Name) - } - if !strings.Contains(out, connection.UUID) { - t.Errorf("%s, not found", connection.UUID) - } -} - -func TestPipelinesTable(t *testing.T) { - pipelineIDAlign := &meroxa.Pipeline{} - pipelineWithEnv := &meroxa.Pipeline{} - - pipelineBase := &meroxa.Pipeline{ - UUID: "6f380820-dfed-4a69-b708-10d134866a35", - Name: "pipeline-base", - } - deepCopy(pipelineBase, pipelineIDAlign) - pipelineIDAlign.UUID = "0e1d29b9-2e62-4cc2-a49d-126f2e1b15ef" - pipelineIDAlign.Name = "pipeline-align" - - deepCopy(pipelineBase, pipelineWithEnv) - pipelineWithEnv.UUID = "038de172-c4b0-49d8-a1d9-26fbeaa2f726" - pipelineWithEnv.Environment = &meroxa.EntityIdentifier{ - UUID: null.StringFrom("e56b1b2e-b6d7-455d-887e-84a0823d84a8"), - Name: null.StringFrom("my-environment"), - } - - tests := map[string][]*meroxa.Pipeline{ - "Base": {pipelineBase}, - "ID_Alignment": {pipelineBase, pipelineIDAlign}, - "With_Environment": {pipelineBase, pipelineIDAlign, pipelineWithEnv}, - } - - tableHeaders := []string{"UUID", "ID", "NAME", "ENVIRONMENT", "STATE"} - - for name, pipelines := range tests { - t.Run(name, func(t *testing.T) { - out := CaptureOutput(func() { - PrintPipelinesTable(pipelines, false) - }) - - for _, header := range tableHeaders { - if !strings.Contains(out, header) { - t.Errorf("%s header is missing", header) - } - } - - switch name { - case "Base": - if !strings.Contains(out, pipelineBase.Name) { - t.Errorf("%s, not found", pipelineBase.Name) - } - if !strings.Contains(out, pipelineBase.UUID) { - t.Errorf("%s, not found", pipelineBase.UUID) - } - if !strings.Contains(out, string(meroxa.EnvironmentTypeCommon)) { - t.Errorf("environment should be %s", string(meroxa.EnvironmentTypeCommon)) - } - case "ID_Alignment": - if !strings.Contains(out, pipelineIDAlign.Name) { - t.Errorf("%s, not found", pipelineIDAlign.Name) - } - if !strings.Contains(out, pipelineIDAlign.UUID) { - t.Errorf("%s, not found", pipelineIDAlign.UUID) - } - case "With_Environment": - if !strings.Contains(out, pipelineWithEnv.Environment.Name.String) { - t.Errorf("expected environment name to be %q", pipelineWithEnv.Environment.Name.String) - } - } - - fmt.Println(out) - }) - } -} - -func TestPipelineTable(t *testing.T) { - pipelineWithEnv := &meroxa.Pipeline{} - - pipelineBase := &meroxa.Pipeline{ - UUID: "6f380820-dfed-4a69-b708-10d134866a35", - Name: "pipeline-base", - } - - deepCopy(pipelineBase, pipelineWithEnv) - pipelineWithEnv.UUID = "038de172-c4b0-49d8-a1d9-26fbeaa2f726" - pipelineWithEnv.Environment = &meroxa.EntityIdentifier{ - UUID: null.StringFrom("e56b1b2e-b6d7-455d-887e-84a0823d84a8"), - Name: null.StringFrom("my-environment"), - } - - tests := map[string]*meroxa.Pipeline{ - "Base": pipelineBase, - "With_Environment": pipelineWithEnv, - } - - tableHeaders := []string{"UUID", "ID", "Name", "State"} - var envHeader = "Environment Name" - - for name, p := range tests { - t.Run(name, func(t *testing.T) { - out := CaptureOutput(func() { - PrintPipelineTable(p) - }) - - for _, header := range tableHeaders { - if !strings.Contains(out, header) { - t.Errorf("%q header is missing", header) - } - } - - switch name { - case "Base": - if !strings.Contains(out, pipelineBase.Name) { - t.Errorf("%s, not found", pipelineBase.Name) - } - if !strings.Contains(out, pipelineBase.UUID) { - t.Errorf("%s, not found", pipelineBase.UUID) - } - if !strings.Contains(out, pipelineBase.UUID) { - t.Errorf("%s, not found", pipelineBase.UUID) - } - if !strings.Contains(out, envHeader) { - t.Errorf("%q not found", envHeader) - } - case "With_Environment": - if !strings.Contains(out, pipelineWithEnv.Environment.UUID.String) { - t.Errorf("expected environment UUID to be %q", pipelineWithEnv.Environment.UUID.String) - } - } - fmt.Println(out) - }) - } -} - -func TestPipelinesTableWithoutHeaders(t *testing.T) { - pipeline := &meroxa.Pipeline{ - UUID: "6f380820-dfed-4a69-b708-10d134866a35", - Name: "pipeline-base", - } - - var pipelines []*meroxa.Pipeline - tableHeaders := []string{"ID", "NAME", "STATE"} - - pipelines = append(pipelines, pipeline) - - out := CaptureOutput(func() { - PrintPipelinesTable(pipelines, true) - }) - - for _, header := range tableHeaders { - if strings.Contains(out, header) { - t.Errorf("%s header should not be displayed", header) - } - } - - if !strings.Contains(out, pipeline.Name) { - t.Errorf("%s, not found", pipeline.Name) - } - if !strings.Contains(out, pipeline.UUID) { - t.Errorf("%s, not found", pipeline.UUID) - } -} - -func TestEnvironmentsTable(t *testing.T) { - e := &meroxa.Environment{ - Type: meroxa.EnvironmentTypePrivate, - Name: "environment-1234", - Provider: meroxa.EnvironmentProviderAws, - Region: meroxa.EnvironmentRegionUsEast1, - Status: meroxa.EnvironmentViewStatus{State: meroxa.EnvironmentStateReady}, - UUID: "531428f7-4e86-4094-8514-d397d49026f7", - } - - tests := map[string][]*meroxa.Environment{ - "Base": {e}, - } - - tableHeaders := []string{"ID", "NAME", "TYPE", "PROVIDER", "REGION", "STATE"} - - for name, environments := range tests { - t.Run(name, func(t *testing.T) { - out := CaptureOutput(func() { - PrintEnvironmentsTable(environments, false) - }) - - for _, header := range tableHeaders { - if !strings.Contains(out, header) { - t.Errorf("%s header is missing", header) - } - } - - if !strings.Contains(out, e.UUID) { - t.Errorf("%s, not found", e.UUID) - } - if !strings.Contains(out, e.Name) { - t.Errorf("%s, not found", e.Name) - } - if !strings.Contains(out, string(e.Type)) { - t.Errorf("%s, not found", e.Type) - } - if !strings.Contains(out, string(e.Region)) { - t.Errorf("%s, not found", e.Region) - } - if !strings.Contains(out, string(e.Status.State)) { - t.Errorf("%s, not found", e.Status.State) - } - if !strings.Contains(out, e.UUID) { - t.Errorf("%s, not found", e.UUID) - } - - fmt.Println(out) - }) - } -} - -func TestEnvironmentsTablePreflightFailed(t *testing.T) { - e := GenerateEnvironmentFailed("environment-preflight-failed") - - tests := map[string][]*meroxa.Environment{ - "Base": {&e}, - } - - tableHeaders := []string{"ID", "NAME", "TYPE", "PROVIDER", "REGION", "STATE"} - - for name, environments := range tests { - t.Run(name, func(t *testing.T) { - out := CaptureOutput(func() { - PrintEnvironmentsTable(environments, false) - }) - - for _, header := range tableHeaders { - if !strings.Contains(out, header) { - t.Errorf("%s header is missing", header) - } - } - - if !strings.Contains(out, e.UUID) { - t.Errorf("%s, not found", e.UUID) - } - if !strings.Contains(out, e.Name) { - t.Errorf("%s, not found", e.Name) - } - if !strings.Contains(out, string(e.Type)) { - t.Errorf("%s, not found", e.Type) - } - if !strings.Contains(out, string(e.Region)) { - t.Errorf("%s, not found", e.Region) - } - if !strings.Contains(out, string(e.Status.State)) { - t.Errorf("%s, not found", e.Status.State) - } - if !strings.Contains(out, e.UUID) { - t.Errorf("%s, not found", e.UUID) - } - - fmt.Println(out) - }) - } -} - -func TestEnvironmentsTableWithoutHeaders(t *testing.T) { - e := &meroxa.Environment{ - Type: meroxa.EnvironmentTypePrivate, - Name: "environment-1234", - Provider: meroxa.EnvironmentProviderAws, - Region: meroxa.EnvironmentRegionUsEast1, - Status: meroxa.EnvironmentViewStatus{State: meroxa.EnvironmentStateReady}, - UUID: "531428f7-4e86-4094-8514-d397d49026f7", - } - - var environments []*meroxa.Environment - tableHeaders := []string{"ID", "NAME", "TYPE", "PROVIDER", "REGION", "STATE"} - - environments = append(environments, e) - - out := CaptureOutput(func() { - PrintEnvironmentsTable(environments, true) - }) - - for _, header := range tableHeaders { - if strings.Contains(out, header) { - t.Errorf("%s header should not be displayed", header) - } - } - - if !strings.Contains(out, e.UUID) { - t.Errorf("%s, not found", e.UUID) - } - if !strings.Contains(out, e.Name) { - t.Errorf("%s, not found", e.Name) - } - if !strings.Contains(out, string(e.Type)) { - t.Errorf("%s, not found", e.Type) - } - if !strings.Contains(out, string(e.Region)) { - t.Errorf("%s, not found", e.Region) - } - if !strings.Contains(out, string(e.Status.State)) { - t.Errorf("%s, not found", e.Status.State) - } - if !strings.Contains(out, e.UUID) { - t.Errorf("%s, not found", e.UUID) - } -} - -func deepCopy(a, b interface{}) { - byt, _ := json.Marshal(a) - _ = json.Unmarshal(byt, b) -} diff --git a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/application.go b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/application.go index a7d38cc51..d30e0c8c9 100644 --- a/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/application.go +++ b/vendor/github.com/meroxa/meroxa-go/pkg/meroxa/application.go @@ -6,6 +6,8 @@ import ( "fmt" "net/http" "time" + + "github.com/volatiletech/null/v8" ) type ApplicationState string @@ -17,20 +19,31 @@ const ( const applicationsBasePath = "/v1/applications" +type ResourceCollection struct { + Name null.String `json:"name,omitempty"` + Source null.String `json:"source,omitempty"` + Destination null.String `json:"destination,omitempty"` +} + +type ApplicationResource struct { + EntityIdentifier + Collection ResourceCollection `json:"collection,omitempty"` +} + // Application represents the Meroxa Application type within the Meroxa API type Application struct { - UUID string `json:"uuid"` - Name string `json:"name"` - Language string `json:"language"` - GitSha string `json:"git_sha"` - Status ApplicationStatus `json:"status,omitempty"` - Pipeline EntityIdentifier `json:"pipeline,omitempty"` - Connectors []EntityIdentifier `json:"connectors,omitempty"` - Functions []EntityIdentifier `json:"functions,omitempty"` - Resources []EntityIdentifier `json:"resources,omitempty"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` + UUID string `json:"uuid"` + Name string `json:"name"` + Language string `json:"language"` + GitSha string `json:"git_sha"` + Status ApplicationStatus `json:"status,omitempty"` + Pipeline EntityIdentifier `json:"pipeline,omitempty"` + Connectors []EntityIdentifier `json:"connectors,omitempty"` + Functions []EntityIdentifier `json:"functions,omitempty"` + Resources []ApplicationResource `json:"resources,omitempty"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + DeletedAt time.Time `json:"deleted_at,omitempty"` } // CreateApplicationInput represents the input for a Meroxa Application create operation in the API diff --git a/vendor/modules.txt b/vendor/modules.txt index 8118dab37..723773d2a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -189,11 +189,11 @@ github.com/mattn/go-runewidth # github.com/mattn/go-shellwords v1.0.12 ## explicit; go 1.13 github.com/mattn/go-shellwords -# github.com/meroxa/meroxa-go v0.0.0-20220711165903-c09da3162930 +# github.com/meroxa/meroxa-go v0.0.0-20220802095537-beb01d916646 ## explicit; go 1.17 github.com/meroxa/meroxa-go/pkg/meroxa github.com/meroxa/meroxa-go/pkg/mock -# github.com/meroxa/turbine-go v0.0.0-20220720222241-fb02bcb83a88 => ../turbine-go +# github.com/meroxa/turbine-go v0.0.0-20220720222241-fb02bcb83a88 ## explicit; go 1.18 github.com/meroxa/turbine-go github.com/meroxa/turbine-go/deploy @@ -389,4 +389,3 @@ gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# github.com/meroxa/turbine-go => ../turbine-go