Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,55 @@ func createNotificationConfiguration(t *testing.T, client *Client, w *Workspace,
}
}

func createTeamNotificationConfiguration(t *testing.T, client *Client, team *Team, options *NotificationConfigurationCreateOptions) (*NotificationConfiguration, func()) {
var tCleanup func()

if team == nil {
team, tCleanup = createTeam(t, client, nil)
}

// Team notification configurations do not actually require a run task, but we'll
// reuse this as a URL that returns a 200.
runTaskURL := os.Getenv("TFC_RUN_TASK_URL")
if runTaskURL == "" {
t.Error("You must set TFC_RUN_TASK_URL for run task related tests.")
}

if options == nil {
options = &NotificationConfigurationCreateOptions{
DestinationType: NotificationDestination(NotificationDestinationTypeGeneric),
Enabled: Bool(false),
Name: String(randomString(t)),
Token: String(randomString(t)),
URL: String(runTaskURL),
Triggers: []NotificationTriggerType{NotificationTriggerChangeRequestCreated},
SubscribableChoice: &NotificationConfigurationSubscribableChoice{Team: team},
}
}

ctx := context.Background()
nc, err := client.NotificationConfigurations.Create(
ctx,
team.ID,
*options,
)
if err != nil {
t.Fatal(err)
}

return nc, func() {
if err := client.NotificationConfigurations.Delete(ctx, nc.ID); err != nil {
t.Errorf("Error destroying team notification configuration! WARNING: Dangling\n"+
"resources may exist! The full error is shown below.\n\n"+
"NotificationConfiguration: %s\nError: %s", nc.ID, err)
}

if tCleanup != nil {
tCleanup()
}
}
}

