Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Microsoft Teams destination to notification_configuration #484

Merged
merged 5 commits into from Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -12,6 +12,7 @@ FEATURES:
* **New Resource**: `tfe_workspace_run_task` ([#488](https://github.com/hashicorp/terraform-provider-tfe/pull/488))
* **New Data Source**: d/tfe_organization_run_task ([#488](https://github.com/hashicorp/terraform-provider-tfe/pull/488))
* **New Data Source**: d/tfe_workspace_run_task ([#488](https://github.com/hashicorp/terraform-provider-tfe/pull/488))
* r/tfe_notification_configuration: Add Microsoft Teams notification type ([#484](https://github.com/hashicorp/terraform-provider-tfe/pull/484))

BREAKING CHANGES:
* r/tfe_workspace: Default value of the `file_triggers_enabled` field is changed to `false`. This will align the
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Expand Up @@ -13,7 +13,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/hashicorp/go-slug v0.8.1
github.com/hashicorp/go-tfe v1.2.0
github.com/hashicorp/go-tfe v1.3.0
github.com/hashicorp/go-version v1.5.0
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
github.com/hashicorp/hcl/v2 v2.10.0 // indirect
Expand Down Expand Up @@ -51,7 +51,7 @@ require (
github.com/hashicorp/go-getter v1.5.3 // indirect
github.com/hashicorp/go-plugin v1.4.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.15.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Expand Up @@ -219,10 +219,16 @@ github.com/hashicorp/go-slug v0.8.1 h1:srN7ivgAjHfZddYY1DjBaihRCFy20+vCcOrlx1O2A
github.com/hashicorp/go-slug v0.8.1/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
github.com/hashicorp/go-tfe v1.2.0 h1:L29LCo/qIjOqBUjfiUsZSAzBdxmsOLzwnwZpA+68WW8=
github.com/hashicorp/go-tfe v1.2.0/go.mod h1:tJF/OlAXzVbmjiimAPLplSLgwg6kZDUOy0MzHuMwvF4=
github.com/hashicorp/go-tfe v1.2.1-0.20220607193402-515f37b540ef h1:asJwJP0YiJsUWGsHHHiFnWeWiXiWU5WSpbS9mEPOOCE=
github.com/hashicorp/go-tfe v1.2.1-0.20220607193402-515f37b540ef/go.mod h1:a8UuFhW0D+aLZkFLFxwu8wr/DmPma1544mx/nsOTy/U=
github.com/hashicorp/go-tfe v1.3.0 h1:5sboIfj0Uz6YAfPeDAVRXBKf3EI3D054kTbmOoUUW3g=
github.com/hashicorp/go-tfe v1.3.0/go.mod h1:5PORBlPPMya01sElYhCLUMu07BHGTwP5CRedU26SjPM=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
Expand Down
41 changes: 41 additions & 0 deletions tfe/resource_tfe_notification_configuration.go
Expand Up @@ -34,6 +34,7 @@ func resourceTFENotificationConfiguration() *schema.Resource {
string(tfe.NotificationDestinationTypeEmail),
string(tfe.NotificationDestinationTypeGeneric),
string(tfe.NotificationDestinationTypeSlack),
string(tfe.NotificationDestinationTypeMicrosoftTeams),
},
false,
),
Expand Down Expand Up @@ -138,6 +139,14 @@ func resourceTFENotificationConfigurationCreate(d *schema.ResourceData, meta int
if err != nil {
return err
}
} else if destinationType == tfe.NotificationDestinationTypeMicrosoftTeams {
// When destination_type is 'microsoft-teams':
// 1. email_addresses, email_user_ids, and token cannot be set
// 2. url must be set
err := validateSchemaAttributesForDestinationTypeMicrosoftTeams(d)
if err != nil {
return err
}
}

// Create a new options struct
Expand Down Expand Up @@ -259,6 +268,14 @@ func resourceTFENotificationConfigurationUpdate(d *schema.ResourceData, meta int
if err != nil {
return err
}
} else if destinationType == tfe.NotificationDestinationTypeMicrosoftTeams {
// When destination_type is 'microsoft-teams':
// 1. email_addresses, email_user_ids, and token cannot be set
// 2. url must be set
err := validateSchemaAttributesForDestinationTypeMicrosoftTeams(d)
if err != nil {
return err
}
}

// Create a new options struct
Expand Down Expand Up @@ -370,3 +387,27 @@ func validateSchemaAttributesForDestinationTypeSlack(d *schema.ResourceData) err

return nil
}

func validateSchemaAttributesForDestinationTypeMicrosoftTeams(d *schema.ResourceData) error {
// Make sure email_addresses, email_user_ids, and token are not set when destination_type is 'microsoft-teams'
_, emailAddressesIsSet := d.GetOk("email_addresses")
if emailAddressesIsSet {
return fmt.Errorf("Email addresses cannot be set with destination type of %s", string(tfe.NotificationDestinationTypeMicrosoftTeams))
}
_, emailUserIDsIsSet := d.GetOk("email_user_ids")
if emailUserIDsIsSet {
return fmt.Errorf("Email user IDs cannot be set with destination type of %s", string(tfe.NotificationDestinationTypeMicrosoftTeams))
}
token, tokenIsSet := d.GetOk("token")
if tokenIsSet && token != "" {
return fmt.Errorf("Token cannot be set with destination type of %s", string(tfe.NotificationDestinationTypeMicrosoftTeams))
}

// Make sure url is set when destination_type is 'microsoft-teams'
_, urlIsSet := d.GetOk("url")
if !urlIsSet {
return fmt.Errorf("URL is required with destination type of %s", string(tfe.NotificationDestinationTypeMicrosoftTeams))
}

return nil
}
201 changes: 201 additions & 0 deletions tfe/resource_tfe_notification_configuration_test.go
Expand Up @@ -248,6 +248,33 @@ func TestAccTFENotificationConfiguration_validateSchemaAttributesSlack(t *testin
})
}

func TestAccTFENotificationConfiguration_validateSchemaAttributesMicrosoftTeams(t *testing.T) {
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccTFENotificationConfiguration_microsoftTeamsWithEmailAddresses(rInt),
ExpectError: regexp.MustCompile(`Email addresses cannot be set with destination type of microsoft-teams`),
},
{
Config: testAccTFENotificationConfiguration_microsoftTeamsWithEmailUserIDs(rInt),
ExpectError: regexp.MustCompile(`Email user IDs cannot be set with destination type of microsoft-teams`),
},
{
Config: testAccTFENotificationConfiguration_microsoftTeamsWithToken(rInt),
ExpectError: regexp.MustCompile(`Token cannot be set with destination type of microsoft-teams`),
},
{
Config: testAccTFENotificationConfiguration_microsoftTeamsWithoutURL(rInt),
ExpectError: regexp.MustCompile(`URL is required with destination type of microsoft-teams`),
},
},
})
}

func TestAccTFENotificationConfiguration_updateValidateSchemaAttributesEmail(t *testing.T) {
notificationConfiguration := &tfe.NotificationConfiguration{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
Expand Down Expand Up @@ -377,6 +404,49 @@ func TestAccTFENotificationConfiguration_updateValidateSchemaAttributesSlack(t *
})
}

func TestAccTFENotificationConfiguration_updateValidateSchemaAttributesMicrosoftTeams(t *testing.T) {
notificationConfiguration := &tfe.NotificationConfiguration{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFENotificationConfigurationDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFENotificationConfiguration_microsoftTeams(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFENotificationConfigurationExists(
"tfe_notification_configuration.foobar", notificationConfiguration),
testAccCheckTFENotificationConfigurationAttributesMicrosoftTeams(notificationConfiguration),
resource.TestCheckResourceAttr(
"tfe_notification_configuration.foobar", "destination_type", "microsoft-teams"),
resource.TestCheckResourceAttr(
"tfe_notification_configuration.foobar", "name", "notification_msteams"),
resource.TestCheckResourceAttr(
"tfe_notification_configuration.foobar", "url", "http://example.com"),
),
},
{
Config: testAccTFENotificationConfiguration_microsoftTeamsWithEmailAddresses(rInt),
ExpectError: regexp.MustCompile(`Email addresses cannot be set with destination type of microsoft-teams`),
},
{
Config: testAccTFENotificationConfiguration_microsoftTeamsWithEmailUserIDs(rInt),
ExpectError: regexp.MustCompile(`Email user IDs cannot be set with destination type of microsoft-teams`),
},
{
Config: testAccTFENotificationConfiguration_microsoftTeamsWithToken(rInt),
ExpectError: regexp.MustCompile(`Token cannot be set with destination type of microsoft-teams`),
},
{
Config: testAccTFENotificationConfiguration_microsoftTeamsWithoutURL(rInt),
ExpectError: regexp.MustCompile(`URL is required with destination type of microsoft-teams`),
},
},
})
}

