From 561d7d24a11ffc4aff724bd1b22d60d0b2ee5e2a Mon Sep 17 00:00:00 2001 From: Dylan Ratcliffe Date: Tue, 13 Feb 2024 21:48:15 +0000 Subject: [PATCH 1/8] Initial restructure of commands --- README.md | 2 +- cmd/bookmarks.go | 34 +++++++++++++++++++ ...okmark.go => bookmarks_create_bookmark.go} | 4 +-- ...go => bookmarks_get_affected_bookmarks.go} | 4 +-- ...tbookmark.go => bookmarks_get_bookmark.go} | 4 +-- cmd/changes.go | 32 +++++++++++++++++ cmd/{endchange.go => changes_end_change.go} | 4 +-- cmd/{getchange.go => changes_get_change.go} | 6 ++-- ...listchanges.go => changes_list_changes.go} | 4 +-- ...nualchange.go => changes_manual_change.go} | 4 +-- cmd/{submitplan.go => changes_submit_plan.go} | 8 ++--- ...startchange.go => chnages_start_change.go} | 4 +-- cmd/invites.go | 30 ++++++++++++++++ cmd/{invite.go => invites_crud.go} | 8 ++--- cmd/request.go | 7 ++-- cmd/root.go | 26 +++++++++++--- cmd/snapshots.go | 32 +++++++++++++++++ ...tsnapshot.go => snapshots_get_snapshot.go} | 4 +-- cmd/terraform.go | 30 ++++++++++++++++ go.mod | 2 +- main.go | 2 +- tracing/main.go | 4 +-- 22 files changed, 216 insertions(+), 39 deletions(-) create mode 100644 cmd/bookmarks.go rename cmd/{createbookmark.go => bookmarks_create_bookmark.go} (98%) rename cmd/{getaffectedbookmarks.go => bookmarks_get_affected_bookmarks.go} (97%) rename cmd/{getbookmark.go => bookmarks_get_bookmark.go} (97%) create mode 100644 cmd/changes.go rename cmd/{endchange.go => changes_end_change.go} (97%) rename cmd/{getchange.go => changes_get_change.go} (98%) rename cmd/{listchanges.go => changes_list_changes.go} (99%) rename cmd/{manualchange.go => changes_manual_change.go} (99%) rename cmd/{submitplan.go => changes_submit_plan.go} (99%) rename cmd/{startchange.go => chnages_start_change.go} (97%) create mode 100644 cmd/invites.go rename cmd/{invite.go => invites_crud.go} (97%) create mode 100644 cmd/snapshots.go rename cmd/{getsnapshot.go => snapshots_get_snapshot.go} (98%) create mode 100644 cmd/terraform.go diff --git a/README.md b/README.md index 3d449052..7b3082eb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ovm-cli +# Overmind CLI CLI to interact with the overmind API diff --git a/cmd/bookmarks.go b/cmd/bookmarks.go new file mode 100644 index 00000000..a4004719 --- /dev/null +++ b/cmd/bookmarks.go @@ -0,0 +1,34 @@ +/* +Copyright © 2024 NAME HERE +*/ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// bookmarksCmd represents the bookmarks command +var bookmarksCmd = &cobra.Command{ + Use: "bookmarks", + GroupID: "api", + Short: "Interact with the bookarks that were created in the Explore view", + Long: `A bookmark in Overmind is a set of queries that are stored together and can be +executed as a single block.`, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} + +func init() { + rootCmd.AddCommand(bookmarksCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // bookmarksCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // bookmarksCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/createbookmark.go b/cmd/bookmarks_create_bookmark.go similarity index 98% rename from cmd/createbookmark.go rename to cmd/bookmarks_create_bookmark.go index cd4e93d8..877662a7 100644 --- a/cmd/createbookmark.go +++ b/cmd/bookmarks_create_bookmark.go @@ -12,7 +12,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -140,7 +140,7 @@ func CreateBookmark(ctx context.Context, ready chan bool) int { } func init() { - rootCmd.AddCommand(createBookmarkCmd) + bookmarksCmd.AddCommand(createBookmarkCmd) createBookmarkCmd.PersistentFlags().String("bookmark-url", "", "The bookmark service API endpoint (defaults to --url)") diff --git a/cmd/getaffectedbookmarks.go b/cmd/bookmarks_get_affected_bookmarks.go similarity index 97% rename from cmd/getaffectedbookmarks.go rename to cmd/bookmarks_get_affected_bookmarks.go index 250ba769..5181f623 100644 --- a/cmd/getaffectedbookmarks.go +++ b/cmd/bookmarks_get_affected_bookmarks.go @@ -10,7 +10,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -116,7 +116,7 @@ func GetAffectedBookmarks(ctx context.Context, ready chan bool) int { } func init() { - rootCmd.AddCommand(getAffectedBookmarksCmd) + bookmarksCmd.AddCommand(getAffectedBookmarksCmd) getAffectedBookmarksCmd.PersistentFlags().String("bookmark-url", "", "The bookmark service API endpoint (defaults to --url)") getAffectedBookmarksCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") diff --git a/cmd/getbookmark.go b/cmd/bookmarks_get_bookmark.go similarity index 97% rename from cmd/getbookmark.go rename to cmd/bookmarks_get_bookmark.go index 1964645c..587bd5af 100644 --- a/cmd/getbookmark.go +++ b/cmd/bookmarks_get_bookmark.go @@ -11,7 +11,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -113,7 +113,7 @@ func GetBookmark(ctx context.Context, ready chan bool) int { } func init() { - rootCmd.AddCommand(getBookmarkCmd) + bookmarksCmd.AddCommand(getBookmarkCmd) getBookmarkCmd.PersistentFlags().String("bookmark-url", "", "The bookmark service API endpoint (defaults to --url)") diff --git a/cmd/changes.go b/cmd/changes.go new file mode 100644 index 00000000..46b768df --- /dev/null +++ b/cmd/changes.go @@ -0,0 +1,32 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// changesCmd represents the changes command +var changesCmd = &cobra.Command{ + Use: "changes", + GroupID: "api", + Short: "Create, update and delete changes in Overmind", + Long: `Manage changes that are being tracked using Overmind. NOTE: It is probably +easier to use our IaC wrappers such as 'overmind terraform plan' rather than +using these commands directly, but they are provided for flexibility.`, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} + +func init() { + rootCmd.AddCommand(changesCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // changesCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // changesCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/endchange.go b/cmd/changes_end_change.go similarity index 97% rename from cmd/endchange.go rename to cmd/changes_end_change.go index 815d93b9..76cf3731 100644 --- a/cmd/endchange.go +++ b/cmd/changes_end_change.go @@ -9,7 +9,7 @@ import ( "time" "connectrpc.com/connect" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -114,7 +114,7 @@ func EndChange(ctx context.Context, ready chan bool) int { } func init() { - rootCmd.AddCommand(endChangeCmd) + changesCmd.AddCommand(endChangeCmd) withChangeUuidFlags(endChangeCmd) diff --git a/cmd/getchange.go b/cmd/changes_get_change.go similarity index 98% rename from cmd/getchange.go rename to cmd/changes_get_change.go index a3be68f3..7d4c62a8 100644 --- a/cmd/getchange.go +++ b/cmd/changes_get_change.go @@ -17,7 +17,7 @@ import ( "github.com/hexops/gotextdiff" "github.com/hexops/gotextdiff/myers" diffspan "github.com/hexops/gotextdiff/span" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -245,7 +245,7 @@ fetch: BlastItems: int(changeRes.Msg.GetChange().GetMetadata().GetNumAffectedItems()), BlastEdges: int(changeRes.Msg.GetChange().GetMetadata().GetNumAffectedEdges()), Risks: []TemplateRisk{}, - AssetPath: fmt.Sprintf("https://raw.githubusercontent.com/overmindtech/ovm-cli/%v/assets", assetVersion), + AssetPath: fmt.Sprintf("https://raw.githubusercontent.com/overmindtech/cli/%v/assets", assetVersion), } for _, item := range changeRes.Msg.GetChange().GetProperties().GetPlannedChanges() { @@ -324,7 +324,7 @@ fetch: } func init() { - rootCmd.AddCommand(getChangeCmd) + changesCmd.AddCommand(getChangeCmd) withChangeUuidFlags(getChangeCmd) getChangeCmd.PersistentFlags().String("status", "", "The expected status of the change. Use this with --ticket-link. Allowed values: CHANGE_STATUS_UNSPECIFIED, CHANGE_STATUS_DEFINING, CHANGE_STATUS_HAPPENING, CHANGE_STATUS_PROCESSING, CHANGE_STATUS_DONE") diff --git a/cmd/listchanges.go b/cmd/changes_list_changes.go similarity index 99% rename from cmd/listchanges.go rename to cmd/changes_list_changes.go index d2d570b6..bb160ab8 100644 --- a/cmd/listchanges.go +++ b/cmd/changes_list_changes.go @@ -12,7 +12,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -287,7 +287,7 @@ func printJson(ctx context.Context, b []byte, prefix, id string) error { } func init() { - rootCmd.AddCommand(listChangesCmd) + changesCmd.AddCommand(listChangesCmd) listChangesCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") listChangesCmd.PersistentFlags().String("format", "files", "How to render the change. Possible values: files, json") diff --git a/cmd/manualchange.go b/cmd/changes_manual_change.go similarity index 99% rename from cmd/manualchange.go rename to cmd/changes_manual_change.go index 7679d600..dec719ab 100644 --- a/cmd/manualchange.go +++ b/cmd/changes_manual_change.go @@ -11,7 +11,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" "github.com/overmindtech/sdp-go/sdpws" log "github.com/sirupsen/logrus" @@ -225,7 +225,7 @@ func ManualChange(ctx context.Context, ready chan bool) int { } func init() { - rootCmd.AddCommand(manualChangeCmd) + changesCmd.AddCommand(manualChangeCmd) manualChangeCmd.PersistentFlags().String("changes-url", "", "The changes service API endpoint (defaults to --url)") manualChangeCmd.PersistentFlags().String("management-url", "", "The management service API endpoint (defaults to --url)") diff --git a/cmd/submitplan.go b/cmd/changes_submit_plan.go similarity index 99% rename from cmd/submitplan.go rename to cmd/changes_submit_plan.go index 80cb28c5..5148c80f 100644 --- a/cmd/submitplan.go +++ b/cmd/changes_submit_plan.go @@ -17,8 +17,8 @@ import ( "connectrpc.com/connect" "github.com/getsentry/sentry-go" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/cmd/datamaps" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/cmd/datamaps" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -730,13 +730,13 @@ func SubmitPlan(ctx context.Context, files []string, ready chan bool) int { } func init() { - rootCmd.AddCommand(submitPlanCmd) + changesCmd.AddCommand(submitPlanCmd) submitPlanCmd.PersistentFlags().String("changes-url", "", "The changes service API endpoint (defaults to --url)") submitPlanCmd.PersistentFlags().String("management-url", "", "The management service API endpoint (defaults to --url)") submitPlanCmd.PersistentFlags().String("frontend", "https://app.overmind.tech", "The frontend base URL") - submitPlanCmd.PersistentFlags().String("title", "", "Short title for this change. If this is not specified, ovm-cli will try to come up with one for you.") + submitPlanCmd.PersistentFlags().String("title", "", "Short title for this change. If this is not specified, overmind will try to come up with one for you.") submitPlanCmd.PersistentFlags().String("description", "", "Quick description of the change.") submitPlanCmd.PersistentFlags().String("ticket-link", "*", "Link to the ticket for this change.") submitPlanCmd.PersistentFlags().String("owner", "", "The owner of this change.") diff --git a/cmd/startchange.go b/cmd/chnages_start_change.go similarity index 97% rename from cmd/startchange.go rename to cmd/chnages_start_change.go index ca50b443..58c6fe27 100644 --- a/cmd/startchange.go +++ b/cmd/chnages_start_change.go @@ -9,7 +9,7 @@ import ( "time" "connectrpc.com/connect" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -114,7 +114,7 @@ func StartChange(ctx context.Context, ready chan bool) int { } func init() { - rootCmd.AddCommand(startChangeCmd) + changesCmd.AddCommand(startChangeCmd) withChangeUuidFlags(startChangeCmd) diff --git a/cmd/invites.go b/cmd/invites.go new file mode 100644 index 00000000..18790d87 --- /dev/null +++ b/cmd/invites.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// invitesCmd represents the invites command +var invitesCmd = &cobra.Command{ + Use: "invites", + GroupID: "api", + Short: "Manage invites for your team to Overmind", + Long: `Create and revoke Overmind invitations`, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} + +func init() { + rootCmd.AddCommand(invitesCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // invitesCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // invitesCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/invite.go b/cmd/invites_crud.go similarity index 97% rename from cmd/invite.go rename to cmd/invites_crud.go index 886624d5..cceb5566 100644 --- a/cmd/invite.go +++ b/cmd/invites_crud.go @@ -9,7 +9,7 @@ import ( "connectrpc.com/connect" "github.com/jedib0t/go-pretty/v6/table" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -237,16 +237,16 @@ func InvitesList(ctx context.Context) int { func init() { // list sub-command - rootCmd.AddCommand(listCmd) + invitesCmd.AddCommand(listCmd) listCmd.PersistentFlags().String("invite-url", "", "A custom URL for the invites API (optional)") // create sub-command - rootCmd.AddCommand(createCmd) + invitesCmd.AddCommand(createCmd) createCmd.PersistentFlags().String("invite-url", "", "A custom URL for the invites API (optional)") createCmd.PersistentFlags().StringSlice("emails", []string{}, "A list of emails to invite") // revoke sub-command - rootCmd.AddCommand(revokeCmd) + invitesCmd.AddCommand(revokeCmd) revokeCmd.PersistentFlags().String("invite-url", "", "A custom URL for the invites API (optional)") revokeCmd.PersistentFlags().String("email", "", "The email address to revoke") } diff --git a/cmd/request.go b/cmd/request.go index 631ced3d..8f9e6f45 100644 --- a/cmd/request.go +++ b/cmd/request.go @@ -10,7 +10,7 @@ import ( "time" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" "github.com/overmindtech/sdp-go/sdpws" log "github.com/sirupsen/logrus" @@ -24,8 +24,9 @@ import ( // requestCmd represents the start command var requestCmd = &cobra.Command{ - Use: "request", - Short: "Runs a request against the overmind API", + Use: "request", + GroupID: "api", + Short: "Runs a request against the overmind API", PreRun: func(cmd *cobra.Command, args []string) { // Bind these to viper err := viper.BindPFlags(cmd.Flags()) diff --git a/cmd/root.go b/cmd/root.go index 4bec76ee..15fc4f6d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -17,7 +17,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -34,9 +34,9 @@ var cliVersion string // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "ovm-cli", - Short: "A CLI to interact with the overmind API", - Long: `The ovm-cli allows direct access to the overmind API`, + Use: "overmind", + Short: "The Overmind CLI", + Long: `Calculate the blast radius of your changes, track risks, and make changes with confidence`, Version: cliVersion, PreRun: func(cmd *cobra.Command, args []string) { // Bind these to viper @@ -415,6 +415,14 @@ func withChangeUuidFlags(cmd *cobra.Command) { func init() { cobra.OnInitialize(initConfig) + // TODO: I'm leaving this for now but I want to go over these and remove a + // bunch of them, but I want to get options before I do. The things I'm + // considering are: + // + // * Move some into a helper like `withChangeUuidFlags` such as log level + // * For things that are only used internally, move to only using env vars i.e. honeycomb, sentry, client_id + // * Completely remove things that aren't used such as stdout trace dump + // General Config rootCmd.PersistentFlags().StringVar(&logLevel, "log", "info", "Set the log level. Valid values: panic, fatal, error, warn, info, debug, trace") @@ -442,6 +450,16 @@ func init() { // debugging rootCmd.PersistentFlags().Bool("stdout-trace-dump", false, "Dump all otel traces to stdout for debugging. This requires --otel to be set.") + // Create groups + rootCmd.AddGroup(&cobra.Group{ + ID: "iac", + Title: "Infrastructure as Code:", + }) + rootCmd.AddGroup(&cobra.Group{ + ID: "api", + Title: "Overmind API:", + }) + // Run this before we do anything to set up the loglevel rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { formatter := new(log.TextFormatter) diff --git a/cmd/snapshots.go b/cmd/snapshots.go new file mode 100644 index 00000000..41c66908 --- /dev/null +++ b/cmd/snapshots.go @@ -0,0 +1,32 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// snapshotsCmd represents the snapshots command +var snapshotsCmd = &cobra.Command{ + Use: "snapshots", + GroupID: "api", + Short: "Create, view and delete snapshots if your infrastructure", + Long: `Overmind automatically creates snapshots are part of the change lifecycle, +however you can use these commands to interact directly with the API if +required.`, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} + +func init() { + rootCmd.AddCommand(snapshotsCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // snapshotsCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // snapshotsCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/getsnapshot.go b/cmd/snapshots_get_snapshot.go similarity index 98% rename from cmd/getsnapshot.go rename to cmd/snapshots_get_snapshot.go index 77dfdd32..d6c8d63b 100644 --- a/cmd/getsnapshot.go +++ b/cmd/snapshots_get_snapshot.go @@ -11,7 +11,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" - "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -128,7 +128,7 @@ func GetSnapshot(ctx context.Context, ready chan bool) int { } func init() { - rootCmd.AddCommand(getSnapshotCmd) + snapshotsCmd.AddCommand(getSnapshotCmd) getSnapshotCmd.PersistentFlags().String("snapshot-url", "", "The snapshot service API endpoint (defaults to --url)") getSnapshotCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") diff --git a/cmd/terraform.go b/cmd/terraform.go new file mode 100644 index 00000000..63079bdf --- /dev/null +++ b/cmd/terraform.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// terraformCmd represents the terraform command +var terraformCmd = &cobra.Command{ + Use: "terraform", + GroupID: "iac", + Short: "Run Terrafrom with Overmind's change tracking - COMING SOON", + Long: `COMING SOON`, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} + +func init() { + rootCmd.AddCommand(terraformCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // terraformCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // terraformCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/go.mod b/go.mod index 5ff9820c..85c1f980 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/overmindtech/ovm-cli +module github.com/overmindtech/cli go 1.22.0 diff --git a/main.go b/main.go index d4ba0778..27cce098 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,6 @@ package main -import "github.com/overmindtech/ovm-cli/cmd" +import "github.com/overmindtech/cli/cmd" func main() { cmd.Execute() diff --git a/tracing/main.go b/tracing/main.go index f04c95fd..ce3a3d3a 100644 --- a/tracing/main.go +++ b/tracing/main.go @@ -28,7 +28,7 @@ import ( //go:embed commit.txt var instrumentationVersion string -const instrumentationName = "github.com/overmindtech/ovm-cli" +const instrumentationName = "github.com/overmindtech/cli" var tracer = otel.GetTracerProvider().Tracer( instrumentationName, @@ -70,7 +70,7 @@ func tracingResource() *resource.Resource { resource.WithSchemaURL(semconv.SchemaURL), // Add your own custom attributes to identify your application resource.WithAttributes( - semconv.ServiceNameKey.String("ovm-cli"), + semconv.ServiceNameKey.String("overmind-cli"), semconv.ServiceVersionKey.String("0.0.1"), ), ) From caedb485226081d3e3c7432932f283afcf752e55 Mon Sep 17 00:00:00 2001 From: Dylan Ratcliffe Date: Tue, 13 Feb 2024 21:54:21 +0000 Subject: [PATCH 2/8] Change binary name --- .goreleaser.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 28f131a1..174541de 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -13,6 +13,7 @@ builds: - linux - windows - darwin + binary: overmind archives: - format: tar.gz From 4223eef5afe9e3b330faccfc894fc41f4ea361c3 Mon Sep 17 00:00:00 2001 From: Dylan Ratcliffe Date: Tue, 13 Feb 2024 22:05:48 +0000 Subject: [PATCH 3/8] Update tarfile name to be more logical --- .goreleaser.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 174541de..4d9f6066 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -19,6 +19,7 @@ archives: - format: tar.gz # this name template makes the OS and Arch compatible with the results of uname. name_template: >- + {{ .Binary }}_ {{ .ProjectName }}_ {{- .Version }}_ {{- title .Os }}_ From ede0fd222d8ea1693ec69efa80b68200c145d278 Mon Sep 17 00:00:00 2001 From: Dylan Ratcliffe Date: Wed, 14 Feb 2024 11:27:05 +0000 Subject: [PATCH 4/8] Removed old args that were disused --- cmd/root.go | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 15fc4f6d..2fef036c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -441,14 +441,11 @@ func init() { rootCmd.PersistentFlags().String("auth0-domain", "om-prod.eu.auth0.com", "Auth0 domain to connect to") // tracing - rootCmd.PersistentFlags().Bool("otel", false, "If specified, configures opentelemetry and - optionally, see --sentry-dsn - sentry using their default environment configs.") rootCmd.PersistentFlags().String("honeycomb-api-key", "", "If specified, configures opentelemetry libraries to submit traces to honeycomb. This requires --otel to be set.") - rootCmd.PersistentFlags().String("sentry-dsn", "", "If specified, configures sentry libraries to capture errors. This requires --otel to be set.") - rootCmd.PersistentFlags().String("run-mode", "release", "Set the run mode for this service, 'release', 'debug' or 'test'. Defaults to 'release'.") - rootCmd.PersistentFlags().Bool("json-log", false, "Set to true to emit logs as json for easier parsing.") - - // debugging - rootCmd.PersistentFlags().Bool("stdout-trace-dump", false, "Dump all otel traces to stdout for debugging. This requires --otel to be set.") + // Mark this as hidden. This means that it will still be parsed of supplied, + // and we will still look for it in the environment, but it won't be shown + // in the help + rootCmd.Flags().MarkHidden("honeycomb-api-key") // Create groups rootCmd.AddGroup(&cobra.Group{ @@ -480,21 +477,20 @@ func init() { } log.SetLevel(lvl) - if viper.GetBool("json-log") { - log.SetFormatter(&log.JSONFormatter{}) - } + if honeycombApiKey := viper.GetString("honeycomb-api-key"); honeycombApiKey != "" { + if err := tracing.InitTracerWithHoneycomb(honeycombApiKey); err != nil { + log.Fatal(err) + } - if err := tracing.InitTracerWithHoneycomb(viper.GetString("honeycomb-api-key")); err != nil { - log.Fatal(err) - } + log.AddHook(otellogrus.NewHook(otellogrus.WithLevels( + log.AllLevels[:log.GetLevel()+1]..., + ))) - log.AddHook(otellogrus.NewHook(otellogrus.WithLevels( - log.AllLevels[:log.GetLevel()+1]..., - ))) - } - // shut down tracing at the end of the process - rootCmd.PersistentPostRun = func(cmd *cobra.Command, args []string) { - tracing.ShutdownTracer() + // shut down tracing at the end of the process + rootCmd.PersistentPostRun = func(cmd *cobra.Command, args []string) { + tracing.ShutdownTracer() + } + } } } From 9b7ce7b694204d2e3a58ba497df4954b2716f19d Mon Sep 17 00:00:00 2001 From: Dylan Ratcliffe Date: Wed, 14 Feb 2024 12:06:15 +0000 Subject: [PATCH 5/8] Removed most of the root parameters --- cmd/auth_client.go | 16 ++++----------- cmd/changes_manual_change.go | 11 +++------- cmd/changes_submit_plan.go | 8 +------- cmd/request.go | 10 +++------ cmd/root.go | 39 ++++++++++++++++-------------------- internal/paths.go | 10 +++++++++ 6 files changed, 38 insertions(+), 56 deletions(-) create mode 100644 internal/paths.go diff --git a/cmd/auth_client.go b/cmd/auth_client.go index a53e5441..9661f01f 100644 --- a/cmd/auth_client.go +++ b/cmd/auth_client.go @@ -16,24 +16,16 @@ import ( // embedded in the context and otel instrumentation func AuthenticatedApiKeyClient(ctx context.Context) sdpconnect.ApiKeyServiceClient { httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient) - url := viper.GetString("api-key-url") - if url == "" { - url = viper.GetString("url") - viper.Set("api-key-url", url) - } - log.WithContext(ctx).WithField("api-key-url", url).Debug("Connecting to overmind apikeys API (pre-authenticated)") + url := viper.GetString("url") + log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind apikeys API (pre-authenticated)") return sdpconnect.NewApiKeyServiceClient(httpClient, url) } // UnauthenticatedApiKeyClient Returns an apikey client with otel instrumentation // but no authentication. Can only be used for ExchangeKeyForToken func UnauthenticatedApiKeyClient(ctx context.Context) sdpconnect.ApiKeyServiceClient { - url := viper.GetString("api-key-url") - if url == "" { - url = viper.GetString("url") - viper.Set("api-key-url", url) - } - log.WithContext(ctx).WithField("api-key-url", url).Debug("Connecting to overmind apikeys API") + url := viper.GetString("url") + log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind apikeys API") return sdpconnect.NewApiKeyServiceClient(otelhttp.DefaultClient, url) } diff --git a/cmd/changes_manual_change.go b/cmd/changes_manual_change.go index dec719ab..70c8103c 100644 --- a/cmd/changes_manual_change.go +++ b/cmd/changes_manual_change.go @@ -11,6 +11,7 @@ import ( "connectrpc.com/connect" "github.com/google/uuid" + "github.com/overmindtech/cli/internal" "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" "github.com/overmindtech/sdp-go/sdpws" @@ -67,17 +68,11 @@ func ManualChange(ctx context.Context, ready chan bool) int { )) defer span.End() - gatewayUrl := viper.GetString("gateway-url") - if gatewayUrl == "" { - gatewayUrl = fmt.Sprintf("%v/api/gateway", viper.GetString("url")) - viper.Set("gateway-url", gatewayUrl) - } - lf := log.Fields{} ctx, err = ensureToken(ctx, []string{"changes:write"}) if err != nil { - log.WithContext(ctx).WithFields(lf).WithField("api-key-url", viper.GetString("api-key-url")).WithError(err).Error("failed to authenticate") + log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate") return 1 } @@ -130,7 +125,7 @@ func ManualChange(ctx context.Context, ready chan bool) int { return 1 } - ws, err := sdpws.DialBatch(ctx, gatewayUrl, otelhttp.DefaultClient, nil) + ws, err := sdpws.DialBatch(ctx, internal.GatewayURL(viper.GetString("url")), otelhttp.DefaultClient, nil) if err != nil { log.WithContext(ctx).WithFields(lf).WithError(err).Error("Failed to connect to gateway") return 1 diff --git a/cmd/changes_submit_plan.go b/cmd/changes_submit_plan.go index 5148c80f..78d73e4f 100644 --- a/cmd/changes_submit_plan.go +++ b/cmd/changes_submit_plan.go @@ -564,17 +564,11 @@ func SubmitPlan(ctx context.Context, files []string, ready chan bool) int { )) defer span.End() - gatewayUrl := viper.GetString("gateway-url") - if gatewayUrl == "" { - gatewayUrl = fmt.Sprintf("%v/api/gateway", viper.GetString("url")) - viper.Set("gateway-url", gatewayUrl) - } - lf := log.Fields{} ctx, err = ensureToken(ctx, []string{"changes:write"}) if err != nil { - log.WithContext(ctx).WithFields(lf).WithField("api-key-url", viper.GetString("api-key-url")).WithError(err).Error("failed to authenticate") + log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate") return 1 } diff --git a/cmd/request.go b/cmd/request.go index 8f9e6f45..6fe85342 100644 --- a/cmd/request.go +++ b/cmd/request.go @@ -10,6 +10,7 @@ import ( "time" "github.com/google/uuid" + "github.com/overmindtech/cli/internal" "github.com/overmindtech/cli/tracing" "github.com/overmindtech/sdp-go" "github.com/overmindtech/sdp-go/sdpws" @@ -141,17 +142,11 @@ func Request(ctx context.Context, ready chan bool) int { )) defer span.End() - gatewayUrl := viper.GetString("gateway-url") - if gatewayUrl == "" { - gatewayUrl = fmt.Sprintf("%v/api/gateway", viper.GetString("url")) - viper.Set("gateway-url", gatewayUrl) - } - lf := log.Fields{} ctx, err = ensureToken(ctx, []string{"explore:read"}) if err != nil { - log.WithContext(ctx).WithFields(lf).WithField("api-key-url", viper.GetString("api-key-url")).WithError(err).Error("failed to authenticate") + log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate") return 1 } @@ -166,6 +161,7 @@ func Request(ctx context.Context, ready chan bool) int { edges: []*sdp.Edge{}, msgLog: []*sdp.GatewayResponse{}, } + gatewayUrl := internal.GatewayURL(viper.GetString("url")) c, err := sdpws.DialBatch(ctx, gatewayUrl, NewAuthenticatedClient(ctx, otelhttp.DefaultClient), handler, diff --git a/cmd/root.go b/cmd/root.go index 2fef036c..95630146 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -26,6 +26,9 @@ import ( "golang.org/x/oauth2" ) +const Auth0ClientId = "j3LylZtIosVPZtouKI8WuVHmE6Lluva1" +const Auth0Domain = "om-prod.eu.auth0.com" + var logLevel string //go:generate sh -c "echo -n $(git describe --tags --long) > commit.txt" @@ -34,9 +37,14 @@ var cliVersion string // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "overmind", - Short: "The Overmind CLI", - Long: `Calculate the blast radius of your changes, track risks, and make changes with confidence`, + Use: "overmind", + Short: "The Overmind CLI", + Long: `Calculate the blast radius of your changes, track risks, and make changes with +confidence. + +This CLI will prompt you for authentication using Overmind's OAuth service, +however it can also be configured to use an API key by setting the OVM_API_KEY +environment variable.`, Version: cliVersion, PreRun: func(cmd *cobra.Command, args []string) { // Bind these to viper @@ -162,7 +170,7 @@ func ensureToken(ctx context.Context, requiredScopes []string) (context.Context, log.WithContext(ctx).Debug("successfully authenticated") apiKey = resp.Msg.GetAccessToken() } else { - return ctx, errors.New("--api-key does not match pattern 'ovm_api_*'") + return ctx, errors.New("OVM_API_KEY does not match pattern 'ovm_api_*'") } return context.WithValue(ctx, sdp.UserTokenContextKey{}, apiKey), nil } @@ -198,11 +206,11 @@ func ensureToken(ctx context.Context, requiredScopes []string) (context.Context, // Authenticate using the oauth resource owner password flow config := oauth2.Config{ - ClientID: viper.GetString("auth0-client-id"), + ClientID: Auth0ClientId, Scopes: requestScopes, Endpoint: oauth2.Endpoint{ - AuthURL: fmt.Sprintf("https://%v/authorize", viper.GetString("auth0-domain")), - TokenURL: fmt.Sprintf("https://%v/oauth/token", viper.GetString("auth0-domain")), + AuthURL: fmt.Sprintf("https://%v/authorize", Auth0Domain), + TokenURL: fmt.Sprintf("https://%v/oauth/token", Auth0Domain), }, RedirectURL: "http://127.0.0.1:7837/oauth/callback", } @@ -327,7 +335,7 @@ func ensureToken(ctx context.Context, requiredScopes []string) (context.Context, // Set the token return context.WithValue(ctx, sdp.UserTokenContextKey{}, token.AccessToken), nil } - return ctx, fmt.Errorf("no --api-key configured and target URL (%v) is insecure", parsed) + return ctx, fmt.Errorf("no OVM_API_KEY configured and target URL (%v) is insecure", parsed) } // getChangeUuid returns the UUID of a change, as selected by --uuid or --change, or a state with the specified status and having --ticket-link @@ -415,30 +423,17 @@ func withChangeUuidFlags(cmd *cobra.Command) { func init() { cobra.OnInitialize(initConfig) - // TODO: I'm leaving this for now but I want to go over these and remove a - // bunch of them, but I want to get options before I do. The things I'm - // considering are: - // - // * Move some into a helper like `withChangeUuidFlags` such as log level - // * For things that are only used internally, move to only using env vars i.e. honeycomb, sentry, client_id - // * Completely remove things that aren't used such as stdout trace dump - // General Config rootCmd.PersistentFlags().StringVar(&logLevel, "log", "info", "Set the log level. Valid values: panic, fatal, error, warn, info, debug, trace") // api endpoint rootCmd.PersistentFlags().String("url", "https://api.prod.overmind.tech", "The overmind API endpoint") - rootCmd.PersistentFlags().String("gateway-url", "", "The overmind Gateway endpoint (defaults to /api/gateway on --url)") - // authorization - rootCmd.PersistentFlags().String("api-key", "", "The API key to use for authentication, also read from OVM_API_KEY environment variable") + // Support API Keys in the environment err := viper.BindEnv("api-key", "OVM_API_KEY", "API_KEY") if err != nil { log.WithError(err).Fatal("could not bind api key to env") } - rootCmd.PersistentFlags().String("api-key-url", "", "The overmind API Keys endpoint (defaults to --url)") - rootCmd.PersistentFlags().String("auth0-client-id", "j3LylZtIosVPZtouKI8WuVHmE6Lluva1", "OAuth Client ID to use when connecting with auth") - rootCmd.PersistentFlags().String("auth0-domain", "om-prod.eu.auth0.com", "Auth0 domain to connect to") // tracing rootCmd.PersistentFlags().String("honeycomb-api-key", "", "If specified, configures opentelemetry libraries to submit traces to honeycomb. This requires --otel to be set.") diff --git a/internal/paths.go b/internal/paths.go new file mode 100644 index 00000000..7919fa0f --- /dev/null +++ b/internal/paths.go @@ -0,0 +1,10 @@ +package internal + +import "fmt" + +// GatewayURL returns the URL for the gateway for a given pase URL. For example +// if the base URL is https://api.prod.overmind.tech, the gateway URL will be +// https://api.prod.overmind.tech/api/gateway +func GatewayURL(base string) string { + return fmt.Sprintf("%v/api/gateway", base) +} From 6d55832f53af5312c5e596cea632019ea608b6cf Mon Sep 17 00:00:00 2001 From: Dylan Ratcliffe Date: Wed, 14 Feb 2024 12:28:14 +0000 Subject: [PATCH 6/8] Massively simplify arguments --- cmd/auth_client.go | 40 +++++++------------------ cmd/bookmarks.go | 2 ++ cmd/bookmarks_create_bookmark.go | 6 +--- cmd/bookmarks_get_affected_bookmarks.go | 7 +---- cmd/bookmarks_get_bookmark.go | 6 +--- cmd/changes.go | 2 ++ cmd/changes_end_change.go | 6 +--- cmd/changes_get_change.go | 4 +-- cmd/changes_list_changes.go | 3 -- cmd/changes_manual_change.go | 4 --- cmd/changes_submit_plan.go | 4 --- cmd/chnages_start_change.go | 6 +--- cmd/invites.go | 1 + cmd/invites_crud.go | 3 -- cmd/root.go | 11 ++++--- cmd/snapshots.go | 2 ++ cmd/snapshots_get_snapshot.go | 7 +---- cmd/terraform.go | 3 ++ 18 files changed, 34 insertions(+), 83 deletions(-) diff --git a/cmd/auth_client.go b/cmd/auth_client.go index 9661f01f..9b2865ef 100644 --- a/cmd/auth_client.go +++ b/cmd/auth_client.go @@ -33,12 +33,8 @@ func UnauthenticatedApiKeyClient(ctx context.Context) sdpconnect.ApiKeyServiceCl // embedded in the context and otel instrumentation func AuthenticatedBookmarkClient(ctx context.Context) sdpconnect.BookmarksServiceClient { httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient) - url := viper.GetString("bookmark-url") - if url == "" { - url = viper.GetString("url") - viper.Set("bookmark-url", url) - } - log.WithContext(ctx).WithField("bookmark-url", url).Debug("Connecting to overmind bookmark API") + url := viper.GetString("url") + log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind bookmark API") return sdpconnect.NewBookmarksServiceClient(httpClient, url) } @@ -46,12 +42,8 @@ func AuthenticatedBookmarkClient(ctx context.Context) sdpconnect.BookmarksServic // embedded in the context and otel instrumentation func AuthenticatedChangesClient(ctx context.Context) sdpconnect.ChangesServiceClient { httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient) - url := viper.GetString("changes-url") - if url == "" { - url = viper.GetString("url") - viper.Set("changes-url", url) - } - log.WithContext(ctx).WithField("changes-url", url).Debug("Connecting to overmind changes API") + url := viper.GetString("url") + log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind changes API") return sdpconnect.NewChangesServiceClient(httpClient, url) } @@ -59,12 +51,8 @@ func AuthenticatedChangesClient(ctx context.Context) sdpconnect.ChangesServiceCl // embedded in the context and otel instrumentation func AuthenticatedManagementClient(ctx context.Context) sdpconnect.ManagementServiceClient { httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient) - url := viper.GetString("management-url") - if url == "" { - url = viper.GetString("url") - viper.Set("management-url", url) - } - log.WithContext(ctx).WithField("management-url", url).Debug("Connecting to overmind management API") + url := viper.GetString("url") + log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind management API") return sdpconnect.NewManagementServiceClient(httpClient, url) } @@ -72,12 +60,8 @@ func AuthenticatedManagementClient(ctx context.Context) sdpconnect.ManagementSer // embedded in the context and otel instrumentation func AuthenticatedSnapshotsClient(ctx context.Context) sdpconnect.SnapshotsServiceClient { httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient) - url := viper.GetString("snapshot-url") - if url == "" { - url = viper.GetString("url") - viper.Set("snapshot-url", url) - } - log.WithContext(ctx).WithField("snapshot-url", url).Debug("Connecting to overmind snapshot API") + url := viper.GetString("url") + log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind snapshot API") return sdpconnect.NewSnapshotsServiceClient(httpClient, url) } @@ -85,12 +69,8 @@ func AuthenticatedSnapshotsClient(ctx context.Context) sdpconnect.SnapshotsServi // embedded in the context and otel instrumentation func AuthenticatedInviteClient(ctx context.Context) sdpconnect.InviteServiceClient { httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient) - url := viper.GetString("invite-url") - if url == "" { - url = viper.GetString("url") - viper.Set("invite-url", url) - } - log.WithContext(ctx).WithField("invite-url", url).Debug("Connecting to overmind invite API") + url := viper.GetString("url") + log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind invite API") return sdpconnect.NewInviteServiceClient(httpClient, url) } diff --git a/cmd/bookmarks.go b/cmd/bookmarks.go index a4004719..9e1694f9 100644 --- a/cmd/bookmarks.go +++ b/cmd/bookmarks.go @@ -22,6 +22,8 @@ executed as a single block.`, func init() { rootCmd.AddCommand(bookmarksCmd) + addAPIFlags(bookmarksCmd) + // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command diff --git a/cmd/bookmarks_create_bookmark.go b/cmd/bookmarks_create_bookmark.go index 877662a7..586a5aa4 100644 --- a/cmd/bookmarks_create_bookmark.go +++ b/cmd/bookmarks_create_bookmark.go @@ -108,7 +108,7 @@ func CreateBookmark(ctx context.Context, ready chan bool) int { }) if err != nil { log.WithContext(ctx).WithError(err).WithFields(log.Fields{ - "bookmark-url": viper.GetString("bookmark-url"), + "url": viper.GetString("url"), }).Error("failed to get bookmark") return 1 } @@ -142,9 +142,5 @@ func CreateBookmark(ctx context.Context, ready chan bool) int { func init() { bookmarksCmd.AddCommand(createBookmarkCmd) - createBookmarkCmd.PersistentFlags().String("bookmark-url", "", "The bookmark service API endpoint (defaults to --url)") - createBookmarkCmd.PersistentFlags().String("file", "", "JSON formatted file to read bookmark. (defaults to stdin)") - - createBookmarkCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") } diff --git a/cmd/bookmarks_get_affected_bookmarks.go b/cmd/bookmarks_get_affected_bookmarks.go index 5181f623..5c00541a 100644 --- a/cmd/bookmarks_get_affected_bookmarks.go +++ b/cmd/bookmarks_get_affected_bookmarks.go @@ -102,7 +102,7 @@ func GetAffectedBookmarks(ctx context.Context, ready chan bool) int { }) if err != nil { log.WithContext(ctx).WithError(err).WithFields(log.Fields{ - "bookmark-url": viper.GetString("bookmark-url"), + "url": viper.GetString("url"), }).Error("failed to get affected bookmarks") return 1 } @@ -118,11 +118,6 @@ func GetAffectedBookmarks(ctx context.Context, ready chan bool) int { func init() { bookmarksCmd.AddCommand(getAffectedBookmarksCmd) - getAffectedBookmarksCmd.PersistentFlags().String("bookmark-url", "", "The bookmark service API endpoint (defaults to --url)") - getAffectedBookmarksCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") - getAffectedBookmarksCmd.PersistentFlags().String("snapshot-uuid", "", "The UUID of the snapshot that should be checked.") getAffectedBookmarksCmd.PersistentFlags().String("bookmark-uuids", "", "A comma separated list of UUIDs of the potentially affected bookmarks.") - - getAffectedBookmarksCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") } diff --git a/cmd/bookmarks_get_bookmark.go b/cmd/bookmarks_get_bookmark.go index 587bd5af..57aa390c 100644 --- a/cmd/bookmarks_get_bookmark.go +++ b/cmd/bookmarks_get_bookmark.go @@ -91,7 +91,7 @@ func GetBookmark(ctx context.Context, ready chan bool) int { }) if err != nil { log.WithContext(ctx).WithError(err).WithFields(log.Fields{ - "bookmark-url": viper.GetString("bookmark-url"), + "url": viper.GetString("url"), }).Error("failed to get bookmark") return 1 } @@ -115,9 +115,5 @@ func GetBookmark(ctx context.Context, ready chan bool) int { func init() { bookmarksCmd.AddCommand(getBookmarkCmd) - getBookmarkCmd.PersistentFlags().String("bookmark-url", "", "The bookmark service API endpoint (defaults to --url)") - getBookmarkCmd.PersistentFlags().String("uuid", "", "The UUID of the bookmark that should be displayed.") - - getBookmarkCmd.PersistentFlags().String("timeout", "1m", "How long to wait for responses") } diff --git a/cmd/changes.go b/cmd/changes.go index 46b768df..dbb1ea9f 100644 --- a/cmd/changes.go +++ b/cmd/changes.go @@ -20,6 +20,8 @@ using these commands directly, but they are provided for flexibility.`, func init() { rootCmd.AddCommand(changesCmd) + addAPIFlags(changesCmd) + // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command diff --git a/cmd/changes_end_change.go b/cmd/changes_end_change.go index 76cf3731..de02b6d2 100644 --- a/cmd/changes_end_change.go +++ b/cmd/changes_end_change.go @@ -116,9 +116,5 @@ func EndChange(ctx context.Context, ready chan bool) int { func init() { changesCmd.AddCommand(endChangeCmd) - withChangeUuidFlags(endChangeCmd) - - endChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") - - endChangeCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") + addChangeUuidFlags(endChangeCmd) } diff --git a/cmd/changes_get_change.go b/cmd/changes_get_change.go index 7d4c62a8..b4046b26 100644 --- a/cmd/changes_get_change.go +++ b/cmd/changes_get_change.go @@ -326,11 +326,9 @@ fetch: func init() { changesCmd.AddCommand(getChangeCmd) - withChangeUuidFlags(getChangeCmd) + addChangeUuidFlags(getChangeCmd) getChangeCmd.PersistentFlags().String("status", "", "The expected status of the change. Use this with --ticket-link. Allowed values: CHANGE_STATUS_UNSPECIFIED, CHANGE_STATUS_DEFINING, CHANGE_STATUS_HAPPENING, CHANGE_STATUS_PROCESSING, CHANGE_STATUS_DONE") getChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") getChangeCmd.PersistentFlags().String("format", "json", "How to render the change. Possible values: json, markdown") - - getChangeCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") } diff --git a/cmd/changes_list_changes.go b/cmd/changes_list_changes.go index bb160ab8..b000585a 100644 --- a/cmd/changes_list_changes.go +++ b/cmd/changes_list_changes.go @@ -289,10 +289,7 @@ func printJson(ctx context.Context, b []byte, prefix, id string) error { func init() { changesCmd.AddCommand(listChangesCmd) - listChangesCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") listChangesCmd.PersistentFlags().String("format", "files", "How to render the change. Possible values: files, json") listChangesCmd.PersistentFlags().String("dir", "./output", "A directory name to use for rendering changes when using the 'files' format") listChangesCmd.PersistentFlags().Bool("fetch-data", false, "also fetch the blast radius and system state snapshots for each change") - - listChangesCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") } diff --git a/cmd/changes_manual_change.go b/cmd/changes_manual_change.go index 70c8103c..72ec5140 100644 --- a/cmd/changes_manual_change.go +++ b/cmd/changes_manual_change.go @@ -222,8 +222,6 @@ func ManualChange(ctx context.Context, ready chan bool) int { func init() { changesCmd.AddCommand(manualChangeCmd) - manualChangeCmd.PersistentFlags().String("changes-url", "", "The changes service API endpoint (defaults to --url)") - manualChangeCmd.PersistentFlags().String("management-url", "", "The management service API endpoint (defaults to --url)") manualChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech", "The frontend base URL") manualChangeCmd.PersistentFlags().String("title", "", "Short title for this change.") @@ -236,6 +234,4 @@ func init() { manualChangeCmd.PersistentFlags().String("query-scope", "*", "The scope to query") manualChangeCmd.PersistentFlags().String("query-type", "*", "The type to query") manualChangeCmd.PersistentFlags().String("query", "", "The actual query to send") - - manualChangeCmd.PersistentFlags().String("timeout", "3m", "How long to wait for responses") } diff --git a/cmd/changes_submit_plan.go b/cmd/changes_submit_plan.go index 78d73e4f..3dfc5718 100644 --- a/cmd/changes_submit_plan.go +++ b/cmd/changes_submit_plan.go @@ -726,8 +726,6 @@ func SubmitPlan(ctx context.Context, files []string, ready chan bool) int { func init() { changesCmd.AddCommand(submitPlanCmd) - submitPlanCmd.PersistentFlags().String("changes-url", "", "The changes service API endpoint (defaults to --url)") - submitPlanCmd.PersistentFlags().String("management-url", "", "The management service API endpoint (defaults to --url)") submitPlanCmd.PersistentFlags().String("frontend", "https://app.overmind.tech", "The frontend base URL") submitPlanCmd.PersistentFlags().String("title", "", "Short title for this change. If this is not specified, overmind will try to come up with one for you.") @@ -738,6 +736,4 @@ func init() { submitPlanCmd.PersistentFlags().String("terraform-plan-output", "", "Filename of cached terraform plan output for this change.") submitPlanCmd.PersistentFlags().String("code-changes-diff", "", "Fileame of the code diff of this change.") - - submitPlanCmd.PersistentFlags().String("timeout", "3m", "How long to wait for responses") } diff --git a/cmd/chnages_start_change.go b/cmd/chnages_start_change.go index 58c6fe27..3f7b154e 100644 --- a/cmd/chnages_start_change.go +++ b/cmd/chnages_start_change.go @@ -116,9 +116,5 @@ func StartChange(ctx context.Context, ready chan bool) int { func init() { changesCmd.AddCommand(startChangeCmd) - withChangeUuidFlags(startChangeCmd) - - startChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") - - startChangeCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") + addChangeUuidFlags(startChangeCmd) } diff --git a/cmd/invites.go b/cmd/invites.go index 18790d87..f896515f 100644 --- a/cmd/invites.go +++ b/cmd/invites.go @@ -18,6 +18,7 @@ var invitesCmd = &cobra.Command{ func init() { rootCmd.AddCommand(invitesCmd) + addAPIFlags(invitesCmd) // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command diff --git a/cmd/invites_crud.go b/cmd/invites_crud.go index cceb5566..5351bd78 100644 --- a/cmd/invites_crud.go +++ b/cmd/invites_crud.go @@ -238,15 +238,12 @@ func InvitesList(ctx context.Context) int { func init() { // list sub-command invitesCmd.AddCommand(listCmd) - listCmd.PersistentFlags().String("invite-url", "", "A custom URL for the invites API (optional)") // create sub-command invitesCmd.AddCommand(createCmd) - createCmd.PersistentFlags().String("invite-url", "", "A custom URL for the invites API (optional)") createCmd.PersistentFlags().StringSlice("emails", []string{}, "A list of emails to invite") // revoke sub-command invitesCmd.AddCommand(revokeCmd) - revokeCmd.PersistentFlags().String("invite-url", "", "A custom URL for the invites API (optional)") revokeCmd.PersistentFlags().String("email", "", "The email address to revoke") } diff --git a/cmd/root.go b/cmd/root.go index 95630146..19c57ceb 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -413,20 +413,23 @@ func parseChangeUrl(changeUrlString string) (uuid.UUID, error) { return changeUuid, nil } -func withChangeUuidFlags(cmd *cobra.Command) { +func addChangeUuidFlags(cmd *cobra.Command) { cmd.PersistentFlags().String("change", "", "The frontend URL of the change to get") cmd.PersistentFlags().String("ticket-link", "", "Link to the ticket for this change.") cmd.PersistentFlags().String("uuid", "", "The UUID of the change that should be displayed.") cmd.MarkFlagsMutuallyExclusive("change", "ticket-link", "uuid") } +// Adds common flags to API commands e.g. timeout +func addAPIFlags(cnd *cobra.Command) { + createBookmarkCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") +} + func init() { cobra.OnInitialize(initConfig) // General Config rootCmd.PersistentFlags().StringVar(&logLevel, "log", "info", "Set the log level. Valid values: panic, fatal, error, warn, info, debug, trace") - - // api endpoint rootCmd.PersistentFlags().String("url", "https://api.prod.overmind.tech", "The overmind API endpoint") // Support API Keys in the environment @@ -440,7 +443,7 @@ func init() { // Mark this as hidden. This means that it will still be parsed of supplied, // and we will still look for it in the environment, but it won't be shown // in the help - rootCmd.Flags().MarkHidden("honeycomb-api-key") + rootCmd.PersistentFlags().MarkHidden("honeycomb-api-key") // Create groups rootCmd.AddGroup(&cobra.Group{ diff --git a/cmd/snapshots.go b/cmd/snapshots.go index 41c66908..29b5bed3 100644 --- a/cmd/snapshots.go +++ b/cmd/snapshots.go @@ -20,6 +20,8 @@ required.`, func init() { rootCmd.AddCommand(snapshotsCmd) + addAPIFlags(snapshotsCmd) + // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command diff --git a/cmd/snapshots_get_snapshot.go b/cmd/snapshots_get_snapshot.go index d6c8d63b..d22c6877 100644 --- a/cmd/snapshots_get_snapshot.go +++ b/cmd/snapshots_get_snapshot.go @@ -91,7 +91,7 @@ func GetSnapshot(ctx context.Context, ready chan bool) int { }) if err != nil { log.WithContext(ctx).WithError(err).WithFields(log.Fields{ - "snapshot-url": viper.GetString("snapshot-url"), + "url": viper.GetString("url"), }).Error("failed to get snapshot") return 1 } @@ -130,10 +130,5 @@ func GetSnapshot(ctx context.Context, ready chan bool) int { func init() { snapshotsCmd.AddCommand(getSnapshotCmd) - getSnapshotCmd.PersistentFlags().String("snapshot-url", "", "The snapshot service API endpoint (defaults to --url)") - getSnapshotCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") - getSnapshotCmd.PersistentFlags().String("uuid", "", "The UUID of the snapshot that should be displayed.") - - getSnapshotCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") } diff --git a/cmd/terraform.go b/cmd/terraform.go index 63079bdf..f9736b7f 100644 --- a/cmd/terraform.go +++ b/cmd/terraform.go @@ -18,6 +18,9 @@ var terraformCmd = &cobra.Command{ func init() { rootCmd.AddCommand(terraformCmd) + // Hide this flag from the Terraform help as we don't want it to be messy + rootCmd.PersistentFlags().MarkHidden("url") + // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command From cfdece1077e4802c9312c00e8845f86317428bb3 Mon Sep 17 00:00:00 2001 From: Dylan Ratcliffe Date: Wed, 14 Feb 2024 13:49:31 +0000 Subject: [PATCH 7/8] Small changes to readme, bug ones will come soon --- README.md | 60 ++++++++++++++++++------------------------------ cmd/root.go | 6 ++--- cmd/terraform.go | 3 --- 3 files changed, 25 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 7b3082eb..97a966b7 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,31 @@ # Overmind CLI -CLI to interact with the overmind API +CLI to interact with the Overmind API ``` Usage: - ovm-cli [command] - -Available Commands: - completion Generate the autocompletion script for the specified shell - create-bookmark Creates a bookmark from JSON. - create-invite Create a new invite - end-change Finishes the specified change. Call this just after you finished the change. This will store a snapshot of the current system state for later reference. - get-affected-bookmarks Calculates the bookmarks that would be overlapping with a snapshot. - get-bookmark Displays the contents of a bookmark. - get-change Displays the contents of a change. - get-snapshot Displays the contents of a snapshot. - help Help about any command - list-changes Displays the contents of a change. - list-invites List all invites - manual-change Creates a new Change from a given query - request Runs a request against the overmind API - revoke-invites Revoke an existing invite - start-change Starts the specified change. Call this just before you're about to start the change. This will store a snapshot of the current system state for later reference. - submit-plan Creates a new Change from a given terraform plan file + overmind [command] + +Infrastructure as Code: + terraform Run Terrafrom with Overmind's change tracking - COMING SOON + +Overmind API: + bookmarks Interact with the bookarks that were created in the Explore view + changes Create, update and delete changes in Overmind + invites Manage invites for your team to Overmind + request Runs a request against the overmind API + snapshots Create, view and delete snapshots if your infrastructure + +Additional Commands: + completion Generate the autocompletion script for the specified shell + help Help about any command Flags: - --api-key string The API key to use for authentication, also read from OVM_API_KEY environment variable - --api-key-url string The overmind API Keys endpoint (defaults to --url) - --auth0-client-id string OAuth Client ID to use when connecting with auth (default "j3LylZtIosVPZtouKI8WuVHmE6Lluva1") - --auth0-domain string Auth0 domain to connect to (default "om-prod.eu.auth0.com") - --gateway-url string The overmind Gateway endpoint (defaults to /api/gateway on --url) - -h, --help help for ovm-cli - --honeycomb-api-key string If specified, configures opentelemetry libraries to submit traces to honeycomb. This requires --otel to be set. - --json-log Set to true to emit logs as json for easier parsing. - --log string Set the log level. Valid values: panic, fatal, error, warn, info, debug, trace (default "info") - --otel If specified, configures opentelemetry and - optionally, see --sentry-dsn - sentry using their default environment configs. - --run-mode string Set the run mode for this service, 'release', 'debug' or 'test'. Defaults to 'release'. (default "release") - --sentry-dsn string If specified, configures sentry libraries to capture errors. This requires --otel to be set. - --stdout-trace-dump Dump all otel traces to stdout for debugging. This requires --otel to be set. - --url string The overmind API endpoint (default "https://api.prod.overmind.tech") - -v, --version version for ovm-cli - -Use "ovm-cli [command] --help" for more information about a command. + -h, --help help for overmind + --log string Set the log level. Valid values: panic, fatal, error, warn, info, debug, trace (default "info") + -v, --version version for overmind + +Use "overmind [command] --help" for more information about a command. ``` ## Examples @@ -50,7 +34,7 @@ Upload a terraform plan to overmind for Blast Radius Analysis: ``` terraform show -json ./tfplan > ./tfplan.json -ovm-cli submit-plan --title "example change" ./tfplan1.json ./tfplan2.json ./tfplan3.json +overmind changes submit-plan --title "example change" ./tfplan1.json ./tfplan2.json ./tfplan3.json ``` ## Terraform ➡ Overmind Mapping diff --git a/cmd/root.go b/cmd/root.go index 19c57ceb..21932bcc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -421,8 +421,9 @@ func addChangeUuidFlags(cmd *cobra.Command) { } // Adds common flags to API commands e.g. timeout -func addAPIFlags(cnd *cobra.Command) { - createBookmarkCmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") +func addAPIFlags(cmd *cobra.Command) { + cmd.PersistentFlags().String("timeout", "5m", "How long to wait for responses") + cmd.PersistentFlags().String("url", "https://api.prod.overmind.tech", "The overmind API endpoint") } func init() { @@ -430,7 +431,6 @@ func init() { // General Config rootCmd.PersistentFlags().StringVar(&logLevel, "log", "info", "Set the log level. Valid values: panic, fatal, error, warn, info, debug, trace") - rootCmd.PersistentFlags().String("url", "https://api.prod.overmind.tech", "The overmind API endpoint") // Support API Keys in the environment err := viper.BindEnv("api-key", "OVM_API_KEY", "API_KEY") diff --git a/cmd/terraform.go b/cmd/terraform.go index f9736b7f..63079bdf 100644 --- a/cmd/terraform.go +++ b/cmd/terraform.go @@ -18,9 +18,6 @@ var terraformCmd = &cobra.Command{ func init() { rootCmd.AddCommand(terraformCmd) - // Hide this flag from the Terraform help as we don't want it to be messy - rootCmd.PersistentFlags().MarkHidden("url") - // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command From e0d033aded9aacb7128d196fa154c4da57eb2d4f Mon Sep 17 00:00:00 2001 From: Dylan Ratcliffe Date: Wed, 14 Feb 2024 13:52:13 +0000 Subject: [PATCH 8/8] Fix linting issues --- cmd/bookmarks.go | 2 +- cmd/changes.go | 2 +- cmd/invites.go | 2 +- cmd/root.go | 5 ++++- cmd/snapshots.go | 2 +- cmd/terraform.go | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cmd/bookmarks.go b/cmd/bookmarks.go index 9e1694f9..38981f43 100644 --- a/cmd/bookmarks.go +++ b/cmd/bookmarks.go @@ -15,7 +15,7 @@ var bookmarksCmd = &cobra.Command{ Long: `A bookmark in Overmind is a set of queries that are stored together and can be executed as a single block.`, Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + _ = cmd.Help() }, } diff --git a/cmd/changes.go b/cmd/changes.go index dbb1ea9f..ac0cbb22 100644 --- a/cmd/changes.go +++ b/cmd/changes.go @@ -13,7 +13,7 @@ var changesCmd = &cobra.Command{ easier to use our IaC wrappers such as 'overmind terraform plan' rather than using these commands directly, but they are provided for flexibility.`, Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + _ = cmd.Help() }, } diff --git a/cmd/invites.go b/cmd/invites.go index f896515f..406f1d86 100644 --- a/cmd/invites.go +++ b/cmd/invites.go @@ -11,7 +11,7 @@ var invitesCmd = &cobra.Command{ Short: "Manage invites for your team to Overmind", Long: `Create and revoke Overmind invitations`, Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + _ = cmd.Help() }, } diff --git a/cmd/root.go b/cmd/root.go index 21932bcc..c75742dc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -443,7 +443,10 @@ func init() { // Mark this as hidden. This means that it will still be parsed of supplied, // and we will still look for it in the environment, but it won't be shown // in the help - rootCmd.PersistentFlags().MarkHidden("honeycomb-api-key") + err = rootCmd.PersistentFlags().MarkHidden("honeycomb-api-key") + if err != nil { + log.WithError(err).Fatal("could not mark `honeycomb-api-key` flag as hidden") + } // Create groups rootCmd.AddGroup(&cobra.Group{ diff --git a/cmd/snapshots.go b/cmd/snapshots.go index 29b5bed3..8604c72f 100644 --- a/cmd/snapshots.go +++ b/cmd/snapshots.go @@ -13,7 +13,7 @@ var snapshotsCmd = &cobra.Command{ however you can use these commands to interact directly with the API if required.`, Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + _ = cmd.Help() }, } diff --git a/cmd/terraform.go b/cmd/terraform.go index 63079bdf..6f96fe0f 100644 --- a/cmd/terraform.go +++ b/cmd/terraform.go @@ -11,7 +11,7 @@ var terraformCmd = &cobra.Command{ Short: "Run Terrafrom with Overmind's change tracking - COMING SOON", Long: `COMING SOON`, Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + _ = cmd.Help() }, }