func createPolicySetParameter(t *testing.T, client *Client, ps *PolicySet) (*PolicySetParameter, func()) {
var psCleanup func()

Expand Down
16 changes: 8 additions & 8 deletions mocks/notification_configuration_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 88 additions & 13 deletions notification_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ var _ NotificationConfigurations = (*notificationConfigurations)(nil)
// https://developer.hashicorp.com/terraform/cloud-docs/api-docs/notification-configurations
type NotificationConfigurations interface {
// List all the notification configurations within a workspace.
List(ctx context.Context, workspaceID string, options *NotificationConfigurationListOptions) (*NotificationConfigurationList, error)
List(ctx context.Context, subscribableID string, options *NotificationConfigurationListOptions) (*NotificationConfigurationList, error)

// Create a new notification configuration with the given options.
Create(ctx context.Context, workspaceID string, options NotificationConfigurationCreateOptions) (*NotificationConfiguration, error)
Create(ctx context.Context, subscribableID string, options NotificationConfigurationCreateOptions) (*NotificationConfiguration, error)

// Read a notification configuration by its ID.
Read(ctx context.Context, notificationConfigurationID string) (*NotificationConfiguration, error)
Expand Down Expand Up @@ -59,6 +59,7 @@ const (
NotificationTriggerAssessmentCheckFailed NotificationTriggerType = "assessment:check_failure"
NotificationTriggerWorkspaceAutoDestroyReminder NotificationTriggerType = "workspace:auto_destroy_reminder"
NotificationTriggerWorkspaceAutoDestroyRunResults NotificationTriggerType = "workspace:auto_destroy_run_results"
NotificationTriggerChangeRequestCreated NotificationTriggerType = "change_request:created"
)

// NotificationDestinationType represents the destination type of the
Expand All @@ -80,6 +81,14 @@ type NotificationConfigurationList struct {
Items []*NotificationConfiguration
}

// NotificationConfigurationSubscribableChoice is a choice type struct that represents the possible values
// within a polymorphic relation. If a value is available, exactly one field
// will be non-nil.
type NotificationConfigurationSubscribableChoice struct {
Team *Team
Workspace *Workspace
}

// NotificationConfiguration represents a Notification Configuration.
type NotificationConfiguration struct {
ID string `jsonapi:"primary,notification-configurations"`
Expand All @@ -97,8 +106,11 @@ type NotificationConfiguration struct {
EmailAddresses []string `jsonapi:"attr,email-addresses"`

// Relations
Subscribable *Workspace `jsonapi:"relation,subscribable"`
EmailUsers []*User `jsonapi:"relation,users"`
// DEPRECATED. The subscribable field is polymorphic. Use NotificationConfigurationSubscribableChoice instead.
Subscribable *Workspace `jsonapi:"relation,subscribable,omitempty"`
SubscribableChoice *NotificationConfigurationSubscribableChoice `jsonapi:"polyrelation,subscribable"`

EmailUsers []*User `jsonapi:"relation,users"`
}

// DeliveryResponse represents a notification configuration delivery response.
Expand All @@ -115,6 +127,8 @@ type DeliveryResponse struct {
// notification configurations.
type NotificationConfigurationListOptions struct {
ListOptions

SubscribableChoice *NotificationConfigurationSubscribableChoice
}

// NotificationConfigurationCreateOptions represents the options for
Expand Down Expand Up @@ -150,6 +164,9 @@ type NotificationConfigurationCreateOptions struct {

// Optional: The list of users belonging to the organization that will receive notification emails.
EmailUsers []*User `jsonapi:"relation,users,omitempty"`

// Required: The workspace or team that the notification configuration is associated with.
SubscribableChoice *NotificationConfigurationSubscribableChoice `jsonapi:"polyrelation,subscribable"`
}

// NotificationConfigurationUpdateOptions represents the options for
Expand Down Expand Up @@ -185,12 +202,32 @@ type NotificationConfigurationUpdateOptions struct {
}

// List all the notification configurations associated with a workspace.
func (s *notificationConfigurations) List(ctx context.Context, workspaceID string, options *NotificationConfigurationListOptions) (*NotificationConfigurationList, error) {
if !validStringID(&workspaceID) {
return nil, ErrInvalidWorkspaceID
func (s *notificationConfigurations) List(ctx context.Context, subscribableID string, options *NotificationConfigurationListOptions) (*NotificationConfigurationList, error) {
var u string
if options == nil {
options = &NotificationConfigurationListOptions{
SubscribableChoice: &NotificationConfigurationSubscribableChoice{
Workspace: &Workspace{ID: subscribableID},
},
}
} else if options.SubscribableChoice == nil {
options.SubscribableChoice = &NotificationConfigurationSubscribableChoice{
Workspace: &Workspace{ID: subscribableID},
}
}

if options.SubscribableChoice.Team != nil {
if !validStringID(&subscribableID) {
return nil, ErrInvalidTeamID
}
u = fmt.Sprintf("teams/%s/notification-configurations", url.PathEscape(subscribableID))
} else {
if !validStringID(&subscribableID) {
return nil, ErrInvalidWorkspaceID
}
u = fmt.Sprintf("workspaces/%s/notification-configurations", url.PathEscape(subscribableID))
}

u := fmt.Sprintf("workspaces/%s/notification-configurations", url.PathEscape(workspaceID))
req, err := s.client.NewRequest("GET", u, options)
if err != nil {
return nil, err
Expand All @@ -202,30 +239,43 @@ func (s *notificationConfigurations) List(ctx context.Context, workspaceID strin
return nil, err
}

for i := range ncl.Items {
backfillDeprecatedSubscribable(ncl.Items[i])
}

return ncl, nil
}

// Create a notification configuration with the given options.
func (s *notificationConfigurations) Create(ctx context.Context, workspaceID string, options NotificationConfigurationCreateOptions) (*NotificationConfiguration, error) {
if !validStringID(&workspaceID) {
return nil, ErrInvalidWorkspaceID
func (s *notificationConfigurations) Create(ctx context.Context, subscribableID string, options NotificationConfigurationCreateOptions) (*NotificationConfiguration, error) {
var u string
var subscribableChoice *NotificationConfigurationSubscribableChoice
if options.SubscribableChoice == nil || options.SubscribableChoice.Team == nil {
u = fmt.Sprintf("workspaces/%s/notification-configurations", url.PathEscape(subscribableID))
options.SubscribableChoice = &NotificationConfigurationSubscribableChoice{Workspace: &Workspace{ID: subscribableID}}
} else {
u = fmt.Sprintf("teams/%s/notification-configurations", url.PathEscape(subscribableID))
options.SubscribableChoice = &NotificationConfigurationSubscribableChoice{Team: &Team{ID: subscribableID}}
}

if err := options.valid(); err != nil {
return nil, err
}

u := fmt.Sprintf("workspaces/%s/notification-configurations", url.PathEscape(workspaceID))
req, err := s.client.NewRequest("POST", u, &options)
if err != nil {
return nil, err
}

nc := &NotificationConfiguration{}
nc := &NotificationConfiguration{SubscribableChoice: subscribableChoice}
err = req.Do(ctx, nc)

if err != nil {
return nil, err
}

backfillDeprecatedSubscribable(nc)

return nc, nil
}

Expand All @@ -247,6 +297,8 @@ func (s *notificationConfigurations) Read(ctx context.Context, notificationConfi
return nil, err
}

backfillDeprecatedSubscribable(nc)

return nc, nil
}

Expand All @@ -272,6 +324,8 @@ func (s *notificationConfigurations) Update(ctx context.Context, notificationCon
return nil, err
}

backfillDeprecatedSubscribable(nc)

return nc, nil
}

Expand Down Expand Up @@ -314,6 +368,16 @@ func (s *notificationConfigurations) Verify(ctx context.Context, notificationCon
}

func (o NotificationConfigurationCreateOptions) valid() error {
if o.SubscribableChoice == nil || o.SubscribableChoice.Workspace != nil {
if !validStringID(&o.SubscribableChoice.Workspace.ID) {
return ErrInvalidWorkspaceID
}
} else {
if !validStringID(&o.SubscribableChoice.Team.ID) {
return ErrInvalidTeamID
}
}

if o.DestinationType == nil {
return ErrRequiredDestinationType
}
Expand Down Expand Up @@ -350,6 +414,16 @@ func (o NotificationConfigurationUpdateOptions) valid() error {
return nil
}

func backfillDeprecatedSubscribable(notification *NotificationConfiguration) {
if notification.Subscribable != nil || notification.SubscribableChoice == nil {
return
}

if notification.SubscribableChoice.Workspace != nil {
notification.Subscribable = notification.SubscribableChoice.Workspace
}
}

func validNotificationTriggerType(triggers []NotificationTriggerType) bool {
for _, t := range triggers {
switch t {
Expand All @@ -363,6 +437,7 @@ func validNotificationTriggerType(triggers []NotificationTriggerType) bool {
NotificationTriggerAssessmentFailed,
NotificationTriggerWorkspaceAutoDestroyReminder,
NotificationTriggerWorkspaceAutoDestroyRunResults,
NotificationTriggerChangeRequestCreated,
NotificationTriggerAssessmentCheckFailed:
continue
default:
Expand Down
Loading
Loading