func TestAccTFENotificationConfiguration_duplicateTriggers(t *testing.T) {
notificationConfiguration := &tfe.NotificationConfiguration{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
Expand Down Expand Up @@ -638,6 +708,32 @@ func testAccCheckTFENotificationConfigurationAttributesSlack(notificationConfigu
}
}

func testAccCheckTFENotificationConfigurationAttributesMicrosoftTeams(notificationConfiguration *tfe.NotificationConfiguration) resource.TestCheckFunc {
return func(s *terraform.State) error {
if notificationConfiguration.Name != "notification_msteams" {
return fmt.Errorf("Bad name: %s", notificationConfiguration.Name)
}

if notificationConfiguration.DestinationType != tfe.NotificationDestinationTypeMicrosoftTeams {
return fmt.Errorf("Bad destination type: %s", notificationConfiguration.DestinationType)
}

if notificationConfiguration.Enabled != false {
return fmt.Errorf("Bad enabled value: %t", notificationConfiguration.Enabled)
}

if !reflect.DeepEqual(notificationConfiguration.Triggers, []string{}) {
return fmt.Errorf("Bad triggers: %v", notificationConfiguration.Triggers)
}

if notificationConfiguration.URL != "http://example.com" {
return fmt.Errorf("Bad URL: %s", notificationConfiguration.URL)
}

return nil
}
}

func testAccCheckTFENotificationConfigurationAttributesDuplicateTriggers(notificationConfiguration *tfe.NotificationConfiguration) resource.TestCheckFunc {
return func(s *terraform.State) error {
if notificationConfiguration.Name != "notification_duplicate_triggers" {
Expand Down Expand Up @@ -751,6 +847,26 @@ resource "tfe_notification_configuration" "foobar" {
}`, rInt)
}

func testAccTFENotificationConfiguration_microsoftTeams(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "admin@company.com"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
}

resource "tfe_notification_configuration" "foobar" {
name = "notification_msteams"
destination_type = "microsoft-teams"
url = "http://example.com"
workspace_id = tfe_workspace.foobar.id
}`, rInt)
}

func testAccTFENotificationConfiguration_update(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
Expand Down Expand Up @@ -989,6 +1105,91 @@ resource "tfe_notification_configuration" "foobar" {
}`, rInt)
}

func testAccTFENotificationConfiguration_microsoftTeamsWithEmailAddresses(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "admin@company.com"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
}

resource "tfe_notification_configuration" "foobar" {
name = "notification_msteams_with_email_addresses"
destination_type = "microsoft-teams"
email_addresses = ["test@example.com", "test2@example.com"]
workspace_id = tfe_workspace.foobar.id
}`, rInt)
}

func testAccTFENotificationConfiguration_microsoftTeamsWithEmailUserIDs(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "admin@company.com"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
}

resource "tfe_organization_membership" "foobar" {
organization = tfe_organization.foobar.id
email = "foo@foobar.com"
}

resource "tfe_notification_configuration" "foobar" {
name = "notification_msteams_with_email_user_ids"
destination_type = "microsoft-teams"
email_user_ids = [tfe_organization_membership.foobar.id]
workspace_id = tfe_workspace.foobar.id
}`, rInt)
}

func testAccTFENotificationConfiguration_microsoftTeamsWithToken(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "admin@company.com"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
}

resource "tfe_notification_configuration" "foobar" {
name = "notification_msteams_with_token"
destination_type = "microsoft-teams"
token = "1234567890"
url = "http://example.com"
workspace_id = tfe_workspace.foobar.id
}`, rInt)
}

