From 333b7b386d0ba3e4f99536ca7e996910939311f1 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 24 Nov 2025 13:59:34 -0500 Subject: [PATCH 01/13] Datadog Alert CRUD --- pkg/argparser/common.go | 4 + pkg/commands/commands.go | 16 + .../ngwaf/workspace/alert/common/builder.go | 8 + .../ngwaf/workspace/alert/common/doc.go | 2 + .../ngwaf/workspace/alert/common/flags.go | 29 ++ .../ngwaf/workspace/alert/datadog/create.go | 96 ++++++ .../ngwaf/workspace/alert/datadog/delete.go | 94 ++++++ .../ngwaf/workspace/alert/datadog/doc.go | 2 + .../ngwaf/workspace/alert/datadog/get.go | 88 ++++++ .../ngwaf/workspace/alert/datadog/list.go | 80 +++++ .../ngwaf/workspace/alert/datadog/root.go | 31 ++ .../ngwaf/workspace/alert/datadog/update.go | 97 ++++++ pkg/commands/ngwaf/workspace/alert/doc.go | 2 + pkg/commands/ngwaf/workspace/alert/root.go | 31 ++ pkg/text/alerts.go | 282 ++++++++++++++++++ 15 files changed, 862 insertions(+) create mode 100644 pkg/commands/ngwaf/workspace/alert/common/builder.go create mode 100644 pkg/commands/ngwaf/workspace/alert/common/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/common/flags.go create mode 100644 pkg/commands/ngwaf/workspace/alert/datadog/create.go create mode 100644 pkg/commands/ngwaf/workspace/alert/datadog/delete.go create mode 100644 pkg/commands/ngwaf/workspace/alert/datadog/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/datadog/get.go create mode 100644 pkg/commands/ngwaf/workspace/alert/datadog/list.go create mode 100644 pkg/commands/ngwaf/workspace/alert/datadog/root.go create mode 100644 pkg/commands/ngwaf/workspace/alert/datadog/update.go create mode 100644 pkg/commands/ngwaf/workspace/alert/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/root.go create mode 100644 pkg/text/alerts.go diff --git a/pkg/argparser/common.go b/pkg/argparser/common.go index 5a92eb7fe..5800637ba 100644 --- a/pkg/argparser/common.go +++ b/pkg/argparser/common.go @@ -9,6 +9,10 @@ var ( FlagJSONName = "json" // FlagJSONDesc is the flag description. FlagJSONDesc = "Render output as JSON" + // FlagNGWAFAlertID is the alert ID. + FlagNGWAFAlertID = "alert-id" + // FlagNGWAFAlertIDDesc + FlagNGWAFAlertIDDesc = "Alphanumeric string identifying the alert" // FlagNGWAFWorkspaceID is the workspace ID. FlagNGWAFWorkspaceID = "workspace-id" // FlagNGWAFWorkspaceIDDesc is the workspace ID flag description. diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index bf2328c21..61e3fde57 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -58,6 +58,8 @@ import ( "github.com/fastly/cli/pkg/commands/ngwaf" "github.com/fastly/cli/pkg/commands/ngwaf/virtualpatch" "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + workspaceAlertDatadog "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/datadog" "github.com/fastly/cli/pkg/commands/objectstorage" "github.com/fastly/cli/pkg/commands/objectstorage/accesskeys" "github.com/fastly/cli/pkg/commands/pop" @@ -407,6 +409,13 @@ func Define( // nolint:revive // function-length ngwafWorkspacesGet := workspace.NewGetCommand(ngwafWorkspacesRoot.CmdClause, data) ngwafWorkspacesList := workspace.NewListCommand(ngwafWorkspacesRoot.CmdClause, data) ngwafWorkspacesUpdate := workspace.NewUpdateCommand(ngwafWorkspacesRoot.CmdClause, data) + ngwafWorkspacesAlertRoot := alert.NewRootCommand(ngwafWorkspacesRoot.CmdClause, data) + ngwafWorkspacesAlertDatadogRoot := workspaceAlertDatadog.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) + ngwafWorkspacesAlertDatadogCreate := workspaceAlertDatadog.NewCreateCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) + ngwafWorkspacesAlertDatadogDelete := workspaceAlertDatadog.NewDeleteCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) + ngwafWorkspacesAlertDatadogGet := workspaceAlertDatadog.NewGetCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) + ngwafWorkspacesAlertDatadogList := workspaceAlertDatadog.NewListCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) + ngwafWorkspacesAlertDatadogUpdate := workspaceAlertDatadog.NewUpdateCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) objectStorageRoot := objectstorage.NewRootCommand(app, data) objectStorageAccesskeysRoot := accesskeys.NewRootCommand(objectStorageRoot.CmdClause, data) objectStorageAccesskeysCreate := accesskeys.NewCreateCommand(objectStorageAccesskeysRoot.CmdClause, data) @@ -837,6 +846,13 @@ func Define( // nolint:revive // function-length ngwafWorkspacesGet, ngwafWorkspacesList, ngwafWorkspacesUpdate, + ngwafWorkspacesAlertRoot, + ngwafWorkspacesAlertDatadogRoot, + ngwafWorkspacesAlertDatadogCreate, + ngwafWorkspacesAlertDatadogDelete, + ngwafWorkspacesAlertDatadogGet, + ngwafWorkspacesAlertDatadogList, + ngwafWorkspacesAlertDatadogUpdate, objectStorageRoot, objectStorageAccesskeysRoot, objectStorageAccesskeysCreate, diff --git a/pkg/commands/ngwaf/workspace/alert/common/builder.go b/pkg/commands/ngwaf/workspace/alert/common/builder.go new file mode 100644 index 000000000..497bd14a6 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/common/builder.go @@ -0,0 +1,8 @@ +package common + +// GetDefaultEvents returns the hardcoded events value for all alerts. +// Currently the only supported value is "flag". +func GetDefaultEvents() *[]string { + events := []string{"flag"} + return &events +} diff --git a/pkg/commands/ngwaf/workspace/alert/common/doc.go b/pkg/commands/ngwaf/workspace/alert/common/doc.go new file mode 100644 index 000000000..0fadce1a2 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/common/doc.go @@ -0,0 +1,2 @@ +// Package common contains shared types and helpers for NGWAF alert commands. +package common diff --git a/pkg/commands/ngwaf/workspace/alert/common/flags.go b/pkg/commands/ngwaf/workspace/alert/common/flags.go new file mode 100644 index 000000000..35d56898e --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/common/flags.go @@ -0,0 +1,29 @@ +package common + +import "github.com/fastly/cli/pkg/argparser" + +// BaseAlertFlags contains flags that are common to all alert commands. +type BaseAlertFlags struct { + WorkspaceID argparser.OptionalWorkspaceID +} + +// AlertIDFlags contains flags for identifying a specific alert (used in update/delete/get). +type AlertIDFlags struct { + AlertID string +} + +// AlertDataFlags contains optional data fields for alerts (used in create/update). +type AlertDataFlags struct { + Description argparser.OptionalString +} + +// DatadogConfigFlags contains Datadog specific configuration flags. +type DatadogConfigFlags struct { + Key string + Site string +} + +// WebhookConfigFlags contains webhook URL configrations (used by webhook, slack, etc...) +type WebhookConfigFlags struct { + Webhook string +} diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/create.go b/pkg/commands/ngwaf/workspace/alert/datadog/create.go new file mode 100644 index 000000000..5b776b86f --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/datadog/create.go @@ -0,0 +1,96 @@ +package datadog + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/datadog" +) + +// CreateCommand calls the Fastly API to create Datadog alerts. +type CreateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags + common.DatadogConfigFlags + + // Optional. + common.AlertDataFlags +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { + c := CreateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("create", "Create a Datadog alert").Alias("add") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + }) + c.CmdClause.Flag("key", "Datadog integration key.").Required().StringVar(&c.Key) + c.CmdClause.Flag("site", "Datadog site.").Required().StringVar(&c.Site) + + // Optional. + c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + input := &datadog.CreateInput{ + WorkspaceID: &c.WorkspaceID.Value, + Config: &datadog.CreateConfig{ + Key: &c.Key, + Site: &c.Site, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + if c.Description.WasSet { + input.Description = &c.Description.Value + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := datadog.Create(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Created a '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go new file mode 100644 index 000000000..d27891bc5 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go @@ -0,0 +1,94 @@ +package datadog + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/datadog" +) + +// DeleteCommand calls the Fastly API to delete Datadog alerts. +type DeleteCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand { + c := DeleteCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("delete", "Delete a Datadog alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + err := datadog.Delete(context.TODO(), fc, &datadog.DeleteInput{ + WorkspaceID: &c.WorkspaceID.Value, + AlertID: &c.AlertID, + }) + if err != nil { + return err + } + + if c.JSONOutput.Enabled { + o := struct { + ID string `json:"id"` + Deleted bool `json:"deleted"` + }{ + c.AlertID, + true, + } + _, err := c.WriteJSON(out, o) + return err + } + + text.Success(out, "Deleted alert '%s' (workspace-id: %s)", c.AlertID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/doc.go b/pkg/commands/ngwaf/workspace/alert/datadog/doc.go new file mode 100644 index 000000000..717e21995 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/datadog/doc.go @@ -0,0 +1,2 @@ +// Package datadog contains commands to inspect and manipulate NGWAF Datadog alerts. +package datadog diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/get.go b/pkg/commands/ngwaf/workspace/alert/datadog/get.go new file mode 100644 index 000000000..a83a7d8c8 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/datadog/get.go @@ -0,0 +1,88 @@ +package datadog + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/datadog" +) + +// GetCommand calls the Fastly API to get Datadog alerts. +type GetCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetCommand returns a usable command registered under the parent. +func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { + c := GetCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get", "Get a Datadog alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &datadog.GetInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := datadog.Get(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlert(out, data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/list.go b/pkg/commands/ngwaf/workspace/alert/datadog/list.go new file mode 100644 index 000000000..a08babe58 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/datadog/list.go @@ -0,0 +1,80 @@ +package datadog + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/datadog" +) + +// ListCommand calls the Fastly API to list Datadog alerts. +type ListCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { + c := ListCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("list", "List Datadog alerts") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &datadog.ListInput{ + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := datadog.List(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlertTbl(out, data.Data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/root.go b/pkg/commands/ngwaf/workspace/alert/datadog/root.go new file mode 100644 index 000000000..725dceacc --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/datadog/root.go @@ -0,0 +1,31 @@ +package datadog + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "datadog" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage Datadog workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/update.go b/pkg/commands/ngwaf/workspace/alert/datadog/update.go new file mode 100644 index 000000000..1ec821443 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/datadog/update.go @@ -0,0 +1,97 @@ +package datadog + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/datadog" +) + +// UpdateCommand calls the Fastly API to update Datadog alerts. +type UpdateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags + common.DatadogConfigFlags +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { + c := UpdateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("update", "Update a Datadog alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + c.CmdClause.Flag("key", "Datadog integration key.").Required().StringVar(&c.Key) + c.CmdClause.Flag("site", "Datadog site.").Required().StringVar(&c.Site) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + input := &datadog.UpdateInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + Config: &datadog.UpdateConfig{ + Key: &c.Key, + Site: &c.Site, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := datadog.Update(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Updated '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/doc.go b/pkg/commands/ngwaf/workspace/alert/doc.go new file mode 100644 index 000000000..b8072fb1f --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/doc.go @@ -0,0 +1,2 @@ +// Package alert contains commands to inspect and manipulate NGWAF alerts. +package alert diff --git a/pkg/commands/ngwaf/workspace/alert/root.go b/pkg/commands/ngwaf/workspace/alert/root.go new file mode 100644 index 000000000..c61c3c2dc --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/root.go @@ -0,0 +1,31 @@ +package alert + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "alert" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/text/alerts.go b/pkg/text/alerts.go new file mode 100644 index 000000000..01c6e5539 --- /dev/null +++ b/pkg/text/alerts.go @@ -0,0 +1,282 @@ +package text + +import ( + "fmt" + "io" + "strings" + + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/datadog" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/jira" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/mailinglist" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/microsoftteams" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/opsgenie" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/pagerduty" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/slack" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +// PrintAlert displays a single alert. +// Accepts any alert type (datadog, slack, webhook, etc.) via any. +func PrintAlert(out io.Writer, alert any) { + var id, alertType, description, createdAt, createdBy string + var config any + + // Extract common fields based on type + switch a := alert.(type) { + case *datadog.Alert: + id = a.ID + alertType = a.Type + description = a.Description + createdAt = a.CreatedAt + createdBy = a.CreatedBy + config = a.Config + case *jira.Alert: + id = a.ID + alertType = a.Type + description = a.Description + createdAt = a.CreatedAt + createdBy = a.CreatedBy + config = a.Config + case *mailinglist.Alert: + id = a.ID + alertType = a.Type + description = a.Description + createdAt = a.CreatedAt + createdBy = a.CreatedBy + config = a.Config + case *microsoftteams.Alert: + id = a.ID + alertType = a.Type + description = a.Description + createdAt = a.CreatedAt + createdBy = a.CreatedBy + config = a.Config + case *opsgenie.Alert: + id = a.ID + alertType = a.Type + description = a.Description + createdAt = a.CreatedAt + createdBy = a.CreatedBy + config = a.Config + case *pagerduty.Alert: + id = a.ID + alertType = a.Type + description = a.Description + createdAt = a.CreatedAt + createdBy = a.CreatedBy + config = a.Config + case *slack.Alert: + id = a.ID + alertType = a.Type + description = a.Description + createdAt = a.CreatedAt + createdBy = a.CreatedBy + config = a.Config + case *webhook.Alert: + id = a.ID + alertType = a.Type + description = a.Description + createdAt = a.CreatedAt + createdBy = a.CreatedBy + config = a.Config + default: + fmt.Fprintf(out, "Unknown alert type\n") + return + } + + fmt.Fprintf(out, "ID: %s\n", id) + fmt.Fprintf(out, "Type: %s\n", alertType) + fmt.Fprintf(out, "Description: %s\n", description) + fmt.Fprintf(out, "Created At: %s\n", createdAt) + fmt.Fprintf(out, "Created By: %s\n", createdBy) + printAlertConfig(out, alertType, config) +} + +// printAlertConfig prints alert configuration based on type. +func printAlertConfig(out io.Writer, alertType string, config any) { + fmt.Fprint(out, "Config:\n") + switch alertType { + case "datadog": + printDatadogConfig(out, config) + case "jira": + printJiraConfig(out, config) + case "mailinglist": + printMailingListConfig(out, config) + case "microsoftteams", "slack", "webhook": + printWebhookConfig(out, config) + case "opsgenie", "pagerduty": + printKeyConfig(out, config) + default: + fmt.Fprintf(out, " (unknown type: %s)\n", alertType) + } +} + +// printDatadogConfig prints Datadog-specific configuration. +func printDatadogConfig(out io.Writer, config any) { + if cfg, ok := config.(datadog.ResponseConfig); ok { + if cfg.Key != nil { + fmt.Fprintf(out, " Key: \n") + } + if cfg.Site != nil { + fmt.Fprintf(out, " Site: %s\n", *cfg.Site) + } + } +} + +// printWebhookConfig prints webhook-based configuration (slack, webhook, microsoftteams). +func printWebhookConfig(out io.Writer, config any) { + var hasWebhook bool + + switch cfg := config.(type) { + case slack.ResponseConfig: + hasWebhook = cfg.Webhook != nil + case webhook.ResponseConfig: + hasWebhook = cfg.Webhook != nil + case microsoftteams.ResponseConfig: + hasWebhook = cfg.Webhook != nil + } + + if hasWebhook { + fmt.Fprintf(out, " Webhook: \n") + } +} + +// printJiraConfig prints Jira-specific configuration. +func printJiraConfig(out io.Writer, config any) { + if cfg, ok := config.(jira.ResponseConfig); ok { + if cfg.Host != nil { + fmt.Fprintf(out, " Host: %s\n", *cfg.Host) + } + if cfg.Username != nil { + fmt.Fprintf(out, " Username: %s\n", *cfg.Username) + } + if cfg.Project != nil { + fmt.Fprintf(out, " Project: %s\n", *cfg.Project) + } + if cfg.IssueType != nil { + fmt.Fprintf(out, " Issue Type: %s\n", *cfg.IssueType) + } + if cfg.Key != nil { + fmt.Fprintf(out, " Key: \n") + } + } +} + +// printMailingListConfig prints Mailing List-specific configuration. +func printMailingListConfig(out io.Writer, config any) { + if cfg, ok := config.(mailinglist.ResponseConfig); ok { + if cfg.Address != nil { + fmt.Fprintf(out, " Address: %s\n", *cfg.Address) + } + } +} + +// printKeyConfig prints key-based configuration (opsgenie, pagerduty). +func printKeyConfig(out io.Writer, config any) { + var hasKey bool + + switch cfg := config.(type) { + case opsgenie.ResponseConfig: + hasKey = cfg.Key != nil + case pagerduty.ResponseConfig: + hasKey = cfg.Key != nil + } + + if hasKey { + fmt.Fprintf(out, " Key: \n") + } +} + +// getConfigSummary returns a string summary of the alert config with sensitive fields redacted. +func getConfigSummary(alertType string, config any) string { + switch alertType { + case "datadog": + if cfg, ok := config.(datadog.ResponseConfig); ok { + parts := []string{} + if cfg.Site != nil { + parts = append(parts, fmt.Sprintf("Site: %s", *cfg.Site)) + } + if cfg.Key != nil { + parts = append(parts, "Key: ") + } + return strings.Join(parts, ", ") + } + case "jira": + if cfg, ok := config.(jira.ResponseConfig); ok { + parts := []string{} + if cfg.Host != nil { + parts = append(parts, fmt.Sprintf("Host: %s", *cfg.Host)) + } + if cfg.Project != nil { + parts = append(parts, fmt.Sprintf("Project: %s", *cfg.Project)) + } + if cfg.Key != nil { + parts = append(parts, "Key: ") + } + return strings.Join(parts, ", ") + } + case "mailinglist": + if cfg, ok := config.(mailinglist.ResponseConfig); ok { + if cfg.Address != nil { + return fmt.Sprintf("Address: %s", *cfg.Address) + } + } + case "microsoftteams", "slack", "webhook": + return "Webhook: " + case "opsgenie", "pagerduty": + return "Key: " + } + return "" +} + +// PrintAlertTbl prints a table of alerts. +func PrintAlertTbl(out io.Writer, alerts any) { + tbl := NewTable(out) + tbl.AddHeader("ID", "Type", "Description", "Created At", "Created By", "Config") + + // Handle different alert type slices + switch a := alerts.(type) { + case []datadog.Alert: + for _, alert := range a { + configSummary := getConfigSummary(alert.Type, alert.Config) + tbl.AddLine(alert.ID, alert.Type, alert.Description, alert.CreatedAt, alert.CreatedBy, configSummary) + } + case []slack.Alert: + for _, alert := range a { + configSummary := getConfigSummary(alert.Type, alert.Config) + tbl.AddLine(alert.ID, alert.Type, alert.Description, alert.CreatedAt, alert.CreatedBy, configSummary) + } + case []webhook.Alert: + for _, alert := range a { + configSummary := getConfigSummary(alert.Type, alert.Config) + tbl.AddLine(alert.ID, alert.Type, alert.Description, alert.CreatedAt, alert.CreatedBy, configSummary) + } + case []jira.Alert: + for _, alert := range a { + configSummary := getConfigSummary(alert.Type, alert.Config) + tbl.AddLine(alert.ID, alert.Type, alert.Description, alert.CreatedAt, alert.CreatedBy, configSummary) + } + case []mailinglist.Alert: + for _, alert := range a { + configSummary := getConfigSummary(alert.Type, alert.Config) + tbl.AddLine(alert.ID, alert.Type, alert.Description, alert.CreatedAt, alert.CreatedBy, configSummary) + } + case []microsoftteams.Alert: + for _, alert := range a { + configSummary := getConfigSummary(alert.Type, alert.Config) + tbl.AddLine(alert.ID, alert.Type, alert.Description, alert.CreatedAt, alert.CreatedBy, configSummary) + } + case []opsgenie.Alert: + for _, alert := range a { + configSummary := getConfigSummary(alert.Type, alert.Config) + tbl.AddLine(alert.ID, alert.Type, alert.Description, alert.CreatedAt, alert.CreatedBy, configSummary) + } + case []pagerduty.Alert: + for _, alert := range a { + configSummary := getConfigSummary(alert.Type, alert.Config) + tbl.AddLine(alert.ID, alert.Type, alert.Description, alert.CreatedAt, alert.CreatedBy, configSummary) + } + } + + tbl.Print() +} From 57374f9df3cb7dcc4b02d28ee654d45e67af024d Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 24 Nov 2025 15:21:57 -0500 Subject: [PATCH 02/13] jira + workspace require override --- pkg/argparser/flags.go | 23 ++-- pkg/commands/commands.go | 13 +++ .../ngwaf/workspace/alert/common/flags.go | 19 +++ .../ngwaf/workspace/alert/datadog/create.go | 7 +- .../ngwaf/workspace/alert/jira/create.go | 104 +++++++++++++++++ .../ngwaf/workspace/alert/jira/delete.go | 95 +++++++++++++++ .../ngwaf/workspace/alert/jira/doc.go | 2 + .../ngwaf/workspace/alert/jira/get.go | 89 ++++++++++++++ .../ngwaf/workspace/alert/jira/list.go | 81 +++++++++++++ .../ngwaf/workspace/alert/jira/root.go | 31 +++++ .../ngwaf/workspace/alert/jira/update.go | 109 ++++++++++++++++++ 11 files changed, 563 insertions(+), 10 deletions(-) create mode 100644 pkg/commands/ngwaf/workspace/alert/jira/create.go create mode 100644 pkg/commands/ngwaf/workspace/alert/jira/delete.go create mode 100644 pkg/commands/ngwaf/workspace/alert/jira/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/jira/get.go create mode 100644 pkg/commands/ngwaf/workspace/alert/jira/list.go create mode 100644 pkg/commands/ngwaf/workspace/alert/jira/root.go create mode 100644 pkg/commands/ngwaf/workspace/alert/jira/update.go diff --git a/pkg/argparser/flags.go b/pkg/argparser/flags.go index c08a685d9..05eaad90f 100644 --- a/pkg/argparser/flags.go +++ b/pkg/argparser/flags.go @@ -30,12 +30,13 @@ var ( // StringFlagOpts enables easy configuration of a flag. type StringFlagOpts struct { - Action kingpin.Action - Description string - Dst *string - Name string - Required bool - Short rune + Action kingpin.Action + Description string + Dst *string + ForceRequired bool // Shows as required in help text without enforcing at parse time + Name string + Required bool + Short rune } // RegisterFlag defines a flag. @@ -44,7 +45,15 @@ func (b Base) RegisterFlag(opts StringFlagOpts) { if opts.Short > 0 { clause = clause.Short(opts.Short) } - if opts.Required { + // ForceRequired makes the flag show as required and uses env var as fallback + if opts.ForceRequired { + // For workspace-id, use FASTLY_WORKSPACE_ID env var as fallback + if opts.Name == FlagNGWAFWorkspaceID { + clause = clause.Required().Envar(env.WorkspaceID) + } else { + clause = clause.Required() + } + } else if opts.Required { clause = clause.Required() } if opts.Action != nil { diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 61e3fde57..e3f19917c 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -60,6 +60,7 @@ import ( "github.com/fastly/cli/pkg/commands/ngwaf/workspace" "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" workspaceAlertDatadog "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/datadog" + workspaceAlertJira "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/jira" "github.com/fastly/cli/pkg/commands/objectstorage" "github.com/fastly/cli/pkg/commands/objectstorage/accesskeys" "github.com/fastly/cli/pkg/commands/pop" @@ -416,6 +417,12 @@ func Define( // nolint:revive // function-length ngwafWorkspacesAlertDatadogGet := workspaceAlertDatadog.NewGetCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) ngwafWorkspacesAlertDatadogList := workspaceAlertDatadog.NewListCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) ngwafWorkspacesAlertDatadogUpdate := workspaceAlertDatadog.NewUpdateCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) + ngwafWorkspacesAlertJiraRoot := workspaceAlertJira.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) + ngwafWorkspacesAlertJiraCreate := workspaceAlertJira.NewCreateCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) + ngwafWorkspacesAlertJiraDelete := workspaceAlertJira.NewDeleteCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) + ngwafWorkspacesAlertJiraGet := workspaceAlertJira.NewGetCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) + ngwafWorkspacesAlertJiraList := workspaceAlertJira.NewListCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) + ngwafWorkspacesAlertJiraUpdate := workspaceAlertJira.NewUpdateCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) objectStorageRoot := objectstorage.NewRootCommand(app, data) objectStorageAccesskeysRoot := accesskeys.NewRootCommand(objectStorageRoot.CmdClause, data) objectStorageAccesskeysCreate := accesskeys.NewCreateCommand(objectStorageAccesskeysRoot.CmdClause, data) @@ -853,6 +860,12 @@ func Define( // nolint:revive // function-length ngwafWorkspacesAlertDatadogGet, ngwafWorkspacesAlertDatadogList, ngwafWorkspacesAlertDatadogUpdate, + ngwafWorkspacesAlertJiraRoot, + ngwafWorkspacesAlertJiraCreate, + ngwafWorkspacesAlertJiraDelete, + ngwafWorkspacesAlertJiraGet, + ngwafWorkspacesAlertJiraList, + ngwafWorkspacesAlertJiraUpdate, objectStorageRoot, objectStorageAccesskeysRoot, objectStorageAccesskeysCreate, diff --git a/pkg/commands/ngwaf/workspace/alert/common/flags.go b/pkg/commands/ngwaf/workspace/alert/common/flags.go index 35d56898e..530ea51ea 100644 --- a/pkg/commands/ngwaf/workspace/alert/common/flags.go +++ b/pkg/commands/ngwaf/workspace/alert/common/flags.go @@ -23,6 +23,25 @@ type DatadogConfigFlags struct { Site string } +// JiraCreateConfigFlags contains Jira create specific configuration flags. +type JiraCreateConfigFlags struct { + Host string + IssueType string + Key string + Project string + Username string +} + +// JiraUpdateConfigFlags contains Jira update specific configuration flags. +// The `IssueType` field is removed here, as it's not a required field for +// update operations. +type JiraUpdateConfigFlags struct { + Host string + Key string + Project string + Username string +} + // WebhookConfigFlags contains webhook URL configrations (used by webhook, slack, etc...) type WebhookConfigFlags struct { Webhook string diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/create.go b/pkg/commands/ngwaf/workspace/alert/datadog/create.go index 5b776b86f..1ea8f7ffe 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/create.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/create.go @@ -56,14 +56,15 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman // Exec invokes the application logic for the command. func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { - if c.Globals.Verbose() && c.JSONOutput.Enabled { - return fsterr.ErrInvalidVerboseJSONCombo - } // Call Parse() to ensure that we check if workspaceID // is set or to throw the appropriate error. if err := c.WorkspaceID.Parse(); err != nil { return err } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &datadog.CreateInput{ WorkspaceID: &c.WorkspaceID.Value, Config: &datadog.CreateConfig{ diff --git a/pkg/commands/ngwaf/workspace/alert/jira/create.go b/pkg/commands/ngwaf/workspace/alert/jira/create.go new file mode 100644 index 000000000..19c8da636 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/jira/create.go @@ -0,0 +1,104 @@ +package jira + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/jira" +) + +// CreateCommand calls the Fastly API to create Jira alerts. +type CreateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags + common.JiraCreateConfigFlags + + // Optional. + common.AlertDataFlags +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { + c := CreateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("create", "Create a Jira alert").Alias("add") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.CmdClause.Flag("host", "Host name of the Jira instance.").Required().StringVar(&c.Host) + c.CmdClause.Flag("issue-type", "The Jira issue type associated with the ticket. (Default Task)").Required().StringVar(&c.IssueType) + c.CmdClause.Flag("key", "Jira API key.").Required().StringVar(&c.Key) + c.CmdClause.Flag("project", "Specifies the Jira project where the issue will be created.").Required().StringVar(&c.Project) + c.CmdClause.Flag("username", "Jira username of the user who created the ticket.").Required().StringVar(&c.Username) + + // Optional. + c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &jira.CreateInput{ + WorkspaceID: &c.WorkspaceID.Value, + Config: &jira.CreateConfig{ + Host: &c.Host, + IssueType: &c.IssueType, + Key: &c.Key, + Project: &c.Project, + Username: &c.Username, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + if c.Description.WasSet { + input.Description = &c.Description.Value + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := jira.Create(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Created a '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/jira/delete.go b/pkg/commands/ngwaf/workspace/alert/jira/delete.go new file mode 100644 index 000000000..f4eed9f48 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/jira/delete.go @@ -0,0 +1,95 @@ +package jira + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/jira" +) + +// DeleteCommand calls the Fastly API to delete Jira alerts. +type DeleteCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand { + c := DeleteCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("delete", "Delete a Jira alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + err := jira.Delete(context.TODO(), fc, &jira.DeleteInput{ + WorkspaceID: &c.WorkspaceID.Value, + AlertID: &c.AlertID, + }) + if err != nil { + return err + } + + if c.JSONOutput.Enabled { + o := struct { + ID string `json:"id"` + Deleted bool `json:"deleted"` + }{ + c.AlertID, + true, + } + _, err := c.WriteJSON(out, o) + return err + } + + text.Success(out, "Deleted alert '%s' (workspace-id: %s)", c.AlertID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/jira/doc.go b/pkg/commands/ngwaf/workspace/alert/jira/doc.go new file mode 100644 index 000000000..79434c647 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/jira/doc.go @@ -0,0 +1,2 @@ +// Package jira contains commands to inspect and manipulate NGWAF Jira alerts. +package jira diff --git a/pkg/commands/ngwaf/workspace/alert/jira/get.go b/pkg/commands/ngwaf/workspace/alert/jira/get.go new file mode 100644 index 000000000..70be24d0e --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/jira/get.go @@ -0,0 +1,89 @@ +package jira + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/jira" +) + +// GetCommand calls the Fastly API to get Jira alerts. +type GetCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetCommand returns a usable command registered under the parent. +func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { + c := GetCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get", "Get a Jira alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &jira.GetInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := jira.Get(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlert(out, data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/jira/list.go b/pkg/commands/ngwaf/workspace/alert/jira/list.go new file mode 100644 index 000000000..371e02adc --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/jira/list.go @@ -0,0 +1,81 @@ +package jira + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/jira" +) + +// ListCommand calls the Fastly API to list Jira alerts. +type ListCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { + c := ListCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("list", "List Jira alerts") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &jira.ListInput{ + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := jira.List(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlertTbl(out, data.Data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/jira/root.go b/pkg/commands/ngwaf/workspace/alert/jira/root.go new file mode 100644 index 000000000..38997a4bc --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/jira/root.go @@ -0,0 +1,31 @@ +package jira + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "jira" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage Jira workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/commands/ngwaf/workspace/alert/jira/update.go b/pkg/commands/ngwaf/workspace/alert/jira/update.go new file mode 100644 index 000000000..4e1ac9224 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/jira/update.go @@ -0,0 +1,109 @@ +package jira + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/jira" +) + +// UpdateCommand calls the Fastly API to update Jira alerts. +type UpdateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags + common.JiraUpdateConfigFlags + + // Optional + // issueType is optional for the Update operation. + issueType argparser.OptionalString +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { + c := UpdateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("update", "Update a Jira alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + c.CmdClause.Flag("host", "Host name of the Jira instance.").Required().StringVar(&c.Host) + c.CmdClause.Flag("key", "Jira API key.").Required().StringVar(&c.Key) + c.CmdClause.Flag("project", "Specifies the Jira project where the issue will be created.").Required().StringVar(&c.Project) + c.CmdClause.Flag("username", "Jira username of the user who created the ticket.").Required().StringVar(&c.Username) + + // Optional. + c.CmdClause.Flag("issue-type", "The Jira issue type associated with the ticket. (Default Task)").Action(c.issueType.Set).StringVar(&c.issueType.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &jira.UpdateInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + Config: &jira.UpdateConfig{ + Host: &c.Host, + IssueType: &c.issueType.Value, + Key: &c.Key, + Project: &c.Project, + Username: &c.Username, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := jira.Update(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Updated '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} From 51f07465f63490d4e03c85e3ddee0d219f944bfe Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 24 Nov 2025 15:26:08 -0500 Subject: [PATCH 03/13] move comment --- pkg/argparser/flags.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/argparser/flags.go b/pkg/argparser/flags.go index 05eaad90f..ae73f0611 100644 --- a/pkg/argparser/flags.go +++ b/pkg/argparser/flags.go @@ -30,10 +30,11 @@ var ( // StringFlagOpts enables easy configuration of a flag. type StringFlagOpts struct { - Action kingpin.Action - Description string - Dst *string - ForceRequired bool // Shows as required in help text without enforcing at parse time + Action kingpin.Action + Description string + Dst *string + // Shows as required in help text without enforcing at parse time + ForceRequired bool Name string Required bool Short rune From e4fd6f3be765c5ea912e7040c230155b3a43bd01 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Tue, 25 Nov 2025 14:35:09 -0500 Subject: [PATCH 04/13] alerts & tests --- pkg/commands/commands.go | 82 +++ .../ngwaf/workspace/alert/common/flags.go | 26 +- .../workspace/alert/datadog/datadog_test.go | 424 ++++++++++++++ .../ngwaf/workspace/alert/jira/create.go | 17 +- .../ngwaf/workspace/alert/jira/jira_test.go | 469 +++++++++++++++ .../ngwaf/workspace/alert/jira/update.go | 19 +- .../workspace/alert/mailinglist/create.go | 96 +++ .../workspace/alert/mailinglist/delete.go | 95 +++ .../ngwaf/workspace/alert/mailinglist/doc.go | 2 + .../ngwaf/workspace/alert/mailinglist/get.go | 89 +++ .../ngwaf/workspace/alert/mailinglist/list.go | 81 +++ .../alert/mailinglist/mailinglist_test.go | 414 +++++++++++++ .../ngwaf/workspace/alert/mailinglist/root.go | 31 + .../workspace/alert/mailinglist/update.go | 97 +++ .../workspace/alert/microsoftteams/create.go | 96 +++ .../workspace/alert/microsoftteams/delete.go | 95 +++ .../workspace/alert/microsoftteams/doc.go | 2 + .../workspace/alert/microsoftteams/get.go | 89 +++ .../workspace/alert/microsoftteams/list.go | 81 +++ .../microsoftteams/microsoftteams_test.go | 412 +++++++++++++ .../workspace/alert/microsoftteams/root.go | 31 + .../workspace/alert/microsoftteams/update.go | 97 +++ .../ngwaf/workspace/alert/opsgenie/create.go | 96 +++ .../ngwaf/workspace/alert/opsgenie/delete.go | 95 +++ .../ngwaf/workspace/alert/opsgenie/doc.go | 2 + .../ngwaf/workspace/alert/opsgenie/get.go | 89 +++ .../ngwaf/workspace/alert/opsgenie/list.go | 81 +++ .../workspace/alert/opsgenie/opsgenie_test.go | 412 +++++++++++++ .../ngwaf/workspace/alert/opsgenie/root.go | 31 + .../ngwaf/workspace/alert/opsgenie/update.go | 97 +++ .../ngwaf/workspace/alert/pagerduty/create.go | 96 +++ .../ngwaf/workspace/alert/pagerduty/delete.go | 95 +++ .../ngwaf/workspace/alert/pagerduty/doc.go | 2 + .../ngwaf/workspace/alert/pagerduty/get.go | 89 +++ .../ngwaf/workspace/alert/pagerduty/list.go | 81 +++ .../alert/pagerduty/pagerduty_test.go | 412 +++++++++++++ .../ngwaf/workspace/alert/pagerduty/root.go | 31 + .../ngwaf/workspace/alert/pagerduty/update.go | 97 +++ .../ngwaf/workspace/alert/slack/create.go | 96 +++ .../ngwaf/workspace/alert/slack/delete.go | 95 +++ .../ngwaf/workspace/alert/slack/doc.go | 2 + .../ngwaf/workspace/alert/slack/get.go | 89 +++ .../ngwaf/workspace/alert/slack/list.go | 81 +++ .../ngwaf/workspace/alert/slack/root.go | 31 + .../ngwaf/workspace/alert/slack/slack_test.go | 412 +++++++++++++ .../ngwaf/workspace/alert/slack/update.go | 97 +++ .../ngwaf/workspace/alert/webhook/create.go | 96 +++ .../ngwaf/workspace/alert/webhook/delete.go | 95 +++ .../ngwaf/workspace/alert/webhook/doc.go | 2 + .../alert/webhook/get-signing-key.go | 89 +++ .../ngwaf/workspace/alert/webhook/get.go | 89 +++ .../ngwaf/workspace/alert/webhook/list.go | 81 +++ .../ngwaf/workspace/alert/webhook/root.go | 31 + .../alert/webhook/rotate-signing-key.go | 89 +++ .../ngwaf/workspace/alert/webhook/update.go | 97 +++ .../workspace/alert/webhook/webhook_test.go | 550 ++++++++++++++++++ pkg/text/alerts.go | 10 +- 57 files changed, 6754 insertions(+), 29 deletions(-) create mode 100644 pkg/commands/ngwaf/workspace/alert/datadog/datadog_test.go create mode 100644 pkg/commands/ngwaf/workspace/alert/jira/jira_test.go create mode 100644 pkg/commands/ngwaf/workspace/alert/mailinglist/create.go create mode 100644 pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go create mode 100644 pkg/commands/ngwaf/workspace/alert/mailinglist/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/mailinglist/get.go create mode 100644 pkg/commands/ngwaf/workspace/alert/mailinglist/list.go create mode 100644 pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go create mode 100644 pkg/commands/ngwaf/workspace/alert/mailinglist/root.go create mode 100644 pkg/commands/ngwaf/workspace/alert/mailinglist/update.go create mode 100644 pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go create mode 100644 pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go create mode 100644 pkg/commands/ngwaf/workspace/alert/microsoftteams/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go create mode 100644 pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go create mode 100644 pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go create mode 100644 pkg/commands/ngwaf/workspace/alert/microsoftteams/root.go create mode 100644 pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go create mode 100644 pkg/commands/ngwaf/workspace/alert/opsgenie/create.go create mode 100644 pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go create mode 100644 pkg/commands/ngwaf/workspace/alert/opsgenie/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/opsgenie/get.go create mode 100644 pkg/commands/ngwaf/workspace/alert/opsgenie/list.go create mode 100644 pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go create mode 100644 pkg/commands/ngwaf/workspace/alert/opsgenie/root.go create mode 100644 pkg/commands/ngwaf/workspace/alert/opsgenie/update.go create mode 100644 pkg/commands/ngwaf/workspace/alert/pagerduty/create.go create mode 100644 pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go create mode 100644 pkg/commands/ngwaf/workspace/alert/pagerduty/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/pagerduty/get.go create mode 100644 pkg/commands/ngwaf/workspace/alert/pagerduty/list.go create mode 100644 pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go create mode 100644 pkg/commands/ngwaf/workspace/alert/pagerduty/root.go create mode 100644 pkg/commands/ngwaf/workspace/alert/pagerduty/update.go create mode 100644 pkg/commands/ngwaf/workspace/alert/slack/create.go create mode 100644 pkg/commands/ngwaf/workspace/alert/slack/delete.go create mode 100644 pkg/commands/ngwaf/workspace/alert/slack/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/slack/get.go create mode 100644 pkg/commands/ngwaf/workspace/alert/slack/list.go create mode 100644 pkg/commands/ngwaf/workspace/alert/slack/root.go create mode 100644 pkg/commands/ngwaf/workspace/alert/slack/slack_test.go create mode 100644 pkg/commands/ngwaf/workspace/alert/slack/update.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/create.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/delete.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/doc.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/get.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/list.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/root.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/update.go create mode 100644 pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index e3f19917c..cdbeb3a54 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -61,6 +61,12 @@ import ( "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" workspaceAlertDatadog "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/datadog" workspaceAlertJira "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/jira" + workspaceAlertMailinglist "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/mailinglist" + workspaceAlertMicrosoftteams "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/microsoftteams" + workspaceAlertOpsgenie "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/opsgenie" + workspaceAlertPagerduty "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/pagerduty" + workspaceAlertSlack "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/slack" + workspaceAlertWebhook "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/webhook" "github.com/fastly/cli/pkg/commands/objectstorage" "github.com/fastly/cli/pkg/commands/objectstorage/accesskeys" "github.com/fastly/cli/pkg/commands/pop" @@ -423,6 +429,44 @@ func Define( // nolint:revive // function-length ngwafWorkspacesAlertJiraGet := workspaceAlertJira.NewGetCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) ngwafWorkspacesAlertJiraList := workspaceAlertJira.NewListCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) ngwafWorkspacesAlertJiraUpdate := workspaceAlertJira.NewUpdateCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) + ngwafWorkspacesAlertMailinglistRoot := workspaceAlertMailinglist.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) + ngwafWorkspacesAlertMailinglistCreate := workspaceAlertMailinglist.NewCreateCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) + ngwafWorkspacesAlertMailinglistDelete := workspaceAlertMailinglist.NewDeleteCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) + ngwafWorkspacesAlertMailinglistGet := workspaceAlertMailinglist.NewGetCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) + ngwafWorkspacesAlertMailinglistList := workspaceAlertMailinglist.NewListCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) + ngwafWorkspacesAlertMailinglistUpdate := workspaceAlertMailinglist.NewUpdateCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) + ngwafWorkspacesAlertMicrosoftteamsRoot := workspaceAlertMicrosoftteams.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) + ngwafWorkspacesAlertMicrosoftteamsCreate := workspaceAlertMicrosoftteams.NewCreateCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspacesAlertMicrosoftteamsDelete := workspaceAlertMicrosoftteams.NewDeleteCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspacesAlertMicrosoftteamsGet := workspaceAlertMicrosoftteams.NewGetCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspacesAlertMicrosoftteamsList := workspaceAlertMicrosoftteams.NewListCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspacesAlertMicrosoftteamsUpdate := workspaceAlertMicrosoftteams.NewUpdateCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspacesAlertOpsgenieRoot := workspaceAlertOpsgenie.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) + ngwafWorkspacesAlertOpsgenieCreate := workspaceAlertOpsgenie.NewCreateCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspacesAlertOpsgenieDelete := workspaceAlertOpsgenie.NewDeleteCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspacesAlertOpsgenieGet := workspaceAlertOpsgenie.NewGetCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspacesAlertOpsgenieList := workspaceAlertOpsgenie.NewListCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspacesAlertOpsgenieUpdate := workspaceAlertOpsgenie.NewUpdateCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspacesAlertPagerdutyRoot := workspaceAlertPagerduty.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) + ngwafWorkspacesAlertPagerdutyCreate := workspaceAlertPagerduty.NewCreateCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspacesAlertPagerdutyDelete := workspaceAlertPagerduty.NewDeleteCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspacesAlertPagerdutyGet := workspaceAlertPagerduty.NewGetCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspacesAlertPagerdutyList := workspaceAlertPagerduty.NewListCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspacesAlertPagerdutyUpdate := workspaceAlertPagerduty.NewUpdateCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspacesAlertSlackRoot := workspaceAlertSlack.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) + ngwafWorkspacesAlertSlackCreate := workspaceAlertSlack.NewCreateCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) + ngwafWorkspacesAlertSlackDelete := workspaceAlertSlack.NewDeleteCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) + ngwafWorkspacesAlertSlackGet := workspaceAlertSlack.NewGetCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) + ngwafWorkspacesAlertSlackList := workspaceAlertSlack.NewListCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) + ngwafWorkspacesAlertSlackUpdate := workspaceAlertSlack.NewUpdateCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) + ngwafWorkspacesAlertWebhookRoot := workspaceAlertWebhook.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) + ngwafWorkspacesAlertWebhookCreate := workspaceAlertWebhook.NewCreateCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) + ngwafWorkspacesAlertWebhookDelete := workspaceAlertWebhook.NewDeleteCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) + ngwafWorkspacesAlertWebhookGet := workspaceAlertWebhook.NewGetCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) + ngwafWorkspacesAlertWebhookGetSigningKey := workspaceAlertWebhook.NewGetSigningKeyCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) + ngwafWorkspacesAlertWebhookList := workspaceAlertWebhook.NewListCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) + ngwafWorkspacesAlertWebhookRotateSigningKey := workspaceAlertWebhook.NewRotateSigningKeyCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) + ngwafWorkspacesAlertWebhookUpdate := workspaceAlertWebhook.NewUpdateCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) objectStorageRoot := objectstorage.NewRootCommand(app, data) objectStorageAccesskeysRoot := accesskeys.NewRootCommand(objectStorageRoot.CmdClause, data) objectStorageAccesskeysCreate := accesskeys.NewCreateCommand(objectStorageAccesskeysRoot.CmdClause, data) @@ -866,6 +910,44 @@ func Define( // nolint:revive // function-length ngwafWorkspacesAlertJiraGet, ngwafWorkspacesAlertJiraList, ngwafWorkspacesAlertJiraUpdate, + ngwafWorkspacesAlertMailinglistRoot, + ngwafWorkspacesAlertMailinglistCreate, + ngwafWorkspacesAlertMailinglistDelete, + ngwafWorkspacesAlertMailinglistGet, + ngwafWorkspacesAlertMailinglistList, + ngwafWorkspacesAlertMailinglistUpdate, + ngwafWorkspacesAlertMicrosoftteamsRoot, + ngwafWorkspacesAlertMicrosoftteamsCreate, + ngwafWorkspacesAlertMicrosoftteamsDelete, + ngwafWorkspacesAlertMicrosoftteamsGet, + ngwafWorkspacesAlertMicrosoftteamsList, + ngwafWorkspacesAlertMicrosoftteamsUpdate, + ngwafWorkspacesAlertOpsgenieRoot, + ngwafWorkspacesAlertOpsgenieCreate, + ngwafWorkspacesAlertOpsgenieDelete, + ngwafWorkspacesAlertOpsgenieGet, + ngwafWorkspacesAlertOpsgenieList, + ngwafWorkspacesAlertOpsgenieUpdate, + ngwafWorkspacesAlertPagerdutyRoot, + ngwafWorkspacesAlertPagerdutyCreate, + ngwafWorkspacesAlertPagerdutyDelete, + ngwafWorkspacesAlertPagerdutyGet, + ngwafWorkspacesAlertPagerdutyList, + ngwafWorkspacesAlertPagerdutyUpdate, + ngwafWorkspacesAlertSlackRoot, + ngwafWorkspacesAlertSlackCreate, + ngwafWorkspacesAlertSlackDelete, + ngwafWorkspacesAlertSlackGet, + ngwafWorkspacesAlertSlackList, + ngwafWorkspacesAlertSlackUpdate, + ngwafWorkspacesAlertWebhookRoot, + ngwafWorkspacesAlertWebhookCreate, + ngwafWorkspacesAlertWebhookDelete, + ngwafWorkspacesAlertWebhookGet, + ngwafWorkspacesAlertWebhookGetSigningKey, + ngwafWorkspacesAlertWebhookList, + ngwafWorkspacesAlertWebhookRotateSigningKey, + ngwafWorkspacesAlertWebhookUpdate, objectStorageRoot, objectStorageAccesskeysRoot, objectStorageAccesskeysCreate, diff --git a/pkg/commands/ngwaf/workspace/alert/common/flags.go b/pkg/commands/ngwaf/workspace/alert/common/flags.go index 530ea51ea..f011b85a9 100644 --- a/pkg/commands/ngwaf/workspace/alert/common/flags.go +++ b/pkg/commands/ngwaf/workspace/alert/common/flags.go @@ -23,26 +23,30 @@ type DatadogConfigFlags struct { Site string } -// JiraCreateConfigFlags contains Jira create specific configuration flags. -type JiraCreateConfigFlags struct { - Host string +// JiraOptConfigFlags contains optional Jira specific configuration flags. +type JiraOptConfigFlags struct { IssueType string - Key string - Project string - Username string } -// JiraUpdateConfigFlags contains Jira update specific configuration flags. -// The `IssueType` field is removed here, as it's not a required field for -// update operations. -type JiraUpdateConfigFlags struct { +// JiraConfigFlags contains Jira specific configuration flags. +type JiraConfigFlags struct { Host string Key string Project string Username string } -// WebhookConfigFlags contains webhook URL configrations (used by webhook, slack, etc...) +// AddressConfigFlags contains Address configurations used by mailing lists. +type AddressConfigFlags struct { + Address string +} + +// KeyConfigFlags contains the Key configuration (used by opsgenie, pagerduty, etc...). +type KeyConfigFlags struct { + Key string +} + +// WebhookConfigFlags contains the Webhook configuration (used by webhook, slack, etc...). type WebhookConfigFlags struct { Webhook string } diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/datadog_test.go b/pkg/commands/ngwaf/workspace/alert/datadog/datadog_test.go new file mode 100644 index 000000000..7d61eada0 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/datadog/datadog_test.go @@ -0,0 +1,424 @@ +package datadog_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "testing" + + root "github.com/fastly/cli/pkg/commands/ngwaf" + workspaceroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + alertroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + sub "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/datadog" + fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/datadog" +) + +const ( + alertID = "7890abcdef12345678901234" + workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" + description = "Test Datadog alert" +) + +var ( + key = "a1b2c3d4e5f67890abcdef1234567890" + site = "datadoghq.com" + datadogAlert = datadog.Alert{ + ID: alertID, + Type: "datadog", + Description: description, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: datadog.ResponseConfig{ + Key: &key, + Site: &site, + }, + } +) + +func TestDatadogAlertCreate(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--key %s --site %s", key, site), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --key flag", + Args: fmt.Sprintf("--workspace-id %s --site %s", workspaceID, site), + WantError: "error parsing arguments: required flag --key not provided", + }, + { + Name: "validate missing --site flag", + Args: fmt.Sprintf("--workspace-id %s --key %s", workspaceID, key), + WantError: "error parsing arguments: required flag --site not provided", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --key %s --site %s", workspaceID, key, site), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(datadogAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", datadogAlert.Type, datadogAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --key %s --site %s --description %s", workspaceID, key, site, description), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(datadogAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", datadogAlert.Type, datadogAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --key %s --site %s --json", workspaceID, key, site), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(datadogAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(datadogAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "create"}, scenarios) +} + +func TestDatadogAlertList(t *testing.T) { + alertsObject := datadog.Alerts{ + Data: []datadog.Alert{ + { + ID: "1a2b3c4d5e6f7890abcdef12", + Type: "datadog", + Description: "First Datadog alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: datadog.ResponseConfig{ + Key: &key, + Site: &site, + }, + }, + { + ID: "2b3c4d5e6f7890abcdef1234", + Type: "datadog", + Description: "Second Datadog alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: datadog.ResponseConfig{ + Key: &key, + Site: &site, + }, + }, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: "", + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate internal server error", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + Status: http.StatusText(http.StatusInternalServerError), + }, + }, + }, + WantError: "500 - Internal Server Error", + }, + { + Name: "validate API success (zero alerts)", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(datadog.Alerts{ + Data: []datadog.Alert{}, + }))), + }, + }, + }, + WantOutput: zeroListString, + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: listString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --json", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(alertsObject), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "list"}, scenarios) +} + +func TestDatadogAlertGet(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(datadogAlert)))), + }, + }, + }, + WantOutput: alertString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(datadogAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(datadogAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get"}, scenarios) +} + +func TestDatadogAlertUpdate(t *testing.T) { + updatedKey := "updated-key-9876543210" + updatedSite := "datadoghq.eu" + updatedAlert := datadog.Alert{ + ID: alertID, + Type: "datadog", + Description: "Updated description", + Config: datadog.ResponseConfig{ + Key: &updatedKey, + Site: &updatedSite, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --key updated-key-9876543210", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success with key and site", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210 --site datadoghq.eu", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210 --site datadoghq.eu --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(updatedAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "update"}, scenarios) +} + +func TestDatadogAlertDelete(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNoContent, + Status: http.StatusText(http.StatusNoContent), + }, + }, + }, + WantOutput: fstfmt.Success("Deleted alert '%s' (workspace-id: %s)", alertID, workspaceID), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "delete"}, scenarios) +} + +var alertString = strings.TrimSpace(` +ID: 7890abcdef12345678901234 +Type: datadog +Description: Test Datadog alert +Created At: 2025-11-25T16:40:12Z +Created By: test@example.com +Config: + Key: + Site: datadoghq.com +`) + +var listString = strings.TrimSpace(` +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 datadog First Datadog alert 2025-11-25T16:40:12Z test@example.com Site: datadoghq.com, Key: +2b3c4d5e6f7890abcdef1234 datadog Second Datadog alert 2025-11-25T16:40:12Z test@example.com Site: datadoghq.com, Key: +`) + "\n" + +var zeroListString = strings.TrimSpace(` +ID Type Description Created At Created By Config +`) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/jira/create.go b/pkg/commands/ngwaf/workspace/alert/jira/create.go index 19c8da636..29104e51d 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/create.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/create.go @@ -22,10 +22,11 @@ type CreateCommand struct { // Required. common.BaseAlertFlags - common.JiraCreateConfigFlags + common.JiraConfigFlags // Optional. common.AlertDataFlags + common.JiraOptConfigFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -46,13 +47,13 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman ForceRequired: true, }) c.CmdClause.Flag("host", "Host name of the Jira instance.").Required().StringVar(&c.Host) - c.CmdClause.Flag("issue-type", "The Jira issue type associated with the ticket. (Default Task)").Required().StringVar(&c.IssueType) c.CmdClause.Flag("key", "Jira API key.").Required().StringVar(&c.Key) c.CmdClause.Flag("project", "Specifies the Jira project where the issue will be created.").Required().StringVar(&c.Project) c.CmdClause.Flag("username", "Jira username of the user who created the ticket.").Required().StringVar(&c.Username) // Optional. c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.CmdClause.Flag("issue-type", "An optional Jira issue type associated with the ticket. (Default Task)").StringVar(&c.IssueType) c.RegisterFlagBool(c.JSONFlag()) return &c @@ -72,15 +73,17 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { input := &jira.CreateInput{ WorkspaceID: &c.WorkspaceID.Value, Config: &jira.CreateConfig{ - Host: &c.Host, - IssueType: &c.IssueType, - Key: &c.Key, - Project: &c.Project, - Username: &c.Username, + Host: &c.Host, + Key: &c.Key, + Project: &c.Project, + Username: &c.Username, }, // Set 'Events' to the only possible value, 'flag' Events: common.GetDefaultEvents(), } + if c.IssueType != "" { + input.Config.IssueType = &c.IssueType + } if c.Description.WasSet { input.Description = &c.Description.Value } diff --git a/pkg/commands/ngwaf/workspace/alert/jira/jira_test.go b/pkg/commands/ngwaf/workspace/alert/jira/jira_test.go new file mode 100644 index 000000000..5047aaa1f --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/jira/jira_test.go @@ -0,0 +1,469 @@ +package jira_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "testing" + + root "github.com/fastly/cli/pkg/commands/ngwaf" + workspaceroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + alertroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + sub "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/jira" + fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/jira" +) + +const ( + alertID = "890abcdef1234567890123ab" + workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" + description = "TestJiraAlert" +) + +var ( + host = "example.atlassian.net" + key = "jira-api-key-123456" + project = "PROJ" + username = "user@example.com" + issueType = "Task" + jiraAlert = jira.Alert{ + ID: alertID, + Type: "jira", + Description: description, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: jira.ResponseConfig{ + Host: &host, + Key: &key, + Project: &project, + Username: &username, + IssueType: &issueType, + }, + } +) + +func TestJiraAlertCreate(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--host %s --key %s --project %s --username %s", host, key, project, username), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --host flag", + Args: fmt.Sprintf("--workspace-id %s --key %s --project %s --username %s", workspaceID, key, project, username), + WantError: "error parsing arguments: required flag --host not provided", + }, + { + Name: "validate missing --key flag", + Args: fmt.Sprintf("--workspace-id %s --host %s --project %s --username %s", workspaceID, host, project, username), + WantError: "error parsing arguments: required flag --key not provided", + }, + { + Name: "validate missing --project flag", + Args: fmt.Sprintf("--workspace-id %s --host %s --key %s --username %s", workspaceID, host, key, username), + WantError: "error parsing arguments: required flag --project not provided", + }, + { + Name: "validate missing --username flag", + Args: fmt.Sprintf("--workspace-id %s --host %s --key %s --project %s", workspaceID, host, key, project), + WantError: "error parsing arguments: required flag --username not provided", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --host %s --key %s --project %s --username %s", workspaceID, host, key, project, username), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(jiraAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", jiraAlert.Type, jiraAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --host %s --key %s --project %s --username %s --description %s", workspaceID, host, key, project, username, description), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(jiraAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", jiraAlert.Type, jiraAlert.ID, workspaceID), + }, + { + Name: "validate API success with issue-type", + Args: fmt.Sprintf("--workspace-id %s --host %s --key %s --project %s --username %s --issue-type %s", workspaceID, host, key, project, username, issueType), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(jiraAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", jiraAlert.Type, jiraAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --host %s --key %s --project %s --username %s --json", workspaceID, host, key, project, username), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(jiraAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(jiraAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "create"}, scenarios) +} + +func TestJiraAlertList(t *testing.T) { + alertsObject := jira.Alerts{ + Data: []jira.Alert{ + { + ID: "1a2b3c4d5e6f7890abcdef12", + Type: "jira", + Description: "First Jira alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: jira.ResponseConfig{ + Host: &host, + Key: &key, + Project: &project, + Username: &username, + IssueType: &issueType, + }, + }, + { + ID: "2b3c4d5e6f7890abcdef1234", + Type: "jira", + Description: "Second Jira alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: jira.ResponseConfig{ + Host: &host, + Key: &key, + Project: &project, + Username: &username, + IssueType: &issueType, + }, + }, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: "", + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate internal server error", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + Status: http.StatusText(http.StatusInternalServerError), + }, + }, + }, + WantError: "500 - Internal Server Error", + }, + { + Name: "validate API success (zero alerts)", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(jira.Alerts{ + Data: []jira.Alert{}, + }))), + }, + }, + }, + WantOutput: zeroListString, + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: listString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --json", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(alertsObject), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "list"}, scenarios) +} + +func TestJiraAlertGet(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(jiraAlert)))), + }, + }, + }, + WantOutput: alertString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(jiraAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(jiraAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get"}, scenarios) +} + +func TestJiraAlertUpdate(t *testing.T) { + updatedHost := "updated.atlassian.net" + updatedKey := "updated-jira-key-456" + updatedProject := "UPDT" + updatedUsername := "updated@example.com" + updatedIssueType := "Bug" + updatedAlert := jira.Alert{ + ID: alertID, + Type: "jira", + Description: "Updated description", + Config: jira.ResponseConfig{ + Host: &updatedHost, + Key: &updatedKey, + Project: &updatedProject, + Username: &updatedUsername, + IssueType: &updatedIssueType, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --host updated.atlassian.net", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success with all config fields", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --host updated.atlassian.net --key updated-jira-key-456 --project UPDT --username updated@example.com --issue-type Bug", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --host updated.atlassian.net --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(updatedAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "update"}, scenarios) +} + +func TestJiraAlertDelete(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNoContent, + Status: http.StatusText(http.StatusNoContent), + }, + }, + }, + WantOutput: fstfmt.Success("Deleted alert '%s' (workspace-id: %s)", alertID, workspaceID), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "delete"}, scenarios) +} + +var alertString = strings.TrimSpace(` +ID: 890abcdef1234567890123ab +Type: jira +Description: TestJiraAlert +Created At: 2025-11-25T16:40:12Z +Created By: test@example.com +Config: + Host: example.atlassian.net + Username: user@example.com + Project: PROJ + Issue Type: Task + Key: +`) + +var listString = strings.TrimSpace(` +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 jira First Jira alert 2025-11-25T16:40:12Z test@example.com Host: example.atlassian.net, Issue Type: Task, Key: , Project: PROJ, Username: user@example.com +2b3c4d5e6f7890abcdef1234 jira Second Jira alert 2025-11-25T16:40:12Z test@example.com Host: example.atlassian.net, Issue Type: Task, Key: , Project: PROJ, Username: user@example.com +`) + "\n" + +var zeroListString = strings.TrimSpace(` +ID Type Description Created At Created By Config +`) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/jira/update.go b/pkg/commands/ngwaf/workspace/alert/jira/update.go index 4e1ac9224..871fec924 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/update.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/update.go @@ -23,11 +23,10 @@ type UpdateCommand struct { // Required. common.AlertIDFlags common.BaseAlertFlags - common.JiraUpdateConfigFlags + common.JiraConfigFlags // Optional - // issueType is optional for the Update operation. - issueType argparser.OptionalString + common.JiraOptConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -59,7 +58,7 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman c.CmdClause.Flag("username", "Jira username of the user who created the ticket.").Required().StringVar(&c.Username) // Optional. - c.CmdClause.Flag("issue-type", "The Jira issue type associated with the ticket. (Default Task)").Action(c.issueType.Set).StringVar(&c.issueType.Value) + c.CmdClause.Flag("issue-type", "An optional Jira issue type associated with the ticket. (Default Task)").StringVar(&c.IssueType) c.RegisterFlagBool(c.JSONFlag()) return &c @@ -80,15 +79,17 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { AlertID: &c.AlertID, WorkspaceID: &c.WorkspaceID.Value, Config: &jira.UpdateConfig{ - Host: &c.Host, - IssueType: &c.issueType.Value, - Key: &c.Key, - Project: &c.Project, - Username: &c.Username, + Host: &c.Host, + Key: &c.Key, + Project: &c.Project, + Username: &c.Username, }, // Set 'Events' to the only possible value, 'flag' Events: common.GetDefaultEvents(), } + if c.IssueType != "" { + input.Config.IssueType = &c.IssueType + } fc, ok := c.Globals.APIClient.(*fastly.Client) if !ok { diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go new file mode 100644 index 000000000..ee2db1f7a --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go @@ -0,0 +1,96 @@ +package mailinglist + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/mailinglist" +) + +// CreateCommand calls the Fastly API to create Mailing List alerts. +type CreateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags + common.AddressConfigFlags + + // Optional. + common.AlertDataFlags +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { + c := CreateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("create", "Create a Mailing List alert").Alias("add") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.CmdClause.Flag("address", "An email address.").Required().StringVar(&c.Address) + + // Optional. + c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &mailinglist.CreateInput{ + WorkspaceID: &c.WorkspaceID.Value, + Config: &mailinglist.CreateConfig{ + Address: &c.Address, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + if c.Description.WasSet { + input.Description = &c.Description.Value + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := mailinglist.Create(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Created a '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go new file mode 100644 index 000000000..4fc7d149b --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go @@ -0,0 +1,95 @@ +package mailinglist + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/mailinglist" +) + +// DeleteCommand calls the Fastly API to delete Mailing List alerts. +type DeleteCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand { + c := DeleteCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("delete", "Delete a Mailing List alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + err := mailinglist.Delete(context.TODO(), fc, &mailinglist.DeleteInput{ + WorkspaceID: &c.WorkspaceID.Value, + AlertID: &c.AlertID, + }) + if err != nil { + return err + } + + if c.JSONOutput.Enabled { + o := struct { + ID string `json:"id"` + Deleted bool `json:"deleted"` + }{ + c.AlertID, + true, + } + _, err := c.WriteJSON(out, o) + return err + } + + text.Success(out, "Deleted alert '%s' (workspace-id: %s)", c.AlertID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/doc.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/doc.go new file mode 100644 index 000000000..a5a5a45f1 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/doc.go @@ -0,0 +1,2 @@ +// Package mailinglist contains commands to inspect and manipulate NGWAF Mailing List alerts. +package mailinglist diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go new file mode 100644 index 000000000..a9cdb6e81 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go @@ -0,0 +1,89 @@ +package mailinglist + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/mailinglist" +) + +// GetCommand calls the Fastly API to get Mailing List alerts. +type GetCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetCommand returns a usable command registered under the parent. +func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { + c := GetCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get", "Get a Mailing List alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &mailinglist.GetInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := mailinglist.Get(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlert(out, data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go new file mode 100644 index 000000000..0b82e4df9 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go @@ -0,0 +1,81 @@ +package mailinglist + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/mailinglist" +) + +// ListCommand calls the Fastly API to list Mailing List alerts. +type ListCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { + c := ListCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("list", "List Mailing List alerts") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &mailinglist.ListInput{ + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := mailinglist.List(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlertTbl(out, data.Data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go new file mode 100644 index 000000000..07f5e2414 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go @@ -0,0 +1,414 @@ +package mailinglist_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "testing" + + root "github.com/fastly/cli/pkg/commands/ngwaf" + workspaceroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + alertroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + sub "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/mailinglist" + fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/mailinglist" +) + +const ( + alertID = "2b3c4d5e6f7890abcdef1234" + workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" + description = "Test mailing list alert" +) + +var ( + address = "alerts@example.com" + mailinglistAlert = mailinglist.Alert{ + ID: alertID, + Type: "mailingList", + Description: description, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: mailinglist.ResponseConfig{ + Address: &address, + }, + } +) + +func TestMailingListAlertCreate(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--address %s", address), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --address flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --address not provided", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --address %s", workspaceID, address), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(mailinglistAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", mailinglistAlert.Type, mailinglistAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --address %s --description %s", workspaceID, address, description), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(mailinglistAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", mailinglistAlert.Type, mailinglistAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --address %s --json", workspaceID, address), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(mailinglistAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(mailinglistAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "create"}, scenarios) +} + +func TestMailingListAlertList(t *testing.T) { + alertAddress1 := "alerts1@example.com" + alertAddress2 := "alerts2@example.com" + alertsObject := mailinglist.Alerts{ + Data: []mailinglist.Alert{ + { + ID: "1a2b3c4d5e6f7890abcdef12", + Type: "mailingList", + Description: "First mailing list alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: mailinglist.ResponseConfig{ + Address: &alertAddress1, + }, + }, + { + ID: "2b3c4d5e6f7890abcdef1234", + Type: "mailingList", + Description: "Second mailing list alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: mailinglist.ResponseConfig{ + Address: &alertAddress2, + }, + }, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: "", + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate internal server error", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + Status: http.StatusText(http.StatusInternalServerError), + }, + }, + }, + WantError: "500 - Internal Server Error", + }, + { + Name: "validate API success (zero alerts)", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(mailinglist.Alerts{ + Data: []mailinglist.Alert{}, + }))), + }, + }, + }, + WantOutput: zeroListString, + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: listString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --json", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(alertsObject), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "list"}, scenarios) +} + +func TestMailingListAlertGet(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(mailinglistAlert)))), + }, + }, + }, + WantOutput: alertString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(mailinglistAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(mailinglistAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get"}, scenarios) +} + +func TestMailingListAlertUpdate(t *testing.T) { + updatedAddress := "updated@example.com" + updatedAlert := mailinglist.Alert{ + ID: alertID, + Type: "mailingList", + Description: "Updated description", + Config: mailinglist.ResponseConfig{ + Address: &updatedAddress, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --address updated@example.com", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success with address", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --address updated@example.com", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --address updated@example.com --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(updatedAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "update"}, scenarios) +} + +func TestMailingListAlertDelete(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNoContent, + Status: http.StatusText(http.StatusNoContent), + }, + }, + }, + WantOutput: fstfmt.Success("Deleted alert '%s' (workspace-id: %s)", alertID, workspaceID), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "delete"}, scenarios) +} + +var alertString = strings.TrimSpace(` +ID: 2b3c4d5e6f7890abcdef1234 +Type: mailingList +Description: Test mailing list alert +Created At: 2025-11-25T16:40:12Z +Created By: test@example.com +Config: + Address: alerts@example.com +`) + +var listString = strings.TrimSpace(` +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 mailingList First mailing list alert 2025-11-25T16:40:12Z test@example.com Address: alerts1@example.com +2b3c4d5e6f7890abcdef1234 mailingList Second mailing list alert 2025-11-25T16:40:12Z test@example.com Address: alerts2@example.com +`) + "\n" + +var zeroListString = strings.TrimSpace(` +ID Type Description Created At Created By Config +`) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/root.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/root.go new file mode 100644 index 000000000..455d68531 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/root.go @@ -0,0 +1,31 @@ +package mailinglist + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "mailinglist" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage Mailing List workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go new file mode 100644 index 000000000..e5d238c9d --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go @@ -0,0 +1,97 @@ +package mailinglist + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/mailinglist" +) + +// UpdateCommand calls the Fastly API to update Mailing List alerts. +type UpdateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags + common.AddressConfigFlags +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { + c := UpdateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("update", "Update a Mailing List alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + c.CmdClause.Flag("address", "An email address.").Required().StringVar(&c.Address) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &mailinglist.UpdateInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + Config: &mailinglist.UpdateConfig{ + Address: &c.Address, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := mailinglist.Update(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Updated '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go new file mode 100644 index 000000000..3e2f20a74 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go @@ -0,0 +1,96 @@ +package microsoftteams + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/microsoftteams" +) + +// CreateCommand calls the Fastly API to create Microsoft Teams alerts. +type CreateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags + common.WebhookConfigFlags + + // Optional. + common.AlertDataFlags +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { + c := CreateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("create", "Create a Microsoft Teams alert").Alias("add") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.CmdClause.Flag("webhook", "Microsoft Teams webhook.").Required().StringVar(&c.Webhook) + + // Optional. + c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := µsoftteams.CreateInput{ + WorkspaceID: &c.WorkspaceID.Value, + Config: µsoftteams.CreateConfig{ + Webhook: &c.Webhook, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + if c.Description.WasSet { + input.Description = &c.Description.Value + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := microsoftteams.Create(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Created a '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go new file mode 100644 index 000000000..76440a40c --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go @@ -0,0 +1,95 @@ +package microsoftteams + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/microsoftteams" +) + +// DeleteCommand calls the Fastly API to delete Microsoft Teams alerts. +type DeleteCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand { + c := DeleteCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("delete", "Delete a Microsoft Teams alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + err := microsoftteams.Delete(context.TODO(), fc, µsoftteams.DeleteInput{ + WorkspaceID: &c.WorkspaceID.Value, + AlertID: &c.AlertID, + }) + if err != nil { + return err + } + + if c.JSONOutput.Enabled { + o := struct { + ID string `json:"id"` + Deleted bool `json:"deleted"` + }{ + c.AlertID, + true, + } + _, err := c.WriteJSON(out, o) + return err + } + + text.Success(out, "Deleted alert '%s' (workspace-id: %s)", c.AlertID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/doc.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/doc.go new file mode 100644 index 000000000..86e4e1cb8 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/doc.go @@ -0,0 +1,2 @@ +// Package microsoftteams contains commands to inspect and manipulate NGWAF Microsoft Teams alerts. +package microsoftteams diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go new file mode 100644 index 000000000..cf01b5330 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go @@ -0,0 +1,89 @@ +package microsoftteams + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/microsoftteams" +) + +// GetCommand calls the Fastly API to get Microsoft Teams alerts. +type GetCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetCommand returns a usable command registered under the parent. +func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { + c := GetCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get", "Get a Microsoft Teams alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := µsoftteams.GetInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := microsoftteams.Get(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlert(out, data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go new file mode 100644 index 000000000..87b980844 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go @@ -0,0 +1,81 @@ +package microsoftteams + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/microsoftteams" +) + +// ListCommand calls the Fastly API to list Microsoft Teams alerts. +type ListCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { + c := ListCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("list", "List Microsoft Teams alerts") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := µsoftteams.ListInput{ + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := microsoftteams.List(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlertTbl(out, data.Data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go new file mode 100644 index 000000000..38017bbc9 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go @@ -0,0 +1,412 @@ +package microsoftteams_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "testing" + + root "github.com/fastly/cli/pkg/commands/ngwaf" + workspaceroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + alertroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + sub "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/microsoftteams" + fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/microsoftteams" +) + +const ( + alertID = "3c4d5e6f7890abcdef123456" + workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" + description = "Test Microsoft Teams alert" +) + +var ( + webhook = "https://outlook.office.com/webhook/example" + teamsAlert = microsoftteams.Alert{ + ID: alertID, + Type: "microsoftTeams", + Description: description, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: microsoftteams.ResponseConfig{ + Webhook: &webhook, + }, + } +) + +func TestMicrosoftTeamsAlertCreate(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--webhook %s", webhook), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --webhook flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --webhook not provided", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --webhook %s", workspaceID, webhook), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(teamsAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", teamsAlert.Type, teamsAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --webhook %s --description %s", workspaceID, webhook, description), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(teamsAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", teamsAlert.Type, teamsAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --webhook %s --json", workspaceID, webhook), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(teamsAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(teamsAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "create"}, scenarios) +} + +func TestMicrosoftTeamsAlertList(t *testing.T) { + alertsObject := microsoftteams.Alerts{ + Data: []microsoftteams.Alert{ + { + ID: "1a2b3c4d5e6f7890abcdef12", + Type: "microsoftTeams", + Description: "First Microsoft Teams alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: microsoftteams.ResponseConfig{ + Webhook: &webhook, + }, + }, + { + ID: "2b3c4d5e6f7890abcdef1234", + Type: "microsoftTeams", + Description: "Second Microsoft Teams alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: microsoftteams.ResponseConfig{ + Webhook: &webhook, + }, + }, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: "", + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate internal server error", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + Status: http.StatusText(http.StatusInternalServerError), + }, + }, + }, + WantError: "500 - Internal Server Error", + }, + { + Name: "validate API success (zero alerts)", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(microsoftteams.Alerts{ + Data: []microsoftteams.Alert{}, + }))), + }, + }, + }, + WantOutput: zeroListString, + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: listString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --json", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(alertsObject), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "list"}, scenarios) +} + +func TestMicrosoftTeamsAlertGet(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(teamsAlert)))), + }, + }, + }, + WantOutput: alertString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(teamsAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(teamsAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get"}, scenarios) +} + +func TestMicrosoftTeamsAlertUpdate(t *testing.T) { + updatedWebhook := "https://outlook.office.com/webhook/updated" + updatedAlert := microsoftteams.Alert{ + ID: alertID, + Type: "microsoftTeams", + Description: "Updated description", + Config: microsoftteams.ResponseConfig{ + Webhook: &updatedWebhook, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --webhook https://outlook.office.com/webhook/updated", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success with webhook", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://outlook.office.com/webhook/updated", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://outlook.office.com/webhook/updated --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(updatedAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "update"}, scenarios) +} + +func TestMicrosoftTeamsAlertDelete(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNoContent, + Status: http.StatusText(http.StatusNoContent), + }, + }, + }, + WantOutput: fstfmt.Success("Deleted alert '%s' (workspace-id: %s)", alertID, workspaceID), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "delete"}, scenarios) +} + +var alertString = strings.TrimSpace(` +ID: 3c4d5e6f7890abcdef123456 +Type: microsoftTeams +Description: Test Microsoft Teams alert +Created At: 2025-11-25T16:40:12Z +Created By: test@example.com +Config: + Webhook: +`) + +var listString = strings.TrimSpace(` +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 microsoftTeams First Microsoft Teams alert 2025-11-25T16:40:12Z test@example.com Webhook: +2b3c4d5e6f7890abcdef1234 microsoftTeams Second Microsoft Teams alert 2025-11-25T16:40:12Z test@example.com Webhook: +`) + "\n" + +var zeroListString = strings.TrimSpace(` +ID Type Description Created At Created By Config +`) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/root.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/root.go new file mode 100644 index 000000000..773d49152 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/root.go @@ -0,0 +1,31 @@ +package microsoftteams + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "microsoftteams" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage Microsoft Teams workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go new file mode 100644 index 000000000..f1172a2d0 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go @@ -0,0 +1,97 @@ +package microsoftteams + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/microsoftteams" +) + +// UpdateCommand calls the Fastly API to update Microsoft Teams alerts. +type UpdateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags + common.WebhookConfigFlags +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { + c := UpdateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("update", "Update a Microsoft Teams alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + c.CmdClause.Flag("webhook", "Microsoft Teams webhook.").Required().StringVar(&c.Webhook) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := µsoftteams.UpdateInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + Config: µsoftteams.UpdateConfig{ + Webhook: &c.Webhook, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := microsoftteams.Update(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Updated '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go new file mode 100644 index 000000000..8eea51902 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go @@ -0,0 +1,96 @@ +package opsgenie + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/opsgenie" +) + +// CreateCommand calls the Fastly API to create Opsgenie alerts. +type CreateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags + common.KeyConfigFlags + + // Optional. + common.AlertDataFlags +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { + c := CreateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("create", "Create a Opsgenie alert").Alias("add") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.CmdClause.Flag("key", "Opsgenie integration key.").Required().StringVar(&c.Key) + + // Optional. + c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &opsgenie.CreateInput{ + WorkspaceID: &c.WorkspaceID.Value, + Config: &opsgenie.CreateConfig{ + Key: &c.Key, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + if c.Description.WasSet { + input.Description = &c.Description.Value + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := opsgenie.Create(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Created a '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go new file mode 100644 index 000000000..60bfb2fd0 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go @@ -0,0 +1,95 @@ +package opsgenie + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/opsgenie" +) + +// DeleteCommand calls the Fastly API to delete Opsgenie alerts. +type DeleteCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand { + c := DeleteCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("delete", "Delete a Opsgenie alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + err := opsgenie.Delete(context.TODO(), fc, &opsgenie.DeleteInput{ + WorkspaceID: &c.WorkspaceID.Value, + AlertID: &c.AlertID, + }) + if err != nil { + return err + } + + if c.JSONOutput.Enabled { + o := struct { + ID string `json:"id"` + Deleted bool `json:"deleted"` + }{ + c.AlertID, + true, + } + _, err := c.WriteJSON(out, o) + return err + } + + text.Success(out, "Deleted alert '%s' (workspace-id: %s)", c.AlertID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/doc.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/doc.go new file mode 100644 index 000000000..5a7b0b054 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/doc.go @@ -0,0 +1,2 @@ +// Package opsgenie contains commands to inspect and manipulate NGWAF Opsgenie alerts. +package opsgenie diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go new file mode 100644 index 000000000..927a1a263 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go @@ -0,0 +1,89 @@ +package opsgenie + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/opsgenie" +) + +// GetCommand calls the Fastly API to get Opsgenie alerts. +type GetCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetCommand returns a usable command registered under the parent. +func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { + c := GetCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get", "Get a Opsgenie alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &opsgenie.GetInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := opsgenie.Get(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlert(out, data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go new file mode 100644 index 000000000..595c36a6a --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go @@ -0,0 +1,81 @@ +package opsgenie + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/opsgenie" +) + +// ListCommand calls the Fastly API to list Opsgenie alerts. +type ListCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { + c := ListCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("list", "List Opsgenie alerts") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &opsgenie.ListInput{ + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := opsgenie.List(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlertTbl(out, data.Data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go new file mode 100644 index 000000000..6538df787 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go @@ -0,0 +1,412 @@ +package opsgenie_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "testing" + + root "github.com/fastly/cli/pkg/commands/ngwaf" + workspaceroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + alertroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + sub "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/opsgenie" + fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/opsgenie" +) + +const ( + alertID = "4d5e6f7890abcdef12345678" + workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" + description = "Test Opsgenie alert" +) + +var ( + key = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + opsgenieAlert = opsgenie.Alert{ + ID: alertID, + Type: "opsgenie", + Description: description, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: opsgenie.ResponseConfig{ + Key: &key, + }, + } +) + +func TestOpsgenieAlertCreate(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--key %s", key), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --key flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --key not provided", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --key %s", workspaceID, key), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(opsgenieAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", opsgenieAlert.Type, opsgenieAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --key %s --description %s", workspaceID, key, description), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(opsgenieAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", opsgenieAlert.Type, opsgenieAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --key %s --json", workspaceID, key), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(opsgenieAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(opsgenieAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "create"}, scenarios) +} + +func TestOpsgenieAlertList(t *testing.T) { + alertsObject := opsgenie.Alerts{ + Data: []opsgenie.Alert{ + { + ID: "1a2b3c4d5e6f7890abcdef12", + Type: "opsgenie", + Description: "First Opsgenie alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: opsgenie.ResponseConfig{ + Key: &key, + }, + }, + { + ID: "2b3c4d5e6f7890abcdef1234", + Type: "opsgenie", + Description: "Second Opsgenie alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: opsgenie.ResponseConfig{ + Key: &key, + }, + }, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: "", + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate internal server error", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + Status: http.StatusText(http.StatusInternalServerError), + }, + }, + }, + WantError: "500 - Internal Server Error", + }, + { + Name: "validate API success (zero alerts)", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(opsgenie.Alerts{ + Data: []opsgenie.Alert{}, + }))), + }, + }, + }, + WantOutput: zeroListString, + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: listString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --json", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(alertsObject), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "list"}, scenarios) +} + +func TestOpsgenieAlertGet(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(opsgenieAlert)))), + }, + }, + }, + WantOutput: alertString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(opsgenieAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(opsgenieAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get"}, scenarios) +} + +func TestOpsgenieAlertUpdate(t *testing.T) { + updatedKey := "updated-key-1234" + updatedAlert := opsgenie.Alert{ + ID: alertID, + Type: "opsgenie", + Description: "Updated description", + Config: opsgenie.ResponseConfig{ + Key: &updatedKey, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --key updated-key-1234", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success with key", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-1234", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-1234 --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(updatedAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "update"}, scenarios) +} + +func TestOpsgenieAlertDelete(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNoContent, + Status: http.StatusText(http.StatusNoContent), + }, + }, + }, + WantOutput: fstfmt.Success("Deleted alert '%s' (workspace-id: %s)", alertID, workspaceID), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "delete"}, scenarios) +} + +var alertString = strings.TrimSpace(` +ID: 4d5e6f7890abcdef12345678 +Type: opsgenie +Description: Test Opsgenie alert +Created At: 2025-11-25T16:40:12Z +Created By: test@example.com +Config: + Key: +`) + +var listString = strings.TrimSpace(` +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 opsgenie First Opsgenie alert 2025-11-25T16:40:12Z test@example.com Key: +2b3c4d5e6f7890abcdef1234 opsgenie Second Opsgenie alert 2025-11-25T16:40:12Z test@example.com Key: +`) + "\n" + +var zeroListString = strings.TrimSpace(` +ID Type Description Created At Created By Config +`) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/root.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/root.go new file mode 100644 index 000000000..79a53ab72 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/root.go @@ -0,0 +1,31 @@ +package opsgenie + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "opsgenie" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage Opsgenie workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go new file mode 100644 index 000000000..14503b735 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go @@ -0,0 +1,97 @@ +package opsgenie + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/opsgenie" +) + +// UpdateCommand calls the Fastly API to update Opsgenie alerts. +type UpdateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags + common.KeyConfigFlags +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { + c := UpdateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("update", "Update a Opsgenie alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + c.CmdClause.Flag("key", "Opsgenie integration key.").Required().StringVar(&c.Key) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &opsgenie.UpdateInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + Config: &opsgenie.UpdateConfig{ + Key: &c.Key, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := opsgenie.Update(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Updated '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go new file mode 100644 index 000000000..bb5742dce --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go @@ -0,0 +1,96 @@ +package pagerduty + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/pagerduty" +) + +// CreateCommand calls the Fastly API to create PagerDuty alerts. +type CreateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags + common.KeyConfigFlags + + // Optional. + common.AlertDataFlags +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { + c := CreateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("create", "Create a PagerDuty alert").Alias("add") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.CmdClause.Flag("key", "PagerDuty integration key.").Required().StringVar(&c.Key) + + // Optional. + c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &pagerduty.CreateInput{ + WorkspaceID: &c.WorkspaceID.Value, + Config: &pagerduty.CreateConfig{ + Key: &c.Key, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + if c.Description.WasSet { + input.Description = &c.Description.Value + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := pagerduty.Create(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Created a '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go new file mode 100644 index 000000000..74e57ecc1 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go @@ -0,0 +1,95 @@ +package pagerduty + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/pagerduty" +) + +// DeleteCommand calls the Fastly API to delete PagerDuty alerts. +type DeleteCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand { + c := DeleteCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("delete", "Delete a PagerDuty alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + err := pagerduty.Delete(context.TODO(), fc, &pagerduty.DeleteInput{ + WorkspaceID: &c.WorkspaceID.Value, + AlertID: &c.AlertID, + }) + if err != nil { + return err + } + + if c.JSONOutput.Enabled { + o := struct { + ID string `json:"id"` + Deleted bool `json:"deleted"` + }{ + c.AlertID, + true, + } + _, err := c.WriteJSON(out, o) + return err + } + + text.Success(out, "Deleted alert '%s' (workspace-id: %s)", c.AlertID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/doc.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/doc.go new file mode 100644 index 000000000..6ec40bc20 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/doc.go @@ -0,0 +1,2 @@ +// Package pagerduty contains commands to inspect and manipulate NGWAF PagerDuty alerts. +package pagerduty diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go new file mode 100644 index 000000000..b3af0a62c --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go @@ -0,0 +1,89 @@ +package pagerduty + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/pagerduty" +) + +// GetCommand calls the Fastly API to get PagerDuty alerts. +type GetCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetCommand returns a usable command registered under the parent. +func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { + c := GetCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get", "Get a PagerDuty alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &pagerduty.GetInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := pagerduty.Get(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlert(out, data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go new file mode 100644 index 000000000..e957bd18d --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go @@ -0,0 +1,81 @@ +package pagerduty + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/pagerduty" +) + +// ListCommand calls the Fastly API to list PagerDuty alerts. +type ListCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { + c := ListCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("list", "List PagerDuty alerts") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &pagerduty.ListInput{ + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := pagerduty.List(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlertTbl(out, data.Data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go new file mode 100644 index 000000000..361abbc98 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go @@ -0,0 +1,412 @@ +package pagerduty_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "testing" + + root "github.com/fastly/cli/pkg/commands/ngwaf" + workspaceroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + alertroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + sub "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/pagerduty" + fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/pagerduty" +) + +const ( + alertID = "5e6f7890abcdef1234567890" + workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" + description = "Test PagerDuty alert" +) + +var ( + key = "a1b2c3d4e5f67890abcdef1234567890" + pagerdutyAlert = pagerduty.Alert{ + ID: alertID, + Type: "pagerDuty", + Description: description, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: pagerduty.ResponseConfig{ + Key: &key, + }, + } +) + +func TestPagerDutyAlertCreate(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--key %s", key), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --key flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --key not provided", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --key %s", workspaceID, key), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(pagerdutyAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", pagerdutyAlert.Type, pagerdutyAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --key %s --description %s", workspaceID, key, description), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(pagerdutyAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", pagerdutyAlert.Type, pagerdutyAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --key %s --json", workspaceID, key), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(pagerdutyAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(pagerdutyAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "create"}, scenarios) +} + +func TestPagerDutyAlertList(t *testing.T) { + alertsObject := pagerduty.Alerts{ + Data: []pagerduty.Alert{ + { + ID: "1a2b3c4d5e6f7890abcdef12", + Type: "pagerDuty", + Description: "First PagerDuty alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: pagerduty.ResponseConfig{ + Key: &key, + }, + }, + { + ID: "2b3c4d5e6f7890abcdef1234", + Type: "pagerDuty", + Description: "Second PagerDuty alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: pagerduty.ResponseConfig{ + Key: &key, + }, + }, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: "", + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate internal server error", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + Status: http.StatusText(http.StatusInternalServerError), + }, + }, + }, + WantError: "500 - Internal Server Error", + }, + { + Name: "validate API success (zero alerts)", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(pagerduty.Alerts{ + Data: []pagerduty.Alert{}, + }))), + }, + }, + }, + WantOutput: zeroListString, + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: listString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --json", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(alertsObject), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "list"}, scenarios) +} + +func TestPagerDutyAlertGet(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(pagerdutyAlert)))), + }, + }, + }, + WantOutput: alertString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(pagerdutyAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(pagerdutyAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get"}, scenarios) +} + +func TestPagerDutyAlertUpdate(t *testing.T) { + updatedKey := "updated-key-9876543210" + updatedAlert := pagerduty.Alert{ + ID: alertID, + Type: "pagerDuty", + Description: "Updated description", + Config: pagerduty.ResponseConfig{ + Key: &updatedKey, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --key updated-key-9876543210", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success with key", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210 --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(updatedAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "update"}, scenarios) +} + +func TestPagerDutyAlertDelete(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNoContent, + Status: http.StatusText(http.StatusNoContent), + }, + }, + }, + WantOutput: fstfmt.Success("Deleted alert '%s' (workspace-id: %s)", alertID, workspaceID), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "delete"}, scenarios) +} + +var alertString = strings.TrimSpace(` +ID: 5e6f7890abcdef1234567890 +Type: pagerDuty +Description: Test PagerDuty alert +Created At: 2025-11-25T16:40:12Z +Created By: test@example.com +Config: + Key: +`) + +var listString = strings.TrimSpace(` +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 pagerDuty First PagerDuty alert 2025-11-25T16:40:12Z test@example.com Key: +2b3c4d5e6f7890abcdef1234 pagerDuty Second PagerDuty alert 2025-11-25T16:40:12Z test@example.com Key: +`) + "\n" + +var zeroListString = strings.TrimSpace(` +ID Type Description Created At Created By Config +`) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/root.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/root.go new file mode 100644 index 000000000..b0b85dd6c --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/root.go @@ -0,0 +1,31 @@ +package pagerduty + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "pagerduty" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage PagerDuty workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go new file mode 100644 index 000000000..a3a461f20 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go @@ -0,0 +1,97 @@ +package pagerduty + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/pagerduty" +) + +// UpdateCommand calls the Fastly API to update PagerDuty alerts. +type UpdateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags + common.KeyConfigFlags +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { + c := UpdateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("update", "Update a PagerDuty alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + c.CmdClause.Flag("key", "PagerDuty integration key.").Required().StringVar(&c.Key) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &pagerduty.UpdateInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + Config: &pagerduty.UpdateConfig{ + Key: &c.Key, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := pagerduty.Update(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Updated '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/slack/create.go b/pkg/commands/ngwaf/workspace/alert/slack/create.go new file mode 100644 index 000000000..439837d21 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/slack/create.go @@ -0,0 +1,96 @@ +package slack + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/slack" +) + +// CreateCommand calls the Fastly API to create Slack alerts. +type CreateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags + common.WebhookConfigFlags + + // Optional. + common.AlertDataFlags +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { + c := CreateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("create", "Create a Slack alert").Alias("add") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.CmdClause.Flag("webhook", "Slack webhook.").Required().StringVar(&c.Webhook) + + // Optional. + c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &slack.CreateInput{ + WorkspaceID: &c.WorkspaceID.Value, + Config: &slack.CreateConfig{ + Webhook: &c.Webhook, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + if c.Description.WasSet { + input.Description = &c.Description.Value + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := slack.Create(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Created a '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/slack/delete.go b/pkg/commands/ngwaf/workspace/alert/slack/delete.go new file mode 100644 index 000000000..6af5c688f --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/slack/delete.go @@ -0,0 +1,95 @@ +package slack + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/slack" +) + +// DeleteCommand calls the Fastly API to delete Slack alerts. +type DeleteCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand { + c := DeleteCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("delete", "Delete a Slack alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + err := slack.Delete(context.TODO(), fc, &slack.DeleteInput{ + WorkspaceID: &c.WorkspaceID.Value, + AlertID: &c.AlertID, + }) + if err != nil { + return err + } + + if c.JSONOutput.Enabled { + o := struct { + ID string `json:"id"` + Deleted bool `json:"deleted"` + }{ + c.AlertID, + true, + } + _, err := c.WriteJSON(out, o) + return err + } + + text.Success(out, "Deleted alert '%s' (workspace-id: %s)", c.AlertID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/slack/doc.go b/pkg/commands/ngwaf/workspace/alert/slack/doc.go new file mode 100644 index 000000000..cc6bc76c1 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/slack/doc.go @@ -0,0 +1,2 @@ +// Package slack contains commands to inspect and manipulate NGWAF Slack alerts. +package slack diff --git a/pkg/commands/ngwaf/workspace/alert/slack/get.go b/pkg/commands/ngwaf/workspace/alert/slack/get.go new file mode 100644 index 000000000..d429bb000 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/slack/get.go @@ -0,0 +1,89 @@ +package slack + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/slack" +) + +// GetCommand calls the Fastly API to get Slack alerts. +type GetCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetCommand returns a usable command registered under the parent. +func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { + c := GetCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get", "Get a Slack alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &slack.GetInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := slack.Get(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlert(out, data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/slack/list.go b/pkg/commands/ngwaf/workspace/alert/slack/list.go new file mode 100644 index 000000000..c44b52fa2 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/slack/list.go @@ -0,0 +1,81 @@ +package slack + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/slack" +) + +// ListCommand calls the Fastly API to list Slack alerts. +type ListCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { + c := ListCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("list", "List Slack alerts") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &slack.ListInput{ + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := slack.List(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlertTbl(out, data.Data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/slack/root.go b/pkg/commands/ngwaf/workspace/alert/slack/root.go new file mode 100644 index 000000000..e8253a1e4 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/slack/root.go @@ -0,0 +1,31 @@ +package slack + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "slack" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage Slack workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go b/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go new file mode 100644 index 000000000..af89b9fe5 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go @@ -0,0 +1,412 @@ +package slack_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "testing" + + root "github.com/fastly/cli/pkg/commands/ngwaf" + workspaceroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + alertroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + sub "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/slack" + fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/slack" +) + +const ( + alertID = "1a2b3c4d5e6f7890abcdef12" + workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" + description = "Test slack alert" +) + +var ( + webhook = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX" + slackAlert = slack.Alert{ + ID: alertID, + Type: "slack", + Description: description, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: slack.ResponseConfig{ + Webhook: &webhook, + }, + } +) + +func TestSlackAlertCreate(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--webhook %s", webhook), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --webhook flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --webhook not provided", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --webhook %s", workspaceID, webhook), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(slackAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", slackAlert.Type, slackAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --webhook %s --description %s", workspaceID, webhook, description), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(slackAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", slackAlert.Type, slackAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --webhook %s --json", workspaceID, webhook), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(slackAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(slackAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "create"}, scenarios) +} + +func TestSlackAlertList(t *testing.T) { + alertsObject := slack.Alerts{ + Data: []slack.Alert{ + { + ID: "1a2b3c4d5e6f7890abcdef12", + Type: "slack", + Description: "First slack alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: slack.ResponseConfig{ + Webhook: &webhook, + }, + }, + { + ID: "2b3c4d5e6f7890abcdef1234", + Type: "slack", + Description: "Second slack alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: slack.ResponseConfig{ + Webhook: &webhook, + }, + }, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: "", + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate internal server error", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + Status: http.StatusText(http.StatusInternalServerError), + }, + }, + }, + WantError: "500 - Internal Server Error", + }, + { + Name: "validate API success (zero alerts)", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(slack.Alerts{ + Data: []slack.Alert{}, + }))), + }, + }, + }, + WantOutput: zeroListString, + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: listString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --json", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(alertsObject), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "list"}, scenarios) +} + +func TestSlackAlertGet(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(slackAlert)))), + }, + }, + }, + WantOutput: alertString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(slackAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(slackAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get"}, scenarios) +} + +func TestSlackAlertUpdate(t *testing.T) { + updatedWebhook := "https://hooks.slack.com/services/updated" + updatedAlert := slack.Alert{ + ID: alertID, + Type: "slack", + Description: "Updated description", + Config: slack.ResponseConfig{ + Webhook: &updatedWebhook, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --webhook https://hooks.slack.com/services/updated", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success with webhook", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://hooks.slack.com/services/updated", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://hooks.slack.com/services/updated --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(updatedAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "update"}, scenarios) +} + +func TestSlackAlertDelete(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNoContent, + Status: http.StatusText(http.StatusNoContent), + }, + }, + }, + WantOutput: fstfmt.Success("Deleted alert '%s' (workspace-id: %s)", alertID, workspaceID), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "delete"}, scenarios) +} + +var alertString = strings.TrimSpace(` +ID: 1a2b3c4d5e6f7890abcdef12 +Type: slack +Description: Test slack alert +Created At: 2025-11-25T16:40:12Z +Created By: test@example.com +Config: + Webhook: +`) + +var listString = strings.TrimSpace(` +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 slack First slack alert 2025-11-25T16:40:12Z test@example.com Webhook: +2b3c4d5e6f7890abcdef1234 slack Second slack alert 2025-11-25T16:40:12Z test@example.com Webhook: +`) + "\n" + +var zeroListString = strings.TrimSpace(` +ID Type Description Created At Created By Config +`) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/slack/update.go b/pkg/commands/ngwaf/workspace/alert/slack/update.go new file mode 100644 index 000000000..e091406e5 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/slack/update.go @@ -0,0 +1,97 @@ +package slack + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/slack" +) + +// UpdateCommand calls the Fastly API to update Slack alerts. +type UpdateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags + common.WebhookConfigFlags +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { + c := UpdateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("update", "Update a Slack alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + c.CmdClause.Flag("webhook", "Slack webhook.").Required().StringVar(&c.Webhook) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &slack.UpdateInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + Config: &slack.UpdateConfig{ + Webhook: &c.Webhook, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := slack.Update(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Updated '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/create.go b/pkg/commands/ngwaf/workspace/alert/webhook/create.go new file mode 100644 index 000000000..9ea99f1a8 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/create.go @@ -0,0 +1,96 @@ +package webhook + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +// CreateCommand calls the Fastly API to create Webhook alerts. +type CreateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags + common.WebhookConfigFlags + + // Optional. + common.AlertDataFlags +} + +// NewCreateCommand returns a usable command registered under the parent. +func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { + c := CreateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("create", "Create a Webhook alert").Alias("add") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.CmdClause.Flag("webhook", "Webhook webhook.").Required().StringVar(&c.Webhook) + + // Optional. + c.CmdClause.Flag("description", "An optional description for the alert.").Action(c.Description.Set).StringVar(&c.Description.Value) + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &webhook.CreateInput{ + WorkspaceID: &c.WorkspaceID.Value, + Config: &webhook.CreateConfig{ + Webhook: &c.Webhook, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + if c.Description.WasSet { + input.Description = &c.Description.Value + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := webhook.Create(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Created a '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go new file mode 100644 index 000000000..c1085fd34 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go @@ -0,0 +1,95 @@ +package webhook + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +// DeleteCommand calls the Fastly API to delete Webhook alerts. +type DeleteCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewDeleteCommand returns a usable command registered under the parent. +func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand { + c := DeleteCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("delete", "Delete a Webhook alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + err := webhook.Delete(context.TODO(), fc, &webhook.DeleteInput{ + WorkspaceID: &c.WorkspaceID.Value, + AlertID: &c.AlertID, + }) + if err != nil { + return err + } + + if c.JSONOutput.Enabled { + o := struct { + ID string `json:"id"` + Deleted bool `json:"deleted"` + }{ + c.AlertID, + true, + } + _, err := c.WriteJSON(out, o) + return err + } + + text.Success(out, "Deleted alert '%s' (workspace-id: %s)", c.AlertID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/doc.go b/pkg/commands/ngwaf/workspace/alert/webhook/doc.go new file mode 100644 index 000000000..09586faed --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/doc.go @@ -0,0 +1,2 @@ +// Package webhook contains commands to inspect and manipulate NGWAF Webhook alerts. +package webhook diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go new file mode 100644 index 000000000..f3879c5e1 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go @@ -0,0 +1,89 @@ +package webhook + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +// GetSigningKeyCommand calls the Fastly API to get Webhook alerts. +type GetSigningKeyCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetSigningKeyCommand returns a usable command registered under the parent. +func NewGetSigningKeyCommand(parent argparser.Registerer, g *global.Data) *GetSigningKeyCommand { + c := GetSigningKeyCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get-signing-key", "Retrieves details of a webhook alert signing key") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetSigningKeyCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &webhook.GetKeyInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := webhook.GetKey(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Signing Key: '%s' (Workspace: %s)", data.SigningKey, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get.go b/pkg/commands/ngwaf/workspace/alert/webhook/get.go new file mode 100644 index 000000000..3a33add53 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get.go @@ -0,0 +1,89 @@ +package webhook + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +// GetCommand calls the Fastly API to get Webhook alerts. +type GetCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewGetCommand returns a usable command registered under the parent. +func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { + c := GetCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("get", "Get a Webhook alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &webhook.GetInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := webhook.Get(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlert(out, data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/list.go b/pkg/commands/ngwaf/workspace/alert/webhook/list.go new file mode 100644 index 000000000..612cdafd0 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/list.go @@ -0,0 +1,81 @@ +package webhook + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +// ListCommand calls the Fastly API to list Webhook alerts. +type ListCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.BaseAlertFlags +} + +// NewListCommand returns a usable command registered under the parent. +func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { + c := ListCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("list", "List Webhook alerts") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &webhook.ListInput{ + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := webhook.List(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.PrintAlertTbl(out, data.Data) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/root.go b/pkg/commands/ngwaf/workspace/alert/webhook/root.go new file mode 100644 index 000000000..a6dcccadb --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/root.go @@ -0,0 +1,31 @@ +package webhook + +import ( + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/global" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + argparser.Base + // no flags +} + +// CommandName is the string to be used to invoke this command. +const CommandName = "webhook" + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + c.CmdClause = parent.Command(CommandName, "Manage Webhook workspace alerts") + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { + panic("unreachable") +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go new file mode 100644 index 000000000..b78372137 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go @@ -0,0 +1,89 @@ +package webhook + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +// RotateSigningKeyCommand calls the Fastly API to get Webhook alerts. +type RotateSigningKeyCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags +} + +// NewRotateSigningKeyCommand returns a usable command registered under the parent. +func NewRotateSigningKeyCommand(parent argparser.Registerer, g *global.Data) *RotateSigningKeyCommand { + c := RotateSigningKeyCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("rotate-signing-key", "Rotate webhook alert signing key") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *RotateSigningKeyCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + input := &webhook.RotateKeyInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := webhook.RotateKey(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Signing Key: '%s' (Workspace: %s)", data.SigningKey, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/update.go b/pkg/commands/ngwaf/workspace/alert/webhook/update.go new file mode 100644 index 000000000..8440f6d65 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/update.go @@ -0,0 +1,97 @@ +package webhook + +import ( + "context" + "errors" + "io" + + "github.com/fastly/cli/pkg/argparser" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/text" + "github.com/fastly/go-fastly/v12/fastly" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +// UpdateCommand calls the Fastly API to update Webhook alerts. +type UpdateCommand struct { + argparser.Base + argparser.JSONOutput + + // Required. + common.AlertIDFlags + common.BaseAlertFlags + common.WebhookConfigFlags +} + +// NewUpdateCommand returns a usable command registered under the parent. +func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { + c := UpdateCommand{ + Base: argparser.Base{ + Globals: g, + }, + } + c.CmdClause = parent.Command("update", "Update a Webhook alert") + + // Required. + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, + ForceRequired: true, + }) + c.RegisterFlag(argparser.StringFlagOpts{ + Name: argparser.FlagNGWAFAlertID, + Description: argparser.FlagNGWAFAlertIDDesc, + Dst: &c.AlertID, + Required: true, + }) + c.CmdClause.Flag("webhook", "Webhook webhook.").Required().StringVar(&c.Webhook) + + // Optional. + c.RegisterFlagBool(c.JSONFlag()) + + return &c +} + +// Exec invokes the application logic for the command. +func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { + // Call Parse() to ensure that we check if workspaceID + // is set or to throw the appropriate error. + if err := c.WorkspaceID.Parse(); err != nil { + return err + } + if c.Globals.Verbose() && c.JSONOutput.Enabled { + return fsterr.ErrInvalidVerboseJSONCombo + } + + input := &webhook.UpdateInput{ + AlertID: &c.AlertID, + WorkspaceID: &c.WorkspaceID.Value, + Config: &webhook.UpdateConfig{ + Webhook: &c.Webhook, + }, + // Set 'Events' to the only possible value, 'flag' + Events: common.GetDefaultEvents(), + } + + fc, ok := c.Globals.APIClient.(*fastly.Client) + if !ok { + return errors.New("failed to convert interface to a fastly client") + } + + data, err := webhook.Update(context.TODO(), fc, input) + if err != nil { + return err + } + + if ok, err := c.WriteJSON(out, data); ok { + return err + } + + text.Success(out, "Updated '%s' alert '%s' (workspace-id: %s)", data.Type, data.ID, c.WorkspaceID.Value) + return nil +} diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go b/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go new file mode 100644 index 000000000..e82ff100f --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go @@ -0,0 +1,550 @@ +package webhook_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "strings" + "testing" + + root "github.com/fastly/cli/pkg/commands/ngwaf" + workspaceroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace" + alertroot "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" + sub "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/webhook" + fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/testutil" + "github.com/fastly/go-fastly/v12/fastly/ngwaf/v1/workspaces/alerts/webhook" +) + +const ( + alertID = "6f7890abcdef123456789012" + workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" + description = "Test webhook alert" + signingKey = "a1b2c3d4e5f67890abcdef1234567890" +) + +var ( + webhookURL = "https://example.com/webhook" + webhookAlert = webhook.Alert{ + ID: alertID, + Type: "webhook", + Description: description, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: webhook.ResponseConfig{ + Webhook: &webhookURL, + }, + } +) + +func TestWebhookAlertCreate(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--webhook %s", webhookURL), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --webhook flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --webhook not provided", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --webhook %s", workspaceID, webhookURL), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(webhookAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", webhookAlert.Type, webhookAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --webhook %s --description %s", workspaceID, webhookURL, description), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(webhookAlert)))), + }, + }, + }, + WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", webhookAlert.Type, webhookAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --webhook %s --json", workspaceID, webhookURL), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusCreated, + Status: http.StatusText(http.StatusCreated), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(webhookAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(webhookAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "create"}, scenarios) +} + +func TestWebhookAlertList(t *testing.T) { + alertsObject := webhook.Alerts{ + Data: []webhook.Alert{ + { + ID: "1a2b3c4d5e6f7890abcdef12", + Type: "webhook", + Description: "First webhook alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: webhook.ResponseConfig{ + Webhook: &webhookURL, + }, + }, + { + ID: "2b3c4d5e6f7890abcdef1234", + Type: "webhook", + Description: "Second webhook alert", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", + Config: webhook.ResponseConfig{ + Webhook: &webhookURL, + }, + }, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: "", + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate internal server error", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + Status: http.StatusText(http.StatusInternalServerError), + }, + }, + }, + WantError: "500 - Internal Server Error", + }, + { + Name: "validate API success (zero alerts)", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(webhook.Alerts{ + Data: []webhook.Alert{}, + }))), + }, + }, + }, + WantOutput: zeroListString, + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: listString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --json", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(alertsObject))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(alertsObject), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "list"}, scenarios) +} + +func TestWebhookAlertGet(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(webhookAlert)))), + }, + }, + }, + WantOutput: alertString, + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(webhookAlert)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(webhookAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get"}, scenarios) +} + +func TestWebhookAlertUpdate(t *testing.T) { + updatedWebhookURL := "https://example.com/webhook/updated" + updatedAlert := webhook.Alert{ + ID: alertID, + Type: "webhook", + Description: "Updated description", + Config: webhook.ResponseConfig{ + Webhook: &updatedWebhookURL, + }, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --webhook https://example.com/webhook/updated", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success with webhook", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://example.com/webhook/updated", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate API success with description", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://example.com/webhook/updated --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(updatedAlert), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "update"}, scenarios) +} + +func TestWebhookAlertDelete(t *testing.T) { + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNoContent, + Status: http.StatusText(http.StatusNoContent), + }, + }, + }, + WantOutput: fstfmt.Success("Deleted alert '%s' (workspace-id: %s)", alertID, workspaceID), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "delete"}, scenarios) +} + +func TestWebhookGetSigningKey(t *testing.T) { + signingKeyResponse := webhook.AlertsKey{ + SigningKey: signingKey, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(signingKeyResponse)))), + }, + }, + }, + WantOutput: fstfmt.Success("Signing Key: '%s' (Workspace: %s)", signingKeyResponse.SigningKey, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(signingKeyResponse)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(signingKeyResponse), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "get-signing-key"}, scenarios) +} + +func TestWebhookRotateSigningKey(t *testing.T) { + newSigningKey := "new-signing-key-0987654321" + signingKeyResponse := webhook.AlertsKey{ + SigningKey: newSigningKey, + } + + scenarios := []testutil.CLIScenario{ + { + Name: "validate missing --workspace-id flag", + Args: fmt.Sprintf("--alert-id %s", alertID), + WantError: "error parsing arguments: required flag --workspace-id not provided", + }, + { + Name: "validate missing --alert-id flag", + Args: fmt.Sprintf("--workspace-id %s", workspaceID), + WantError: "error parsing arguments: required flag --alert-id not provided", + }, + { + Name: "validate not found", + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid", workspaceID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(` + { + "title": "This resource does not exist", + "status": 404 + } + `))), + }, + }, + }, + WantError: "404 - Not Found", + }, + { + Name: "validate API success", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(signingKeyResponse)))), + }, + }, + }, + WantOutput: fstfmt.Success("Signing Key: '%s' (Workspace: %s)", signingKeyResponse.SigningKey, workspaceID), + }, + { + Name: "validate optional --json flag", + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --json", workspaceID, alertID), + Client: &http.Client{ + Transport: &testutil.MockRoundTripper{ + Response: &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(signingKeyResponse)))), + }, + }, + }, + WantOutput: fstfmt.EncodeJSON(signingKeyResponse), + }, + } + + testutil.RunCLIScenarios(t, []string{root.CommandName, workspaceroot.CommandName, alertroot.CommandName, sub.CommandName, "rotate-signing-key"}, scenarios) +} + +var alertString = strings.TrimSpace(` +ID: 6f7890abcdef123456789012 +Type: webhook +Description: Test webhook alert +Created At: 2025-11-25T16:40:12Z +Created By: test@example.com +Config: + Webhook: +`) + +var listString = strings.TrimSpace(` +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 webhook First webhook alert 2025-11-25T16:40:12Z test@example.com Webhook: +2b3c4d5e6f7890abcdef1234 webhook Second webhook alert 2025-11-25T16:40:12Z test@example.com Webhook: +`) + "\n" + +var zeroListString = strings.TrimSpace(` +ID Type Description Created At Created By Config +`) + "\n" diff --git a/pkg/text/alerts.go b/pkg/text/alerts.go index 01c6e5539..661cced87 100644 --- a/pkg/text/alerts.go +++ b/pkg/text/alerts.go @@ -207,12 +207,18 @@ func getConfigSummary(alertType string, config any) string { if cfg.Host != nil { parts = append(parts, fmt.Sprintf("Host: %s", *cfg.Host)) } - if cfg.Project != nil { - parts = append(parts, fmt.Sprintf("Project: %s", *cfg.Project)) + if cfg.IssueType != nil { + parts = append(parts, fmt.Sprintf("Issue Type: %s", *cfg.IssueType)) } if cfg.Key != nil { parts = append(parts, "Key: ") } + if cfg.Project != nil { + parts = append(parts, fmt.Sprintf("Project: %s", *cfg.Project)) + } + if cfg.Username != nil { + parts = append(parts, fmt.Sprintf("Username: %s", *cfg.Username)) + } return strings.Join(parts, ", ") } case "mailinglist": From 2100a7cea85827edaf0d7d6efef943e30d47ce90 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 1 Dec 2025 14:02:35 -0500 Subject: [PATCH 05/13] Test Updates and Revert back to Parse() Usage --- pkg/argparser/flags.go | 18 +-- .../workspace/alert/datadog/datadog_test.go | 82 +++++++----- .../ngwaf/workspace/alert/jira/create.go | 9 +- .../ngwaf/workspace/alert/jira/delete.go | 9 +- .../ngwaf/workspace/alert/jira/get.go | 9 +- .../ngwaf/workspace/alert/jira/jira_test.go | 71 +++++----- .../ngwaf/workspace/alert/jira/list.go | 9 +- .../ngwaf/workspace/alert/jira/update.go | 9 +- .../workspace/alert/mailinglist/create.go | 9 +- .../workspace/alert/mailinglist/delete.go | 9 +- .../ngwaf/workspace/alert/mailinglist/get.go | 9 +- .../ngwaf/workspace/alert/mailinglist/list.go | 9 +- .../alert/mailinglist/mailinglist_test.go | 123 ++++++++++-------- .../workspace/alert/mailinglist/update.go | 9 +- .../workspace/alert/microsoftteams/create.go | 9 +- .../workspace/alert/microsoftteams/delete.go | 9 +- .../workspace/alert/microsoftteams/get.go | 9 +- .../workspace/alert/microsoftteams/list.go | 9 +- .../microsoftteams/microsoftteams_test.go | 121 +++++++++-------- .../workspace/alert/microsoftteams/update.go | 9 +- .../ngwaf/workspace/alert/opsgenie/create.go | 9 +- .../ngwaf/workspace/alert/opsgenie/delete.go | 9 +- .../ngwaf/workspace/alert/opsgenie/get.go | 9 +- .../ngwaf/workspace/alert/opsgenie/list.go | 9 +- .../workspace/alert/opsgenie/opsgenie_test.go | 93 ++++++++----- .../ngwaf/workspace/alert/opsgenie/update.go | 9 +- .../ngwaf/workspace/alert/pagerduty/create.go | 9 +- .../ngwaf/workspace/alert/pagerduty/delete.go | 9 +- .../ngwaf/workspace/alert/pagerduty/get.go | 9 +- .../ngwaf/workspace/alert/pagerduty/list.go | 9 +- .../alert/pagerduty/pagerduty_test.go | 121 +++++++++-------- .../ngwaf/workspace/alert/pagerduty/update.go | 9 +- .../ngwaf/workspace/alert/slack/create.go | 9 +- .../ngwaf/workspace/alert/slack/delete.go | 9 +- .../ngwaf/workspace/alert/slack/get.go | 9 +- .../ngwaf/workspace/alert/slack/list.go | 9 +- .../ngwaf/workspace/alert/slack/slack_test.go | 107 ++++++++------- .../ngwaf/workspace/alert/slack/update.go | 9 +- .../ngwaf/workspace/alert/webhook/create.go | 9 +- .../ngwaf/workspace/alert/webhook/delete.go | 9 +- .../alert/webhook/get-signing-key.go | 9 +- .../ngwaf/workspace/alert/webhook/get.go | 9 +- .../ngwaf/workspace/alert/webhook/list.go | 9 +- .../alert/webhook/rotate-signing-key.go | 9 +- .../ngwaf/workspace/alert/webhook/update.go | 9 +- .../workspace/alert/webhook/webhook_test.go | 111 +++++++++------- pkg/testutil/client.go | 22 ++++ 47 files changed, 636 insertions(+), 566 deletions(-) diff --git a/pkg/argparser/flags.go b/pkg/argparser/flags.go index ae73f0611..c08a685d9 100644 --- a/pkg/argparser/flags.go +++ b/pkg/argparser/flags.go @@ -33,11 +33,9 @@ type StringFlagOpts struct { Action kingpin.Action Description string Dst *string - // Shows as required in help text without enforcing at parse time - ForceRequired bool - Name string - Required bool - Short rune + Name string + Required bool + Short rune } // RegisterFlag defines a flag. @@ -46,15 +44,7 @@ func (b Base) RegisterFlag(opts StringFlagOpts) { if opts.Short > 0 { clause = clause.Short(opts.Short) } - // ForceRequired makes the flag show as required and uses env var as fallback - if opts.ForceRequired { - // For workspace-id, use FASTLY_WORKSPACE_ID env var as fallback - if opts.Name == FlagNGWAFWorkspaceID { - clause = clause.Required().Envar(env.WorkspaceID) - } else { - clause = clause.Required() - } - } else if opts.Required { + if opts.Required { clause = clause.Required() } if opts.Action != nil { diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/datadog_test.go b/pkg/commands/ngwaf/workspace/alert/datadog/datadog_test.go index 7d61eada0..3f1791d3f 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/datadog_test.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/datadog_test.go @@ -20,7 +20,7 @@ import ( const ( alertID = "7890abcdef12345678901234" workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" - description = "Test Datadog alert" + description = "TestDatadogAlert" ) var ( @@ -44,7 +44,7 @@ func TestDatadogAlertCreate(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--key %s --site %s", key, site), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --key flag", @@ -129,13 +129,16 @@ func TestDatadogAlertList(t *testing.T) { }, }, }, + Meta: datadog.MetaAlerts{ + Total: 2, + }, } scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", Args: "", - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate internal server error", @@ -204,7 +207,7 @@ func TestDatadogAlertGet(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -266,10 +269,13 @@ func TestDatadogAlertGet(t *testing.T) { func TestDatadogAlertUpdate(t *testing.T) { updatedKey := "updated-key-9876543210" updatedSite := "datadoghq.eu" + updatedDescription := "Updated description" updatedAlert := datadog.Alert{ ID: alertID, Type: "datadog", - Description: "Updated description", + Description: updatedDescription, + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", Config: datadog.ResponseConfig{ Key: &updatedKey, Site: &updatedSite, @@ -279,17 +285,17 @@ func TestDatadogAlertUpdate(t *testing.T) { scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", - Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + Args: fmt.Sprintf("--alert-id %s --key %s --site %s", alertID, key, site), + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", - Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --key %s --site %s", workspaceID, key, site), WantError: "error parsing arguments: required flag --alert-id not provided", }, { Name: "validate not found", - Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --key updated-key-9876543210", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --key updated-key-9876543210 --site datadoghq.eu", workspaceID), Client: &http.Client{ Transport: &testutil.MockRoundTripper{ Response: &http.Response{ @@ -310,25 +316,20 @@ func TestDatadogAlertUpdate(t *testing.T) { Name: "validate API success with key and site", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210 --site datadoghq.eu", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), - }, - }, - }, - WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), - }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + Transport: &testutil.MultiResponseRoundTripper{ + Responses: []*http.Response{ + // First response for GET (fetching current alert) + { + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(datadogAlert)))), + }, + // Second response for PATCH (updating alert) + { + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(updatedAlert)))), + }, }, }, }, @@ -338,11 +339,20 @@ func TestDatadogAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210 --site datadoghq.eu --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + Transport: &testutil.MultiResponseRoundTripper{ + Responses: []*http.Response{ + // First response for GET (fetching current alert) + { + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(datadogAlert)))), + }, + // Second response for PATCH (updating alert) + { + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(updatedAlert)))), + }, }, }, }, @@ -358,7 +368,7 @@ func TestDatadogAlertDelete(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -405,7 +415,7 @@ func TestDatadogAlertDelete(t *testing.T) { var alertString = strings.TrimSpace(` ID: 7890abcdef12345678901234 Type: datadog -Description: Test Datadog alert +Description: TestDatadogAlert Created At: 2025-11-25T16:40:12Z Created By: test@example.com Config: @@ -414,7 +424,7 @@ Config: `) var listString = strings.TrimSpace(` -ID Type Description Created At Created By Config +ID Type Description Created At Created By Config 1a2b3c4d5e6f7890abcdef12 datadog First Datadog alert 2025-11-25T16:40:12Z test@example.com Site: datadoghq.com, Key: 2b3c4d5e6f7890abcdef1234 datadog Second Datadog alert 2025-11-25T16:40:12Z test@example.com Site: datadoghq.com, Key: `) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/jira/create.go b/pkg/commands/ngwaf/workspace/alert/jira/create.go index 29104e51d..dc801e843 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/create.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/create.go @@ -40,11 +40,10 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.CmdClause.Flag("host", "Host name of the Jira instance.").Required().StringVar(&c.Host) c.CmdClause.Flag("key", "Jira API key.").Required().StringVar(&c.Key) diff --git a/pkg/commands/ngwaf/workspace/alert/jira/delete.go b/pkg/commands/ngwaf/workspace/alert/jira/delete.go index f4eed9f48..7fb31b030 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/delete.go @@ -36,11 +36,10 @@ func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/jira/get.go b/pkg/commands/ngwaf/workspace/alert/jira/get.go index 70be24d0e..836b18f7e 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/get.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/get.go @@ -36,11 +36,10 @@ func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/jira/jira_test.go b/pkg/commands/ngwaf/workspace/alert/jira/jira_test.go index 5047aaa1f..4376917f0 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/jira_test.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/jira_test.go @@ -50,7 +50,7 @@ func TestJiraAlertCreate(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--host %s --key %s --project %s --username %s", host, key, project, username), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --host flag", @@ -165,13 +165,16 @@ func TestJiraAlertList(t *testing.T) { }, }, }, + Meta: jira.MetaAlerts{ + Total: 2, + }, } scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", Args: "", - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate internal server error", @@ -240,7 +243,7 @@ func TestJiraAlertGet(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -309,6 +312,8 @@ func TestJiraAlertUpdate(t *testing.T) { ID: alertID, Type: "jira", Description: "Updated description", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", Config: jira.ResponseConfig{ Host: &updatedHost, Key: &updatedKey, @@ -321,17 +326,17 @@ func TestJiraAlertUpdate(t *testing.T) { scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", - Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + Args: fmt.Sprintf("--alert-id %s --host %s --key %s --project %s --username %s", alertID, host, key, project, username), + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", - Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --host %s --key %s --project %s --username %s", workspaceID, host, key, project, username), WantError: "error parsing arguments: required flag --alert-id not provided", }, { Name: "validate not found", - Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --host updated.atlassian.net", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --alert-id invalid --host updated.atlassian.net --key updated-jira-key-456 --project UPDT --username updated@example.com", workspaceID), Client: &http.Client{ Transport: &testutil.MockRoundTripper{ Response: &http.Response{ @@ -352,25 +357,18 @@ func TestJiraAlertUpdate(t *testing.T) { Name: "validate API success with all config fields", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --host updated.atlassian.net --key updated-jira-key-456 --project UPDT --username updated@example.com --issue-type Bug", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), - }, - }, - }, - WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), - }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + Transport: &testutil.MultiResponseRoundTripper{ + Responses: []*http.Response{ + { + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(jiraAlert))), + }, + { + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -378,13 +376,20 @@ func TestJiraAlertUpdate(t *testing.T) { }, { Name: "validate optional --json flag", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --host updated.atlassian.net --json", workspaceID, alertID), + Args: fmt.Sprintf("--workspace-id %s --alert-id %s --host updated.atlassian.net --key updated-jira-key-456 --project UPDT --username updated@example.com --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + Transport: &testutil.MultiResponseRoundTripper{ + Responses: []*http.Response{ + { + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(jiraAlert))), + }, + { + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -400,7 +405,7 @@ func TestJiraAlertDelete(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", diff --git a/pkg/commands/ngwaf/workspace/alert/jira/list.go b/pkg/commands/ngwaf/workspace/alert/jira/list.go index 371e02adc..0e8061b82 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/list.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/list.go @@ -35,11 +35,10 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) // Optional. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/update.go b/pkg/commands/ngwaf/workspace/alert/jira/update.go index 871fec924..35ce089fa 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/update.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/update.go @@ -40,11 +40,10 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go index ee2db1f7a..e7c4cd8ea 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go @@ -39,11 +39,10 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.CmdClause.Flag("address", "An email address.").Required().StringVar(&c.Address) diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go index 4fc7d149b..285994ce6 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go @@ -36,11 +36,10 @@ func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go index a9cdb6e81..554ae3d65 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go @@ -36,11 +36,10 @@ func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go index 0b82e4df9..31a522419 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go @@ -35,11 +35,10 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) // Optional. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go index 07f5e2414..784caa596 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go @@ -20,14 +20,16 @@ import ( const ( alertID = "2b3c4d5e6f7890abcdef1234" workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" - description = "Test mailing list alert" + description = "TestMailingListAlert" ) var ( address = "alerts@example.com" + alertAddress1 = "alerts1@example.com" + alertAddress2 = "alerts2@example.com" mailinglistAlert = mailinglist.Alert{ ID: alertID, - Type: "mailingList", + Type: "mailinglist", Description: description, CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -42,7 +44,7 @@ func TestMailingListAlertCreate(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--address %s", address), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --address flag", @@ -63,20 +65,6 @@ func TestMailingListAlertCreate(t *testing.T) { }, WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", mailinglistAlert.Type, mailinglistAlert.ID, workspaceID), }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --address %s --description %s", workspaceID, address, description), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusCreated, - Status: http.StatusText(http.StatusCreated), - Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(mailinglistAlert)))), - }, - }, - }, - WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", mailinglistAlert.Type, mailinglistAlert.ID, workspaceID), - }, { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --address %s --json", workspaceID, address), @@ -97,13 +85,11 @@ func TestMailingListAlertCreate(t *testing.T) { } func TestMailingListAlertList(t *testing.T) { - alertAddress1 := "alerts1@example.com" - alertAddress2 := "alerts2@example.com" alertsObject := mailinglist.Alerts{ Data: []mailinglist.Alert{ { ID: "1a2b3c4d5e6f7890abcdef12", - Type: "mailingList", + Type: "mailinglist", Description: "First mailing list alert", CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -113,7 +99,7 @@ func TestMailingListAlertList(t *testing.T) { }, { ID: "2b3c4d5e6f7890abcdef1234", - Type: "mailingList", + Type: "mailinglist", Description: "Second mailing list alert", CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -122,13 +108,16 @@ func TestMailingListAlertList(t *testing.T) { }, }, }, + Meta: mailinglist.MetaAlerts{ + Total: 2, + }, } scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", Args: "", - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate internal server error", @@ -197,7 +186,7 @@ func TestMailingListAlertGet(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -262,6 +251,8 @@ func TestMailingListAlertUpdate(t *testing.T) { ID: alertID, Type: "mailingList", Description: "Updated description", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", Config: mailinglist.ResponseConfig{ Address: &updatedAddress, }, @@ -270,12 +261,12 @@ func TestMailingListAlertUpdate(t *testing.T) { scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", - Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + Args: fmt.Sprintf("--alert-id %s --address %s", alertID, address), + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", - Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --address %s", workspaceID, address), WantError: "error parsing arguments: required flag --alert-id not provided", }, { @@ -301,25 +292,28 @@ func TestMailingListAlertUpdate(t *testing.T) { Name: "validate API success with address", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --address updated@example.com", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), - }, - }, - }, - WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), - }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(mailinglistAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -329,11 +323,28 @@ func TestMailingListAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --address updated@example.com --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(mailinglistAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -349,7 +360,7 @@ func TestMailingListAlertDelete(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -395,8 +406,8 @@ func TestMailingListAlertDelete(t *testing.T) { var alertString = strings.TrimSpace(` ID: 2b3c4d5e6f7890abcdef1234 -Type: mailingList -Description: Test mailing list alert +Type: mailinglist +Description: TestMailingListAlert Created At: 2025-11-25T16:40:12Z Created By: test@example.com Config: @@ -404,9 +415,9 @@ Config: `) var listString = strings.TrimSpace(` -ID Type Description Created At Created By Config -1a2b3c4d5e6f7890abcdef12 mailingList First mailing list alert 2025-11-25T16:40:12Z test@example.com Address: alerts1@example.com -2b3c4d5e6f7890abcdef1234 mailingList Second mailing list alert 2025-11-25T16:40:12Z test@example.com Address: alerts2@example.com +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 mailinglist First mailing list alert 2025-11-25T16:40:12Z test@example.com Address: alerts1@example.com +2b3c4d5e6f7890abcdef1234 mailinglist Second mailing list alert 2025-11-25T16:40:12Z test@example.com Address: alerts2@example.com `) + "\n" var zeroListString = strings.TrimSpace(` diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go index e5d238c9d..b60b8e2e4 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go @@ -37,11 +37,10 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go index 3e2f20a74..491ee75a3 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go @@ -39,11 +39,10 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.CmdClause.Flag("webhook", "Microsoft Teams webhook.").Required().StringVar(&c.Webhook) diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go index 76440a40c..e96c6f758 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go @@ -36,11 +36,10 @@ func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go index cf01b5330..cec46674b 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go @@ -36,11 +36,10 @@ func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go index 87b980844..34647bd56 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go @@ -35,11 +35,10 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) // Optional. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go index 38017bbc9..8621cf634 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go @@ -20,14 +20,14 @@ import ( const ( alertID = "3c4d5e6f7890abcdef123456" workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" - description = "Test Microsoft Teams alert" + description = "TestMicrosoftTeamsAlert" ) var ( webhook = "https://outlook.office.com/webhook/example" teamsAlert = microsoftteams.Alert{ ID: alertID, - Type: "microsoftTeams", + Type: "microsoftteams", Description: description, CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -42,7 +42,7 @@ func TestMicrosoftTeamsAlertCreate(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--webhook %s", webhook), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --webhook flag", @@ -63,20 +63,6 @@ func TestMicrosoftTeamsAlertCreate(t *testing.T) { }, WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", teamsAlert.Type, teamsAlert.ID, workspaceID), }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --webhook %s --description %s", workspaceID, webhook, description), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusCreated, - Status: http.StatusText(http.StatusCreated), - Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(teamsAlert)))), - }, - }, - }, - WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", teamsAlert.Type, teamsAlert.ID, workspaceID), - }, { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --webhook %s --json", workspaceID, webhook), @@ -101,7 +87,7 @@ func TestMicrosoftTeamsAlertList(t *testing.T) { Data: []microsoftteams.Alert{ { ID: "1a2b3c4d5e6f7890abcdef12", - Type: "microsoftTeams", + Type: "microsoftteams", Description: "First Microsoft Teams alert", CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -111,7 +97,7 @@ func TestMicrosoftTeamsAlertList(t *testing.T) { }, { ID: "2b3c4d5e6f7890abcdef1234", - Type: "microsoftTeams", + Type: "microsoftteams", Description: "Second Microsoft Teams alert", CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -120,13 +106,16 @@ func TestMicrosoftTeamsAlertList(t *testing.T) { }, }, }, + Meta: microsoftteams.MetaAlerts{ + Total: 2, + }, } scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", Args: "", - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate internal server error", @@ -195,7 +184,7 @@ func TestMicrosoftTeamsAlertGet(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -258,8 +247,10 @@ func TestMicrosoftTeamsAlertUpdate(t *testing.T) { updatedWebhook := "https://outlook.office.com/webhook/updated" updatedAlert := microsoftteams.Alert{ ID: alertID, - Type: "microsoftTeams", + Type: "microsoftteams", Description: "Updated description", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", Config: microsoftteams.ResponseConfig{ Webhook: &updatedWebhook, }, @@ -268,12 +259,12 @@ func TestMicrosoftTeamsAlertUpdate(t *testing.T) { scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", - Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + Args: fmt.Sprintf("--alert-id %s --webhook %s", alertID, webhook), + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", - Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --webhook %s", workspaceID, webhook), WantError: "error parsing arguments: required flag --alert-id not provided", }, { @@ -299,25 +290,28 @@ func TestMicrosoftTeamsAlertUpdate(t *testing.T) { Name: "validate API success with webhook", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://outlook.office.com/webhook/updated", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), - }, - }, - }, - WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), - }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(teamsAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -327,11 +321,28 @@ func TestMicrosoftTeamsAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://outlook.office.com/webhook/updated --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(teamsAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -347,7 +358,7 @@ func TestMicrosoftTeamsAlertDelete(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -393,8 +404,8 @@ func TestMicrosoftTeamsAlertDelete(t *testing.T) { var alertString = strings.TrimSpace(` ID: 3c4d5e6f7890abcdef123456 -Type: microsoftTeams -Description: Test Microsoft Teams alert +Type: microsoftteams +Description: TestMicrosoftTeamsAlert Created At: 2025-11-25T16:40:12Z Created By: test@example.com Config: @@ -402,9 +413,9 @@ Config: `) var listString = strings.TrimSpace(` -ID Type Description Created At Created By Config -1a2b3c4d5e6f7890abcdef12 microsoftTeams First Microsoft Teams alert 2025-11-25T16:40:12Z test@example.com Webhook: -2b3c4d5e6f7890abcdef1234 microsoftTeams Second Microsoft Teams alert 2025-11-25T16:40:12Z test@example.com Webhook: +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 microsoftteams First Microsoft Teams alert 2025-11-25T16:40:12Z test@example.com Webhook: +2b3c4d5e6f7890abcdef1234 microsoftteams Second Microsoft Teams alert 2025-11-25T16:40:12Z test@example.com Webhook: `) + "\n" var zeroListString = strings.TrimSpace(` diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go index f1172a2d0..75228d11e 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go @@ -37,11 +37,10 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go index 8eea51902..e833e339a 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go @@ -39,11 +39,10 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.CmdClause.Flag("key", "Opsgenie integration key.").Required().StringVar(&c.Key) diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go index 60bfb2fd0..ef1c20480 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go @@ -36,11 +36,10 @@ func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go index 927a1a263..6b69c7c27 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go @@ -36,11 +36,10 @@ func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go index 595c36a6a..fa51df47b 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go @@ -35,11 +35,10 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) // Optional. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go index 6538df787..1e5e3e388 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go @@ -20,7 +20,7 @@ import ( const ( alertID = "4d5e6f7890abcdef12345678" workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" - description = "Test Opsgenie alert" + description = "TestOpsgenieAlert" ) var ( @@ -42,7 +42,7 @@ func TestOpsgenieAlertCreate(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--key %s", key), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --key flag", @@ -120,13 +120,16 @@ func TestOpsgenieAlertList(t *testing.T) { }, }, }, + Meta: opsgenie.MetaAlerts{ + Total: 2, + }, } scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", Args: "", - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate internal server error", @@ -195,7 +198,7 @@ func TestOpsgenieAlertGet(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -260,6 +263,8 @@ func TestOpsgenieAlertUpdate(t *testing.T) { ID: alertID, Type: "opsgenie", Description: "Updated description", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", Config: opsgenie.ResponseConfig{ Key: &updatedKey, }, @@ -268,12 +273,12 @@ func TestOpsgenieAlertUpdate(t *testing.T) { scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", - Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + Args: fmt.Sprintf("--alert-id %s --key %s", alertID, key), + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", - Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --key %s", workspaceID, key), WantError: "error parsing arguments: required flag --alert-id not provided", }, { @@ -299,25 +304,28 @@ func TestOpsgenieAlertUpdate(t *testing.T) { Name: "validate API success with key", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-1234", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), - }, - }, - }, - WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), - }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(opsgenieAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -327,11 +335,28 @@ func TestOpsgenieAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-1234 --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(opsgenieAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -347,7 +372,7 @@ func TestOpsgenieAlertDelete(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -394,7 +419,7 @@ func TestOpsgenieAlertDelete(t *testing.T) { var alertString = strings.TrimSpace(` ID: 4d5e6f7890abcdef12345678 Type: opsgenie -Description: Test Opsgenie alert +Description: TestOpsgenieAlert Created At: 2025-11-25T16:40:12Z Created By: test@example.com Config: @@ -402,7 +427,7 @@ Config: `) var listString = strings.TrimSpace(` -ID Type Description Created At Created By Config +ID Type Description Created At Created By Config 1a2b3c4d5e6f7890abcdef12 opsgenie First Opsgenie alert 2025-11-25T16:40:12Z test@example.com Key: 2b3c4d5e6f7890abcdef1234 opsgenie Second Opsgenie alert 2025-11-25T16:40:12Z test@example.com Key: `) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go index 14503b735..b28a3439f 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go @@ -37,11 +37,10 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go index bb5742dce..93166374e 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go @@ -39,11 +39,10 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.CmdClause.Flag("key", "PagerDuty integration key.").Required().StringVar(&c.Key) diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go index 74e57ecc1..d0cac1370 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go @@ -36,11 +36,10 @@ func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go index b3af0a62c..11db69fd3 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go @@ -36,11 +36,10 @@ func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go index e957bd18d..5793f5c31 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go @@ -35,11 +35,10 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) // Optional. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go index 361abbc98..9632ae3df 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go @@ -20,14 +20,14 @@ import ( const ( alertID = "5e6f7890abcdef1234567890" workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" - description = "Test PagerDuty alert" + description = "TestPagerDutyAlert" ) var ( key = "a1b2c3d4e5f67890abcdef1234567890" pagerdutyAlert = pagerduty.Alert{ ID: alertID, - Type: "pagerDuty", + Type: "pagerduty", Description: description, CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -42,7 +42,7 @@ func TestPagerDutyAlertCreate(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--key %s", key), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --key flag", @@ -63,20 +63,6 @@ func TestPagerDutyAlertCreate(t *testing.T) { }, WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", pagerdutyAlert.Type, pagerdutyAlert.ID, workspaceID), }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --key %s --description %s", workspaceID, key, description), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusCreated, - Status: http.StatusText(http.StatusCreated), - Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(pagerdutyAlert)))), - }, - }, - }, - WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", pagerdutyAlert.Type, pagerdutyAlert.ID, workspaceID), - }, { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --key %s --json", workspaceID, key), @@ -101,7 +87,7 @@ func TestPagerDutyAlertList(t *testing.T) { Data: []pagerduty.Alert{ { ID: "1a2b3c4d5e6f7890abcdef12", - Type: "pagerDuty", + Type: "pagerduty", Description: "First PagerDuty alert", CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -111,7 +97,7 @@ func TestPagerDutyAlertList(t *testing.T) { }, { ID: "2b3c4d5e6f7890abcdef1234", - Type: "pagerDuty", + Type: "pagerduty", Description: "Second PagerDuty alert", CreatedAt: "2025-11-25T16:40:12Z", CreatedBy: "test@example.com", @@ -120,13 +106,16 @@ func TestPagerDutyAlertList(t *testing.T) { }, }, }, + Meta: pagerduty.MetaAlerts{ + Total: 2, + }, } scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", Args: "", - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate internal server error", @@ -195,7 +184,7 @@ func TestPagerDutyAlertGet(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -258,8 +247,10 @@ func TestPagerDutyAlertUpdate(t *testing.T) { updatedKey := "updated-key-9876543210" updatedAlert := pagerduty.Alert{ ID: alertID, - Type: "pagerDuty", + Type: "pagerduty", Description: "Updated description", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", Config: pagerduty.ResponseConfig{ Key: &updatedKey, }, @@ -268,12 +259,12 @@ func TestPagerDutyAlertUpdate(t *testing.T) { scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", - Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + Args: fmt.Sprintf("--alert-id %s --key %s", alertID, key), + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", - Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --key %s", workspaceID, key), WantError: "error parsing arguments: required flag --alert-id not provided", }, { @@ -299,25 +290,28 @@ func TestPagerDutyAlertUpdate(t *testing.T) { Name: "validate API success with key", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), - }, - }, - }, - WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), - }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(pagerdutyAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -327,11 +321,28 @@ func TestPagerDutyAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210 --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(pagerdutyAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -347,7 +358,7 @@ func TestPagerDutyAlertDelete(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -393,8 +404,8 @@ func TestPagerDutyAlertDelete(t *testing.T) { var alertString = strings.TrimSpace(` ID: 5e6f7890abcdef1234567890 -Type: pagerDuty -Description: Test PagerDuty alert +Type: pagerduty +Description: TestPagerDutyAlert Created At: 2025-11-25T16:40:12Z Created By: test@example.com Config: @@ -402,9 +413,9 @@ Config: `) var listString = strings.TrimSpace(` -ID Type Description Created At Created By Config -1a2b3c4d5e6f7890abcdef12 pagerDuty First PagerDuty alert 2025-11-25T16:40:12Z test@example.com Key: -2b3c4d5e6f7890abcdef1234 pagerDuty Second PagerDuty alert 2025-11-25T16:40:12Z test@example.com Key: +ID Type Description Created At Created By Config +1a2b3c4d5e6f7890abcdef12 pagerduty First PagerDuty alert 2025-11-25T16:40:12Z test@example.com Key: +2b3c4d5e6f7890abcdef1234 pagerduty Second PagerDuty alert 2025-11-25T16:40:12Z test@example.com Key: `) + "\n" var zeroListString = strings.TrimSpace(` diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go index a3a461f20..3c005c406 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go @@ -37,11 +37,10 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/slack/create.go b/pkg/commands/ngwaf/workspace/alert/slack/create.go index 439837d21..5806e6a76 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/create.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/create.go @@ -39,11 +39,10 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.CmdClause.Flag("webhook", "Slack webhook.").Required().StringVar(&c.Webhook) diff --git a/pkg/commands/ngwaf/workspace/alert/slack/delete.go b/pkg/commands/ngwaf/workspace/alert/slack/delete.go index 6af5c688f..415c2d1c4 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/delete.go @@ -36,11 +36,10 @@ func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/slack/get.go b/pkg/commands/ngwaf/workspace/alert/slack/get.go index d429bb000..d7ff31076 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/get.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/get.go @@ -36,11 +36,10 @@ func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/slack/list.go b/pkg/commands/ngwaf/workspace/alert/slack/list.go index c44b52fa2..f85e15757 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/list.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/list.go @@ -35,11 +35,10 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) // Optional. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go b/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go index af89b9fe5..ddc47ba7f 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go @@ -20,7 +20,7 @@ import ( const ( alertID = "1a2b3c4d5e6f7890abcdef12" workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" - description = "Test slack alert" + description = "TestSlackAlert" ) var ( @@ -42,7 +42,7 @@ func TestSlackAlertCreate(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--webhook %s", webhook), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --webhook flag", @@ -63,20 +63,6 @@ func TestSlackAlertCreate(t *testing.T) { }, WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", slackAlert.Type, slackAlert.ID, workspaceID), }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --webhook %s --description %s", workspaceID, webhook, description), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusCreated, - Status: http.StatusText(http.StatusCreated), - Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(slackAlert)))), - }, - }, - }, - WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", slackAlert.Type, slackAlert.ID, workspaceID), - }, { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --webhook %s --json", workspaceID, webhook), @@ -120,13 +106,16 @@ func TestSlackAlertList(t *testing.T) { }, }, }, + Meta: slack.MetaAlerts{ + Total: 2, + }, } scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", Args: "", - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate internal server error", @@ -195,7 +184,7 @@ func TestSlackAlertGet(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -260,6 +249,8 @@ func TestSlackAlertUpdate(t *testing.T) { ID: alertID, Type: "slack", Description: "Updated description", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", Config: slack.ResponseConfig{ Webhook: &updatedWebhook, }, @@ -268,12 +259,12 @@ func TestSlackAlertUpdate(t *testing.T) { scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", - Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + Args: fmt.Sprintf("--alert-id %s --webhook %s", alertID, webhook), + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", - Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --webhook %s", workspaceID, webhook), WantError: "error parsing arguments: required flag --alert-id not provided", }, { @@ -299,25 +290,28 @@ func TestSlackAlertUpdate(t *testing.T) { Name: "validate API success with webhook", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://hooks.slack.com/services/updated", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), - }, - }, - }, - WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), - }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(slackAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -327,11 +321,28 @@ func TestSlackAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://hooks.slack.com/services/updated --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(slackAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -347,7 +358,7 @@ func TestSlackAlertDelete(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -394,7 +405,7 @@ func TestSlackAlertDelete(t *testing.T) { var alertString = strings.TrimSpace(` ID: 1a2b3c4d5e6f7890abcdef12 Type: slack -Description: Test slack alert +Description: TestSlackAlert Created At: 2025-11-25T16:40:12Z Created By: test@example.com Config: @@ -402,7 +413,7 @@ Config: `) var listString = strings.TrimSpace(` -ID Type Description Created At Created By Config +ID Type Description Created At Created By Config 1a2b3c4d5e6f7890abcdef12 slack First slack alert 2025-11-25T16:40:12Z test@example.com Webhook: 2b3c4d5e6f7890abcdef1234 slack Second slack alert 2025-11-25T16:40:12Z test@example.com Webhook: `) + "\n" diff --git a/pkg/commands/ngwaf/workspace/alert/slack/update.go b/pkg/commands/ngwaf/workspace/alert/slack/update.go index e091406e5..14e4e3b6a 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/update.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/update.go @@ -37,11 +37,10 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/create.go b/pkg/commands/ngwaf/workspace/alert/webhook/create.go index 9ea99f1a8..0c960acef 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/create.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/create.go @@ -39,11 +39,10 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.CmdClause.Flag("webhook", "Webhook webhook.").Required().StringVar(&c.Webhook) diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go index c1085fd34..74a8b05d5 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go @@ -36,11 +36,10 @@ func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go index f3879c5e1..785a392f6 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go @@ -36,11 +36,10 @@ func NewGetSigningKeyCommand(parent argparser.Registerer, g *global.Data) *GetSi // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get.go b/pkg/commands/ngwaf/workspace/alert/webhook/get.go index 3a33add53..d5322469f 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get.go @@ -36,11 +36,10 @@ func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/list.go b/pkg/commands/ngwaf/workspace/alert/webhook/list.go index 612cdafd0..08b31fc8e 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/list.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/list.go @@ -35,11 +35,10 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand { // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) // Optional. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go index b78372137..5268db034 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go @@ -36,11 +36,10 @@ func NewRotateSigningKeyCommand(parent argparser.Registerer, g *global.Data) *Ro // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/update.go b/pkg/commands/ngwaf/workspace/alert/webhook/update.go index 8440f6d65..b23e75337 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/update.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/update.go @@ -37,11 +37,10 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman // Required. c.RegisterFlag(argparser.StringFlagOpts{ - Name: argparser.FlagNGWAFWorkspaceID, - Description: argparser.FlagNGWAFWorkspaceIDDesc, - Dst: &c.WorkspaceID.Value, - Action: c.WorkspaceID.Set, - ForceRequired: true, + Name: argparser.FlagNGWAFWorkspaceID, + Description: argparser.FlagNGWAFWorkspaceIDDesc, + Dst: &c.WorkspaceID.Value, + Action: c.WorkspaceID.Set, }) c.RegisterFlag(argparser.StringFlagOpts{ Name: argparser.FlagNGWAFAlertID, diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go b/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go index e82ff100f..3cc77c3b7 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go @@ -20,7 +20,7 @@ import ( const ( alertID = "6f7890abcdef123456789012" workspaceID = "nBw2ENWfOY1M2dpSwK1l5R" - description = "Test webhook alert" + description = "TestWebhookAlert" signingKey = "a1b2c3d4e5f67890abcdef1234567890" ) @@ -43,7 +43,7 @@ func TestWebhookAlertCreate(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--webhook %s", webhookURL), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --webhook flag", @@ -64,20 +64,6 @@ func TestWebhookAlertCreate(t *testing.T) { }, WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", webhookAlert.Type, webhookAlert.ID, workspaceID), }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --webhook %s --description %s", workspaceID, webhookURL, description), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusCreated, - Status: http.StatusText(http.StatusCreated), - Body: io.NopCloser(bytes.NewReader((testutil.GenJSON(webhookAlert)))), - }, - }, - }, - WantOutput: fstfmt.Success("Created a '%s' alert '%s' (workspace-id: %s)", webhookAlert.Type, webhookAlert.ID, workspaceID), - }, { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --webhook %s --json", workspaceID, webhookURL), @@ -121,13 +107,16 @@ func TestWebhookAlertList(t *testing.T) { }, }, }, + Meta: webhook.MetaAlerts{ + Total: 2, + }, } scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", Args: "", - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate internal server error", @@ -196,7 +185,7 @@ func TestWebhookAlertGet(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -261,6 +250,8 @@ func TestWebhookAlertUpdate(t *testing.T) { ID: alertID, Type: "webhook", Description: "Updated description", + CreatedAt: "2025-11-25T16:40:12Z", + CreatedBy: "test@example.com", Config: webhook.ResponseConfig{ Webhook: &updatedWebhookURL, }, @@ -269,12 +260,12 @@ func TestWebhookAlertUpdate(t *testing.T) { scenarios := []testutil.CLIScenario{ { Name: "validate missing --workspace-id flag", - Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + Args: fmt.Sprintf("--alert-id %s --webhook %s", alertID, webhookURL), + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", - Args: fmt.Sprintf("--workspace-id %s", workspaceID), + Args: fmt.Sprintf("--workspace-id %s --webhook %s", workspaceID, webhookURL), WantError: "error parsing arguments: required flag --alert-id not provided", }, { @@ -300,25 +291,28 @@ func TestWebhookAlertUpdate(t *testing.T) { Name: "validate API success with webhook", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://example.com/webhook/updated", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), - }, - }, - }, - WantOutput: fstfmt.Success("Updated '%s' alert '%s' (workspace-id: %s)", updatedAlert.Type, updatedAlert.ID, workspaceID), - }, - { - Name: "validate API success with description", - Args: fmt.Sprintf("--workspace-id %s --alert-id %s --description \"Updated description\"", workspaceID, alertID), - Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(webhookAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -328,11 +322,28 @@ func TestWebhookAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://example.com/webhook/updated --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MockRoundTripper{ - Response: &http.Response{ - StatusCode: http.StatusOK, - Status: http.StatusText(http.StatusOK), - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + + Transport: &testutil.MultiResponseRoundTripper{ + + Responses: []*http.Response{ + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(webhookAlert))), + }, + + { + + StatusCode: http.StatusOK, + + Status: http.StatusText(http.StatusOK), + + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + }, }, }, }, @@ -348,7 +359,7 @@ func TestWebhookAlertDelete(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -401,7 +412,7 @@ func TestWebhookGetSigningKey(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -470,7 +481,7 @@ func TestWebhookRotateSigningKey(t *testing.T) { { Name: "validate missing --workspace-id flag", Args: fmt.Sprintf("--alert-id %s", alertID), - WantError: "error parsing arguments: required flag --workspace-id not provided", + WantError: "error reading workspace ID: no workspace ID found", }, { Name: "validate missing --alert-id flag", @@ -532,7 +543,7 @@ func TestWebhookRotateSigningKey(t *testing.T) { var alertString = strings.TrimSpace(` ID: 6f7890abcdef123456789012 Type: webhook -Description: Test webhook alert +Description: TestWebhookAlert Created At: 2025-11-25T16:40:12Z Created By: test@example.com Config: @@ -540,7 +551,7 @@ Config: `) var listString = strings.TrimSpace(` -ID Type Description Created At Created By Config +ID Type Description Created At Created By Config 1a2b3c4d5e6f7890abcdef12 webhook First webhook alert 2025-11-25T16:40:12Z test@example.com Webhook: 2b3c4d5e6f7890abcdef1234 webhook Second webhook alert 2025-11-25T16:40:12Z test@example.com Webhook: `) + "\n" diff --git a/pkg/testutil/client.go b/pkg/testutil/client.go index 53899df69..213645a62 100644 --- a/pkg/testutil/client.go +++ b/pkg/testutil/client.go @@ -13,3 +13,25 @@ type MockRoundTripper struct { func (m *MockRoundTripper) RoundTrip(_ *http.Request) (*http.Response, error) { return m.Response, m.Err } + +// MultiResponseRoundTripper implements [http.RoundTripper] for mocking multiple +// sequential HTTP responses. This is useful when the code under test makes +// multiple HTTP calls (e.g., GET then PATCH). +// +// When we perform a get and update in go-fastly operations (such as for alerts), +// we need to be able to parse multiple responses back from the API. +type MultiResponseRoundTripper struct { + Responses []*http.Response + index int +} + +// RoundTrip executes a single HTTP transaction, returning the next Response +// in sequence. +func (m *MultiResponseRoundTripper) RoundTrip(_ *http.Request) (*http.Response, error) { + if m.index >= len(m.Responses) { + return m.Responses[len(m.Responses)-1], nil + } + resp := m.Responses[m.index] + m.index++ + return resp, nil +} From 01172490e10b7bea88e2ad0f5cd4e66389716d54 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 1 Dec 2025 14:07:14 -0500 Subject: [PATCH 06/13] changelog updates --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 482be5714..03710d382 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ ### Enhancements: - feat(commands/ngwaf/workspaces): add support for update operation for NGWAF workspaces ([#1578](https://github.com/fastly/cli/pull/1578)) -- feat(commands/ngwaf/lists): add support for CRUD operations for NGWAF Lists ([#1582](https://github.com/fastly/cli/pull/1582)) +- feat(commands/ngwaf/workspace/lists): add support for CRUD operations for NGWAF Lists ([#1582](https://github.com/fastly/cli/pull/1582)) +- feat(commands/ngwaf/workspaces/alerts): add support for operations for NGWAF alerts ([#1589](https://github.com/fastly/cli/pull/1589)) + ### Bug fixes: From 831f8321c3267c46109ac0330047386c63588160 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 1 Dec 2025 14:35:37 -0500 Subject: [PATCH 07/13] Linting Fix --- pkg/argparser/common.go | 2 +- .../workspace/alert/{common => alertutil}/builder.go | 2 +- pkg/commands/ngwaf/workspace/alert/alertutil/doc.go | 2 ++ .../workspace/alert/{common => alertutil}/flags.go | 2 +- pkg/commands/ngwaf/workspace/alert/common/doc.go | 2 -- pkg/commands/ngwaf/workspace/alert/datadog/create.go | 10 +++++----- pkg/commands/ngwaf/workspace/alert/datadog/delete.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/datadog/get.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/datadog/list.go | 4 ++-- pkg/commands/ngwaf/workspace/alert/datadog/update.go | 10 +++++----- pkg/commands/ngwaf/workspace/alert/jira/create.go | 12 ++++++------ pkg/commands/ngwaf/workspace/alert/jira/delete.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/jira/get.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/jira/list.go | 4 ++-- pkg/commands/ngwaf/workspace/alert/jira/update.go | 12 ++++++------ .../ngwaf/workspace/alert/mailinglist/create.go | 10 +++++----- .../ngwaf/workspace/alert/mailinglist/delete.go | 6 +++--- .../ngwaf/workspace/alert/mailinglist/get.go | 6 +++--- .../ngwaf/workspace/alert/mailinglist/list.go | 4 ++-- .../workspace/alert/mailinglist/mailinglist_test.go | 10 ---------- .../ngwaf/workspace/alert/mailinglist/update.go | 10 +++++----- .../ngwaf/workspace/alert/microsoftteams/create.go | 10 +++++----- .../ngwaf/workspace/alert/microsoftteams/delete.go | 6 +++--- .../ngwaf/workspace/alert/microsoftteams/get.go | 6 +++--- .../ngwaf/workspace/alert/microsoftteams/list.go | 4 ++-- .../alert/microsoftteams/microsoftteams_test.go | 10 ---------- .../ngwaf/workspace/alert/microsoftteams/update.go | 10 +++++----- .../ngwaf/workspace/alert/opsgenie/create.go | 10 +++++----- .../ngwaf/workspace/alert/opsgenie/delete.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/opsgenie/get.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/opsgenie/list.go | 4 ++-- .../ngwaf/workspace/alert/opsgenie/opsgenie_test.go | 10 ---------- .../ngwaf/workspace/alert/opsgenie/update.go | 10 +++++----- .../ngwaf/workspace/alert/pagerduty/create.go | 10 +++++----- .../ngwaf/workspace/alert/pagerduty/delete.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/pagerduty/get.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/pagerduty/list.go | 4 ++-- .../workspace/alert/pagerduty/pagerduty_test.go | 10 ---------- .../ngwaf/workspace/alert/pagerduty/update.go | 10 +++++----- pkg/commands/ngwaf/workspace/alert/slack/create.go | 10 +++++----- pkg/commands/ngwaf/workspace/alert/slack/delete.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/slack/get.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/slack/list.go | 4 ++-- .../ngwaf/workspace/alert/slack/slack_test.go | 10 ---------- pkg/commands/ngwaf/workspace/alert/slack/update.go | 10 +++++----- pkg/commands/ngwaf/workspace/alert/webhook/create.go | 10 +++++----- pkg/commands/ngwaf/workspace/alert/webhook/delete.go | 6 +++--- .../ngwaf/workspace/alert/webhook/get-signing-key.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/webhook/get.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/webhook/list.go | 4 ++-- .../workspace/alert/webhook/rotate-signing-key.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/webhook/update.go | 10 +++++----- 52 files changed, 157 insertions(+), 207 deletions(-) rename pkg/commands/ngwaf/workspace/alert/{common => alertutil}/builder.go (91%) create mode 100644 pkg/commands/ngwaf/workspace/alert/alertutil/doc.go rename pkg/commands/ngwaf/workspace/alert/{common => alertutil}/flags.go (98%) delete mode 100644 pkg/commands/ngwaf/workspace/alert/common/doc.go diff --git a/pkg/argparser/common.go b/pkg/argparser/common.go index 5800637ba..4b15fc647 100644 --- a/pkg/argparser/common.go +++ b/pkg/argparser/common.go @@ -11,7 +11,7 @@ var ( FlagJSONDesc = "Render output as JSON" // FlagNGWAFAlertID is the alert ID. FlagNGWAFAlertID = "alert-id" - // FlagNGWAFAlertIDDesc + // FlagNGWAFAlertIDDesc is the alert ID flag description. FlagNGWAFAlertIDDesc = "Alphanumeric string identifying the alert" // FlagNGWAFWorkspaceID is the workspace ID. FlagNGWAFWorkspaceID = "workspace-id" diff --git a/pkg/commands/ngwaf/workspace/alert/common/builder.go b/pkg/commands/ngwaf/workspace/alert/alertutil/builder.go similarity index 91% rename from pkg/commands/ngwaf/workspace/alert/common/builder.go rename to pkg/commands/ngwaf/workspace/alert/alertutil/builder.go index 497bd14a6..e0088c488 100644 --- a/pkg/commands/ngwaf/workspace/alert/common/builder.go +++ b/pkg/commands/ngwaf/workspace/alert/alertutil/builder.go @@ -1,4 +1,4 @@ -package common +package alertutil // GetDefaultEvents returns the hardcoded events value for all alerts. // Currently the only supported value is "flag". diff --git a/pkg/commands/ngwaf/workspace/alert/alertutil/doc.go b/pkg/commands/ngwaf/workspace/alert/alertutil/doc.go new file mode 100644 index 000000000..1ee7df628 --- /dev/null +++ b/pkg/commands/ngwaf/workspace/alert/alertutil/doc.go @@ -0,0 +1,2 @@ +// Package alertutil contains shared types and helpers for NGWAF alert commands. +package alertutil diff --git a/pkg/commands/ngwaf/workspace/alert/common/flags.go b/pkg/commands/ngwaf/workspace/alert/alertutil/flags.go similarity index 98% rename from pkg/commands/ngwaf/workspace/alert/common/flags.go rename to pkg/commands/ngwaf/workspace/alert/alertutil/flags.go index f011b85a9..4e88dfb5a 100644 --- a/pkg/commands/ngwaf/workspace/alert/common/flags.go +++ b/pkg/commands/ngwaf/workspace/alert/alertutil/flags.go @@ -1,4 +1,4 @@ -package common +package alertutil import "github.com/fastly/cli/pkg/argparser" diff --git a/pkg/commands/ngwaf/workspace/alert/common/doc.go b/pkg/commands/ngwaf/workspace/alert/common/doc.go deleted file mode 100644 index 0fadce1a2..000000000 --- a/pkg/commands/ngwaf/workspace/alert/common/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package common contains shared types and helpers for NGWAF alert commands. -package common diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/create.go b/pkg/commands/ngwaf/workspace/alert/datadog/create.go index 1ea8f7ffe..440682ff6 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/create.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags - common.DatadogConfigFlags + alertutil.BaseAlertFlags + alertutil.DatadogConfigFlags // Optional. - common.AlertDataFlags + alertutil.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -72,7 +72,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Site: &c.Site, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go index d27891bc5..47cbdcd45 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/get.go b/pkg/commands/ngwaf/workspace/alert/datadog/get.go index a83a7d8c8..28d722821 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/get.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/list.go b/pkg/commands/ngwaf/workspace/alert/datadog/list.go index a08babe58..23630b317 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/list.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags + alertutil.BaseAlertFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/update.go b/pkg/commands/ngwaf/workspace/alert/datadog/update.go index 1ec821443..673febb92 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/update.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags - common.DatadogConfigFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags + alertutil.DatadogConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -75,7 +75,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Site: &c.Site, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/jira/create.go b/pkg/commands/ngwaf/workspace/alert/jira/create.go index dc801e843..3513f1618 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/create.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,12 +21,12 @@ type CreateCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags - common.JiraConfigFlags + alertutil.BaseAlertFlags + alertutil.JiraConfigFlags // Optional. - common.AlertDataFlags - common.JiraOptConfigFlags + alertutil.AlertDataFlags + alertutil.JiraOptConfigFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -78,7 +78,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Username: &c.Username, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.IssueType != "" { input.Config.IssueType = &c.IssueType diff --git a/pkg/commands/ngwaf/workspace/alert/jira/delete.go b/pkg/commands/ngwaf/workspace/alert/jira/delete.go index 7fb31b030..6ba40407c 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/get.go b/pkg/commands/ngwaf/workspace/alert/jira/get.go index 836b18f7e..f5a9f06af 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/get.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/list.go b/pkg/commands/ngwaf/workspace/alert/jira/list.go index 0e8061b82..66ec24b28 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/list.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags + alertutil.BaseAlertFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/update.go b/pkg/commands/ngwaf/workspace/alert/jira/update.go index 35ce089fa..ec0438cf0 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/update.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,12 +21,12 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags - common.JiraConfigFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags + alertutil.JiraConfigFlags // Optional - common.JiraOptConfigFlags + alertutil.JiraOptConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -84,7 +84,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Username: &c.Username, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.IssueType != "" { input.Config.IssueType = &c.IssueType diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go index e7c4cd8ea..5059532cf 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags - common.AddressConfigFlags + alertutil.BaseAlertFlags + alertutil.AddressConfigFlags // Optional. - common.AlertDataFlags + alertutil.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Address: &c.Address, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go index 285994ce6..772029999 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go index 554ae3d65..b7b82030d 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go index 31a522419..0e84d52e2 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags + alertutil.BaseAlertFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go index 784caa596..fed3b8e19 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/mailinglist_test.go @@ -292,13 +292,9 @@ func TestMailingListAlertUpdate(t *testing.T) { Name: "validate API success with address", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --address updated@example.com", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -307,7 +303,6 @@ func TestMailingListAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -323,13 +318,9 @@ func TestMailingListAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --address updated@example.com --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -338,7 +329,6 @@ func TestMailingListAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go index b60b8e2e4..1d6ce5a30 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags - common.AddressConfigFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags + alertutil.AddressConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Address: &c.Address, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go index 491ee75a3..78e0786aa 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags - common.WebhookConfigFlags + alertutil.BaseAlertFlags + alertutil.WebhookConfigFlags // Optional. - common.AlertDataFlags + alertutil.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go index e96c6f758..4475b4370 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go index cec46674b..89a551928 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go index 34647bd56..08ec16cc0 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags + alertutil.BaseAlertFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go index 8621cf634..764ec132e 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/microsoftteams_test.go @@ -290,13 +290,9 @@ func TestMicrosoftTeamsAlertUpdate(t *testing.T) { Name: "validate API success with webhook", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://outlook.office.com/webhook/updated", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -305,7 +301,6 @@ func TestMicrosoftTeamsAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -321,13 +316,9 @@ func TestMicrosoftTeamsAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://outlook.office.com/webhook/updated --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -336,7 +327,6 @@ func TestMicrosoftTeamsAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go index 75228d11e..b112e3348 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags - common.WebhookConfigFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags + alertutil.WebhookConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go index e833e339a..f6ea7ca8f 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags - common.KeyConfigFlags + alertutil.BaseAlertFlags + alertutil.KeyConfigFlags // Optional. - common.AlertDataFlags + alertutil.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Key: &c.Key, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go index ef1c20480..08f25faf6 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go index 6b69c7c27..e9adb6b60 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go index fa51df47b..7a2af0f8c 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags + alertutil.BaseAlertFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go index 1e5e3e388..a2d5d8572 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/opsgenie_test.go @@ -304,13 +304,9 @@ func TestOpsgenieAlertUpdate(t *testing.T) { Name: "validate API success with key", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-1234", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -319,7 +315,6 @@ func TestOpsgenieAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -335,13 +330,9 @@ func TestOpsgenieAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-1234 --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -350,7 +341,6 @@ func TestOpsgenieAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go index b28a3439f..a1e3a328f 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags - common.KeyConfigFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags + alertutil.KeyConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Key: &c.Key, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go index 93166374e..e0150ed6d 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags - common.KeyConfigFlags + alertutil.BaseAlertFlags + alertutil.KeyConfigFlags // Optional. - common.AlertDataFlags + alertutil.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Key: &c.Key, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go index d0cac1370..dd98a5419 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go index 11db69fd3..4780cbce4 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go index 5793f5c31..e42b6a872 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags + alertutil.BaseAlertFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go index 9632ae3df..94144ca1f 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/pagerduty_test.go @@ -290,13 +290,9 @@ func TestPagerDutyAlertUpdate(t *testing.T) { Name: "validate API success with key", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -305,7 +301,6 @@ func TestPagerDutyAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -321,13 +316,9 @@ func TestPagerDutyAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --key updated-key-9876543210 --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -336,7 +327,6 @@ func TestPagerDutyAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go index 3c005c406..c705a8d38 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags - common.KeyConfigFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags + alertutil.KeyConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Key: &c.Key, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/slack/create.go b/pkg/commands/ngwaf/workspace/alert/slack/create.go index 5806e6a76..6a1aaa100 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/create.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags - common.WebhookConfigFlags + alertutil.BaseAlertFlags + alertutil.WebhookConfigFlags // Optional. - common.AlertDataFlags + alertutil.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/slack/delete.go b/pkg/commands/ngwaf/workspace/alert/slack/delete.go index 415c2d1c4..bd4b747c6 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/get.go b/pkg/commands/ngwaf/workspace/alert/slack/get.go index d7ff31076..5c8088363 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/get.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/list.go b/pkg/commands/ngwaf/workspace/alert/slack/list.go index f85e15757..e33cab94f 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/list.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags + alertutil.BaseAlertFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go b/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go index ddc47ba7f..85e3160a7 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/slack_test.go @@ -290,13 +290,9 @@ func TestSlackAlertUpdate(t *testing.T) { Name: "validate API success with webhook", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://hooks.slack.com/services/updated", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -305,7 +301,6 @@ func TestSlackAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -321,13 +316,9 @@ func TestSlackAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://hooks.slack.com/services/updated --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), @@ -336,7 +327,6 @@ func TestSlackAlertUpdate(t *testing.T) { }, { - StatusCode: http.StatusOK, Status: http.StatusText(http.StatusOK), diff --git a/pkg/commands/ngwaf/workspace/alert/slack/update.go b/pkg/commands/ngwaf/workspace/alert/slack/update.go index 14e4e3b6a..5b127d905 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/update.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags - common.WebhookConfigFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags + alertutil.WebhookConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/create.go b/pkg/commands/ngwaf/workspace/alert/webhook/create.go index 0c960acef..83a831b01 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/create.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags - common.WebhookConfigFlags + alertutil.BaseAlertFlags + alertutil.WebhookConfigFlags // Optional. - common.AlertDataFlags + alertutil.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go index 74a8b05d5..e63bb545f 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go index 785a392f6..3a208c5c3 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetSigningKeyCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetSigningKeyCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get.go b/pkg/commands/ngwaf/workspace/alert/webhook/get.go index d5322469f..c79271fb4 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/list.go b/pkg/commands/ngwaf/workspace/alert/webhook/list.go index 08b31fc8e..52b253919 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/list.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - common.BaseAlertFlags + alertutil.BaseAlertFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go index 5268db034..60b39ce8c 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type RotateSigningKeyCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags } // NewRotateSigningKeyCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/update.go b/pkg/commands/ngwaf/workspace/alert/webhook/update.go index b23e75337..b92c67179 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/update.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/common" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - common.AlertIDFlags - common.BaseAlertFlags - common.WebhookConfigFlags + alertutil.AlertIDFlags + alertutil.BaseAlertFlags + alertutil.WebhookConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: common.GetDefaultEvents(), + Events: alertutil.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) From 66b372ec5203915886a1d380ce24f57e44d3ad68 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 1 Dec 2025 14:43:59 -0500 Subject: [PATCH 08/13] more linting fixes --- .../workspace/alert/webhook/webhook_test.go | 36 +++++-------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go b/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go index 3cc77c3b7..f5030f9be 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/webhook_test.go @@ -291,27 +291,17 @@ func TestWebhookAlertUpdate(t *testing.T) { Name: "validate API success with webhook", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://example.com/webhook/updated", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, - - Status: http.StatusText(http.StatusOK), - - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(webhookAlert))), + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(webhookAlert))), }, - { - StatusCode: http.StatusOK, - - Status: http.StatusText(http.StatusOK), - - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), }, }, }, @@ -322,27 +312,17 @@ func TestWebhookAlertUpdate(t *testing.T) { Name: "validate optional --json flag", Args: fmt.Sprintf("--workspace-id %s --alert-id %s --webhook https://example.com/webhook/updated --json", workspaceID, alertID), Client: &http.Client{ - Transport: &testutil.MultiResponseRoundTripper{ - Responses: []*http.Response{ - { - StatusCode: http.StatusOK, - - Status: http.StatusText(http.StatusOK), - - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(webhookAlert))), + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(webhookAlert))), }, - { - StatusCode: http.StatusOK, - - Status: http.StatusText(http.StatusOK), - - Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(updatedAlert))), }, }, }, From 3bb2c77cabdafe55c9b548a6a7d29a6cc94bafbe Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Mon, 1 Dec 2025 15:07:57 -0500 Subject: [PATCH 09/13] Duplicate Command Fix --- pkg/commands/commands.go | 216 ++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 114 deletions(-) diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 286891c49..cb126e44e 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -493,63 +493,57 @@ func Define( // nolint:revive // function-length ngwafVirtualpatchList := virtualpatch.NewListCommand(ngwafVirtualpatchRoot.CmdClause, data) ngwafVirtualpatchUpdate := virtualpatch.NewUpdateCommand(ngwafVirtualpatchRoot.CmdClause, data) ngwafVirtualpatchRetrieve := virtualpatch.NewRetrieveCommand(ngwafVirtualpatchRoot.CmdClause, data) - ngwafWorkspacesRoot := workspace.NewRootCommand(ngwafRoot.CmdClause, data) - ngwafWorkspacesCreate := workspace.NewCreateCommand(ngwafWorkspacesRoot.CmdClause, data) - ngwafWorkspacesDelete := workspace.NewDeleteCommand(ngwafWorkspacesRoot.CmdClause, data) - ngwafWorkspacesGet := workspace.NewGetCommand(ngwafWorkspacesRoot.CmdClause, data) - ngwafWorkspacesList := workspace.NewListCommand(ngwafWorkspacesRoot.CmdClause, data) - ngwafWorkspacesUpdate := workspace.NewUpdateCommand(ngwafWorkspacesRoot.CmdClause, data) - ngwafWorkspacesAlertRoot := alert.NewRootCommand(ngwafWorkspacesRoot.CmdClause, data) - ngwafWorkspacesAlertDatadogRoot := workspaceAlertDatadog.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) - ngwafWorkspacesAlertDatadogCreate := workspaceAlertDatadog.NewCreateCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) - ngwafWorkspacesAlertDatadogDelete := workspaceAlertDatadog.NewDeleteCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) - ngwafWorkspacesAlertDatadogGet := workspaceAlertDatadog.NewGetCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) - ngwafWorkspacesAlertDatadogList := workspaceAlertDatadog.NewListCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) - ngwafWorkspacesAlertDatadogUpdate := workspaceAlertDatadog.NewUpdateCommand(ngwafWorkspacesAlertDatadogRoot.CmdClause, data) - ngwafWorkspacesAlertJiraRoot := workspaceAlertJira.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) - ngwafWorkspacesAlertJiraCreate := workspaceAlertJira.NewCreateCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) - ngwafWorkspacesAlertJiraDelete := workspaceAlertJira.NewDeleteCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) - ngwafWorkspacesAlertJiraGet := workspaceAlertJira.NewGetCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) - ngwafWorkspacesAlertJiraList := workspaceAlertJira.NewListCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) - ngwafWorkspacesAlertJiraUpdate := workspaceAlertJira.NewUpdateCommand(ngwafWorkspacesAlertJiraRoot.CmdClause, data) - ngwafWorkspacesAlertMailinglistRoot := workspaceAlertMailinglist.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) - ngwafWorkspacesAlertMailinglistCreate := workspaceAlertMailinglist.NewCreateCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) - ngwafWorkspacesAlertMailinglistDelete := workspaceAlertMailinglist.NewDeleteCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) - ngwafWorkspacesAlertMailinglistGet := workspaceAlertMailinglist.NewGetCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) - ngwafWorkspacesAlertMailinglistList := workspaceAlertMailinglist.NewListCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) - ngwafWorkspacesAlertMailinglistUpdate := workspaceAlertMailinglist.NewUpdateCommand(ngwafWorkspacesAlertMailinglistRoot.CmdClause, data) - ngwafWorkspacesAlertMicrosoftteamsRoot := workspaceAlertMicrosoftteams.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) - ngwafWorkspacesAlertMicrosoftteamsCreate := workspaceAlertMicrosoftteams.NewCreateCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) - ngwafWorkspacesAlertMicrosoftteamsDelete := workspaceAlertMicrosoftteams.NewDeleteCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) - ngwafWorkspacesAlertMicrosoftteamsGet := workspaceAlertMicrosoftteams.NewGetCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) - ngwafWorkspacesAlertMicrosoftteamsList := workspaceAlertMicrosoftteams.NewListCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) - ngwafWorkspacesAlertMicrosoftteamsUpdate := workspaceAlertMicrosoftteams.NewUpdateCommand(ngwafWorkspacesAlertMicrosoftteamsRoot.CmdClause, data) - ngwafWorkspacesAlertOpsgenieRoot := workspaceAlertOpsgenie.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) - ngwafWorkspacesAlertOpsgenieCreate := workspaceAlertOpsgenie.NewCreateCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) - ngwafWorkspacesAlertOpsgenieDelete := workspaceAlertOpsgenie.NewDeleteCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) - ngwafWorkspacesAlertOpsgenieGet := workspaceAlertOpsgenie.NewGetCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) - ngwafWorkspacesAlertOpsgenieList := workspaceAlertOpsgenie.NewListCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) - ngwafWorkspacesAlertOpsgenieUpdate := workspaceAlertOpsgenie.NewUpdateCommand(ngwafWorkspacesAlertOpsgenieRoot.CmdClause, data) - ngwafWorkspacesAlertPagerdutyRoot := workspaceAlertPagerduty.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) - ngwafWorkspacesAlertPagerdutyCreate := workspaceAlertPagerduty.NewCreateCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) - ngwafWorkspacesAlertPagerdutyDelete := workspaceAlertPagerduty.NewDeleteCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) - ngwafWorkspacesAlertPagerdutyGet := workspaceAlertPagerduty.NewGetCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) - ngwafWorkspacesAlertPagerdutyList := workspaceAlertPagerduty.NewListCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) - ngwafWorkspacesAlertPagerdutyUpdate := workspaceAlertPagerduty.NewUpdateCommand(ngwafWorkspacesAlertPagerdutyRoot.CmdClause, data) - ngwafWorkspacesAlertSlackRoot := workspaceAlertSlack.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) - ngwafWorkspacesAlertSlackCreate := workspaceAlertSlack.NewCreateCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) - ngwafWorkspacesAlertSlackDelete := workspaceAlertSlack.NewDeleteCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) - ngwafWorkspacesAlertSlackGet := workspaceAlertSlack.NewGetCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) - ngwafWorkspacesAlertSlackList := workspaceAlertSlack.NewListCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) - ngwafWorkspacesAlertSlackUpdate := workspaceAlertSlack.NewUpdateCommand(ngwafWorkspacesAlertSlackRoot.CmdClause, data) - ngwafWorkspacesAlertWebhookRoot := workspaceAlertWebhook.NewRootCommand(ngwafWorkspacesAlertRoot.CmdClause, data) - ngwafWorkspacesAlertWebhookCreate := workspaceAlertWebhook.NewCreateCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) - ngwafWorkspacesAlertWebhookDelete := workspaceAlertWebhook.NewDeleteCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) - ngwafWorkspacesAlertWebhookGet := workspaceAlertWebhook.NewGetCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) - ngwafWorkspacesAlertWebhookGetSigningKey := workspaceAlertWebhook.NewGetSigningKeyCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) - ngwafWorkspacesAlertWebhookList := workspaceAlertWebhook.NewListCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) - ngwafWorkspacesAlertWebhookRotateSigningKey := workspaceAlertWebhook.NewRotateSigningKeyCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) - ngwafWorkspacesAlertWebhookUpdate := workspaceAlertWebhook.NewUpdateCommand(ngwafWorkspacesAlertWebhookRoot.CmdClause, data) + ngwafWorkspaceAlertRoot := alert.NewRootCommand(ngwafWorkspaceRoot.CmdClause, data) + ngwafWorkspaceAlertDatadogRoot := workspaceAlertDatadog.NewRootCommand(ngwafWorkspaceAlertRoot.CmdClause, data) + ngwafWorkspaceAlertDatadogCreate := workspaceAlertDatadog.NewCreateCommand(ngwafWorkspaceAlertDatadogRoot.CmdClause, data) + ngwafWorkspaceAlertDatadogDelete := workspaceAlertDatadog.NewDeleteCommand(ngwafWorkspaceAlertDatadogRoot.CmdClause, data) + ngwafWorkspaceAlertDatadogGet := workspaceAlertDatadog.NewGetCommand(ngwafWorkspaceAlertDatadogRoot.CmdClause, data) + ngwafWorkspaceAlertDatadogList := workspaceAlertDatadog.NewListCommand(ngwafWorkspaceAlertDatadogRoot.CmdClause, data) + ngwafWorkspaceAlertDatadogUpdate := workspaceAlertDatadog.NewUpdateCommand(ngwafWorkspaceAlertDatadogRoot.CmdClause, data) + ngwafWorkspaceAlertJiraRoot := workspaceAlertJira.NewRootCommand(ngwafWorkspaceAlertRoot.CmdClause, data) + ngwafWorkspaceAlertJiraCreate := workspaceAlertJira.NewCreateCommand(ngwafWorkspaceAlertJiraRoot.CmdClause, data) + ngwafWorkspaceAlertJiraDelete := workspaceAlertJira.NewDeleteCommand(ngwafWorkspaceAlertJiraRoot.CmdClause, data) + ngwafWorkspaceAlertJiraGet := workspaceAlertJira.NewGetCommand(ngwafWorkspaceAlertJiraRoot.CmdClause, data) + ngwafWorkspaceAlertJiraList := workspaceAlertJira.NewListCommand(ngwafWorkspaceAlertJiraRoot.CmdClause, data) + ngwafWorkspaceAlertJiraUpdate := workspaceAlertJira.NewUpdateCommand(ngwafWorkspaceAlertJiraRoot.CmdClause, data) + ngwafWorkspaceAlertMailinglistRoot := workspaceAlertMailinglist.NewRootCommand(ngwafWorkspaceAlertRoot.CmdClause, data) + ngwafWorkspaceAlertMailinglistCreate := workspaceAlertMailinglist.NewCreateCommand(ngwafWorkspaceAlertMailinglistRoot.CmdClause, data) + ngwafWorkspaceAlertMailinglistDelete := workspaceAlertMailinglist.NewDeleteCommand(ngwafWorkspaceAlertMailinglistRoot.CmdClause, data) + ngwafWorkspaceAlertMailinglistGet := workspaceAlertMailinglist.NewGetCommand(ngwafWorkspaceAlertMailinglistRoot.CmdClause, data) + ngwafWorkspaceAlertMailinglistList := workspaceAlertMailinglist.NewListCommand(ngwafWorkspaceAlertMailinglistRoot.CmdClause, data) + ngwafWorkspaceAlertMailinglistUpdate := workspaceAlertMailinglist.NewUpdateCommand(ngwafWorkspaceAlertMailinglistRoot.CmdClause, data) + ngwafWorkspaceAlertMicrosoftteamsRoot := workspaceAlertMicrosoftteams.NewRootCommand(ngwafWorkspaceAlertRoot.CmdClause, data) + ngwafWorkspaceAlertMicrosoftteamsCreate := workspaceAlertMicrosoftteams.NewCreateCommand(ngwafWorkspaceAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspaceAlertMicrosoftteamsDelete := workspaceAlertMicrosoftteams.NewDeleteCommand(ngwafWorkspaceAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspaceAlertMicrosoftteamsGet := workspaceAlertMicrosoftteams.NewGetCommand(ngwafWorkspaceAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspaceAlertMicrosoftteamsList := workspaceAlertMicrosoftteams.NewListCommand(ngwafWorkspaceAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspaceAlertMicrosoftteamsUpdate := workspaceAlertMicrosoftteams.NewUpdateCommand(ngwafWorkspaceAlertMicrosoftteamsRoot.CmdClause, data) + ngwafWorkspaceAlertOpsgenieRoot := workspaceAlertOpsgenie.NewRootCommand(ngwafWorkspaceAlertRoot.CmdClause, data) + ngwafWorkspaceAlertOpsgenieCreate := workspaceAlertOpsgenie.NewCreateCommand(ngwafWorkspaceAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspaceAlertOpsgenieDelete := workspaceAlertOpsgenie.NewDeleteCommand(ngwafWorkspaceAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspaceAlertOpsgenieGet := workspaceAlertOpsgenie.NewGetCommand(ngwafWorkspaceAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspaceAlertOpsgenieList := workspaceAlertOpsgenie.NewListCommand(ngwafWorkspaceAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspaceAlertOpsgenieUpdate := workspaceAlertOpsgenie.NewUpdateCommand(ngwafWorkspaceAlertOpsgenieRoot.CmdClause, data) + ngwafWorkspaceAlertPagerdutyRoot := workspaceAlertPagerduty.NewRootCommand(ngwafWorkspaceAlertRoot.CmdClause, data) + ngwafWorkspaceAlertPagerdutyCreate := workspaceAlertPagerduty.NewCreateCommand(ngwafWorkspaceAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspaceAlertPagerdutyDelete := workspaceAlertPagerduty.NewDeleteCommand(ngwafWorkspaceAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspaceAlertPagerdutyGet := workspaceAlertPagerduty.NewGetCommand(ngwafWorkspaceAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspaceAlertPagerdutyList := workspaceAlertPagerduty.NewListCommand(ngwafWorkspaceAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspaceAlertPagerdutyUpdate := workspaceAlertPagerduty.NewUpdateCommand(ngwafWorkspaceAlertPagerdutyRoot.CmdClause, data) + ngwafWorkspaceAlertSlackRoot := workspaceAlertSlack.NewRootCommand(ngwafWorkspaceAlertRoot.CmdClause, data) + ngwafWorkspaceAlertSlackCreate := workspaceAlertSlack.NewCreateCommand(ngwafWorkspaceAlertSlackRoot.CmdClause, data) + ngwafWorkspaceAlertSlackDelete := workspaceAlertSlack.NewDeleteCommand(ngwafWorkspaceAlertSlackRoot.CmdClause, data) + ngwafWorkspaceAlertSlackGet := workspaceAlertSlack.NewGetCommand(ngwafWorkspaceAlertSlackRoot.CmdClause, data) + ngwafWorkspaceAlertSlackList := workspaceAlertSlack.NewListCommand(ngwafWorkspaceAlertSlackRoot.CmdClause, data) + ngwafWorkspaceAlertSlackUpdate := workspaceAlertSlack.NewUpdateCommand(ngwafWorkspaceAlertSlackRoot.CmdClause, data) + ngwafWorkspaceAlertWebhookRoot := workspaceAlertWebhook.NewRootCommand(ngwafWorkspaceAlertRoot.CmdClause, data) + ngwafWorkspaceAlertWebhookCreate := workspaceAlertWebhook.NewCreateCommand(ngwafWorkspaceAlertWebhookRoot.CmdClause, data) + ngwafWorkspaceAlertWebhookDelete := workspaceAlertWebhook.NewDeleteCommand(ngwafWorkspaceAlertWebhookRoot.CmdClause, data) + ngwafWorkspaceAlertWebhookGet := workspaceAlertWebhook.NewGetCommand(ngwafWorkspaceAlertWebhookRoot.CmdClause, data) + ngwafWorkspaceAlertWebhookGetSigningKey := workspaceAlertWebhook.NewGetSigningKeyCommand(ngwafWorkspaceAlertWebhookRoot.CmdClause, data) + ngwafWorkspaceAlertWebhookList := workspaceAlertWebhook.NewListCommand(ngwafWorkspaceAlertWebhookRoot.CmdClause, data) + ngwafWorkspaceAlertWebhookRotateSigningKey := workspaceAlertWebhook.NewRotateSigningKeyCommand(ngwafWorkspaceAlertWebhookRoot.CmdClause, data) + ngwafWorkspaceAlertWebhookUpdate := workspaceAlertWebhook.NewUpdateCommand(ngwafWorkspaceAlertWebhookRoot.CmdClause, data) objectStorageRoot := objectstorage.NewRootCommand(app, data) objectStorageAccesskeysRoot := accesskeys.NewRootCommand(objectStorageRoot.CmdClause, data) objectStorageAccesskeysCreate := accesskeys.NewCreateCommand(objectStorageAccesskeysRoot.CmdClause, data) @@ -1038,63 +1032,57 @@ func Define( // nolint:revive // function-length ngwafVirtualpatchRetrieve, ngwafVirtualpatchRoot, ngwafVirtualpatchUpdate, - ngwafWorkspacesRoot, - ngwafWorkspacesCreate, - ngwafWorkspacesDelete, - ngwafWorkspacesGet, - ngwafWorkspacesList, - ngwafWorkspacesUpdate, - ngwafWorkspacesAlertRoot, - ngwafWorkspacesAlertDatadogRoot, - ngwafWorkspacesAlertDatadogCreate, - ngwafWorkspacesAlertDatadogDelete, - ngwafWorkspacesAlertDatadogGet, - ngwafWorkspacesAlertDatadogList, - ngwafWorkspacesAlertDatadogUpdate, - ngwafWorkspacesAlertJiraRoot, - ngwafWorkspacesAlertJiraCreate, - ngwafWorkspacesAlertJiraDelete, - ngwafWorkspacesAlertJiraGet, - ngwafWorkspacesAlertJiraList, - ngwafWorkspacesAlertJiraUpdate, - ngwafWorkspacesAlertMailinglistRoot, - ngwafWorkspacesAlertMailinglistCreate, - ngwafWorkspacesAlertMailinglistDelete, - ngwafWorkspacesAlertMailinglistGet, - ngwafWorkspacesAlertMailinglistList, - ngwafWorkspacesAlertMailinglistUpdate, - ngwafWorkspacesAlertMicrosoftteamsRoot, - ngwafWorkspacesAlertMicrosoftteamsCreate, - ngwafWorkspacesAlertMicrosoftteamsDelete, - ngwafWorkspacesAlertMicrosoftteamsGet, - ngwafWorkspacesAlertMicrosoftteamsList, - ngwafWorkspacesAlertMicrosoftteamsUpdate, - ngwafWorkspacesAlertOpsgenieRoot, - ngwafWorkspacesAlertOpsgenieCreate, - ngwafWorkspacesAlertOpsgenieDelete, - ngwafWorkspacesAlertOpsgenieGet, - ngwafWorkspacesAlertOpsgenieList, - ngwafWorkspacesAlertOpsgenieUpdate, - ngwafWorkspacesAlertPagerdutyRoot, - ngwafWorkspacesAlertPagerdutyCreate, - ngwafWorkspacesAlertPagerdutyDelete, - ngwafWorkspacesAlertPagerdutyGet, - ngwafWorkspacesAlertPagerdutyList, - ngwafWorkspacesAlertPagerdutyUpdate, - ngwafWorkspacesAlertSlackRoot, - ngwafWorkspacesAlertSlackCreate, - ngwafWorkspacesAlertSlackDelete, - ngwafWorkspacesAlertSlackGet, - ngwafWorkspacesAlertSlackList, - ngwafWorkspacesAlertSlackUpdate, - ngwafWorkspacesAlertWebhookRoot, - ngwafWorkspacesAlertWebhookCreate, - ngwafWorkspacesAlertWebhookDelete, - ngwafWorkspacesAlertWebhookGet, - ngwafWorkspacesAlertWebhookGetSigningKey, - ngwafWorkspacesAlertWebhookList, - ngwafWorkspacesAlertWebhookRotateSigningKey, - ngwafWorkspacesAlertWebhookUpdate, + ngwafWorkspaceAlertRoot, + ngwafWorkspaceAlertDatadogRoot, + ngwafWorkspaceAlertDatadogCreate, + ngwafWorkspaceAlertDatadogDelete, + ngwafWorkspaceAlertDatadogGet, + ngwafWorkspaceAlertDatadogList, + ngwafWorkspaceAlertDatadogUpdate, + ngwafWorkspaceAlertJiraRoot, + ngwafWorkspaceAlertJiraCreate, + ngwafWorkspaceAlertJiraDelete, + ngwafWorkspaceAlertJiraGet, + ngwafWorkspaceAlertJiraList, + ngwafWorkspaceAlertJiraUpdate, + ngwafWorkspaceAlertMailinglistRoot, + ngwafWorkspaceAlertMailinglistCreate, + ngwafWorkspaceAlertMailinglistDelete, + ngwafWorkspaceAlertMailinglistGet, + ngwafWorkspaceAlertMailinglistList, + ngwafWorkspaceAlertMailinglistUpdate, + ngwafWorkspaceAlertMicrosoftteamsRoot, + ngwafWorkspaceAlertMicrosoftteamsCreate, + ngwafWorkspaceAlertMicrosoftteamsDelete, + ngwafWorkspaceAlertMicrosoftteamsGet, + ngwafWorkspaceAlertMicrosoftteamsList, + ngwafWorkspaceAlertMicrosoftteamsUpdate, + ngwafWorkspaceAlertOpsgenieRoot, + ngwafWorkspaceAlertOpsgenieCreate, + ngwafWorkspaceAlertOpsgenieDelete, + ngwafWorkspaceAlertOpsgenieGet, + ngwafWorkspaceAlertOpsgenieList, + ngwafWorkspaceAlertOpsgenieUpdate, + ngwafWorkspaceAlertPagerdutyRoot, + ngwafWorkspaceAlertPagerdutyCreate, + ngwafWorkspaceAlertPagerdutyDelete, + ngwafWorkspaceAlertPagerdutyGet, + ngwafWorkspaceAlertPagerdutyList, + ngwafWorkspaceAlertPagerdutyUpdate, + ngwafWorkspaceAlertSlackRoot, + ngwafWorkspaceAlertSlackCreate, + ngwafWorkspaceAlertSlackDelete, + ngwafWorkspaceAlertSlackGet, + ngwafWorkspaceAlertSlackList, + ngwafWorkspaceAlertSlackUpdate, + ngwafWorkspaceAlertWebhookRoot, + ngwafWorkspaceAlertWebhookCreate, + ngwafWorkspaceAlertWebhookDelete, + ngwafWorkspaceAlertWebhookGet, + ngwafWorkspaceAlertWebhookGetSigningKey, + ngwafWorkspaceAlertWebhookList, + ngwafWorkspaceAlertWebhookRotateSigningKey, + ngwafWorkspaceAlertWebhookUpdate, ngwafWorkspaceRoot, ngwafWorkspaceCreate, ngwafWorkspaceDelete, From 1a24eace25c0df88e148e4c2b58fb3c591c6f1b8 Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Wed, 3 Dec 2025 13:21:08 -0500 Subject: [PATCH 10/13] Alert Common Refactor Restructured common references for alert types into root.go files. Common references stay in the alert root package, and individual attributes are moved to the root.go of the specific alert types. --- .../workspace/alert/alertutil/builder.go | 8 --- .../ngwaf/workspace/alert/alertutil/doc.go | 2 - .../ngwaf/workspace/alert/alertutil/flags.go | 52 ------------------- .../ngwaf/workspace/alert/datadog/create.go | 10 ++-- .../ngwaf/workspace/alert/datadog/delete.go | 6 +-- .../ngwaf/workspace/alert/datadog/get.go | 6 +-- .../ngwaf/workspace/alert/datadog/list.go | 4 +- .../ngwaf/workspace/alert/datadog/root.go | 6 +++ .../ngwaf/workspace/alert/datadog/update.go | 10 ++-- .../ngwaf/workspace/alert/jira/create.go | 13 +++-- .../ngwaf/workspace/alert/jira/delete.go | 7 ++- .../ngwaf/workspace/alert/jira/get.go | 7 ++- .../ngwaf/workspace/alert/jira/list.go | 5 +- .../ngwaf/workspace/alert/jira/root.go | 13 +++++ .../ngwaf/workspace/alert/jira/update.go | 13 +++-- .../workspace/alert/mailinglist/create.go | 10 ++-- .../workspace/alert/mailinglist/delete.go | 6 +-- .../ngwaf/workspace/alert/mailinglist/get.go | 6 +-- .../ngwaf/workspace/alert/mailinglist/list.go | 4 +- .../ngwaf/workspace/alert/mailinglist/root.go | 5 ++ .../workspace/alert/mailinglist/update.go | 10 ++-- .../workspace/alert/microsoftteams/create.go | 10 ++-- .../workspace/alert/microsoftteams/delete.go | 6 +-- .../workspace/alert/microsoftteams/get.go | 6 +-- .../workspace/alert/microsoftteams/list.go | 4 +- .../workspace/alert/microsoftteams/update.go | 10 ++-- .../ngwaf/workspace/alert/opsgenie/create.go | 10 ++-- .../ngwaf/workspace/alert/opsgenie/delete.go | 6 +-- .../ngwaf/workspace/alert/opsgenie/get.go | 6 +-- .../ngwaf/workspace/alert/opsgenie/list.go | 4 +- .../ngwaf/workspace/alert/opsgenie/update.go | 10 ++-- .../ngwaf/workspace/alert/pagerduty/create.go | 10 ++-- .../ngwaf/workspace/alert/pagerduty/delete.go | 6 +-- .../ngwaf/workspace/alert/pagerduty/get.go | 6 +-- .../ngwaf/workspace/alert/pagerduty/list.go | 4 +- .../ngwaf/workspace/alert/pagerduty/update.go | 10 ++-- pkg/commands/ngwaf/workspace/alert/root.go | 32 ++++++++++++ .../ngwaf/workspace/alert/slack/create.go | 10 ++-- .../ngwaf/workspace/alert/slack/delete.go | 6 +-- .../ngwaf/workspace/alert/slack/get.go | 6 +-- .../ngwaf/workspace/alert/slack/list.go | 4 +- .../ngwaf/workspace/alert/slack/update.go | 10 ++-- .../ngwaf/workspace/alert/webhook/create.go | 10 ++-- .../ngwaf/workspace/alert/webhook/delete.go | 6 +-- .../alert/webhook/get-signing-key.go | 6 +-- .../ngwaf/workspace/alert/webhook/get.go | 6 +-- .../ngwaf/workspace/alert/webhook/list.go | 4 +- .../alert/webhook/rotate-signing-key.go | 6 +-- .../ngwaf/workspace/alert/webhook/update.go | 10 ++-- 49 files changed, 208 insertions(+), 219 deletions(-) delete mode 100644 pkg/commands/ngwaf/workspace/alert/alertutil/builder.go delete mode 100644 pkg/commands/ngwaf/workspace/alert/alertutil/doc.go delete mode 100644 pkg/commands/ngwaf/workspace/alert/alertutil/flags.go diff --git a/pkg/commands/ngwaf/workspace/alert/alertutil/builder.go b/pkg/commands/ngwaf/workspace/alert/alertutil/builder.go deleted file mode 100644 index e0088c488..000000000 --- a/pkg/commands/ngwaf/workspace/alert/alertutil/builder.go +++ /dev/null @@ -1,8 +0,0 @@ -package alertutil - -// GetDefaultEvents returns the hardcoded events value for all alerts. -// Currently the only supported value is "flag". -func GetDefaultEvents() *[]string { - events := []string{"flag"} - return &events -} diff --git a/pkg/commands/ngwaf/workspace/alert/alertutil/doc.go b/pkg/commands/ngwaf/workspace/alert/alertutil/doc.go deleted file mode 100644 index 1ee7df628..000000000 --- a/pkg/commands/ngwaf/workspace/alert/alertutil/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package alertutil contains shared types and helpers for NGWAF alert commands. -package alertutil diff --git a/pkg/commands/ngwaf/workspace/alert/alertutil/flags.go b/pkg/commands/ngwaf/workspace/alert/alertutil/flags.go deleted file mode 100644 index 4e88dfb5a..000000000 --- a/pkg/commands/ngwaf/workspace/alert/alertutil/flags.go +++ /dev/null @@ -1,52 +0,0 @@ -package alertutil - -import "github.com/fastly/cli/pkg/argparser" - -// BaseAlertFlags contains flags that are common to all alert commands. -type BaseAlertFlags struct { - WorkspaceID argparser.OptionalWorkspaceID -} - -// AlertIDFlags contains flags for identifying a specific alert (used in update/delete/get). -type AlertIDFlags struct { - AlertID string -} - -// AlertDataFlags contains optional data fields for alerts (used in create/update). -type AlertDataFlags struct { - Description argparser.OptionalString -} - -// DatadogConfigFlags contains Datadog specific configuration flags. -type DatadogConfigFlags struct { - Key string - Site string -} - -// JiraOptConfigFlags contains optional Jira specific configuration flags. -type JiraOptConfigFlags struct { - IssueType string -} - -// JiraConfigFlags contains Jira specific configuration flags. -type JiraConfigFlags struct { - Host string - Key string - Project string - Username string -} - -// AddressConfigFlags contains Address configurations used by mailing lists. -type AddressConfigFlags struct { - Address string -} - -// KeyConfigFlags contains the Key configuration (used by opsgenie, pagerduty, etc...). -type KeyConfigFlags struct { - Key string -} - -// WebhookConfigFlags contains the Webhook configuration (used by webhook, slack, etc...). -type WebhookConfigFlags struct { - Webhook string -} diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/create.go b/pkg/commands/ngwaf/workspace/alert/datadog/create.go index 440682ff6..d237b599d 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/create.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags - alertutil.DatadogConfigFlags + alert.WorkspaceIDFlags + DatadogConfigFlags // Optional. - alertutil.AlertDataFlags + alert.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -72,7 +72,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Site: &c.Site, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go index 47cbdcd45..7bfb1f61a 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/get.go b/pkg/commands/ngwaf/workspace/alert/datadog/get.go index 28d722821..c3b3a8fea 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/get.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/list.go b/pkg/commands/ngwaf/workspace/alert/datadog/list.go index 23630b317..5f91cd57d 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/list.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags + alert.WorkspaceIDFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/root.go b/pkg/commands/ngwaf/workspace/alert/datadog/root.go index 725dceacc..1a7e968a4 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/root.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/root.go @@ -29,3 +29,9 @@ func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { panic("unreachable") } + +// DatadogConfigFlags contains Datadog specific configuration flags. +type DatadogConfigFlags struct { + Key string + Site string +} diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/update.go b/pkg/commands/ngwaf/workspace/alert/datadog/update.go index 673febb92..b72ad8ed0 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/update.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags - alertutil.DatadogConfigFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags + DatadogConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -75,7 +75,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Site: &c.Site, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/jira/create.go b/pkg/commands/ngwaf/workspace/alert/jira/create.go index 3513f1618..adbe4ce7b 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/create.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/create.go @@ -6,8 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" - + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,12 +20,12 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags - alertutil.JiraConfigFlags + alert.WorkspaceIDFlags + JiraConfigFlags // Optional. - alertutil.AlertDataFlags - alertutil.JiraOptConfigFlags + alert.AlertDataFlags + JiraOptConfigFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -78,7 +77,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Username: &c.Username, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.IssueType != "" { input.Config.IssueType = &c.IssueType diff --git a/pkg/commands/ngwaf/workspace/alert/jira/delete.go b/pkg/commands/ngwaf/workspace/alert/jira/delete.go index 6ba40407c..4f60c37c5 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/delete.go @@ -6,8 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" - + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +20,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/get.go b/pkg/commands/ngwaf/workspace/alert/jira/get.go index f5a9f06af..8f4e14f39 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/get.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/get.go @@ -6,8 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" - + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +20,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/list.go b/pkg/commands/ngwaf/workspace/alert/jira/list.go index 66ec24b28..b308f2024 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/list.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/list.go @@ -6,8 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" - + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,7 +20,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags + alert.WorkspaceIDFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/root.go b/pkg/commands/ngwaf/workspace/alert/jira/root.go index 38997a4bc..38e5513a7 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/root.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/root.go @@ -29,3 +29,16 @@ func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { panic("unreachable") } + +// JiraConfigFlags contains Jira specific configuration flags. +type JiraConfigFlags struct { + Host string + Key string + Project string + Username string +} + +// JiraOptConfigFlags contains optional Jira specific configuration flags. +type JiraOptConfigFlags struct { + IssueType string +} diff --git a/pkg/commands/ngwaf/workspace/alert/jira/update.go b/pkg/commands/ngwaf/workspace/alert/jira/update.go index ec0438cf0..82c4cb5c8 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/update.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/update.go @@ -6,8 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" - + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,12 +20,12 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags - alertutil.JiraConfigFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags + JiraConfigFlags // Optional - alertutil.JiraOptConfigFlags + JiraOptConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -84,7 +83,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Username: &c.Username, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.IssueType != "" { input.Config.IssueType = &c.IssueType diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go index 5059532cf..b6d39b32e 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags - alertutil.AddressConfigFlags + alert.WorkspaceIDFlags + AddressConfigFlags // Optional. - alertutil.AlertDataFlags + alert.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Address: &c.Address, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go index 772029999..0f5711668 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go index b7b82030d..badb23083 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go index 0e84d52e2..63e29bc7a 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags + alert.WorkspaceIDFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/root.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/root.go index 455d68531..6a374e477 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/root.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/root.go @@ -29,3 +29,8 @@ func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { panic("unreachable") } + +// AddressConfigFlags contains Address configurations used by mailing lists. +type AddressConfigFlags struct { + Address string +} diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go index 1d6ce5a30..4a94ecdf6 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags - alertutil.AddressConfigFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags + AddressConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Address: &c.Address, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go index 78e0786aa..46d404c79 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags - alertutil.WebhookConfigFlags + alert.WorkspaceIDFlags + alert.WebhookConfigFlags // Optional. - alertutil.AlertDataFlags + alert.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go index 4475b4370..07342db64 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go index 89a551928..a89ddd104 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go index 08ec16cc0..123c12697 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags + alert.WorkspaceIDFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go index b112e3348..63e67ac3f 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags - alertutil.WebhookConfigFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags + alert.WebhookConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go index f6ea7ca8f..65d852540 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags - alertutil.KeyConfigFlags + alert.WorkspaceIDFlags + alert.KeyConfigFlags // Optional. - alertutil.AlertDataFlags + alert.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Key: &c.Key, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go index 08f25faf6..d483993e4 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go index e9adb6b60..0a6023d5c 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go index 7a2af0f8c..77d18289a 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags + alert.WorkspaceIDFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go index a1e3a328f..a6d0cca0b 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags - alertutil.KeyConfigFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags + alert.KeyConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Key: &c.Key, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go index e0150ed6d..bf2f99be6 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags - alertutil.KeyConfigFlags + alert.WorkspaceIDFlags + alert.KeyConfigFlags // Optional. - alertutil.AlertDataFlags + alert.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Key: &c.Key, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go index dd98a5419..9c39f33dd 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go index 4780cbce4..db322ccbb 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go index e42b6a872..34522c8b3 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags + alert.WorkspaceIDFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go index c705a8d38..3d8a51815 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags - alertutil.KeyConfigFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags + alert.KeyConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Key: &c.Key, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/root.go b/pkg/commands/ngwaf/workspace/alert/root.go index c61c3c2dc..5ec3046ef 100644 --- a/pkg/commands/ngwaf/workspace/alert/root.go +++ b/pkg/commands/ngwaf/workspace/alert/root.go @@ -29,3 +29,35 @@ func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand { func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { panic("unreachable") } + +// WorkspaceIDFlags contains the workspace ID flag used by all alert commands. +type WorkspaceIDFlags struct { + WorkspaceID argparser.OptionalWorkspaceID +} + +// AlertIDFlags contains flags for identifying a specific alert (used in update/delete/get). +type AlertIDFlags struct { + AlertID string +} + +// AlertDataFlags contains optional data fields for alerts (used in create/update). +type AlertDataFlags struct { + Description argparser.OptionalString +} + +// KeyConfigFlags contains the Key configuration (used by opsgenie, pagerduty). +type KeyConfigFlags struct { + Key string +} + +// WebhookConfigFlags contains the Webhook configuration (used by webhook, slack, microsoftteams). +type WebhookConfigFlags struct { + Webhook string +} + +// GetDefaultEvents returns the hardcoded events value for all alerts. +// Currently the only supported value is "flag". +func GetDefaultEvents() *[]string { + events := []string{"flag"} + return &events +} diff --git a/pkg/commands/ngwaf/workspace/alert/slack/create.go b/pkg/commands/ngwaf/workspace/alert/slack/create.go index 6a1aaa100..6be6f45ca 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/create.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags - alertutil.WebhookConfigFlags + alert.WorkspaceIDFlags + alert.WebhookConfigFlags // Optional. - alertutil.AlertDataFlags + alert.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/slack/delete.go b/pkg/commands/ngwaf/workspace/alert/slack/delete.go index bd4b747c6..4a5c07abd 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/get.go b/pkg/commands/ngwaf/workspace/alert/slack/get.go index 5c8088363..57d48a086 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/get.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/list.go b/pkg/commands/ngwaf/workspace/alert/slack/list.go index e33cab94f..e7b7150b9 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/list.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags + alert.WorkspaceIDFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/update.go b/pkg/commands/ngwaf/workspace/alert/slack/update.go index 5b127d905..dd1128cc9 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/update.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags - alertutil.WebhookConfigFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags + alert.WebhookConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/create.go b/pkg/commands/ngwaf/workspace/alert/webhook/create.go index 83a831b01..203f15e88 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/create.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/create.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags - alertutil.WebhookConfigFlags + alert.WorkspaceIDFlags + alert.WebhookConfigFlags // Optional. - alertutil.AlertDataFlags + alert.AlertDataFlags } // NewCreateCommand returns a usable command registered under the parent. @@ -70,7 +70,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } if c.Description.WasSet { input.Description = &c.Description.Value diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go index e63bb545f..d240ebe9b 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go index 3a208c5c3..5817f5afb 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetSigningKeyCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetSigningKeyCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get.go b/pkg/commands/ngwaf/workspace/alert/webhook/get.go index c79271fb4..65b21a431 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/list.go b/pkg/commands/ngwaf/workspace/alert/webhook/list.go index 52b253919..5c54b82fa 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/list.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/list.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,7 +21,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alertutil.BaseAlertFlags + alert.WorkspaceIDFlags } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go index 60b39ce8c..11a564d78 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,8 +21,8 @@ type RotateSigningKeyCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags } // NewRotateSigningKeyCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/update.go b/pkg/commands/ngwaf/workspace/alert/webhook/update.go index b92c67179..967f5b367 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/update.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/update.go @@ -6,7 +6,7 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert/alertutil" + "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alertutil.AlertIDFlags - alertutil.BaseAlertFlags - alertutil.WebhookConfigFlags + alert.AlertIDFlags + alert.WorkspaceIDFlags + alert.WebhookConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. @@ -74,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { Webhook: &c.Webhook, }, // Set 'Events' to the only possible value, 'flag' - Events: alertutil.GetDefaultEvents(), + Events: alert.GetDefaultEvents(), } fc, ok := c.Globals.APIClient.(*fastly.Client) From 6fedc2f7ec268148f0a075b7ae430a5a97d5c6cb Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Wed, 3 Dec 2025 13:35:43 -0500 Subject: [PATCH 11/13] Linting Fixes --- pkg/commands/ngwaf/workspace/alert/datadog/create.go | 4 ++-- pkg/commands/ngwaf/workspace/alert/datadog/delete.go | 2 +- pkg/commands/ngwaf/workspace/alert/datadog/get.go | 2 +- pkg/commands/ngwaf/workspace/alert/datadog/root.go | 4 ++-- pkg/commands/ngwaf/workspace/alert/datadog/update.go | 4 ++-- pkg/commands/ngwaf/workspace/alert/jira/create.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/jira/delete.go | 2 +- pkg/commands/ngwaf/workspace/alert/jira/get.go | 2 +- pkg/commands/ngwaf/workspace/alert/jira/root.go | 8 ++++---- pkg/commands/ngwaf/workspace/alert/jira/update.go | 6 +++--- pkg/commands/ngwaf/workspace/alert/mailinglist/create.go | 2 +- pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go | 2 +- pkg/commands/ngwaf/workspace/alert/mailinglist/get.go | 2 +- pkg/commands/ngwaf/workspace/alert/mailinglist/update.go | 2 +- .../ngwaf/workspace/alert/microsoftteams/create.go | 2 +- .../ngwaf/workspace/alert/microsoftteams/delete.go | 2 +- pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go | 2 +- .../ngwaf/workspace/alert/microsoftteams/update.go | 2 +- pkg/commands/ngwaf/workspace/alert/opsgenie/create.go | 2 +- pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go | 2 +- pkg/commands/ngwaf/workspace/alert/opsgenie/get.go | 2 +- pkg/commands/ngwaf/workspace/alert/opsgenie/update.go | 2 +- pkg/commands/ngwaf/workspace/alert/pagerduty/create.go | 2 +- pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go | 2 +- pkg/commands/ngwaf/workspace/alert/pagerduty/get.go | 2 +- pkg/commands/ngwaf/workspace/alert/pagerduty/update.go | 2 +- pkg/commands/ngwaf/workspace/alert/root.go | 8 ++++---- pkg/commands/ngwaf/workspace/alert/slack/create.go | 2 +- pkg/commands/ngwaf/workspace/alert/slack/delete.go | 2 +- pkg/commands/ngwaf/workspace/alert/slack/get.go | 2 +- pkg/commands/ngwaf/workspace/alert/slack/update.go | 2 +- pkg/commands/ngwaf/workspace/alert/webhook/create.go | 2 +- pkg/commands/ngwaf/workspace/alert/webhook/delete.go | 2 +- .../ngwaf/workspace/alert/webhook/get-signing-key.go | 2 +- pkg/commands/ngwaf/workspace/alert/webhook/get.go | 2 +- .../ngwaf/workspace/alert/webhook/rotate-signing-key.go | 2 +- pkg/commands/ngwaf/workspace/alert/webhook/update.go | 2 +- 37 files changed, 50 insertions(+), 50 deletions(-) diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/create.go b/pkg/commands/ngwaf/workspace/alert/datadog/create.go index d237b599d..4f873f16a 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/create.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/create.go @@ -22,10 +22,10 @@ type CreateCommand struct { // Required. alert.WorkspaceIDFlags - DatadogConfigFlags + ConfigFlags // Optional. - alert.AlertDataFlags + alert.DataFlags } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go index 7bfb1f61a..5af02d011 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go @@ -21,7 +21,7 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/get.go b/pkg/commands/ngwaf/workspace/alert/datadog/get.go index c3b3a8fea..76249ae8f 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/get.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/get.go @@ -21,7 +21,7 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/root.go b/pkg/commands/ngwaf/workspace/alert/datadog/root.go index 1a7e968a4..55a216952 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/root.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/root.go @@ -30,8 +30,8 @@ func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { panic("unreachable") } -// DatadogConfigFlags contains Datadog specific configuration flags. -type DatadogConfigFlags struct { +// ConfigFlags contains Datadog specific configuration flags. +type ConfigFlags struct { Key string Site string } diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/update.go b/pkg/commands/ngwaf/workspace/alert/datadog/update.go index b72ad8ed0..0a111a514 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/update.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/update.go @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags - DatadogConfigFlags + ConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/create.go b/pkg/commands/ngwaf/workspace/alert/jira/create.go index adbe4ce7b..35bed8ebe 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/create.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/create.go @@ -21,11 +21,11 @@ type CreateCommand struct { // Required. alert.WorkspaceIDFlags - JiraConfigFlags + ConfigFlags // Optional. - alert.AlertDataFlags - JiraOptConfigFlags + alert.DataFlags + OptConfigFlags } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/delete.go b/pkg/commands/ngwaf/workspace/alert/jira/delete.go index 4f60c37c5..8d79d8ea5 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/delete.go @@ -20,7 +20,7 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/jira/get.go b/pkg/commands/ngwaf/workspace/alert/jira/get.go index 8f4e14f39..5cd62370d 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/get.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/get.go @@ -20,7 +20,7 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/jira/root.go b/pkg/commands/ngwaf/workspace/alert/jira/root.go index 38e5513a7..e97fcf0e8 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/root.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/root.go @@ -30,15 +30,15 @@ func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { panic("unreachable") } -// JiraConfigFlags contains Jira specific configuration flags. -type JiraConfigFlags struct { +// ConfigFlags contains Jira specific configuration flags. +type ConfigFlags struct { Host string Key string Project string Username string } -// JiraOptConfigFlags contains optional Jira specific configuration flags. -type JiraOptConfigFlags struct { +// OptConfigFlags contains optional Jira specific configuration flags. +type OptConfigFlags struct { IssueType string } diff --git a/pkg/commands/ngwaf/workspace/alert/jira/update.go b/pkg/commands/ngwaf/workspace/alert/jira/update.go index 82c4cb5c8..c68cb9d10 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/update.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/update.go @@ -20,12 +20,12 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags - JiraConfigFlags + ConfigFlags // Optional - JiraOptConfigFlags + OptConfigFlags } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go index b6d39b32e..b3575baa4 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go @@ -25,7 +25,7 @@ type CreateCommand struct { AddressConfigFlags // Optional. - alert.AlertDataFlags + alert.DataFlags } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go index 0f5711668..e67dea849 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go @@ -21,7 +21,7 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go index badb23083..97e1a64ac 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go @@ -21,7 +21,7 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go index 4a94ecdf6..216678d6f 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go @@ -21,7 +21,7 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags AddressConfigFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go index 46d404c79..2aa6bba14 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go @@ -25,7 +25,7 @@ type CreateCommand struct { alert.WebhookConfigFlags // Optional. - alert.AlertDataFlags + alert.DataFlags } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go index 07342db64..6f57fb24f 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go @@ -21,7 +21,7 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go index a89ddd104..f7996a0e5 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go @@ -21,7 +21,7 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go index 63e67ac3f..da5530c5e 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go @@ -21,7 +21,7 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags alert.WebhookConfigFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go index 65d852540..209735711 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go @@ -25,7 +25,7 @@ type CreateCommand struct { alert.KeyConfigFlags // Optional. - alert.AlertDataFlags + alert.DataFlags } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go index d483993e4..f02554d8e 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go @@ -21,7 +21,7 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go index 0a6023d5c..e65bab48b 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go @@ -21,7 +21,7 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go index a6d0cca0b..8db3e3b1b 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go @@ -21,7 +21,7 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags alert.KeyConfigFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go index bf2f99be6..36351ccd0 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go @@ -25,7 +25,7 @@ type CreateCommand struct { alert.KeyConfigFlags // Optional. - alert.AlertDataFlags + alert.DataFlags } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go index 9c39f33dd..df3b6d85d 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go @@ -21,7 +21,7 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go index db322ccbb..8819f9d45 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go @@ -21,7 +21,7 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go index 3d8a51815..78d96dfd8 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go @@ -21,7 +21,7 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags alert.KeyConfigFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/root.go b/pkg/commands/ngwaf/workspace/alert/root.go index 5ec3046ef..dd9fe5ad4 100644 --- a/pkg/commands/ngwaf/workspace/alert/root.go +++ b/pkg/commands/ngwaf/workspace/alert/root.go @@ -35,13 +35,13 @@ type WorkspaceIDFlags struct { WorkspaceID argparser.OptionalWorkspaceID } -// AlertIDFlags contains flags for identifying a specific alert (used in update/delete/get). -type AlertIDFlags struct { +// IDFlags contains flags for identifying a specific alert (used in update/delete/get). +type IDFlags struct { AlertID string } -// AlertDataFlags contains optional data fields for alerts (used in create/update). -type AlertDataFlags struct { +// DataFlags contains optional data fields for alerts (used in create/update). +type DataFlags struct { Description argparser.OptionalString } diff --git a/pkg/commands/ngwaf/workspace/alert/slack/create.go b/pkg/commands/ngwaf/workspace/alert/slack/create.go index 6be6f45ca..6a3fdc4c7 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/create.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/create.go @@ -25,7 +25,7 @@ type CreateCommand struct { alert.WebhookConfigFlags // Optional. - alert.AlertDataFlags + alert.DataFlags } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/delete.go b/pkg/commands/ngwaf/workspace/alert/slack/delete.go index 4a5c07abd..3b09671ea 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/delete.go @@ -21,7 +21,7 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/slack/get.go b/pkg/commands/ngwaf/workspace/alert/slack/get.go index 57d48a086..01193e290 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/get.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/get.go @@ -21,7 +21,7 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/slack/update.go b/pkg/commands/ngwaf/workspace/alert/slack/update.go index dd1128cc9..e543b1046 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/update.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/update.go @@ -21,7 +21,7 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags alert.WebhookConfigFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/create.go b/pkg/commands/ngwaf/workspace/alert/webhook/create.go index 203f15e88..8f0cbde82 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/create.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/create.go @@ -25,7 +25,7 @@ type CreateCommand struct { alert.WebhookConfigFlags // Optional. - alert.AlertDataFlags + alert.DataFlags } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go index d240ebe9b..fdb37dfde 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go @@ -21,7 +21,7 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go index 5817f5afb..08adf07f2 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go @@ -21,7 +21,7 @@ type GetSigningKeyCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get.go b/pkg/commands/ngwaf/workspace/alert/webhook/get.go index 65b21a431..28034d05e 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get.go @@ -21,7 +21,7 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go index 11a564d78..7f581ae1c 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go @@ -21,7 +21,7 @@ type RotateSigningKeyCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags } diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/update.go b/pkg/commands/ngwaf/workspace/alert/webhook/update.go index 967f5b367..1ac55a91a 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/update.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/update.go @@ -21,7 +21,7 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.AlertIDFlags + alert.IDFlags alert.WorkspaceIDFlags alert.WebhookConfigFlags } From 57d00c1bbb50c2545bd64cdf2a7b0dc05ed9959c Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Thu, 4 Dec 2025 10:00:30 -0500 Subject: [PATCH 12/13] Removed shared references from root.go parent package. --- .../ngwaf/workspace/alert/datadog/create.go | 7 +++--- .../ngwaf/workspace/alert/datadog/delete.go | 6 ++--- .../ngwaf/workspace/alert/datadog/get.go | 6 ++--- .../ngwaf/workspace/alert/datadog/list.go | 4 +-- .../ngwaf/workspace/alert/datadog/update.go | 7 +++--- .../ngwaf/workspace/alert/jira/create.go | 11 +++++--- .../ngwaf/workspace/alert/jira/delete.go | 5 ++-- .../ngwaf/workspace/alert/jira/get.go | 5 ++-- .../ngwaf/workspace/alert/jira/list.go | 3 +-- .../ngwaf/workspace/alert/jira/update.go | 11 +++++--- .../workspace/alert/mailinglist/create.go | 6 ++--- .../workspace/alert/mailinglist/delete.go | 6 ++--- .../ngwaf/workspace/alert/mailinglist/get.go | 6 ++--- .../ngwaf/workspace/alert/mailinglist/list.go | 4 +-- .../workspace/alert/mailinglist/update.go | 6 ++--- .../workspace/alert/microsoftteams/create.go | 6 ++--- .../workspace/alert/microsoftteams/delete.go | 6 ++--- .../workspace/alert/microsoftteams/get.go | 6 ++--- .../workspace/alert/microsoftteams/list.go | 4 +-- .../workspace/alert/microsoftteams/update.go | 6 ++--- .../ngwaf/workspace/alert/opsgenie/create.go | 6 ++--- .../ngwaf/workspace/alert/opsgenie/delete.go | 6 ++--- .../ngwaf/workspace/alert/opsgenie/get.go | 6 ++--- .../ngwaf/workspace/alert/opsgenie/list.go | 4 +-- .../ngwaf/workspace/alert/opsgenie/update.go | 6 ++--- .../ngwaf/workspace/alert/pagerduty/create.go | 6 ++--- .../ngwaf/workspace/alert/pagerduty/delete.go | 6 ++--- .../ngwaf/workspace/alert/pagerduty/get.go | 6 ++--- .../ngwaf/workspace/alert/pagerduty/list.go | 4 +-- .../ngwaf/workspace/alert/pagerduty/update.go | 6 ++--- pkg/commands/ngwaf/workspace/alert/root.go | 25 ------------------- .../ngwaf/workspace/alert/slack/create.go | 6 ++--- .../ngwaf/workspace/alert/slack/delete.go | 6 ++--- .../ngwaf/workspace/alert/slack/get.go | 6 ++--- .../ngwaf/workspace/alert/slack/list.go | 4 +-- .../ngwaf/workspace/alert/slack/update.go | 6 ++--- .../ngwaf/workspace/alert/webhook/create.go | 6 ++--- .../ngwaf/workspace/alert/webhook/delete.go | 6 ++--- .../alert/webhook/get-signing-key.go | 6 ++--- .../ngwaf/workspace/alert/webhook/get.go | 6 ++--- .../ngwaf/workspace/alert/webhook/list.go | 4 +-- .../alert/webhook/rotate-signing-key.go | 6 ++--- .../ngwaf/workspace/alert/webhook/update.go | 6 ++--- 43 files changed, 102 insertions(+), 168 deletions(-) diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/create.go b/pkg/commands/ngwaf/workspace/alert/datadog/create.go index 4f873f16a..d1fc860fa 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/create.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/create.go @@ -21,11 +21,12 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags - ConfigFlags + WorkspaceID argparser.OptionalWorkspaceID + Key string + Site string // Optional. - alert.DataFlags + Description argparser.OptionalString } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go index 5af02d011..769204a9f 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/delete.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/get.go b/pkg/commands/ngwaf/workspace/alert/datadog/get.go index 76249ae8f..1a64ffeaa 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/get.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/get.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/list.go b/pkg/commands/ngwaf/workspace/alert/datadog/list.go index 5f91cd57d..cfbfc23f4 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/list.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/list.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,7 +19,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags + WorkspaceID argparser.OptionalWorkspaceID } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/datadog/update.go b/pkg/commands/ngwaf/workspace/alert/datadog/update.go index 0a111a514..1b375190a 100644 --- a/pkg/commands/ngwaf/workspace/alert/datadog/update.go +++ b/pkg/commands/ngwaf/workspace/alert/datadog/update.go @@ -21,9 +21,10 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags - ConfigFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID + Key string + Site string } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/create.go b/pkg/commands/ngwaf/workspace/alert/jira/create.go index 35bed8ebe..6877c5731 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/create.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/create.go @@ -20,12 +20,15 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags - ConfigFlags + WorkspaceID argparser.OptionalWorkspaceID + Host string + Key string + Project string + Username string // Optional. - alert.DataFlags - OptConfigFlags + Description argparser.OptionalString + IssueType string } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/delete.go b/pkg/commands/ngwaf/workspace/alert/jira/delete.go index 8d79d8ea5..0f96500ac 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/delete.go @@ -6,7 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -20,8 +19,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/get.go b/pkg/commands/ngwaf/workspace/alert/jira/get.go index 5cd62370d..8d709b012 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/get.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/get.go @@ -6,7 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -20,8 +19,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/list.go b/pkg/commands/ngwaf/workspace/alert/jira/list.go index b308f2024..34be07113 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/list.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/list.go @@ -6,7 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -20,7 +19,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags + WorkspaceID argparser.OptionalWorkspaceID } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/jira/update.go b/pkg/commands/ngwaf/workspace/alert/jira/update.go index c68cb9d10..9533ed4c2 100644 --- a/pkg/commands/ngwaf/workspace/alert/jira/update.go +++ b/pkg/commands/ngwaf/workspace/alert/jira/update.go @@ -20,12 +20,15 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags - ConfigFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID + Host string + Key string + Project string + Username string // Optional - OptConfigFlags + IssueType string } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go index b3575baa4..1eecaf4d2 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/create.go @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags - AddressConfigFlags + WorkspaceID argparser.OptionalWorkspaceID + Address string // Optional. - alert.DataFlags + Description argparser.OptionalString } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go index e67dea849..61f740260 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/delete.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go index 97e1a64ac..e0be7241a 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/get.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go index 63e29bc7a..ee1046b6b 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/list.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,7 +19,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags + WorkspaceID argparser.OptionalWorkspaceID } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go index 216678d6f..8dab37876 100644 --- a/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go +++ b/pkg/commands/ngwaf/workspace/alert/mailinglist/update.go @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags - AddressConfigFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID + Address string } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go index 2aa6bba14..331e6be5f 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/create.go @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags - alert.WebhookConfigFlags + WorkspaceID argparser.OptionalWorkspaceID + Webhook string // Optional. - alert.DataFlags + Description argparser.OptionalString } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go index 6f57fb24f..4a88e1fc0 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/delete.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go index f7996a0e5..ea915b037 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/get.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go index 123c12697..b0face2e0 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/list.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,7 +19,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags + WorkspaceID argparser.OptionalWorkspaceID } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go index da5530c5e..7044cb3c6 100644 --- a/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go +++ b/pkg/commands/ngwaf/workspace/alert/microsoftteams/update.go @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags - alert.WebhookConfigFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID + Webhook string } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go index 209735711..04efe5da4 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/create.go @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags - alert.KeyConfigFlags + WorkspaceID argparser.OptionalWorkspaceID + Key string // Optional. - alert.DataFlags + Description argparser.OptionalString } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go index f02554d8e..3e157c86a 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/delete.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go index e65bab48b..ee196d1a7 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/get.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go index 77d18289a..4f9728a60 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/list.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,7 +19,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags + WorkspaceID argparser.OptionalWorkspaceID } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go index 8db3e3b1b..efa2c47d4 100644 --- a/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go +++ b/pkg/commands/ngwaf/workspace/alert/opsgenie/update.go @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags - alert.KeyConfigFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID + Key string } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go index 36351ccd0..d3181507f 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/create.go @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags - alert.KeyConfigFlags + WorkspaceID argparser.OptionalWorkspaceID + Key string // Optional. - alert.DataFlags + Description argparser.OptionalString } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go index df3b6d85d..7c76c912b 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/delete.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go index 8819f9d45..eea35f0aa 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/get.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go index 34522c8b3..788139068 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/list.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,7 +19,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags + WorkspaceID argparser.OptionalWorkspaceID } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go index 78d96dfd8..00628ad96 100644 --- a/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go +++ b/pkg/commands/ngwaf/workspace/alert/pagerduty/update.go @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags - alert.KeyConfigFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID + Key string } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/root.go b/pkg/commands/ngwaf/workspace/alert/root.go index dd9fe5ad4..59561832c 100644 --- a/pkg/commands/ngwaf/workspace/alert/root.go +++ b/pkg/commands/ngwaf/workspace/alert/root.go @@ -30,31 +30,6 @@ func (c *RootCommand) Exec(_ io.Reader, _ io.Writer) error { panic("unreachable") } -// WorkspaceIDFlags contains the workspace ID flag used by all alert commands. -type WorkspaceIDFlags struct { - WorkspaceID argparser.OptionalWorkspaceID -} - -// IDFlags contains flags for identifying a specific alert (used in update/delete/get). -type IDFlags struct { - AlertID string -} - -// DataFlags contains optional data fields for alerts (used in create/update). -type DataFlags struct { - Description argparser.OptionalString -} - -// KeyConfigFlags contains the Key configuration (used by opsgenie, pagerduty). -type KeyConfigFlags struct { - Key string -} - -// WebhookConfigFlags contains the Webhook configuration (used by webhook, slack, microsoftteams). -type WebhookConfigFlags struct { - Webhook string -} - // GetDefaultEvents returns the hardcoded events value for all alerts. // Currently the only supported value is "flag". func GetDefaultEvents() *[]string { diff --git a/pkg/commands/ngwaf/workspace/alert/slack/create.go b/pkg/commands/ngwaf/workspace/alert/slack/create.go index 6a3fdc4c7..e1bf16a39 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/create.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/create.go @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags - alert.WebhookConfigFlags + WorkspaceID argparser.OptionalWorkspaceID + Webhook string // Optional. - alert.DataFlags + Description argparser.OptionalString } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/delete.go b/pkg/commands/ngwaf/workspace/alert/slack/delete.go index 3b09671ea..db85825e1 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/delete.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/get.go b/pkg/commands/ngwaf/workspace/alert/slack/get.go index 01193e290..a903d0c52 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/get.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/get.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/list.go b/pkg/commands/ngwaf/workspace/alert/slack/list.go index e7b7150b9..d3ce71f11 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/list.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/list.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,7 +19,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags + WorkspaceID argparser.OptionalWorkspaceID } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/slack/update.go b/pkg/commands/ngwaf/workspace/alert/slack/update.go index e543b1046..6e4a8bc47 100644 --- a/pkg/commands/ngwaf/workspace/alert/slack/update.go +++ b/pkg/commands/ngwaf/workspace/alert/slack/update.go @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags - alert.WebhookConfigFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID + Webhook string } // NewUpdateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/create.go b/pkg/commands/ngwaf/workspace/alert/webhook/create.go index 8f0cbde82..4fa30ed07 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/create.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/create.go @@ -21,11 +21,11 @@ type CreateCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags - alert.WebhookConfigFlags + WorkspaceID argparser.OptionalWorkspaceID + Webhook string // Optional. - alert.DataFlags + Description argparser.OptionalString } // NewCreateCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go index fdb37dfde..8b175aba3 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/delete.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/delete.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type DeleteCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewDeleteCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go index 08adf07f2..75493c6e8 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get-signing-key.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type GetSigningKeyCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetSigningKeyCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/get.go b/pkg/commands/ngwaf/workspace/alert/webhook/get.go index 28034d05e..9c225395d 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/get.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/get.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type GetCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewGetCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/list.go b/pkg/commands/ngwaf/workspace/alert/webhook/list.go index 5c54b82fa..6371fc1e2 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/list.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/list.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,7 +19,7 @@ type ListCommand struct { argparser.JSONOutput // Required. - alert.WorkspaceIDFlags + WorkspaceID argparser.OptionalWorkspaceID } // NewListCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go index 7f581ae1c..68fe2d00d 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/rotate-signing-key.go @@ -6,8 +6,6 @@ import ( "io" "github.com/fastly/cli/pkg/argparser" - "github.com/fastly/cli/pkg/commands/ngwaf/workspace/alert" - fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" @@ -21,8 +19,8 @@ type RotateSigningKeyCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID } // NewRotateSigningKeyCommand returns a usable command registered under the parent. diff --git a/pkg/commands/ngwaf/workspace/alert/webhook/update.go b/pkg/commands/ngwaf/workspace/alert/webhook/update.go index 1ac55a91a..544417df2 100644 --- a/pkg/commands/ngwaf/workspace/alert/webhook/update.go +++ b/pkg/commands/ngwaf/workspace/alert/webhook/update.go @@ -21,9 +21,9 @@ type UpdateCommand struct { argparser.JSONOutput // Required. - alert.IDFlags - alert.WorkspaceIDFlags - alert.WebhookConfigFlags + AlertID string + WorkspaceID argparser.OptionalWorkspaceID + Webhook string } // NewUpdateCommand returns a usable command registered under the parent. From e1cea6b2475a3157429d4e1cdc2c17e29939bf8f Mon Sep 17 00:00:00 2001 From: Richard Carillo Date: Thu, 4 Dec 2025 10:02:34 -0500 Subject: [PATCH 13/13] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03710d382..9c622a868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ ### Enhancements: - feat(commands/ngwaf/workspaces): add support for update operation for NGWAF workspaces ([#1578](https://github.com/fastly/cli/pull/1578)) -- feat(commands/ngwaf/workspace/lists): add support for CRUD operations for NGWAF Lists ([#1582](https://github.com/fastly/cli/pull/1582)) +- feat(commands/ngwaf/lists): add support for CRUD operations for NGWAF Lists at account and workspace levels ([#1582](https://github.com/fastly/cli/pull/1582)) - feat(commands/ngwaf/workspaces/alerts): add support for operations for NGWAF alerts ([#1589](https://github.com/fastly/cli/pull/1589))