From 9024fe8c0a26a94ed352d229720f4831b1bcd0e8 Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Thu, 30 May 2024 13:36:30 +0200 Subject: [PATCH 1/9] Add interactive mod to template app command --- cmd/root.go | 17 ++++++++++ cmd/template/app/command.go | 15 +++++++-- cmd/template/app/flag.go | 24 +++++++------- cmd/template/app/runner.go | 50 ++++++++++++++++++++++++++++++ cmd/template/command.go | 7 +++-- go.mod | 9 ++++++ go.sum | 25 +++++++++++++++ pkg/data/domain/app/service.go | 17 ++++++++++ pkg/data/domain/app/spec.go | 1 + pkg/data/domain/catalog/service.go | 23 ++++++++++++++ pkg/data/domain/catalog/spec.go | 14 +++++++++ 11 files changed, 185 insertions(+), 17 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 71ed0533d..382d943ce 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -12,6 +12,7 @@ import ( "github.com/giantswarm/kubectl-gs/v2/cmd/get" "github.com/giantswarm/kubectl-gs/v2/cmd/gitops" + "github.com/giantswarm/kubectl-gs/v2/cmd/install" "github.com/giantswarm/kubectl-gs/v2/cmd/login" "github.com/giantswarm/kubectl-gs/v2/cmd/selfupdate" "github.com/giantswarm/kubectl-gs/v2/cmd/template" @@ -157,6 +158,21 @@ func New(config Config) (*cobra.Command, error) { } } + var installCmd *cobra.Command + { + c := install.Config{ + Logger: config.Logger, + ConfigFlags: &f.config, + Stderr: config.Stderr, + Stdout: config.Stdout, + } + + installCmd, err = install.New(c) + if err != nil { + return nil, microerror.Mask(err) + } + } + var validateCmd *cobra.Command { c := validate.Config{ @@ -203,6 +219,7 @@ func New(config Config) (*cobra.Command, error) { } c.AddCommand(getCmd) c.AddCommand(gitopsCmd) + c.AddCommand(installCmd) c.AddCommand(loginCmd) c.AddCommand(templateCmd) c.AddCommand(updateCmd) diff --git a/cmd/template/app/command.go b/cmd/template/app/command.go index 41f38fb08..e2965192a 100644 --- a/cmd/template/app/command.go +++ b/cmd/template/app/command.go @@ -4,9 +4,11 @@ import ( "io" "os" + "github.com/giantswarm/kubectl-gs/v2/pkg/commonconfig" "github.com/giantswarm/microerror" "github.com/giantswarm/micrologger" "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericclioptions" ) const ( @@ -15,15 +17,19 @@ const ( ) type Config struct { - Logger micrologger.Logger - Stderr io.Writer - Stdout io.Writer + Logger micrologger.Logger + ConfigFlags *genericclioptions.RESTClientGetter + Stderr io.Writer + Stdout io.Writer } func New(config Config) (*cobra.Command, error) { if config.Logger == nil { return nil, microerror.Maskf(invalidConfigError, "%T.Logger must not be empty", config) } + if config.ConfigFlags == nil { + return nil, microerror.Maskf(invalidConfigError, "%T.ConfigFlags must not be empty", config) + } if config.Stderr == nil { config.Stderr = os.Stderr } @@ -34,6 +40,9 @@ func New(config Config) (*cobra.Command, error) { f := &flag{} r := &runner{ + commonService: &commonconfig.CommonConfig{ + ConfigFlags: config.ConfigFlags, + }, flag: f, logger: config.Logger, stderr: config.Stderr, diff --git a/cmd/template/app/flag.go b/cmd/template/app/flag.go index 5f16fbc53..349d4513a 100644 --- a/cmd/template/app/flag.go +++ b/cmd/template/app/flag.go @@ -21,6 +21,7 @@ const ( flagDefaultingEnabled = "defaulting-enabled" flagInCluster = "in-cluster" flagInstallTimeout = "install-timeout" + flagInteractive = "interactive" flagName = "name" flagNamespace = "namespace" flagTargetNamespace = "target-namespace" @@ -45,6 +46,7 @@ type flag struct { DefaultingEnabled bool InCluster bool InstallTimeout time.Duration + Interactive bool Name string Namespace string TargetNamespace string @@ -73,6 +75,7 @@ func (f *flag) Init(cmd *cobra.Command) { cmd.Flags().BoolVar(&f.DefaultingEnabled, flagDefaultingEnabled, true, "Don't template fields that will be defaulted.") cmd.Flags().BoolVar(&f.InCluster, flagInCluster, false, fmt.Sprintf("Deploy the app in the current management cluster rather than in a workload cluster. If this is set, --%s will be ignored.", flagClusterName)) cmd.Flags().DurationVar(&f.InstallTimeout, flagInstallTimeout, 0, "Timeout for the Helm install.") + cmd.Flags().BoolVar(&f.Interactive, flagInteractive, false, "Run in interactive mode.") cmd.Flags().DurationVar(&f.RollbackTimeout, flagRollbackTimeout, 0, "Timeout for the Helm rollback.") cmd.Flags().DurationVar(&f.UninstallTimeout, flagUninstallTimeout, 0, "Timeout for the Helm uninstall.") cmd.Flags().DurationVar(&f.UpgradeTimeout, flagUpgradeTimeout, 0, "Timeout for the Helm upgrade.") @@ -88,20 +91,19 @@ func (f *flag) Init(cmd *cobra.Command) { } func (f *flag) Validate() error { - if f.Catalog == "" { - return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagCatalog) - } - if f.Name == "" { - return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagName) - } - if f.Namespace == "" && f.TargetNamespace == "" { - return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagTargetNamespace) - } if !f.InCluster && f.Cluster == "" && f.ClusterName == "" { return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagClusterName) } - if f.Version == "" { - return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagVersion) + if !f.Interactive { + if f.Catalog == "" { + return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagCatalog) + } + if f.Name == "" { + return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagName) + } + if f.Version == "" { + return microerror.Maskf(invalidFlagError, "--%s must not be empty", flagVersion) + } } _, err := labels.Parse(f.flagNamespaceConfigLabels) diff --git a/cmd/template/app/runner.go b/cmd/template/app/runner.go index 745c3227b..46d23b39c 100644 --- a/cmd/template/app/runner.go +++ b/cmd/template/app/runner.go @@ -17,6 +17,8 @@ import ( "github.com/giantswarm/kubectl-gs/v2/internal/key" "github.com/giantswarm/kubectl-gs/v2/pkg/annotations" + "github.com/giantswarm/kubectl-gs/v2/pkg/commonconfig" + "github.com/giantswarm/kubectl-gs/v2/pkg/data/domain/catalog" "github.com/giantswarm/kubectl-gs/v2/pkg/labels" templateapp "github.com/giantswarm/kubectl-gs/v2/pkg/template/app" ) @@ -24,6 +26,10 @@ import ( type runner struct { flag *flag logger micrologger.Logger + + catalogService catalog.Interface + commonService *commonconfig.CommonConfig + stderr io.Writer stdout io.Writer } @@ -49,6 +55,26 @@ func (r *runner) run(ctx context.Context, cmd *cobra.Command, args []string) err var userConfigSecretYaml []byte var err error + client, err := r.commonService.GetClient(r.logger) + if err != nil { + return microerror.Mask(err) + } + c := catalog.Config{ + Client: client.CtrlClient(), + } + + r.catalogService, err = catalog.New(c) + if err != nil { + return microerror.Mask(err) + } + + if r.flag.Interactive { + err = r.runInteractive() + if err != nil { + return microerror.Mask(err) + } + } + appName := r.flag.AppName if appName == "" { appName = r.flag.Name @@ -63,6 +89,10 @@ func (r *runner) run(ctx context.Context, cmd *cobra.Command, args []string) err targetNamespace = r.flag.Namespace } + if targetNamespace == "" { + targetNamespace = appName + } + clusterName := r.flag.ClusterName if clusterName == "" { clusterName = r.flag.Cluster @@ -204,3 +234,23 @@ func (r *runner) setTimeouts(config *templateapp.Config) { config.UpgradeTimeout = &metav1.Duration{Duration: r.flag.UpgradeTimeout} } } + +func (r *runner) runInteractive() (err error) { + if r.flag.Catalog == "" { + catalog, err := r.promptCatalog() + if err != nil { + return microerror.Mask(err) + } + r.flag.Catalog = catalog.GetName() + } + + if r.flag.Name == "" || r.flag.Version == "" { + catalogEntry, err := r.promptCatalogEntries(r.flag.Catalog, r.flag.Name, r.flag.Version) + if err != nil { + return microerror.Mask(err) + } + r.flag.Name = catalogEntry.Spec.AppName + r.flag.Version = catalogEntry.Spec.Version + } + return nil +} diff --git a/cmd/template/command.go b/cmd/template/command.go index 932908f9d..1b2ff498a 100644 --- a/cmd/template/command.go +++ b/cmd/template/command.go @@ -47,9 +47,10 @@ func New(config Config) (*cobra.Command, error) { var appCmd *cobra.Command { c := app.Config{ - Logger: config.Logger, - Stderr: config.Stderr, - Stdout: config.Stdout, + Logger: config.Logger, + ConfigFlags: config.ConfigFlags, + Stderr: config.Stderr, + Stdout: config.Stdout, } appCmd, err = app.New(c) diff --git a/go.mod b/go.mod index 31b396b5b..c92aa8061 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,8 @@ require ( github.com/giantswarm/release-operator/v4 v4.2.0 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/go-cmp v0.6.0 + github.com/ktr0731/go-fuzzyfinder v0.8.0 + github.com/muesli/reflow v0.3.0 github.com/pkg/errors v0.9.1 github.com/rhysd/go-github-selfupdate v1.2.3 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 @@ -104,6 +106,8 @@ require ( github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.8.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gdamore/encoding v1.0.0 // indirect + github.com/gdamore/tcell/v2 v2.7.4 // indirect github.com/getsops/gopgagent v0.0.0-20170926210634-4d7ea76ff71a // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect @@ -150,12 +154,15 @@ require ( github.com/jongio/azidext/go/azidext v0.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/ktr0731/go-ansisgr v0.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -167,6 +174,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nsf/termbox-go v1.1.1 // indirect github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/opencontainers/runc v1.1.8 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect @@ -176,6 +184,7 @@ require ( github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect diff --git a/go.sum b/go.sum index 5354e0108..7491e4294 100644 --- a/go.sum +++ b/go.sum @@ -186,6 +186,11 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell/v2 v2.6.0/go.mod h1:be9omFATkdr0D9qewWW3d+MEvl5dha+Etb5y65J2H8Y= +github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= +github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= github.com/getsops/gopgagent v0.0.0-20170926210634-4d7ea76ff71a h1:qc+7TV35Pq/FlgqECyS5ywq8cSN9j1fwZg6uyZ7G0B0= github.com/getsops/gopgagent v0.0.0-20170926210634-4d7ea76ff71a/go.mod h1:awFzISqLJoZLm+i9QQ4SgMNHDqljH6jWV0B36V5MrUM= github.com/getsops/sops/v3 v3.8.1 h1:3A6KZEHAolxfXtlgRjncCotTGRiNaQFhSDOB2CUCojY= @@ -367,12 +372,18 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/ktr0731/go-ansisgr v0.1.0 h1:fbuupput8739hQbEmZn1cEKjqQFwtCCZNznnF6ANo5w= +github.com/ktr0731/go-ansisgr v0.1.0/go.mod h1:G9lxwgBwH0iey0Dw5YQd7n6PmQTwTuTM/X5Sgm/UrzE= +github.com/ktr0731/go-fuzzyfinder v0.8.0 h1:+yobwo9lqZZ7jd1URPdCgZXTE2U1mpIVTkQoo4roi6w= +github.com/ktr0731/go-fuzzyfinder v0.8.0/go.mod h1:Bjpz5im+tppKE9Ii6UK1h+6RaX/lUvJ0ruO4LIYRkqo= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -382,6 +393,11 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -410,8 +426,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= +github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY= @@ -448,6 +468,11 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag= github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= diff --git a/pkg/data/domain/app/service.go b/pkg/data/domain/app/service.go index 4871a51b5..377fe1b7d 100644 --- a/pkg/data/domain/app/service.go +++ b/pkg/data/domain/app/service.go @@ -59,6 +59,23 @@ func New(config Config) (*Service, error) { return s, nil } +// Create an app. +func (s *Service) Create(ctx context.Context, app *App) error { + var err error + + err = s.client.Create(ctx, app.CR) + if err != nil { + return microerror.Mask(err) + } + + //app.CR.TypeMeta = metav1.TypeMeta{ + // APIVersion: "app.application.giantswarm.io/v1alpha1", + // Kind: "App", + //} + + return nil +} + // Get fetches a list of app CRs filtered by namespace and optionally by // name. func (s *Service) Get(ctx context.Context, options GetOptions) (Resource, error) { diff --git a/pkg/data/domain/app/spec.go b/pkg/data/domain/app/spec.go index 471267c0c..e5f4dc528 100644 --- a/pkg/data/domain/app/spec.go +++ b/pkg/data/domain/app/spec.go @@ -41,6 +41,7 @@ type Resource interface { // Using this instead of a regular 'struct' makes mocking the // service in tests much simpler. type Interface interface { + Create(context.Context, *App) error Get(context.Context, GetOptions) (Resource, error) Patch(context.Context, PatchOptions) error } diff --git a/pkg/data/domain/catalog/service.go b/pkg/data/domain/catalog/service.go index 9a1f3a452..58628066f 100644 --- a/pkg/data/domain/catalog/service.go +++ b/pkg/data/domain/catalog/service.go @@ -157,6 +157,29 @@ func (s *Service) getByName(ctx context.Context, namespace, name string, labelSe return catalog, nil } +func (s *Service) ListCatalogEntries(ctx context.Context, options ListOptions) (Resource, error) { + var catalogEntryList = applicationv1alpha1.AppCatalogEntryList{} + { + + o := &client.ListOptions{ + LabelSelector: options.LabelSelector, + } + err := s.client.List(ctx, &catalogEntryList, o) + if apimeta.IsNoMatchError(err) { + return nil, microerror.Mask(noMatchError) + } else if err != nil { + return nil, microerror.Mask(err) + } else if len(catalogEntryList.Items) == 0 { + return nil, microerror.Mask(noResourcesError) + } + } + + c := &CatalogEntryList{ + catalogEntryList, + } + return c, nil +} + // omitManagedFields removes managed fields to make YAML output easier to read. // With Kubernetes 1.21 we can use OmitManagedFieldsPrinter and remove this. func omitManagedFields(catalog *applicationv1alpha1.Catalog) *applicationv1alpha1.Catalog { diff --git a/pkg/data/domain/catalog/spec.go b/pkg/data/domain/catalog/spec.go index 6f4a08bbf..cce62021a 100644 --- a/pkg/data/domain/catalog/spec.go +++ b/pkg/data/domain/catalog/spec.go @@ -21,6 +21,10 @@ type Collection struct { Items []Catalog } +type CatalogEntryList struct { + applicationv1alpha1.AppCatalogEntryList +} + // GetOptions are the parameters that the Get method takes. type GetOptions struct { AllNamespaces bool @@ -29,6 +33,11 @@ type GetOptions struct { Namespace string } +// ListOptions are the parameters that the List method takes. +type ListOptions struct { + LabelSelector labels.Selector +} + type Resource interface { Object() runtime.Object } @@ -38,6 +47,7 @@ type Resource interface { // service in tests much simpler. type Interface interface { Get(context.Context, GetOptions) (Resource, error) + ListCatalogEntries(context.Context, ListOptions) (Resource, error) } func (a *Catalog) Object() runtime.Object { @@ -74,3 +84,7 @@ func (cc *Collection) Object() runtime.Object { return list } + +func (c *CatalogEntryList) Object() runtime.Object { + return c +} From 86aa1562388a5c4c182f37c83d9b363133e1c1e2 Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Sat, 1 Jun 2024 00:05:24 +0200 Subject: [PATCH 2/9] update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49dac2e67..df3f84f0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project's packages adheres to [Semantic Versioning](http://semver.org/s ## [Unreleased] +### Added + +- Add interactive mode to `kubectl gs template app` command. + ## [2.55.0] - 2024-05-14 ### Added From 90b55f7bcc9f62ce2449e4223be662e1b6c1ceb5 Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Sat, 1 Jun 2024 12:30:49 +0200 Subject: [PATCH 3/9] add interactive.go --- cmd/template/app/interactive.go | 102 ++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 cmd/template/app/interactive.go diff --git a/cmd/template/app/interactive.go b/cmd/template/app/interactive.go new file mode 100644 index 000000000..dcd77fd83 --- /dev/null +++ b/cmd/template/app/interactive.go @@ -0,0 +1,102 @@ +package app + +import ( + "context" + "fmt" + "sort" + "strings" + + applicationv1alpha1 "github.com/giantswarm/apiextensions-application/api/v1alpha1" + "github.com/giantswarm/kubectl-gs/v2/pkg/data/domain/catalog" + "github.com/giantswarm/microerror" + "github.com/muesli/reflow/wordwrap" + "k8s.io/apimachinery/pkg/labels" + + fuzzyfinder "github.com/ktr0731/go-fuzzyfinder" +) + +func (r *runner) promptCatalog() (*applicationv1alpha1.Catalog, error) { + ctx := context.Background() + o := catalog.GetOptions{} + resource, err := r.catalogService.Get(ctx, o) + if err != nil { + return nil, microerror.Mask(err) + } + catalogs := resource.(*catalog.Collection) + entries := catalogs.Items + sort.Slice(entries, func(i, j int) bool { + return entries[i].CR.GetName() > entries[j].CR.GetName() + }) + + idx, err := fuzzyfinder.Find(entries, func(i int) string { + return entries[i].CR.GetName() + }, fuzzyfinder.WithPreviewWindow(func(i, w, h int) string { + if i == -1 { + return "" + } + return fmt.Sprintf(" %s\n\n%s", entries[i].CR.Spec.Title, wordwrap.String(entries[i].CR.Spec.Description, h)) + })) + + if err != nil { + fmt.Println(err) + return nil, err + } + return entries[idx].CR, nil +} + +func (r *runner) promptCatalogEntries(catalogName, appName, appVersion string) (*applicationv1alpha1.AppCatalogEntry, error) { + var err error + + ctx := context.Background() + o := catalog.ListOptions{} + var selector []string + { + if len(catalogName) > 0 { + selector = append(selector, fmt.Sprintf("application.giantswarm.io/catalog=%s", catalogName)) + } + if len(appName) > 0 { + selector = append(selector, fmt.Sprintf("app.kubernetes.io/name=%s", appName)) + } + if len(appVersion) > 0 { + selector = append(selector, fmt.Sprintf("app.kubernetes.io/version=%s", appVersion)) + } + + } + var labelSelector labels.Selector + { + labelSelector, err = labels.Parse(strings.Join(selector, ",")) + if err != nil { + return nil, microerror.Mask(err) + } + } + o.LabelSelector = labelSelector + + catalogEntries, err := r.catalogService.ListCatalogEntries(ctx, o) + if err != nil { + return nil, microerror.Mask(err) + } + entries := catalogEntries.(*catalog.CatalogEntryList).Items + sort.Slice(entries, func(i, j int) bool { + return entries[j].Spec.DateUpdated.Before(entries[i].Spec.DateUpdated) + }) + + idx, err := fuzzyfinder.Find(entries, func(i int) string { + return fmt.Sprintf("%s/%s@%s", entries[i].Spec.Catalog.Name, entries[i].Spec.AppName, entries[i].Spec.Version) + }, fuzzyfinder.WithPreviewWindow(func(i, w, h int) string { + if i == -1 { + return "" + } + return fmt.Sprintf(" %s\n\n%s\n\nURL: %s\nUpdated: %s\nUpstream version: %s", + entries[i].Spec.AppName, + wordwrap.String(entries[i].Spec.Chart.Description, h), + entries[i].Spec.Chart.Home, + entries[i].Spec.DateUpdated.Format("2006-01-02 15:04:05"), + entries[i].Spec.AppVersion, + ) + })) + if err != nil { + fmt.Println(err) + return nil, err + } + return &entries[idx], nil +} From a3847cbcb97211feb1b410d27949330bf7f6bcb7 Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Sat, 1 Jun 2024 20:19:48 +0200 Subject: [PATCH 4/9] sort import --- cmd/template/app/command.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/template/app/command.go b/cmd/template/app/command.go index e2965192a..d3aa1dd69 100644 --- a/cmd/template/app/command.go +++ b/cmd/template/app/command.go @@ -4,11 +4,12 @@ import ( "io" "os" - "github.com/giantswarm/kubectl-gs/v2/pkg/commonconfig" "github.com/giantswarm/microerror" "github.com/giantswarm/micrologger" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" + + "github.com/giantswarm/kubectl-gs/v2/pkg/commonconfig" ) const ( From 6d89e9ecc8e7937c5846e60fada092227929d732 Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Sat, 1 Jun 2024 20:23:53 +0200 Subject: [PATCH 5/9] fix more imports --- cmd/template/app/interactive.go | 4 ++-- pkg/data/domain/app/service.go | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/template/app/interactive.go b/cmd/template/app/interactive.go index dcd77fd83..24b5b7db8 100644 --- a/cmd/template/app/interactive.go +++ b/cmd/template/app/interactive.go @@ -7,12 +7,12 @@ import ( "strings" applicationv1alpha1 "github.com/giantswarm/apiextensions-application/api/v1alpha1" - "github.com/giantswarm/kubectl-gs/v2/pkg/data/domain/catalog" "github.com/giantswarm/microerror" + fuzzyfinder "github.com/ktr0731/go-fuzzyfinder" "github.com/muesli/reflow/wordwrap" "k8s.io/apimachinery/pkg/labels" - fuzzyfinder "github.com/ktr0731/go-fuzzyfinder" + "github.com/giantswarm/kubectl-gs/v2/pkg/data/domain/catalog" ) func (r *runner) promptCatalog() (*applicationv1alpha1.Catalog, error) { diff --git a/pkg/data/domain/app/service.go b/pkg/data/domain/app/service.go index 377fe1b7d..7e1755607 100644 --- a/pkg/data/domain/app/service.go +++ b/pkg/data/domain/app/service.go @@ -6,6 +6,7 @@ import ( "net/http" applicationv1alpha1 "github.com/giantswarm/apiextensions-application/api/v1alpha1" + "github.com/giantswarm/appcatalog" "github.com/giantswarm/microerror" apierrors "k8s.io/apimachinery/pkg/api/errors" apimeta "k8s.io/apimachinery/pkg/api/meta" @@ -13,8 +14,6 @@ import ( "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/giantswarm/appcatalog" - catalogdata "github.com/giantswarm/kubectl-gs/v2/pkg/data/domain/catalog" ) From 16275c383821a5146871866c0e7211e610204490 Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Sat, 1 Jun 2024 20:30:54 +0200 Subject: [PATCH 6/9] fix linter error --- pkg/data/domain/app/service.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/pkg/data/domain/app/service.go b/pkg/data/domain/app/service.go index 7e1755607..0638745ab 100644 --- a/pkg/data/domain/app/service.go +++ b/pkg/data/domain/app/service.go @@ -60,18 +60,11 @@ func New(config Config) (*Service, error) { // Create an app. func (s *Service) Create(ctx context.Context, app *App) error { - var err error - - err = s.client.Create(ctx, app.CR) + err := s.client.Create(ctx, app.CR) if err != nil { return microerror.Mask(err) } - //app.CR.TypeMeta = metav1.TypeMeta{ - // APIVersion: "app.application.giantswarm.io/v1alpha1", - // Kind: "App", - //} - return nil } From 443670739e46a31af4e62754421adf628c32784e Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Sat, 1 Jun 2024 20:35:38 +0200 Subject: [PATCH 7/9] fix CVE-2024-2660 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 7531579a2..41fea8483 100644 --- a/go.mod +++ b/go.mod @@ -155,7 +155,7 @@ require ( github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect - github.com/hashicorp/vault/api v1.10.0 // indirect + github.com/hashicorp/vault/api v1.16.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect From 5b0d1f6c5ab2460ec6e7db3d8d12e26d79cf667e Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Sat, 1 Jun 2024 20:40:25 +0200 Subject: [PATCH 8/9] Revert "fix CVE-2024-2660" This reverts commit 443670739e46a31af4e62754421adf628c32784e. --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 41fea8483..7531579a2 100644 --- a/go.mod +++ b/go.mod @@ -155,7 +155,7 @@ require ( github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect - github.com/hashicorp/vault/api v1.16.0 // indirect + github.com/hashicorp/vault/api v1.10.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect From 9c508f8c924620c6affca30e90759020913ddda4 Mon Sep 17 00:00:00 2001 From: Theo Brigitte Date: Sat, 1 Jun 2024 22:09:46 +0200 Subject: [PATCH 9/9] extend CVE-2024-2660 ignore to 2024-07-31 Upstream fix https://github.com/getsops/sops/pull/1519 --- .nancy-ignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.nancy-ignore b/.nancy-ignore index 33f46d9e9..31b5750d4 100644 --- a/.nancy-ignore +++ b/.nancy-ignore @@ -1,2 +1,3 @@ # pkg:golang/github.com/hashicorp/vault/api -CVE-2024-2660 until=2024-05-31 +# see https://github.com/getsops/sops/pull/1519 +CVE-2024-2660 until=2024-07-31