From 7d0a4c0b6e325591f1b0b4488cf858acf2be423b Mon Sep 17 00:00:00 2001 From: Oscar Reyes Date: Wed, 10 May 2023 08:02:32 -0600 Subject: [PATCH] feature(cli): version display improvements (#2505) --- api/openapi.yaml | 17 ++++ api/version.yaml | 9 ++ cli/actions/action.go | 40 ++++++++ cli/actions/resource.go | 3 +- cli/actions/version.go | 69 ++++++++++++++ cli/cmd/apply_cmd.go | 24 ++--- cli/cmd/config.go | 17 ++++ cli/cmd/configure_cmd.go | 10 +- cli/cmd/dashboard_cmd.go | 16 +--- cli/cmd/delete_cmd.go | 20 ++-- cli/cmd/export_cmd.go | 16 +--- cli/cmd/get_cmd.go | 25 ++--- cli/cmd/list_cmd.go | 22 ++--- cli/cmd/middleware.go | 31 +++++++ cli/cmd/test_export_cmd.go | 9 +- cli/cmd/test_list_cmd.go | 9 +- cli/cmd/test_run_cmd.go | 12 +-- cli/cmd/{version.go => version_cmd.go} | 9 +- cli/openapi/api_api.go | 100 ++++++++++++++++++++ cli/openapi/model_version.go | 124 +++++++++++++++++++++++++ server/app/app.go | 2 +- server/http/controller.go | 11 +++ server/http/controller_test.go | 1 + server/openapi/api.go | 2 + server/openapi/api_api.go | 19 ++++ server/openapi/model_version.go | 31 +++++++ web/src/types/Generated.types.ts | 29 ++++++ 27 files changed, 554 insertions(+), 123 deletions(-) create mode 100644 api/version.yaml create mode 100644 cli/actions/version.go create mode 100644 cli/cmd/middleware.go rename cli/cmd/{version.go => version_cmd.go} (76%) create mode 100644 cli/openapi/model_version.go create mode 100644 server/openapi/model_version.go diff --git a/api/openapi.yaml b/api/openapi.yaml index c58236ff34..825cf61b30 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1212,3 +1212,20 @@ paths: description: "environment not found" 500: description: "problem deleting an environment" + + /version: + get: + tags: + - api + summary: "Get the version of the API" + description: "Get the version of the API" + operationId: getVersion + responses: + 200: + description: successful operation + content: + application/json: + schema: + $ref: "./version.yaml#/components/schemas/Version" + 500: + description: "problem getting the version of the API" diff --git a/api/version.yaml b/api/version.yaml new file mode 100644 index 0000000000..bc5b476bba --- /dev/null +++ b/api/version.yaml @@ -0,0 +1,9 @@ +openapi: 3.0.0 +components: + schemas: + Version: + type: object + properties: + version: + type: string + example: 1.0.0 diff --git a/cli/actions/action.go b/cli/actions/action.go index 5341ad9863..0228cf57a2 100644 --- a/cli/actions/action.go +++ b/cli/actions/action.go @@ -2,8 +2,48 @@ package actions import ( "context" + + "github.com/kubeshop/tracetest/cli/config" + "github.com/kubeshop/tracetest/cli/openapi" + "go.uber.org/zap" ) type Action[T any] interface { Run(ctx context.Context, args T) error } + +type actionAgs struct { + config config.Config + logger *zap.Logger + client *openapi.APIClient +} + +type ActionArgsOption = func(args *actionAgs) + +func ActionWithClient(client *openapi.APIClient) ActionArgsOption { + return func(args *actionAgs) { + args.client = client + } +} + +func ActionWithLogger(logger *zap.Logger) ActionArgsOption { + return func(args *actionAgs) { + args.logger = logger + } +} + +func ActionWithConfig(config config.Config) ActionArgsOption { + return func(args *actionAgs) { + args.config = config + } +} + +func NewActionArgs(options ...ActionArgsOption) actionAgs { + args := actionAgs{} + + for _, option := range options { + option(&args) + } + + return args +} diff --git a/cli/actions/resource.go b/cli/actions/resource.go index ae44a12dba..d009501aea 100644 --- a/cli/actions/resource.go +++ b/cli/actions/resource.go @@ -2,6 +2,7 @@ package actions import ( "errors" + "fmt" "github.com/kubeshop/tracetest/cli/config" "github.com/kubeshop/tracetest/cli/formatters" @@ -48,7 +49,7 @@ func (r ResourceRegistry) Get(name string) (resourceActions, error) { actions, found := r[name] if !found { - return resourceActions{}, ErrResourceNotRegistered + return resourceActions{}, fmt.Errorf("resource not found: %s", name) } return actions, nil diff --git a/cli/actions/version.go b/cli/actions/version.go new file mode 100644 index 0000000000..1b1161eb73 --- /dev/null +++ b/cli/actions/version.go @@ -0,0 +1,69 @@ +package actions + +import ( + "context" + "fmt" + + "github.com/kubeshop/tracetest/cli/config" +) + +type VersionConfig struct{} + +type versionAction struct { + actionAgs +} + +var _ Action[VersionConfig] = &versionAction{} + +func NewGetServerVersionAction(options ...ActionArgsOption) versionAction { + args := NewActionArgs(options...) + return versionAction{actionAgs: args} +} + +func (a versionAction) Run(ctx context.Context, args VersionConfig) error { + versionText := a.GetVersionText(ctx) + + fmt.Println(versionText) + return nil +} + +func (a versionAction) GetVersionText(ctx context.Context) string { + result := fmt.Sprintf(`CLI: %s`, config.Version) + + if a.config.IsEmpty() { + return result + ` +Server: Not Configured` + } + + version, err := a.GetServerVersion(ctx) + if err != nil { + return result + fmt.Sprintf(` +Server: Failed to get the server version - %s`, err.Error()) + } + + isVersionMatch := version == config.Version + if isVersionMatch { + version += ` +✔️ Version match` + } else { + version += ` +✖️ Version mismatch` + } + + return result + fmt.Sprintf(` +Server: %s`, version) +} + +func (a versionAction) GetServerVersion(ctx context.Context) (string, error) { + if a.config.IsEmpty() { + return "", fmt.Errorf("not Configured") + } + + req := a.client.ApiApi.GetVersion(ctx) + version, _, err := req.Execute() + if err != nil { + return "", err + } + + return *version.Version, nil +} diff --git a/cli/cmd/apply_cmd.go b/cli/cmd/apply_cmd.go index ad8c6ebee1..4793788f02 100644 --- a/cli/cmd/apply_cmd.go +++ b/cli/cmd/apply_cmd.go @@ -3,13 +3,11 @@ package cmd import ( "context" "fmt" - "os" "github.com/kubeshop/tracetest/cli/actions" "github.com/kubeshop/tracetest/cli/analytics" "github.com/kubeshop/tracetest/cli/formatters" "github.com/spf13/cobra" - "go.uber.org/zap" ) var definitionFile string @@ -21,11 +19,9 @@ var applyCmd = &cobra.Command{ Long: "Apply (create/update) resources to your Tracetest server", PreRun: setupCommand(), Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(cmd *cobra.Command, args []string) (string, error) { if definitionFile == "" { - cliLogger.Error("file with definition must be specified") - os.Exit(1) - return + return "", fmt.Errorf("file with definition must be specified") } resourceType := args[0] @@ -38,9 +34,7 @@ var applyCmd = &cobra.Command{ resourceActions, err := resourceRegistry.Get(resourceType) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to get resource instance for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } applyArgs := actions.ApplyArgs{ @@ -49,9 +43,7 @@ var applyCmd = &cobra.Command{ resource, _, err := resourceActions.Apply(ctx, applyArgs) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to apply definition for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } resourceFormatter := resourceActions.Formatter() @@ -59,13 +51,11 @@ var applyCmd = &cobra.Command{ result, err := formatter.Format(resource) if err != nil { - cliLogger.Error("failed to format resource", zap.Error(err)) - os.Exit(1) - return + return "", err } - fmt.Println(result) - }, + return result, nil + }), PostRun: teardownCommand, } diff --git a/cli/cmd/config.go b/cli/cmd/config.go index 691128473b..a49e27aae1 100644 --- a/cli/cmd/config.go +++ b/cli/cmd/config.go @@ -1,6 +1,7 @@ package cmd import ( + "context" "fmt" "os" @@ -17,6 +18,7 @@ import ( var cliConfig config.Config var cliLogger *zap.Logger var resourceRegistry = actions.NewResourceRegistry() +var versionText string type setupConfig struct { shouldValidateConfig bool @@ -43,6 +45,7 @@ func setupCommand(options ...setupOption) func(cmd *cobra.Command, args []string setupLogger(cmd, args) loadConfig(cmd, args) overrideConfig() + setupVersion() baseOptions := []actions.ResourceArgsOption{actions.WithLogger(cliLogger), actions.WithConfig(cliConfig)} @@ -168,3 +171,17 @@ func teardownCommand(cmd *cobra.Command, args []string) { cliLogger.Sync() analytics.Close() } + +func setupVersion() { + ctx := context.Background() + options := []actions.ActionArgsOption{ + actions.ActionWithClient(utils.GetAPIClient(cliConfig)), + actions.ActionWithConfig(cliConfig), + actions.ActionWithLogger(cliLogger), + } + + action := actions.NewGetServerVersionAction(options...) + version := action.GetVersionText(ctx) + + versionText = version +} diff --git a/cli/cmd/configure_cmd.go b/cli/cmd/configure_cmd.go index 5a8ec3a7f4..7df3eabdee 100644 --- a/cli/cmd/configure_cmd.go +++ b/cli/cmd/configure_cmd.go @@ -7,7 +7,6 @@ import ( "github.com/kubeshop/tracetest/cli/analytics" "github.com/kubeshop/tracetest/cli/utils" "github.com/spf13/cobra" - "go.uber.org/zap" ) var analyticsEnabled bool @@ -20,7 +19,7 @@ var configureCmd = &cobra.Command{ Short: "Configure your tracetest CLI", Long: "Configure your tracetest CLI", PreRun: setupLogger, - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(cmd *cobra.Command, _ []string) (string, error) { analytics.Track("Configure", "cmd", map[string]string{}) ctx := context.Background() @@ -41,11 +40,8 @@ var configureCmd = &cobra.Command{ } err := action.Run(ctx, actionConfig) - if err != nil { - cliLogger.Error("could not get tests", zap.Error(err)) - return - } - }, + return "", err + }), PostRun: teardownCommand, } diff --git a/cli/cmd/dashboard_cmd.go b/cli/cmd/dashboard_cmd.go index 5a77f31d1f..94e79647b2 100644 --- a/cli/cmd/dashboard_cmd.go +++ b/cli/cmd/dashboard_cmd.go @@ -2,12 +2,10 @@ package cmd import ( "fmt" - "os" "github.com/kubeshop/tracetest/cli/analytics" "github.com/kubeshop/tracetest/cli/utils" "github.com/spf13/cobra" - "go.uber.org/zap" ) var dashboardCmd = &cobra.Command{ @@ -16,24 +14,20 @@ var dashboardCmd = &cobra.Command{ Short: "Opens the Tracetest Dashboard URL", Long: "Opens the Tracetest Dashboard URL", PreRun: setupCommand(), - Run: func(_ *cobra.Command, _ []string) { + Run: WithResultHandler(func(_ *cobra.Command, _ []string) (string, error) { analytics.Track("Dashboard", "cmd", map[string]string{}) if cliConfig.IsEmpty() { - cliLogger.Error("Missing Tracetest endpoint configuration") - os.Exit(1) - return + return "", fmt.Errorf("missing Tracetest endpoint configuration") } err := utils.OpenBrowser(cliConfig.URL()) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to open the dashboard url: %s", cliConfig.URL()), zap.Error(err)) - os.Exit(1) - return + return "", fmt.Errorf("failed to open the dashboard url: %s", cliConfig.URL()) } - fmt.Println(fmt.Sprintf("Opening \"%s\" in the default browser", cliConfig.URL())) - }, + return fmt.Sprintf("Opening \"%s\" in the default browser", cliConfig.URL()), nil + }), PostRun: teardownCommand, } diff --git a/cli/cmd/delete_cmd.go b/cli/cmd/delete_cmd.go index 5afc8980f7..f9d643f8d6 100644 --- a/cli/cmd/delete_cmd.go +++ b/cli/cmd/delete_cmd.go @@ -3,11 +3,9 @@ package cmd import ( "context" "fmt" - "os" "github.com/kubeshop/tracetest/cli/analytics" "github.com/spf13/cobra" - "go.uber.org/zap" ) var deletedResourceID string @@ -19,11 +17,9 @@ var deleteCmd = &cobra.Command{ Short: "Delete resources", PreRun: setupCommand(), Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(_ *cobra.Command, args []string) (string, error) { if deletedResourceID == "" { - cliLogger.Error("id of the resource to delete must be specified") - os.Exit(1) - return + return "", fmt.Errorf("id of the resource to delete must be specified") } resourceType := args[0] @@ -35,20 +31,16 @@ var deleteCmd = &cobra.Command{ resourceActions, err := resourceRegistry.Get(resourceType) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to get resource instance for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } message, err := resourceActions.Delete(ctx, deletedResourceID) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to apply definition for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } - cmd.Println(fmt.Sprintf("✔ %s", message)) - }, + return fmt.Sprintf("✔ %s", message), nil + }), PostRun: teardownCommand, } diff --git a/cli/cmd/export_cmd.go b/cli/cmd/export_cmd.go index d4b4987687..7a5f02aaf2 100644 --- a/cli/cmd/export_cmd.go +++ b/cli/cmd/export_cmd.go @@ -3,11 +3,9 @@ package cmd import ( "context" "fmt" - "os" "github.com/kubeshop/tracetest/cli/analytics" "github.com/spf13/cobra" - "go.uber.org/zap" ) var ( @@ -22,7 +20,7 @@ var exportCmd = &cobra.Command{ Short: "Export resource", PreRun: setupCommand(), Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(cmd *cobra.Command, args []string) (string, error) { resourceType := args[0] ctx := context.Background() @@ -32,20 +30,16 @@ var exportCmd = &cobra.Command{ resourceActions, err := resourceRegistry.Get(resourceType) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to export resource instance for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } err = resourceActions.Export(ctx, exportResourceID, exportResourceFile) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to export resource for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } - cmd.Println(fmt.Sprintf("✔ Definition exported successfully for resource type: %s", resourceType)) - }, + return fmt.Sprintf("✔ Definition exported successfully for resource type: %s", resourceType), nil + }), PostRun: teardownCommand, } diff --git a/cli/cmd/get_cmd.go b/cli/cmd/get_cmd.go index 8bc5427397..5e4eb26ef3 100644 --- a/cli/cmd/get_cmd.go +++ b/cli/cmd/get_cmd.go @@ -3,12 +3,10 @@ package cmd import ( "context" "fmt" - "os" "github.com/kubeshop/tracetest/cli/analytics" "github.com/kubeshop/tracetest/cli/formatters" "github.com/spf13/cobra" - "go.uber.org/zap" ) var resourceID string @@ -20,11 +18,9 @@ var getCmd = &cobra.Command{ Short: "Get resource", PreRun: setupCommand(), Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(cmd *cobra.Command, args []string) (string, error) { if resourceID == "" { - cliLogger.Error("id of the resource to get must be specified") - os.Exit(1) - return + return "", fmt.Errorf("id of the resource to get must be specified") } resourceType := args[0] @@ -35,18 +31,13 @@ var getCmd = &cobra.Command{ }) resourceActions, err := resourceRegistry.Get(resourceType) - if err != nil { - cliLogger.Error(fmt.Sprintf("failed to get resource instance for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } resource, err := resourceActions.Get(ctx, resourceID) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to get resource for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } resourceFormatter := resourceActions.Formatter() @@ -54,13 +45,11 @@ var getCmd = &cobra.Command{ result, err := formatter.Format(resource) if err != nil { - cliLogger.Error("failed to format resource", zap.Error(err)) - os.Exit(1) - return + return "", err } - fmt.Println(result) - }, + return result, nil + }), PostRun: teardownCommand, } diff --git a/cli/cmd/list_cmd.go b/cli/cmd/list_cmd.go index e9e89fda3c..f0bf3d7bfd 100644 --- a/cli/cmd/list_cmd.go +++ b/cli/cmd/list_cmd.go @@ -2,14 +2,11 @@ package cmd import ( "context" - "fmt" - "os" "github.com/kubeshop/tracetest/cli/analytics" "github.com/kubeshop/tracetest/cli/formatters" "github.com/kubeshop/tracetest/cli/utils" "github.com/spf13/cobra" - "go.uber.org/zap" ) var ( @@ -27,7 +24,7 @@ var listCmd = &cobra.Command{ Short: "List resources", PreRun: setupCommand(), Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(cmd *cobra.Command, args []string) (string, error) { resourceType := args[0] ctx := context.Background() @@ -36,11 +33,8 @@ var listCmd = &cobra.Command{ }) resourceActions, err := resourceRegistry.Get(resourceType) - if err != nil { - cliLogger.Error(fmt.Sprintf("failed to get resource instance for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } listArgs := utils.ListArgs{ @@ -53,9 +47,7 @@ var listCmd = &cobra.Command{ resource, err := resourceActions.List(ctx, listArgs) if err != nil { - cliLogger.Error(fmt.Sprintf("failed to list for type: %s", resourceType), zap.Error(err)) - os.Exit(1) - return + return "", err } resourceFormatter := resourceActions.Formatter() @@ -63,13 +55,11 @@ var listCmd = &cobra.Command{ result, err := formatter.FormatList(resource) if err != nil { - cliLogger.Error("failed to format resource", zap.Error(err)) - os.Exit(1) - return + return "", err } - fmt.Println(result) - }, + return result, nil + }), PostRun: teardownCommand, } diff --git a/cli/cmd/middleware.go b/cli/cmd/middleware.go new file mode 100644 index 0000000000..0441e14fd8 --- /dev/null +++ b/cli/cmd/middleware.go @@ -0,0 +1,31 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + "go.uber.org/zap" +) + +type RunFn func(cmd *cobra.Command, args []string) (string, error) +type CobraRunFn func(cmd *cobra.Command, args []string) + +func WithResultHandler(runFn RunFn) CobraRunFn { + return func(cmd *cobra.Command, args []string) { + res, err := runFn(cmd, args) + if err != nil { + cliLogger.Error(fmt.Sprintf(` +Version +%s + +An error ocurred when executing the command`, versionText), zap.Error(err)) + os.Exit(1) + return + } + + if res != "" { + fmt.Println(res) + } + } +} diff --git a/cli/cmd/test_export_cmd.go b/cli/cmd/test_export_cmd.go index cc0d581674..fbbb8d1a4f 100644 --- a/cli/cmd/test_export_cmd.go +++ b/cli/cmd/test_export_cmd.go @@ -21,7 +21,7 @@ var testExportCmd = &cobra.Command{ Short: "Exports a test into a file", Long: "Exports a test into a file", PreRun: setupCommand(), - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(cmd *cobra.Command, args []string) (string, error) { analytics.Track("Test Export", "cmd", map[string]string{}) ctx := context.Background() @@ -36,11 +36,8 @@ var testExportCmd = &cobra.Command{ } err := exportTestAction.Run(ctx, actionArgs) - if err != nil { - cliLogger.Error("could not get tests", zap.Error(err)) - return - } - }, + return "", err + }), PostRun: teardownCommand, } diff --git a/cli/cmd/test_list_cmd.go b/cli/cmd/test_list_cmd.go index b030c053e9..a89e797c95 100644 --- a/cli/cmd/test_list_cmd.go +++ b/cli/cmd/test_list_cmd.go @@ -15,7 +15,7 @@ var testListCmd = &cobra.Command{ Short: "List all tests", Long: "List all tests", PreRun: setupCommand(), - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(cmd *cobra.Command, args []string) (string, error) { analytics.Track("Test List", "cmd", map[string]string{}) ctx := context.Background() @@ -25,11 +25,8 @@ var testListCmd = &cobra.Command{ actionArgs := actions.ListTestConfig{} err := listTestsAction.Run(ctx, actionArgs) - if err != nil { - cliLogger.Error("could not get tests", zap.Error(err)) - return - } - }, + return "", err + }), PostRun: teardownCommand, } diff --git a/cli/cmd/test_run_cmd.go b/cli/cmd/test_run_cmd.go index 5677631ba8..9628bbf372 100644 --- a/cli/cmd/test_run_cmd.go +++ b/cli/cmd/test_run_cmd.go @@ -2,13 +2,11 @@ package cmd import ( "context" - "os" "github.com/kubeshop/tracetest/cli/actions" "github.com/kubeshop/tracetest/cli/analytics" "github.com/kubeshop/tracetest/cli/utils" "github.com/spf13/cobra" - "go.uber.org/zap" ) var ( @@ -23,7 +21,7 @@ var testRunCmd = &cobra.Command{ Short: "Run a test on your Tracetest server", Long: "Run a test on your Tracetest server", PreRun: setupCommand(), - Run: func(_ *cobra.Command, _ []string) { + Run: WithResultHandler(func(_ *cobra.Command, _ []string) (string, error) { analytics.Track("Test Run", "cmd", map[string]string{}) ctx := context.Background() @@ -42,12 +40,8 @@ var testRunCmd = &cobra.Command{ } err := runTestAction.Run(ctx, actionArgs) - if err != nil { - cliLogger.Error("failed to run test", zap.Error(err)) - os.Exit(1) - return - } - }, + return "", err + }), PostRun: teardownCommand, } diff --git a/cli/cmd/version.go b/cli/cmd/version_cmd.go similarity index 76% rename from cli/cmd/version.go rename to cli/cmd/version_cmd.go index 33ce5ad124..eac2223079 100644 --- a/cli/cmd/version.go +++ b/cli/cmd/version_cmd.go @@ -1,10 +1,7 @@ package cmd import ( - "fmt" - "github.com/kubeshop/tracetest/cli/analytics" - "github.com/kubeshop/tracetest/cli/config" "github.com/spf13/cobra" ) @@ -14,11 +11,11 @@ var versionCmd = &cobra.Command{ Short: "Display this CLI tool version", Long: "Display this CLI tool version", PreRun: setupCommand(), - Run: func(cmd *cobra.Command, args []string) { + Run: WithResultHandler(func(cmd *cobra.Command, args []string) (string, error) { analytics.Track("Version", "cmd", map[string]string{}) - fmt.Println(config.Version) - }, + return versionText, nil + }), PostRun: teardownCommand, } diff --git a/cli/openapi/api_api.go b/cli/openapi/api_api.go index d6fd91cd98..7197a38e42 100644 --- a/cli/openapi/api_api.go +++ b/cli/openapi/api_api.go @@ -3046,6 +3046,106 @@ func (a *ApiApiService) GetTransactionsExecute(r ApiGetTransactionsRequest) ([]T return localVarReturnValue, localVarHTTPResponse, nil } +type ApiGetVersionRequest struct { + ctx context.Context + ApiService *ApiApiService +} + +func (r ApiGetVersionRequest) Execute() (*Version, *http.Response, error) { + return r.ApiService.GetVersionExecute(r) +} + +/* +GetVersion Get the version of the API + +Get the version of the API + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiGetVersionRequest +*/ +func (a *ApiApiService) GetVersion(ctx context.Context) ApiGetVersionRequest { + return ApiGetVersionRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return Version +func (a *ApiApiService) GetVersionExecute(r ApiGetVersionRequest) (*Version, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *Version + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ApiApiService.GetVersion") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/version" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + type ApiImportTestRunRequest struct { ctx context.Context ApiService *ApiApiService diff --git a/cli/openapi/model_version.go b/cli/openapi/model_version.go new file mode 100644 index 0000000000..d463c4884e --- /dev/null +++ b/cli/openapi/model_version.go @@ -0,0 +1,124 @@ +/* +TraceTest + +OpenAPI definition for TraceTest endpoint and resources + +API version: 0.2.1 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the Version type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &Version{} + +// Version struct for Version +type Version struct { + Version *string `json:"version,omitempty"` +} + +// NewVersion instantiates a new Version object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewVersion() *Version { + this := Version{} + return &this +} + +// NewVersionWithDefaults instantiates a new Version object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewVersionWithDefaults() *Version { + this := Version{} + return &this +} + +// GetVersion returns the Version field value if set, zero value otherwise. +func (o *Version) GetVersion() string { + if o == nil || isNil(o.Version) { + var ret string + return ret + } + return *o.Version +} + +// GetVersionOk returns a tuple with the Version field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Version) GetVersionOk() (*string, bool) { + if o == nil || isNil(o.Version) { + return nil, false + } + return o.Version, true +} + +// HasVersion returns a boolean if a field has been set. +func (o *Version) HasVersion() bool { + if o != nil && !isNil(o.Version) { + return true + } + + return false +} + +// SetVersion gets a reference to the given string and assigns it to the Version field. +func (o *Version) SetVersion(v string) { + o.Version = &v +} + +func (o Version) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o Version) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !isNil(o.Version) { + toSerialize["version"] = o.Version + } + return toSerialize, nil +} + +type NullableVersion struct { + value *Version + isSet bool +} + +func (v NullableVersion) Get() *Version { + return v.value +} + +func (v *NullableVersion) Set(val *Version) { + v.value = val + v.isSet = true +} + +func (v NullableVersion) IsSet() bool { + return v.isSet +} + +func (v *NullableVersion) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableVersion(val *Version) *NullableVersion { + return &NullableVersion{value: val, isSet: true} +} + +func (v NullableVersion) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableVersion) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/server/app/app.go b/server/app/app.go index 5d60dbf4ae..07a441976c 100644 --- a/server/app/app.go +++ b/server/app/app.go @@ -412,7 +412,7 @@ func httpRouter( mappers mappings.Mappings, triggerRegistry *trigger.Registry, ) openapi.Router { - controller := httpServer.NewController(testDB, tracedb.Factory(testDB), rf, mappers, triggerRegistry, tracer) + controller := httpServer.NewController(testDB, tracedb.Factory(testDB), rf, mappers, triggerRegistry, tracer, Version) apiApiController := openapi.NewApiApiController(controller) customController := httpServer.NewCustomController(controller, apiApiController, openapi.DefaultErrorHandler, tracer) httpRouter := customController diff --git a/server/http/controller.go b/server/http/controller.go index 5658a88a59..217a70e630 100644 --- a/server/http/controller.go +++ b/server/http/controller.go @@ -35,6 +35,7 @@ type controller struct { newTraceDBFn func(ds datastoreresource.DataStore) (tracedb.TraceDB, error) mappers mappings.Mappings triggerRegistry *trigger.Registry + version string } type runner interface { @@ -51,6 +52,7 @@ func NewController( mappers mappings.Mappings, triggerRegistry *trigger.Registry, tracer trace.Tracer, + version string, ) openapi.ApiApiServicer { return &controller{ tracer: tracer, @@ -59,6 +61,7 @@ func NewController( newTraceDBFn: newTraceDBFn, mappers: mappers, triggerRegistry: triggerRegistry, + version: version, } } @@ -1093,3 +1096,11 @@ func (c *controller) TestConnection(ctx context.Context, dataStore openapi.DataS return openapi.Response(statusCode, c.mappers.Out.ConnectionTestResult(testResult)), nil } + +func (c *controller) GetVersion(ctx context.Context) (openapi.ImplResponse, error) { + version := openapi.Version{ + Version: c.version, + } + + return openapi.Response(http.StatusOK, version), nil +} diff --git a/server/http/controller_test.go b/server/http/controller_test.go index 0125f9a501..6d2a77e86c 100644 --- a/server/http/controller_test.go +++ b/server/http/controller_test.go @@ -122,6 +122,7 @@ func setupController(t *testing.T) controllerFixture { mappings.New(traces.NewConversionConfig(), comparator.DefaultRegistry(), mdb), &trigger.Registry{}, trace.NewNoopTracerProvider().Tracer("tracer"), + "unit-test", ), } } diff --git a/server/openapi/api.go b/server/openapi/api.go index abb17449ab..32f049f00d 100644 --- a/server/openapi/api.go +++ b/server/openapi/api.go @@ -45,6 +45,7 @@ type ApiApiRouter interface { GetTransactionVersion(http.ResponseWriter, *http.Request) GetTransactionVersionDefinitionFile(http.ResponseWriter, *http.Request) GetTransactions(http.ResponseWriter, *http.Request) + GetVersion(http.ResponseWriter, *http.Request) ImportTestRun(http.ResponseWriter, *http.Request) RerunTestRun(http.ResponseWriter, *http.Request) RunTest(http.ResponseWriter, *http.Request) @@ -114,6 +115,7 @@ type ApiApiServicer interface { GetTransactionVersion(context.Context, string, int32) (ImplResponse, error) GetTransactionVersionDefinitionFile(context.Context, string, int32) (ImplResponse, error) GetTransactions(context.Context, int32, int32, string, string, string) (ImplResponse, error) + GetVersion(context.Context) (ImplResponse, error) ImportTestRun(context.Context, ExportedTestInformation) (ImplResponse, error) RerunTestRun(context.Context, string, int32) (ImplResponse, error) RunTest(context.Context, string, RunInformation) (ImplResponse, error) diff --git a/server/openapi/api_api.go b/server/openapi/api_api.go index 04ca388da5..29d132e5e4 100644 --- a/server/openapi/api_api.go +++ b/server/openapi/api_api.go @@ -212,6 +212,12 @@ func (c *ApiApiController) Routes() Routes { "/api/transactions", c.GetTransactions, }, + { + "GetVersion", + strings.ToUpper("Get"), + "/api/version", + c.GetVersion, + }, { "ImportTestRun", strings.ToUpper("Post"), @@ -879,6 +885,19 @@ func (c *ApiApiController) GetTransactions(w http.ResponseWriter, r *http.Reques } +// GetVersion - Get the version of the API +func (c *ApiApiController) GetVersion(w http.ResponseWriter, r *http.Request) { + result, err := c.service.GetVersion(r.Context()) + // If an error occurred, encode the error with the status code + if err != nil { + c.errorHandler(w, r, err, &result) + return + } + // If no error, encode the body and the result code + EncodeJSONResponse(result.Body, &result.Code, w) + +} + // ImportTestRun - import test and test run information func (c *ApiApiController) ImportTestRun(w http.ResponseWriter, r *http.Request) { exportedTestInformationParam := ExportedTestInformation{} diff --git a/server/openapi/model_version.go b/server/openapi/model_version.go new file mode 100644 index 0000000000..369f121cb6 --- /dev/null +++ b/server/openapi/model_version.go @@ -0,0 +1,31 @@ +/* + * TraceTest + * + * OpenAPI definition for TraceTest endpoint and resources + * + * API version: 0.2.1 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package openapi + +type Version struct { + Version string `json:"version,omitempty"` +} + +// AssertVersionRequired checks if the required fields are not zero-ed +func AssertVersionRequired(obj Version) error { + return nil +} + +// AssertRecurseVersionRequired recursively checks if required fields are not zero-ed in a nested slice. +// Accepts only nested slice of Version (e.g. [][]Version), otherwise ErrTypeAssertionError is thrown. +func AssertRecurseVersionRequired(objSlice interface{}) error { + return AssertRecurseInterfaceRequired(objSlice, func(obj interface{}) error { + aVersion, ok := obj.(Version) + if !ok { + return ErrTypeAssertionError + } + return AssertVersionRequired(aVersion) + }) +} diff --git a/web/src/types/Generated.types.ts b/web/src/types/Generated.types.ts index 192aa0e78a..8c9a047858 100644 --- a/web/src/types/Generated.types.ts +++ b/web/src/types/Generated.types.ts @@ -186,6 +186,10 @@ export interface paths { /** Delete an environment from Tracetest */ delete: operations["deleteEnvironment"]; }; + "/version": { + /** Get the version of the API */ + get: operations["getVersion"]; + }; } export interface components {} @@ -1064,6 +1068,19 @@ export interface operations { 500: unknown; }; }; + /** Get the version of the API */ + getVersion: { + responses: { + /** successful operation */ + 200: { + content: { + "application/json": external["version.yaml"]["components"]["schemas"]["Version"]; + }; + }; + /** problem getting the version of the API */ + 500: unknown; + }; + }; } export interface external { @@ -1850,4 +1867,16 @@ export interface external { }; operations: {}; }; + "version.yaml": { + paths: {}; + components: { + schemas: { + Version: { + /** @example 1.0.0 */ + version?: string; + }; + }; + }; + operations: {}; + }; }