func testAccTFENotificationConfiguration_microsoftTeamsWithoutURL(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "admin@company.com"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
}

resource "tfe_notification_configuration" "foobar" {
name = "notification_msteams_without_url"
destination_type = "microsoft-teams"
workspace_id = tfe_workspace.foobar.id
}`, rInt)
}

func testAccTFENotificationConfiguration_duplicateTriggers(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
Expand Down
8 changes: 4 additions & 4 deletions tfe/resource_tfe_team_test.go
Expand Up @@ -251,8 +251,8 @@ func testAccCheckTFETeamAttributes_full(
if !team.OrganizationAccess.ManageRunTasks {
return fmt.Errorf("OrganizationAccess.ManageRunTasks should be true")
}
if *team.SSOTeamID != "team-test-sso-id" {
return fmt.Errorf("Bad SSO Team ID: %s", *team.SSOTeamID)
if team.SSOTeamID != "team-test-sso-id" {
return fmt.Errorf("Bad SSO Team ID: %s", team.SSOTeamID)
}

return nil
Expand Down Expand Up @@ -283,8 +283,8 @@ func testAccCheckTFETeamAttributes_full_update(
return fmt.Errorf("OrganizationAccess.ManageRunTasks should be false")
}

if *team.SSOTeamID != "changed-sso-id" {
return fmt.Errorf("Bad SSO Team ID: %s", *team.SSOTeamID)
if team.SSOTeamID != "changed-sso-id" {
return fmt.Errorf("Bad SSO Team ID: %s", team.SSOTeamID)
}

return nil
Expand Down