From 1c09e9c6af0a0b8b15444c8e0116998e58dc8c0b Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 3 Aug 2023 13:59:06 +0200 Subject: [PATCH 1/4] Implement get-change command --- cmd/getchange.go | 160 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 cmd/getchange.go diff --git a/cmd/getchange.go b/cmd/getchange.go new file mode 100644 index 00000000..bdb158bf --- /dev/null +++ b/cmd/getchange.go @@ -0,0 +1,160 @@ +package cmd + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "os" + "os/signal" + "path" + "syscall" + "time" + + "github.com/bufbuild/connect-go" + "github.com/google/uuid" + "github.com/overmindtech/ovm-cli/tracing" + "github.com/overmindtech/sdp-go" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// getChangeCmd represents the get-change command +var getChangeCmd = &cobra.Command{ + Use: "get-change {--uuid ID | --change https://app.overmind.tech/changes/c772d072-6b0b-4763-b7c5-ff5069beed4c}", + Short: "Displays the contents of a change.", + PreRun: func(cmd *cobra.Command, args []string) { + // Bind these to viper + err := viper.BindPFlags(cmd.Flags()) + if err != nil { + log.WithError(err).Fatal("could not bind `get-change` flags") + } + }, + Run: func(cmd *cobra.Command, args []string) { + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + exitcode := GetChange(sigs, nil) + tracing.ShutdownTracer() + os.Exit(exitcode) + }, +} + +func GetChange(signals chan os.Signal, ready chan bool) int { + timeout, err := time.ParseDuration(viper.GetString("timeout")) + if err != nil { + log.Errorf("invalid --timeout value '%v', error: %v", viper.GetString("timeout"), err) + return 1 + } + + var changeUuid uuid.UUID + if viper.GetString("uuid") != "" { + changeUuid, err = uuid.Parse(viper.GetString("uuid")) + if err != nil { + log.Errorf("invalid --uuid value '%v', error: %v", viper.GetString("uuid"), err) + return 1 + } + } + + if viper.GetString("change") != "" { + changeUrl, err := url.ParseRequestURI(viper.GetString("change")) + if err != nil { + log.Errorf("invalid --change value '%v', error: %v", viper.GetString("change"), err) + return 1 + } + changeUuid, err = uuid.Parse(path.Base(changeUrl.Path)) + if err != nil { + log.Errorf("invalid --change value '%v', couldn't parse: %v", viper.GetString("change"), err) + return 1 + } + } + + if changeUuid == uuid.Nil { + log.Error("no change specified; use one of --uuid or --change") + return 1 + } + + ctx := context.Background() + ctx, span := tracing.Tracer().Start(ctx, "CLI GetChange", trace.WithAttributes( + attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), + )) + defer span.End() + + ctx, err = ensureToken(ctx, signals) + if err != nil { + log.WithContext(ctx).WithError(err).WithFields(log.Fields{ + "url": viper.GetString("url"), + }).Error("failed to authenticate") + return 1 + } + + // apply a timeout to the main body of processing + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + client := AuthenticatedChangesClient(ctx) + response, err := client.GetChange(ctx, &connect.Request[sdp.GetChangeRequest]{ + Msg: &sdp.GetChangeRequest{ + UUID: changeUuid[:], + }, + }) + if err != nil { + log.WithContext(ctx).WithError(err).WithFields(log.Fields{ + "change-url": viper.GetString("change-url"), + }).Error("failed to get change") + return 1 + } + log.WithContext(ctx).WithFields(log.Fields{ + "change-uuid": uuid.UUID(response.Msg.Change.Metadata.UUID), + "change-created": response.Msg.Change.Metadata.CreatedAt.AsTime(), + "change-name": response.Msg.Change.Properties.Title, + "change-description": response.Msg.Change.Properties.Description, + }).Info("found change") + + switch viper.GetString("format") { + case "json": + b, _ := json.MarshalIndent(response.Msg.Change, "", " ") + fmt.Println(string(b)) + case "markdown": + changeUrl := fmt.Sprintf("%v/changes/%v", viper.GetString("frontend"), changeUuid.String()) + if response.Msg.Change.Metadata.NumAffectedApps != 0 || response.Msg.Change.Metadata.NumAffectedItems != 0 { + // we have affected stuff + fmt.Printf(`## Blast Radius   ·   [View in Overmind](%v) chain link icon + +> **Warning** +> Overmind identified potentially affected apps and items as a result of this pull request. + +
+ +| icon for blast radius items  Affected items | +| ------------- | +| [%v items](%v) | +`, changeUrl, response.Msg.Change.Metadata.NumAffectedItems, changeUrl) + } else { + fmt.Printf(`## Blast Radius   ·   [View in Overmind](%v) chain link icon + +> **✅ Checks complete** +> Overmind didn't identify any potentially affected apps and items as a result of this pull request. + +`, changeUrl) + } + } + + return 0 +} + +func init() { + rootCmd.AddCommand(getChangeCmd) + + getChangeCmd.PersistentFlags().String("change", "", "The frontend URL of the change to get") + getChangeCmd.PersistentFlags().String("uuid", "", "The UUID of the change that should be displayed.") + getChangeCmd.MarkFlagsMutuallyExclusive("change", "uuid") + + 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", "1m", "How long to wait for responses") +} From 60cc663682ce0910f0c95f50194233a18c72672e Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 3 Aug 2023 14:11:59 +0200 Subject: [PATCH 2/4] Pull changeUuid params and parsing into separate functions --- cmd/getchange.go | 36 ++++++------------------------------ cmd/root.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/cmd/getchange.go b/cmd/getchange.go index bdb158bf..baeaf08b 100644 --- a/cmd/getchange.go +++ b/cmd/getchange.go @@ -4,10 +4,8 @@ import ( "context" "encoding/json" "fmt" - "net/url" "os" "os/signal" - "path" "syscall" "time" @@ -50,33 +48,13 @@ func GetChange(signals chan os.Signal, ready chan bool) int { return 1 } - var changeUuid uuid.UUID - if viper.GetString("uuid") != "" { - changeUuid, err = uuid.Parse(viper.GetString("uuid")) - if err != nil { - log.Errorf("invalid --uuid value '%v', error: %v", viper.GetString("uuid"), err) - return 1 - } - } - - if viper.GetString("change") != "" { - changeUrl, err := url.ParseRequestURI(viper.GetString("change")) - if err != nil { - log.Errorf("invalid --change value '%v', error: %v", viper.GetString("change"), err) - return 1 - } - changeUuid, err = uuid.Parse(path.Base(changeUrl.Path)) - if err != nil { - log.Errorf("invalid --change value '%v', couldn't parse: %v", viper.GetString("change"), err) - return 1 - } - } - - if changeUuid == uuid.Nil { - log.Error("no change specified; use one of --uuid or --change") + changeUuid, err := getChangeUuid() + if err != nil { + log.WithError(err).WithFields(log.Fields{ + "url": viper.GetString("url"), + }).Error("failed to identify change") return 1 } - ctx := context.Background() ctx, span := tracing.Tracer().Start(ctx, "CLI GetChange", trace.WithAttributes( attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), @@ -149,9 +127,7 @@ func GetChange(signals chan os.Signal, ready chan bool) int { func init() { rootCmd.AddCommand(getChangeCmd) - getChangeCmd.PersistentFlags().String("change", "", "The frontend URL of the change to get") - getChangeCmd.PersistentFlags().String("uuid", "", "The UUID of the change that should be displayed.") - getChangeCmd.MarkFlagsMutuallyExclusive("change", "uuid") + withChangeUuid(getChangeCmd) 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") diff --git a/cmd/root.go b/cmd/root.go index b0e5a524..82da7ec6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "os" + "path" "strings" "time" @@ -183,6 +184,43 @@ func ensureToken(ctx context.Context, signals chan os.Signal) (context.Context, return ctx, fmt.Errorf("no --api-key configured and target URL (%v) is insecure", parsed) } +func getChangeUuid() (uuid.UUID, error) { + var changeUuid uuid.UUID + var err error + + if viper.GetString("uuid") != "" { + changeUuid, err = uuid.Parse(viper.GetString("uuid")) + if err != nil { + return uuid.Nil, fmt.Errorf("invalid --uuid value '%v', error: %v", viper.GetString("uuid"), err) + } + } + + if viper.GetString("change") != "" { + changeUrl, err := url.ParseRequestURI(viper.GetString("change")) + if err != nil { + return uuid.Nil, fmt.Errorf("invalid --change value '%v', error: %v", viper.GetString("change"), err) + } + changeUuid, err = uuid.Parse(path.Base(changeUrl.Path)) + if err != nil { + return uuid.Nil, fmt.Errorf("invalid --change value '%v', couldn't parse: %v", viper.GetString("change"), err) + } + } + + if changeUuid == uuid.Nil { + return uuid.Nil, errors.New("no change specified; use one of --uuid or --change") + } + + return changeUuid, nil +} + +func withChangeUuid(cmd *cobra.Command) { + + cmd.PersistentFlags().String("change", "", "The frontend URL of the change to get") + cmd.PersistentFlags().String("uuid", "", "The UUID of the change that should be displayed.") + cmd.MarkFlagsMutuallyExclusive("change", "uuid") + +} + func init() { cobra.OnInitialize(initConfig) From 84c818db4d9bb4e3c19fc1ba910d2f75a1dc7520 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 3 Aug 2023 14:14:37 +0200 Subject: [PATCH 3/4] Add url parsing for start-change and end-change This is analogous to how get-change works --- cmd/endchange.go | 15 ++++++++------- cmd/getchange.go | 1 + cmd/startchange.go | 15 ++++++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/cmd/endchange.go b/cmd/endchange.go index c6aa13fd..64a3309e 100644 --- a/cmd/endchange.go +++ b/cmd/endchange.go @@ -9,7 +9,6 @@ import ( "time" "github.com/bufbuild/connect-go" - "github.com/google/uuid" "github.com/overmindtech/ovm-cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" @@ -47,9 +46,11 @@ func EndChange(signals chan os.Signal, ready chan bool) int { return 1 } - snapshotUuid, err := uuid.Parse(viper.GetString("uuid")) + changeUuid, err := getChangeUuid() if err != nil { - log.Errorf("invalid --uuid value '%v', error: %v", viper.GetString("uuid"), err) + log.WithError(err).WithFields(log.Fields{ + "url": viper.GetString("url"), + }).Error("failed to identify change") return 1 } @@ -60,7 +61,7 @@ func EndChange(signals chan os.Signal, ready chan bool) int { defer span.End() lf := log.Fields{ - "uuid": snapshotUuid.String(), + "uuid": changeUuid.String(), } ctx, err = ensureToken(ctx, signals) @@ -77,7 +78,7 @@ func EndChange(signals chan os.Signal, ready chan bool) int { client := AuthenticatedChangesClient(ctx) stream, err := client.EndChange(ctx, &connect.Request[sdp.EndChangeRequest]{ Msg: &sdp.EndChangeRequest{ - ChangeUUID: snapshotUuid[:], + ChangeUUID: changeUuid[:], }, }) if err != nil { @@ -100,9 +101,9 @@ func EndChange(signals chan os.Signal, ready chan bool) int { func init() { rootCmd.AddCommand(endChangeCmd) - endChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") + withChangeUuid(endChangeCmd) - endChangeCmd.PersistentFlags().String("uuid", "", "The UUID of the snapshot that should be displayed.") + endChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") endChangeCmd.PersistentFlags().String("timeout", "1m", "How long to wait for responses") } diff --git a/cmd/getchange.go b/cmd/getchange.go index baeaf08b..931ba714 100644 --- a/cmd/getchange.go +++ b/cmd/getchange.go @@ -55,6 +55,7 @@ func GetChange(signals chan os.Signal, ready chan bool) int { }).Error("failed to identify change") return 1 } + ctx := context.Background() ctx, span := tracing.Tracer().Start(ctx, "CLI GetChange", trace.WithAttributes( attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), diff --git a/cmd/startchange.go b/cmd/startchange.go index e7095db7..3bb5f5c3 100644 --- a/cmd/startchange.go +++ b/cmd/startchange.go @@ -9,7 +9,6 @@ import ( "time" "github.com/bufbuild/connect-go" - "github.com/google/uuid" "github.com/overmindtech/ovm-cli/tracing" "github.com/overmindtech/sdp-go" log "github.com/sirupsen/logrus" @@ -47,9 +46,11 @@ func StartChange(signals chan os.Signal, ready chan bool) int { return 1 } - snapshotUuid, err := uuid.Parse(viper.GetString("uuid")) + changeUuid, err := getChangeUuid() if err != nil { - log.Errorf("invalid --uuid value '%v', error: %v", viper.GetString("uuid"), err) + log.WithError(err).WithFields(log.Fields{ + "url": viper.GetString("url"), + }).Error("failed to identify change") return 1 } @@ -60,7 +61,7 @@ func StartChange(signals chan os.Signal, ready chan bool) int { defer span.End() lf := log.Fields{ - "uuid": snapshotUuid.String(), + "uuid": changeUuid.String(), } ctx, err = ensureToken(ctx, signals) @@ -77,7 +78,7 @@ func StartChange(signals chan os.Signal, ready chan bool) int { client := AuthenticatedChangesClient(ctx) stream, err := client.StartChange(ctx, &connect.Request[sdp.StartChangeRequest]{ Msg: &sdp.StartChangeRequest{ - ChangeUUID: snapshotUuid[:], + ChangeUUID: changeUuid[:], }, }) if err != nil { @@ -100,9 +101,9 @@ func StartChange(signals chan os.Signal, ready chan bool) int { func init() { rootCmd.AddCommand(startChangeCmd) - startChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") + withChangeUuid(startChangeCmd) - startChangeCmd.PersistentFlags().String("uuid", "", "The UUID of the snapshot that should be displayed.") + startChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") startChangeCmd.PersistentFlags().String("timeout", "1m", "How long to wait for responses") } From 708212678ae31bcba30061fbfcd83f6553bf03b6 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Thu, 3 Aug 2023 14:45:54 +0200 Subject: [PATCH 4/4] Add lookup by status and ticket link to getChangeUuid and extend *-change commands to use it --- cmd/endchange.go | 27 +++++++++++++-------------- cmd/getchange.go | 24 +++++++++++++----------- cmd/root.go | 38 +++++++++++++++++++++++++++++++------- cmd/startchange.go | 27 +++++++++++++-------------- cmd/submitplan.go | 34 ++++++++++------------------------ 5 files changed, 80 insertions(+), 70 deletions(-) diff --git a/cmd/endchange.go b/cmd/endchange.go index 64a3309e..10bd07a6 100644 --- a/cmd/endchange.go +++ b/cmd/endchange.go @@ -46,27 +46,17 @@ func EndChange(signals chan os.Signal, ready chan bool) int { return 1 } - changeUuid, err := getChangeUuid() - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "url": viper.GetString("url"), - }).Error("failed to identify change") - return 1 - } - ctx := context.Background() ctx, span := tracing.Tracer().Start(ctx, "CLI EndChange", trace.WithAttributes( attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), )) defer span.End() - lf := log.Fields{ - "uuid": changeUuid.String(), - } - ctx, err = ensureToken(ctx, signals) if err != nil { - log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate") + log.WithContext(ctx).WithFields(log.Fields{ + "url": viper.GetString("url"), + }).WithError(err).Error("failed to authenticate") return 1 } @@ -74,6 +64,15 @@ func EndChange(signals chan os.Signal, ready chan bool) int { ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() + lf := log.Fields{} + changeUuid, err := getChangeUuid(ctx, sdp.ChangeStatus_CHANGE_STATUS_HAPPENING) + if err != nil { + log.WithError(err).WithFields(lf).Error("failed to identify change") + return 1 + } + + lf["uuid"] = changeUuid.String() + // snapClient := AuthenticatedSnapshotsClient(ctx) client := AuthenticatedChangesClient(ctx) stream, err := client.EndChange(ctx, &connect.Request[sdp.EndChangeRequest]{ @@ -101,7 +100,7 @@ func EndChange(signals chan os.Signal, ready chan bool) int { func init() { rootCmd.AddCommand(endChangeCmd) - withChangeUuid(endChangeCmd) + withChangeUuidFlags(endChangeCmd) endChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") diff --git a/cmd/getchange.go b/cmd/getchange.go index 931ba714..b342545e 100644 --- a/cmd/getchange.go +++ b/cmd/getchange.go @@ -48,14 +48,6 @@ func GetChange(signals chan os.Signal, ready chan bool) int { return 1 } - changeUuid, err := getChangeUuid() - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "url": viper.GetString("url"), - }).Error("failed to identify change") - return 1 - } - ctx := context.Background() ctx, span := tracing.Tracer().Start(ctx, "CLI GetChange", trace.WithAttributes( attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), @@ -64,9 +56,9 @@ func GetChange(signals chan os.Signal, ready chan bool) int { ctx, err = ensureToken(ctx, signals) if err != nil { - log.WithContext(ctx).WithError(err).WithFields(log.Fields{ + log.WithContext(ctx).WithFields(log.Fields{ "url": viper.GetString("url"), - }).Error("failed to authenticate") + }).WithError(err).Error("failed to authenticate") return 1 } @@ -74,6 +66,15 @@ func GetChange(signals chan os.Signal, ready chan bool) int { ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() + lf := log.Fields{} + changeUuid, err := getChangeUuid(ctx, sdp.ChangeStatus(sdp.ChangeStatus_value[viper.GetString("status")])) + if err != nil { + log.WithError(err).WithFields(lf).Error("failed to identify change") + return 1 + } + + lf["uuid"] = changeUuid.String() + client := AuthenticatedChangesClient(ctx) response, err := client.GetChange(ctx, &connect.Request[sdp.GetChangeRequest]{ Msg: &sdp.GetChangeRequest{ @@ -128,7 +129,8 @@ func GetChange(signals chan os.Signal, ready chan bool) int { func init() { rootCmd.AddCommand(getChangeCmd) - withChangeUuid(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") 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") diff --git a/cmd/root.go b/cmd/root.go index 82da7ec6..42274cc9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -184,7 +184,8 @@ func ensureToken(ctx context.Context, signals chan os.Signal) (context.Context, return ctx, fmt.Errorf("no --api-key configured and target URL (%v) is insecure", parsed) } -func getChangeUuid() (uuid.UUID, error) { +// getChangeUuid returns the UUID of a change, as selected by --uuid or --change, or a state with the specified status and having --ticket-link +func getChangeUuid(ctx context.Context, expectedStatus sdp.ChangeStatus) (uuid.UUID, error) { var changeUuid uuid.UUID var err error @@ -206,19 +207,42 @@ func getChangeUuid() (uuid.UUID, error) { } } - if changeUuid == uuid.Nil { - return uuid.Nil, errors.New("no change specified; use one of --uuid or --change") + if viper.GetString("ticket-link") != "" { + client := AuthenticatedChangesClient(ctx) + + var maybeChangeUuid *uuid.UUID + changesList, err := client.ListChangesByStatus(ctx, &connect.Request[sdp.ListChangesByStatusRequest]{ + Msg: &sdp.ListChangesByStatusRequest{ + Status: expectedStatus, + }, + }) + if err != nil { + return uuid.Nil, errors.New("failed to searching for existing changes") + } + + for _, c := range changesList.Msg.Changes { + if c.Properties.TicketLink == viper.GetString("ticket-link") { + maybeChangeUuid = c.Metadata.GetUUIDParsed() + if maybeChangeUuid != nil { + changeUuid = *maybeChangeUuid + break + } + } + } } + // if changeUuid == uuid.Nil { + // return uuid.Nil, errors.New("no change specified; use one of --change, --ticket-link or --uuid") + // } + return changeUuid, nil } -func withChangeUuid(cmd *cobra.Command) { - +func withChangeUuidFlags(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", "uuid") - + cmd.MarkFlagsMutuallyExclusive("change", "ticket-link", "uuid") } func init() { diff --git a/cmd/startchange.go b/cmd/startchange.go index 3bb5f5c3..86528310 100644 --- a/cmd/startchange.go +++ b/cmd/startchange.go @@ -46,27 +46,17 @@ func StartChange(signals chan os.Signal, ready chan bool) int { return 1 } - changeUuid, err := getChangeUuid() - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "url": viper.GetString("url"), - }).Error("failed to identify change") - return 1 - } - ctx := context.Background() ctx, span := tracing.Tracer().Start(ctx, "CLI StartChange", trace.WithAttributes( attribute.String("om.config", fmt.Sprintf("%v", viper.AllSettings())), )) defer span.End() - lf := log.Fields{ - "uuid": changeUuid.String(), - } - ctx, err = ensureToken(ctx, signals) if err != nil { - log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate") + log.WithContext(ctx).WithFields(log.Fields{ + "url": viper.GetString("url"), + }).WithError(err).Error("failed to authenticate") return 1 } @@ -74,6 +64,15 @@ func StartChange(signals chan os.Signal, ready chan bool) int { ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() + lf := log.Fields{} + changeUuid, err := getChangeUuid(ctx, sdp.ChangeStatus_CHANGE_STATUS_DEFINING) + if err != nil { + log.WithError(err).WithFields(lf).Error("failed to identify change") + return 1 + } + + lf["uuid"] = changeUuid.String() + // snapClient := AuthenticatedSnapshotsClient(ctx) client := AuthenticatedChangesClient(ctx) stream, err := client.StartChange(ctx, &connect.Request[sdp.StartChangeRequest]{ @@ -101,7 +100,7 @@ func StartChange(signals chan os.Signal, ready chan bool) int { func init() { rootCmd.AddCommand(startChangeCmd) - withChangeUuid(startChangeCmd) + withChangeUuidFlags(startChangeCmd) startChangeCmd.PersistentFlags().String("frontend", "https://app.overmind.tech/", "The frontend base URL") diff --git a/cmd/submitplan.go b/cmd/submitplan.go index b555ae62..89838823 100644 --- a/cmd/submitplan.go +++ b/cmd/submitplan.go @@ -221,29 +221,13 @@ func SubmitPlan(signals chan os.Signal, ready chan bool) int { } client := AuthenticatedChangesClient(ctx) - - var changeUUID *uuid.UUID - - changesList, err := client.ListChangesByStatus(ctx, &connect.Request[sdp.ListChangesByStatusRequest]{ - Msg: &sdp.ListChangesByStatusRequest{ - Status: sdp.ChangeStatus_CHANGE_STATUS_DEFINING, - }, - }) + changeUuid, err := getChangeUuid(ctx, sdp.ChangeStatus_CHANGE_STATUS_DEFINING) if err != nil { log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to searching for existing changes") return 1 } - for _, c := range changesList.Msg.Changes { - if c.Properties.TicketLink == viper.GetString("ticket-link") { - changeUUID = c.Metadata.GetUUIDParsed() - if changeUUID != nil { - break - } - } - } - - if changeUUID == nil { + if changeUuid == uuid.Nil { createResponse, err := client.CreateChange(ctx, &connect.Request[sdp.CreateChangeRequest]{ Msg: &sdp.CreateChangeRequest{ Properties: &sdp.ChangeProperties{ @@ -260,14 +244,16 @@ func SubmitPlan(signals chan os.Signal, ready chan bool) int { return 1 } - changeUUID = createResponse.Msg.Change.Metadata.GetUUIDParsed() - if changeUUID == nil { + maybeChangeUuid := createResponse.Msg.Change.Metadata.GetUUIDParsed() + if maybeChangeUuid == nil { log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to read change id") return 1 } + + changeUuid = *maybeChangeUuid } - lf["change"] = changeUUID + lf["change"] = changeUuid log.WithContext(ctx).WithFields(lf).Info("created a new change") receivedItems := []*sdp.Reference{} @@ -449,7 +435,7 @@ func SubmitPlan(signals chan os.Signal, ready chan bool) int { } resultStream, err := client.UpdateChangingItems(ctx, &connect.Request[sdp.UpdateChangingItemsRequest]{ Msg: &sdp.UpdateChangingItemsRequest{ - ChangeUUID: (*changeUUID)[:], + ChangeUUID: changeUuid[:], ChangingItems: receivedItems, }, }) @@ -478,13 +464,13 @@ func SubmitPlan(signals chan os.Signal, ready chan bool) int { } } - changeUrl := fmt.Sprintf("%v/changes/%v", viper.GetString("frontend"), changeUUID) + changeUrl := fmt.Sprintf("%v/changes/%v", viper.GetString("frontend"), changeUuid) log.WithContext(ctx).WithFields(lf).WithField("change-url", changeUrl).Info("change ready") fmt.Println(changeUrl) fetchResponse, err := client.GetChange(ctx, &connect.Request[sdp.GetChangeRequest]{ Msg: &sdp.GetChangeRequest{ - UUID: (*changeUUID)[:], + UUID: changeUuid[:], }, }) if err != nil {