diff --git a/docs/quickstart/quickstart.md b/docs/quickstart/quickstart.md index 756f3d814..0e322fe08 100644 --- a/docs/quickstart/quickstart.md +++ b/docs/quickstart/quickstart.md @@ -66,6 +66,31 @@ $ tanzu plugin group search vmware-tmc/tmc-user Plugins for Tanzu Mission-Control v0.0.1 ``` +### List the plugins of a plugin group + +```console +$ tz plugin group get vmware-tkg/default:v2.1.0 +Plugins in Group: vmware-tkg/default:v2.1.0 + NAME TARGET LATEST + cluster kubernetes v0.28.0 + feature kubernetes v0.28.0 + isolated-cluster global v0.28.0 + kubernetes-release kubernetes v0.28.0 + management-cluster kubernetes v0.28.0 + package kubernetes v0.28.0 + pinniped-auth global v0.28.0 + secret kubernetes v0.28.0 + telemetry kubernetes v0.28.0 +``` + +Note that you can omit the version if you are interested in the contents of the latest version of a group: + +```console +$ tz plugin group get vmware-tkg/default +Plugins in Group: vmware-tkg/default:v2.1.0 +[...] +``` + ### Install all plugins in a group ```console diff --git a/pkg/command/plugin_group.go b/pkg/command/plugin_group.go index 336945362..d8beb3a54 100644 --- a/pkg/command/plugin_group.go +++ b/pkg/command/plugin_group.go @@ -7,10 +7,12 @@ import ( "fmt" "io" + "github.com/fatih/color" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/vmware-tanzu/tanzu-plugin-runtime/component" + "github.com/vmware-tanzu/tanzu-plugin-runtime/log" "github.com/vmware-tanzu/tanzu-cli/pkg/cli" "github.com/vmware-tanzu/tanzu-cli/pkg/discovery" @@ -33,6 +35,7 @@ func newPluginGroupCmd() *cobra.Command { pluginGroupCmd.AddCommand( newSearchCmd(), + newGetCmd(), ) return pluginGroupCmd @@ -48,7 +51,7 @@ func newSearchCmd() *cobra.Command { if groupID != "" { groupIdentifier := plugininventory.PluginGroupIdentifierFromID(groupID) if groupIdentifier == nil { - return errors.Errorf("incorrect plugin group %q specified", groupID) + return errors.Errorf("incorrect plugin-group %q specified", groupID) } criteria = &discovery.GroupDiscoveryCriteria{ @@ -79,6 +82,56 @@ func newSearchCmd() *cobra.Command { return searchCmd } +func newGetCmd() *cobra.Command { + var getCmd = &cobra.Command{ + Use: "get ", + Short: "Get the content of the specified plugin-group", + Long: "Get the content of the specified plugin-group. A plugin-group provides a list of plugin name/version combinations which can be installed in one step. This command allows to see the list of plugins included in the specified group.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + groupID := args[0] + + groupIdentifier := plugininventory.PluginGroupIdentifierFromID(groupID) + if groupIdentifier == nil { + return errors.Errorf("incorrect plugin-group %q specified", groupID) + } + + if groupIdentifier.Version == "" { + groupIdentifier.Version = cli.VersionLatest + } + + groups, err := pluginmanager.DiscoverPluginGroups(&discovery.GroupDiscoveryCriteria{ + Vendor: groupIdentifier.Vendor, + Publisher: groupIdentifier.Publisher, + Name: groupIdentifier.Name, + Version: groupIdentifier.Version, + }) + if err != nil { + return err + } + if len(groups) == 0 { + return errors.Errorf("plugin-group %q cannot be found", groupID) + } + + if len(groups) > 1 { + log.Warningf("unexpectedly found %d entries for group %q. Using the first one", len(groups), groupID) + } + + if outputFormat == "" || outputFormat == string(component.TableOutputType) { + displayGroupContentAsTable(groups[0], cmd.OutOrStdout()) + } else { + displayGroupContentAsList(groups[0], cmd.OutOrStdout()) + } + return nil + }, + } + + f := getCmd.Flags() + f.StringVarP(&outputFormat, "output", "o", "", "output format (yaml|json|table)") + + return getCmd +} + func displayGroupsFound(groups []*plugininventory.PluginGroup, writer io.Writer) { output := component.NewOutputWriter(writer, outputFormat, "group", "description", "latest") @@ -142,3 +195,27 @@ func displayGroupDetails(groups []*plugininventory.PluginGroup, writer io.Writer } component.NewObjectWriter(writer, outputFormat, details).Render() } + +func displayGroupContentAsTable(group *plugininventory.PluginGroup, writer io.Writer) { + cyanBold := color.New(color.FgCyan).Add(color.Bold) + cyanBoldItalic := color.New(color.FgCyan).Add(color.Bold, color.Italic) + output := component.NewOutputWriter(writer, outputFormat, "Name", "Target", "Latest") + + groupID := plugininventory.PluginGroupToID(group) + _, _ = cyanBold.Println("Plugins in Group: ", cyanBoldItalic.Sprintf("%s:%s", groupID, group.RecommendedVersion)) + + for _, plugin := range group.Versions[group.RecommendedVersion] { + output.AddRow(plugin.Name, plugin.Target, plugin.Version) + } + output.Render() +} + +func displayGroupContentAsList(group *plugininventory.PluginGroup, writer io.Writer) { + output := component.NewOutputWriter(writer, outputFormat, "Group", "PluginName", "PluginTarget", "PluginVersion") + + groupID := fmt.Sprintf("%s:%s", plugininventory.PluginGroupToID(group), group.RecommendedVersion) + for _, plugin := range group.Versions[group.RecommendedVersion] { + output.AddRow(groupID, plugin.Name, plugin.Target, plugin.Version) + } + output.Render() +}