diff --git a/cmd/skpr/console/command.go b/cmd/skpr/console/command.go new file mode 100644 index 0000000..d6dc8fc --- /dev/null +++ b/cmd/skpr/console/command.go @@ -0,0 +1,29 @@ +package console + +import ( + "github.com/spf13/cobra" + + skprcommand "github.com/skpr/cli/internal/command" + "github.com/skpr/cli/internal/command/console" +) + +// NewCommand creates a new cobra.Command for 'console' sub command +func NewCommand() *cobra.Command { + command := console.Command{} + + cmd := &cobra.Command{ + Use: "console ", + Args: cobra.ExactArgs(1), + DisableFlagsInUseLine: true, + Short: "Open the Skpr console for an environment in browser.", + GroupID: skprcommand.GroupDebug, + RunE: func(cmd *cobra.Command, args []string) error { + command.Environment = args[0] + return command.Run(cmd.Context()) + }, + } + + cmd.Flags().BoolVarP(&command.Print, "print", "p", false, "Only display the link instead of opening it") + + return cmd +} diff --git a/cmd/skpr/main.go b/cmd/skpr/main.go index 3b4bd6f..702a78d 100644 --- a/cmd/skpr/main.go +++ b/cmd/skpr/main.go @@ -14,6 +14,7 @@ import ( "github.com/skpr/cli/cmd/skpr/alias" "github.com/skpr/cli/cmd/skpr/backup" "github.com/skpr/cli/cmd/skpr/config" + "github.com/skpr/cli/cmd/skpr/console" "github.com/skpr/cli/cmd/skpr/create" "github.com/skpr/cli/cmd/skpr/cron" "github.com/skpr/cli/cmd/skpr/daemon" @@ -94,6 +95,7 @@ func main() { cmd.AddCommand(backup.NewCommand()) cmd.AddCommand(config.NewCommand()) cmd.AddCommand(create.NewCommand()) + cmd.AddCommand(console.NewCommand()) cmd.AddCommand(cron.NewCommand()) cmd.AddCommand(daemon.NewCommand()) cmd.AddCommand(dashboard.NewCommand()) diff --git a/go.mod b/go.mod index 87ecd69..d6e80ab 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/moby/patternmatcher v0.6.1 github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 github.com/pkg/errors v0.9.1 - github.com/skpr/api v1.6.0 + github.com/skpr/api v1.8.0 github.com/skpr/compass/tracing v0.0.0-20251208094547-dafe383c3926 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/spf13/cobra v1.10.2 @@ -40,7 +40,7 @@ require ( golang.org/x/oauth2 v0.36.0 golang.org/x/sync v0.22.0 golang.org/x/term v0.45.0 - google.golang.org/grpc v1.82.0 + google.golang.org/grpc v1.82.1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index bd78e10..4c326ea 100644 --- a/go.sum +++ b/go.sum @@ -217,8 +217,8 @@ github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skpr/api v1.6.0 h1:LzbNm97wXvnWAcm+iyV1r36YKGMFWNn65y+EHhBxgqo= -github.com/skpr/api v1.6.0/go.mod h1:LMyIte2bWjGuO2e8XOA6FKNFUX10itF2qYVTckM7dwg= +github.com/skpr/api v1.8.0 h1:mOfpy6W+8THIaRG2nxIFpQ8wdtTawSoUZbwhcs0VS0M= +github.com/skpr/api v1.8.0/go.mod h1:KMGPWD5+HwbmqqX6HNtdpDylQ1lFfTS/qiSv/bolfdc= github.com/skpr/compass/tracing v0.0.0-20251208094547-dafe383c3926 h1:g8m8qqehB6/GMeM81BaIXQOkD2LZbCQE0HPRGear9Jw= github.com/skpr/compass/tracing v0.0.0-20251208094547-dafe383c3926/go.mod h1:Rokt2mnHteBaBmsSgiNk4P7laV0E8/BLQsSLyGUJLtk= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= @@ -290,8 +290,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1: google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.82.0 h1:vguDnZUPjE26w09A63VoxZPnvPjB5Riyc0mkXPFmAIU= -google.golang.org/grpc v1.82.0/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/client/client.go b/internal/client/client.go index 49b8a48..2341145 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -92,6 +92,11 @@ func (c Client) Environment() pb.EnvironmentClient { return pb.NewEnvironmentClient(c.conn) } +// Cluster client operations. +func (c Client) Cluster() pb.ClusterClient { + return pb.NewClusterClient(c.conn) +} + // Config client operations. func (c Client) Config() pb.ConfigClient { return pb.NewConfigClient(c.conn) diff --git a/internal/command/console/command.go b/internal/command/console/command.go new file mode 100644 index 0000000..5fd56a0 --- /dev/null +++ b/internal/command/console/command.go @@ -0,0 +1,59 @@ +package console + +import ( + "context" + "fmt" + + "github.com/skpr/api/pb" + "github.com/skratchdot/open-golang/open" + + "github.com/skpr/cli/internal/client" + "github.com/skpr/cli/internal/client/config" +) + +// Command for console access. +type Command struct { + Environment string + Print bool +} + +// Run the command. +func (cmd *Command) Run(ctx context.Context) error { + config, err := config.New() + if err != nil { + return err + } + + ctx, client, err := client.New(ctx) + if err != nil { + return err + } + + cluster, err := client.Cluster().Get(ctx, &pb.ClusterGetRequest{}) + if err != nil { + return fmt.Errorf("failed to get cluster information: %w", err) + } + if cluster.Endpoints == nil || cluster.Endpoints.Console == "" { + return fmt.Errorf("cluster does not have a console domain") + } + consoleHost := cluster.Endpoints.Console + + _, err = client.Environment().Get(ctx, &pb.EnvironmentGetRequest{ + Name: cmd.Environment, + }) + if err != nil { + return fmt.Errorf("failed to get environment: %w", err) + } + + // @todo Remove '/metrics' when UI supports it. + consoleURL := fmt.Sprintf("https://%s/projects/%s/%s/metrics", consoleHost, config.Project, cmd.Environment) + + if cmd.Print { + fmt.Println(consoleURL) + return nil + } + + fmt.Println("Opening in Browser") + + return open.Run(consoleURL) +}