From 513bfcecd1e5e72d9825aa634e59ed2f631a5915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0af=C3=A1=C5=99?= Date: Tue, 4 Apr 2023 11:19:31 +0200 Subject: [PATCH] feat: group create, get, list command --- pkg/cmd/registry/group/create/create.go | 132 ++++++++++++++ pkg/cmd/registry/group/get/get.go | 122 +++++++++++++ pkg/cmd/registry/group/group.go | 29 +++ pkg/cmd/registry/group/list/list.go | 165 ++++++++++++++++++ pkg/cmd/registry/registry.go | 2 + .../localize/locales/en/cmd/group.en.toml | 100 +++++++++++ 6 files changed, 550 insertions(+) create mode 100644 pkg/cmd/registry/group/create/create.go create mode 100644 pkg/cmd/registry/group/get/get.go create mode 100644 pkg/cmd/registry/group/group.go create mode 100644 pkg/cmd/registry/group/list/list.go create mode 100644 pkg/core/localize/locales/en/cmd/group.en.toml diff --git a/pkg/cmd/registry/group/create/create.go b/pkg/cmd/registry/group/create/create.go new file mode 100644 index 000000000..4713803ec --- /dev/null +++ b/pkg/cmd/registry/group/create/create.go @@ -0,0 +1,132 @@ +package create + +import ( + "github.com/AlecAivazis/survey/v2" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule/rulecmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/icon" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + registryinstanceclient "github.com/redhat-developer/app-services-sdk-core/app-services-sdk-go/registryinstance/apiv1internal/client" + "github.com/spf13/cobra" + "k8s.io/utils/strings/slices" + + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" +) + +type options struct { + registryID string + + groupId string + description string + properties map[string]string + + f *factory.Factory +} + +// NewCreateCommand creates a new command to create a new artifact group +func NewCreateCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "create", + Short: f.Localizer.MustLocalize("group.create.cmd.description.short"), + Long: f.Localizer.MustLocalize("group.create.cmd.description.long"), + Example: f.Localizer.MustLocalize("group.create.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) (err error) { + var missingFlags []string + + if opts.groupId == "" { + missingFlags = append(missingFlags, "group-id") + } + + if !opts.f.IOStreams.CanPrompt() && len(missingFlags) > 0 { + return flagutil.RequiredWhenNonInteractiveError(missingFlags...) + } + + if len(missingFlags) > 0 { + err = runInteractivePrompt(opts, missingFlags) + if err != nil { + return err + } + } + + if opts.registryID != "" { + return runCreate(opts) + } + + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) + if err != nil { + return err + } + + opts.registryID = registryInstance.GetId() + + return runCreate(opts) + }, + } + + flags := rulecmdutil.NewFlagSet(cmd, f) + + flags.StringVarP(&opts.groupId, "group-id", "g", "", opts.f.Localizer.MustLocalize("group.cmd.create.flag.group-id")) + flags.StringVarP(&opts.description, "description", "d", "", opts.f.Localizer.MustLocalize("group.cmd.create.flag.description")) + flags.StringToStringVarP(&opts.properties, "properties", "p", map[string]string{}, opts.f.Localizer.MustLocalize("group.cmd.create.flag.properties")) + + flags.AddRegistryInstance(&opts.registryID) + + return cmd + +} + +func runCreate(opts *options) error { + conn, err := opts.f.Connection() + if err != nil { + return err + } + + api := conn.API() + + a, _, err := api.ServiceRegistryInstance(opts.registryID) + if err != nil { + return err + } + request := a.GroupsApi.CreateGroup(opts.f.Context) + + createGroupMetaData := registryinstanceclient.CreateGroupMetaData{ + Id: opts.groupId, + Description: &opts.description, + Properties: &opts.properties, + } + + request = request.CreateGroupMetaData(createGroupMetaData) + + _, _, err = request.Execute() + if err != nil { + return registrycmdutil.TransformInstanceError(err) + } + + opts.f.Logger.Info(icon.SuccessPrefix(), opts.f.Localizer.MustLocalize("group.cmd.create.log.info.created", localize.NewEntry("GroupId", opts.groupId))) + + return nil +} + +func runInteractivePrompt(opts *options, missingFlags []string) (err error) { + + if slices.Contains(missingFlags, "group-id") { + settingNamePrompt := &survey.Input{ + Message: opts.f.Localizer.MustLocalize("group.cmd.create.input.group-id.message"), + } + + err = survey.AskOne(settingNamePrompt, &opts.groupId) + if err != nil { + return err + } + } + + return nil +} diff --git a/pkg/cmd/registry/group/get/get.go b/pkg/cmd/registry/group/get/get.go new file mode 100644 index 000000000..db029514d --- /dev/null +++ b/pkg/cmd/registry/group/get/get.go @@ -0,0 +1,122 @@ +package get + +import ( + "github.com/AlecAivazis/survey/v2" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule/rulecmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" + "k8s.io/utils/strings/slices" + + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" +) + +type options struct { + registryID string + + groupId string + outputFormat string + + f *factory.Factory +} + +// NewGetCommand creates a new command to get an artifacts group metadata +func NewGetCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "get", + Short: f.Localizer.MustLocalize("group.get.cmd.description.short"), + Long: f.Localizer.MustLocalize("group.get.cmd.description.long"), + Example: f.Localizer.MustLocalize("group.get.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) (err error) { + var missingFlags []string + + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, flagutil.ValidOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, flagutil.ValidOutputFormats...) + } + + if opts.groupId == "" { + missingFlags = append(missingFlags, "group-id") + } + + if !opts.f.IOStreams.CanPrompt() && len(missingFlags) > 0 { + return flagutil.RequiredWhenNonInteractiveError(missingFlags...) + } + + if len(missingFlags) > 0 { + err = runInteractivePrompt(opts, missingFlags) + if err != nil { + return err + } + } + + if opts.registryID != "" { + return runGet(opts) + } + + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) + if err != nil { + return err + } + + opts.registryID = registryInstance.GetId() + + return runGet(opts) + }, + } + + flags := rulecmdutil.NewFlagSet(cmd, f) + + flags.StringVarP(&opts.groupId, "group-id", "g", "", opts.f.Localizer.MustLocalize("group.cmd.get.flag.group-id")) + flags.AddOutput(&opts.outputFormat) + + flags.AddRegistryInstance(&opts.registryID) + + return cmd + +} + +func runGet(opts *options) error { + conn, err := opts.f.Connection() + if err != nil { + return err + } + + api := conn.API() + + a, _, err := api.ServiceRegistryInstance(opts.registryID) + if err != nil { + return err + } + request := a.GroupsApi.GetGroupById(opts.f.Context, opts.groupId) + + groupMetaData, _, err := request.Execute() + if err != nil { + return registrycmdutil.TransformInstanceError(err) + } + + return dump.Formatted(opts.f.IOStreams.Out, opts.outputFormat, groupMetaData) +} + +func runInteractivePrompt(opts *options, missingFlags []string) (err error) { + + if slices.Contains(missingFlags, "group-id") { + settingNamePrompt := &survey.Input{ + Message: opts.f.Localizer.MustLocalize("group.cmd.get.input.group-id.message"), + } + + err = survey.AskOne(settingNamePrompt, &opts.groupId) + if err != nil { + return err + } + } + + return nil +} diff --git a/pkg/cmd/registry/group/group.go b/pkg/cmd/registry/group/group.go new file mode 100644 index 000000000..67ccec602 --- /dev/null +++ b/pkg/cmd/registry/group/group.go @@ -0,0 +1,29 @@ +package group + +import ( + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/group/create" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/group/get" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/group/list" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + "github.com/spf13/cobra" +) + +func NewGroupCommand(f *factory.Factory) *cobra.Command { + cmd := &cobra.Command{ + Use: "group", + Short: f.Localizer.MustLocalize("group.cmd.description.short"), + Long: f.Localizer.MustLocalize("group.cmd.description.long"), + Example: f.Localizer.MustLocalize("group.cmd.example"), + Args: cobra.MinimumNArgs(1), + Hidden: true, + } + + // add sub-commands + cmd.AddCommand( + list.NewListCommand(f), + create.NewCreateCommand(f), + get.NewGetCommand(f), + ) + + return cmd +} diff --git a/pkg/cmd/registry/group/list/list.go b/pkg/cmd/registry/group/list/list.go new file mode 100644 index 000000000..7b20f076c --- /dev/null +++ b/pkg/cmd/registry/group/list/list.go @@ -0,0 +1,165 @@ +package list + +import ( + "github.com/redhat-developer/app-services-cli/internal/build" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/registrycmdutil" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule/rulecmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil" + "github.com/redhat-developer/app-services-cli/pkg/core/cmdutil/flagutil" + "github.com/redhat-developer/app-services-cli/pkg/core/ioutil/dump" + "github.com/redhat-developer/app-services-cli/pkg/core/localize" + "github.com/redhat-developer/app-services-cli/pkg/shared/factory" + registryinstanceclient "github.com/redhat-developer/app-services-sdk-core/app-services-sdk-go/registryinstance/apiv1internal/client" + "github.com/spf13/cobra" + "time" + + "github.com/redhat-developer/app-services-cli/pkg/shared/contextutil" +) + +// groupRow is the details of a group needed to print to a table +type groupRow struct { + Id string `json:"id" header:"Id"` + + Description string `json:"description" header:"Description"` + + CreatedOn time.Time `json:"createdOn" header:"Created on"` + + CreatedBy string `json:"createdBy" header:"Created by"` + + ModifiedOn time.Time `json:"modifiedOn" header:"Modified on"` + + ModifiedBy string `json:"modifiedBy" header:"Modified by"` +} + +type options struct { + registryID string + + outputFormat string + page int32 + limit int32 + orderBy string + descending bool + + f *factory.Factory +} + +// NewListCommand creates a new command to view a list of groups +func NewListCommand(f *factory.Factory) *cobra.Command { + + opts := &options{ + f: f, + } + + cmd := &cobra.Command{ + Use: "list", + Short: f.Localizer.MustLocalize("group.list.cmd.description.short"), + Long: f.Localizer.MustLocalize("group.list.cmd.description.long"), + Example: f.Localizer.MustLocalize("group.list.cmd.example"), + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) (err error) { + + if opts.outputFormat != "" && !flagutil.IsValidInput(opts.outputFormat, flagutil.ValidOutputFormats...) { + return flagutil.InvalidValueError("output", opts.outputFormat, flagutil.ValidOutputFormats...) + } + if opts.page < 1 { + return opts.f.Localizer.MustLocalizeError("common.validation.page.error.invalid.minValue", localize.NewEntry("Page", opts.page)) + } + + if opts.limit < 1 { + return opts.f.Localizer.MustLocalizeError("common.validation.limit.error.invalid.minValue", localize.NewEntry("Limit", opts.limit)) + } + + if opts.registryID != "" { + return runList(opts) + } + + registryInstance, err := contextutil.GetCurrentRegistryInstance(f) + if err != nil { + return err + } + + opts.registryID = registryInstance.GetId() + + return runList(opts) + }, + } + + flags := rulecmdutil.NewFlagSet(cmd, f) + + flags.Int32VarP(&opts.page, "page", "", cmdutil.ConvertPageValueToInt32(build.DefaultPageNumber), opts.f.Localizer.MustLocalize("group.cmd.list.flag.page")) + flags.Int32VarP(&opts.limit, "limit", "", 100, opts.f.Localizer.MustLocalize("group.cmd.list.flag.limit")) + flags.BoolVar(&opts.descending, "descending", false, opts.f.Localizer.MustLocalize("group.cmd.list.flag.descending")) + flags.StringVar(&opts.orderBy, "order-by", "name", opts.f.Localizer.MustLocalize("group.cmd.list.flag.orderby")) + + flags.AddOutput(&opts.outputFormat) + + flags.AddRegistryInstance(&opts.registryID) + + return cmd + +} + +func runList(opts *options) error { + conn, err := opts.f.Connection() + if err != nil { + return err + } + + api := conn.API() + + a, _, err := api.ServiceRegistryInstance(opts.registryID) + if err != nil { + return err + } + request := a.GroupsApi.ListGroups(opts.f.Context) + + request = request.Limit(opts.limit) + request = request.Offset((opts.page - 1) * opts.limit) + + if opts.descending { + request = request.Order(registryinstanceclient.SORTORDER_DESC) + } else { + request = request.Order(registryinstanceclient.SORTORDER_ASC) + } + + sortBy, err := registryinstanceclient.NewSortByFromValue(opts.orderBy) + if err != nil { + return err + } + request = request.Orderby(*sortBy) + + response, _, err := request.Execute() + if err != nil { + return registrycmdutil.TransformInstanceError(err) + } + + if opts.outputFormat == dump.EmptyFormat { + rows := mapResponseItemsToRows(response) + opts.f.Logger.Info("") + dump.Table(opts.f.IOStreams.Out, rows) + opts.f.Logger.Info("") + } else { + return dump.Formatted(opts.f.IOStreams.Out, opts.outputFormat, response) + } + + return nil +} + +func mapResponseItemsToRows(groupResult registryinstanceclient.GroupSearchResults) []groupRow { + rows := make([]groupRow, groupResult.Count) + + for i, k := range groupResult.Groups { + row := groupRow{ + Id: k.GetId(), + Description: k.GetDescription(), + CreatedOn: k.GetCreatedOn(), + CreatedBy: k.GetCreatedBy(), + ModifiedOn: k.GetModifiedOn(), + ModifiedBy: k.GetModifiedBy(), + } + + rows[i] = row + } + + return rows +} diff --git a/pkg/cmd/registry/registry.go b/pkg/cmd/registry/registry.go index 47dca72ef..fdb21ea87 100644 --- a/pkg/cmd/registry/registry.go +++ b/pkg/cmd/registry/registry.go @@ -8,6 +8,7 @@ import ( "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/create" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/delete" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/describe" + "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/group" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/list" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/rule" "github.com/redhat-developer/app-services-cli/pkg/cmd/registry/setting" @@ -38,6 +39,7 @@ func NewServiceRegistryCommand(f *factory.Factory) *cobra.Command { role.NewRoleCommand(f), rule.NewRuleCommand(f), setting.NewSettingCommand(f), + group.NewGroupCommand(f), ) return cmd diff --git a/pkg/core/localize/locales/en/cmd/group.en.toml b/pkg/core/localize/locales/en/cmd/group.en.toml new file mode 100644 index 000000000..29937405f --- /dev/null +++ b/pkg/core/localize/locales/en/cmd/group.en.toml @@ -0,0 +1,100 @@ +[group.cmd.description.short] +one = 'Manage artifacts groups of Service Registry instance' + +[group.cmd.description.long] +one = ''' +Manage artifacts groups of Service Registry instance +''' + +[group.cmd.example] +one = ''' +## List all artifacts groups of the current Service Registry instance +$ rhoas service-registry group list + +## Get artifact group metadata by group-id +$ rhoas service-registry group get --group-id example-group + +## Create new artifact group +$ rhoas service-registry group create --group-id example-group --description "Description for example-group" --properties prop1=value1 --properties prop2=value2 +''' + +[group.list.cmd.description.short] +one = 'List all artifact groups of a Service Registry instance' + +[group.list.cmd.description.long] +one = ''' +List artifact groups of a Service Registry instance with their id and description +''' + +[group.list.cmd.example] +one = ''' +## List first 100 groups in the current Service Registry instance +$ rhoas service-registry group list --limit 100 --page 1 + +## List first 50 groups in the current Service Registry instance in descending order +$ rhoas service-registry group list --limit 100 --page 1 --descending + +## List first 100 groups in a specific Service Registry instance +$ rhoas service-registry group list --instance-id=8ecff228-1ffe-4cf5-b38b-55223885ee00 --limit 100 --page 1 +''' + +[group.cmd.list.flag.page] +description = 'Description for the --page flag' +one = 'Display the groups from the specified page number' + +[group.cmd.list.flag.limit] +description = 'Description for the --limit flag' +one = 'The maximum number of groups to be returned' + +[group.cmd.list.flag.descending] +description = 'Description for the --descending flag' +one = 'Display the groups in descending order' + +[group.cmd.list.flag.orderby] +description = 'Description for the --order-by flag' +one = 'Display the groups ordered by' + +[group.create.cmd.description.short] +one = 'Create a new artifact group' + +[group.create.cmd.description.long] +one = 'Create a new artifact group with description and properties' + +[group.create.cmd.example] +one = ''' +## Create new artifact group +$ rhoas service-registry group create --group-id example-group --description "Description for example-group" --properties prop1=value1 --properties prop2=value2 +''' + +[group.cmd.create.flag.description] +one = 'Description of the group' + +[group.cmd.create.flag.group-id] +one = 'ID of the group' + +[group.cmd.create.flag.properties] +one = 'List of the group properties in format =' + +[group.cmd.create.log.info.created] +one = 'Group {{.GroupId}} was successfully created' + +[group.cmd.create.input.group-id.message] +one = 'Name of the group:' + +[group.get.cmd.description.short] +one = 'Get metadata of the artifact group' + +[group.get.cmd.description.long] +one = 'Get metadata of the artifact group' + +[group.get.cmd.example] +one = ''' +## Get metadata of the artifact group +$ rhoas service-registry group get --group-id example-group +''' + +[group.cmd.get.flag.group-id] +one = 'ID of the group' + +[group.cmd.get.input.group-id.message] +one = 'Name of the group:' \ No newline at end of file