diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index 947a0db2..48dd36bf 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -118,6 +118,7 @@ jobs: env: ROLLBAR_API_KEY: ${{ secrets.ROLLBAR_API_KEY }} + ROLLBAR_PROJECT_API_KEY: ${{ secrets.ROLLBAR_PROJECT_API_KEY }} steps: diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 650e78ff..9cf07e9b 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -2,8 +2,6 @@ name: Code Quality Analysis on: push: - branches: [ master ] - tags: [ v* ] pull_request: schedule: - cron: '0 10 * * 3' @@ -13,6 +11,11 @@ jobs: name: CodeQL runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + steps: - name: Checkout repository uses: actions/checkout@v2 @@ -21,11 +24,6 @@ jobs: # a pull request then we can checkout the head. fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - # Restore cache - uses: actions/cache@v2 with: @@ -37,7 +35,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -48,7 +46,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -62,7 +60,7 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 golangci: name: golangci-lint diff --git a/client/fixtures/notification/create.json b/client/fixtures/notification/create.json index 06ed6e68..695ff029 100644 --- a/client/fixtures/notification/create.json +++ b/client/fixtures/notification/create.json @@ -2,6 +2,7 @@ "result": [ { "action": "send_email", + "status": "enabled", "trigger": "new_item", "config": { "teams": [ diff --git a/client/fixtures/notification/read.json b/client/fixtures/notification/read.json index d394fd23..dd4874a2 100644 --- a/client/fixtures/notification/read.json +++ b/client/fixtures/notification/read.json @@ -2,6 +2,7 @@ "result": { "action": "send_email", "trigger": "new_item", + "status": "disabled", "config": {}, "id": 5127954, "filters": [ diff --git a/client/fixtures/notification/update.json b/client/fixtures/notification/update.json index 7ff543ae..6f23ef8e 100644 --- a/client/fixtures/notification/update.json +++ b/client/fixtures/notification/update.json @@ -2,6 +2,7 @@ "result": { "action": "send_email", "trigger": "new_item", + "status": "disabled", "config": { "teams": [ "Owners" diff --git a/client/notification.go b/client/notification.go index c04e4768..03109804 100644 --- a/client/notification.go +++ b/client/notification.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Rollbar, Inc. + * Copyright (c) 2024 Rollbar, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,6 +31,7 @@ import ( type Notification struct { ID int `model:"id" mapstructure:"id"` + Status string `model:"status" mapstructure:"status"` Action string `model:"action" mapstructure:"action"` Trigger string `model:"trigger" mapstructure:"trigger"` Channel string `model:"channel" mapstructure:"channel"` @@ -39,7 +40,7 @@ type Notification struct { } // CreateNotification creates a new Rollbar notification. -func (c *RollbarAPIClient) CreateNotification(channel string, filters, trigger, config interface{}) (*Notification, error) { +func (c *RollbarAPIClient) CreateNotification(channel string, filters, trigger, config interface{}, status string) (*Notification, error) { c.m.Lock() defer c.m.Unlock() u := c.BaseURL + pathNotificationCreate @@ -50,7 +51,7 @@ func (c *RollbarAPIClient) CreateNotification(channel string, filters, trigger, l.Debug().Msg("Creating new notification") resp, err := c.Resty.R(). - SetBody([]map[string]interface{}{{"filters": filters, "trigger": trigger, "config": config}}). + SetBody([]map[string]interface{}{{"filters": filters, "trigger": trigger, "config": config, "status": status}}). SetResult(notificationsResponse{}). SetError(ErrorResult{}). Post(u) @@ -70,7 +71,7 @@ func (c *RollbarAPIClient) CreateNotification(channel string, filters, trigger, } // UpdateNotification updates a Rollbar notification. -func (c *RollbarAPIClient) UpdateNotification(notificationID int, channel string, filters, trigger, config interface{}) (*Notification, error) { +func (c *RollbarAPIClient) UpdateNotification(notificationID int, channel string, filters, trigger, config interface{}, status string) (*Notification, error) { c.m.Lock() defer c.m.Unlock() u := c.BaseURL + pathNotificationReadOrDeleteOrUpdate @@ -80,7 +81,7 @@ func (c *RollbarAPIClient) UpdateNotification(notificationID int, channel string l.Debug().Msg("Updating notification") resp, err := c.Resty.R(). - SetBody(map[string]interface{}{"filters": filters, "trigger": trigger, "config": config}). + SetBody(map[string]interface{}{"filters": filters, "trigger": trigger, "config": config, "status": status}). SetResult(notificationResponse{}). SetError(ErrorResult{}). SetPathParams(map[string]string{ diff --git a/client/notification_test.go b/client/notification_test.go index ca070b3c..4a779d4d 100644 --- a/client/notification_test.go +++ b/client/notification_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Rollbar, Inc. + * Copyright (c) 2024 Rollbar, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,10 +24,11 @@ package client import ( "encoding/json" - "github.com/jarcoal/httpmock" "net/http" "strconv" "strings" + + "github.com/jarcoal/httpmock" ) // TestCreateNotification tests creating a Rollbar notification. @@ -38,6 +39,7 @@ func (s *Suite) TestCreateNotification() { u = strings.ReplaceAll(u, "{channel}", channel) action := "send_email" trigger := "new_item" + status := "enabled" filters := []map[string]interface{}{} config := map[string]interface{}{} @@ -52,14 +54,15 @@ func (s *Suite) TestCreateNotification() { } httpmock.RegisterResponder("POST", u, r) - notification, err := s.client.CreateNotification(channel, filters, trigger, config) + notification, err := s.client.CreateNotification(channel, filters, trigger, config, status) s.Nil(err) s.Equal(trigger, notification.Trigger) s.Equal(action, notification.Action) s.Equal(id, notification.ID) + s.Equal(status, notification.Status) s.checkServerErrors("POST", u, func() error { - _, err = s.client.CreateNotification(channel, filters, trigger, config) + _, err = s.client.CreateNotification(channel, filters, trigger, config, status) return err }) } @@ -74,6 +77,7 @@ func (s *Suite) TestUpdateNotification() { action := "send_email" trigger := "new_item" + status := "disabled" filters := []map[string]interface{}{} config := map[string]interface{}{} @@ -88,14 +92,15 @@ func (s *Suite) TestUpdateNotification() { } httpmock.RegisterResponder("PUT", u, r) - notification, err := s.client.UpdateNotification(id, channel, filters, trigger, config) + notification, err := s.client.UpdateNotification(id, channel, filters, trigger, config, status) s.Nil(err) s.Equal(trigger, notification.Trigger) s.Equal(action, notification.Action) s.Equal(id, notification.ID) + s.Equal(status, notification.Status) s.checkServerErrors("PUT", u, func() error { - _, err = s.client.UpdateNotification(id, channel, filters, trigger, config) + _, err = s.client.UpdateNotification(id, channel, filters, trigger, config, status) return err }) } @@ -115,6 +120,7 @@ func (s *Suite) TestReadNotification() { n, err := s.client.ReadNotification(id, channel) s.Nil(err) s.Equal("new_item", n.Trigger) + s.Equal("disabled", n.Status) s.checkServerErrors("GET", u, func() error { _, err := s.client.ReadNotification(id, channel) diff --git a/rollbar/resource_notification.go b/rollbar/resource_notification.go index 5be6cf63..e9b7ef40 100644 --- a/rollbar/resource_notification.go +++ b/rollbar/resource_notification.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Rollbar, Inc. + * Copyright (c) 2024 Rollbar, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,6 +41,11 @@ var configMap = map[string][]string{ "webhook": {"url", "format"}, } +const ( + enabledStatus = "enabled" + disabledStatus = "disabled" +) + var emailDailySummaryConfigList = []string{"summary_time", "environments", "send_only_if_data", "min_item_level"} func CustomNotificationImport(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { @@ -82,6 +87,12 @@ func resourceNotification() *schema.Resource { Type: schema.TypeString, Required: true, }, + "enabled": { + Description: "Enabled", + Type: schema.TypeBool, + Optional: true, + Default: true, + }, "filters": { Description: "Filters", Type: schema.TypeList, @@ -227,16 +238,23 @@ func parseSet(setName string, d *schema.ResourceData) map[string]interface{} { return map[string]interface{}{} } -func parseRule(d *schema.ResourceData) (trigger string, filters interface{}) { +func parseRule(d *schema.ResourceData) (trigger string, filters interface{}, status string) { rule := parseSet("rule", d) for key, value := range rule { - if key == "trigger" { + switch key { + case "trigger": trigger = value.(string) - } else { + case "enabled": + v := value.(bool) + status = disabledStatus + if v { + status = enabledStatus + } + default: filters = value } } - return trigger, filters + return trigger, filters, status } func cleanConfig(channel, trigger string, config map[string]interface{}) map[string]interface{} { @@ -265,7 +283,7 @@ func cleanConfig(channel, trigger string, config map[string]interface{}) map[str func resourceNotificationCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - trigger, filters := parseRule(d) + trigger, filters, status := parseRule(d) channel := d.Get("channel").(string) config := parseSet("config", d) config = cleanConfig(channel, trigger, config) @@ -276,7 +294,7 @@ func resourceNotificationCreate(ctx context.Context, d *schema.ResourceData, m i c := m.(map[string]*client.RollbarAPIClient)[projectKeyToken] c.SetHeaderResource(rollbarNotification) - n, err := c.CreateNotification(channel, filters, trigger, config) + n, err := c.CreateNotification(channel, filters, trigger, config, status) if err != nil { l.Err(err).Send() @@ -294,7 +312,7 @@ func resourceNotificationCreate(ctx context.Context, d *schema.ResourceData, m i func resourceNotificationUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { id := mustGetID(d) - trigger, filters := parseRule(d) + trigger, filters, status := parseRule(d) channel := d.Get("channel").(string) config := parseSet("config", d) config = cleanConfig(channel, trigger, config) @@ -304,7 +322,7 @@ func resourceNotificationUpdate(ctx context.Context, d *schema.ResourceData, m i c := m.(map[string]*client.RollbarAPIClient)[projectKeyToken] c.SetHeaderResource(rollbarNotification) - n, err := c.UpdateNotification(id, channel, filters, trigger, config) + n, err := c.UpdateNotification(id, channel, filters, trigger, config, status) if err != nil { l.Err(err).Send() @@ -332,7 +350,7 @@ func flattenConfig(config map[string]interface{}) *schema.Set { return set } -func flattenRule(filters []interface{}, trigger string) *schema.Set { +func flattenRule(filters []interface{}, trigger, status string) *schema.Set { var out = make([]interface{}, 0) m := make(map[string]interface{}) for _, filter := range filters { @@ -355,6 +373,12 @@ func flattenRule(filters []interface{}, trigger string) *schema.Set { filterConv["value"] = strconv.FormatFloat(v, 'f', -1, 64) } } + if status == enabledStatus { + m["enabled"] = true + } + if status == disabledStatus { + m["enabled"] = false + } m["filters"] = filters out = append(out, m) m["trigger"] = trigger @@ -386,7 +410,7 @@ func resourceNotificationRead(ctx context.Context, d *schema.ResourceData, m int } mustSet(d, "config", flattenConfig(n.Config)) - mustSet(d, "rule", flattenRule(n.Filters, n.Trigger)) + mustSet(d, "rule", flattenRule(n.Filters, n.Trigger, n.Status)) l.Debug().Msg("Successfully read rollbar_notification resource") return nil } diff --git a/rollbar/test2/resource_integration_test.go b/rollbar/test2/resource_integration_test.go index faa448d1..f70ba40b 100644 --- a/rollbar/test2/resource_integration_test.go +++ b/rollbar/test2/resource_integration_test.go @@ -28,7 +28,6 @@ import ( // TestIntegrationCreate tests creating an integration func (s *AccSuite) TestIntegrationCreate() { - s.T().Skip("unauthorized") integrationResourceName := "rollbar_integration.webhook_integration" // language=hcl config := ` @@ -58,7 +57,6 @@ func (s *AccSuite) TestIntegrationCreate() { // TestIntegrationUpdate tests updating an integration func (s *AccSuite) TestIntegrationUpdate() { - s.T().Skip("unauthorized") integrationResourceName := "rollbar_integration.webhook_integration" // language=hcl config1 := ` diff --git a/rollbar/test2/resource_notification_test.go b/rollbar/test2/resource_notification_test.go index 0ad9edf1..28fa46d8 100644 --- a/rollbar/test2/resource_notification_test.go +++ b/rollbar/test2/resource_notification_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Rollbar, Inc. + * Copyright (c) 2024 Rollbar, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -39,7 +39,6 @@ func init() { // TestNotificationCreate tests creating a notification func (s *AccSuite) TestNotificationCreate() { - s.T().Skip("unauthorized") notificationResourceName := "rollbar_notification.webhook_notification" // language=hcl config := ` @@ -77,6 +76,56 @@ func (s *AccSuite) TestNotificationCreate() { resource.TestCheckResourceAttr(notificationResourceName, "rule.0.filters.0.type", "environment"), resource.TestCheckResourceAttr(notificationResourceName, "rule.0.filters.1.type", "framework"), resource.TestCheckResourceAttr(notificationResourceName, "rule.0.trigger", "new_item"), + resource.TestCheckResourceAttr(notificationResourceName, "rule.0.enabled", "true"), + resource.TestCheckResourceAttr(notificationResourceName, "config.0.url", "https://www.rollbar.com"), + resource.TestCheckResourceAttr(notificationResourceName, "config.0.format", "json"), + ), + }, + }, + }) +} + +// TestNotificationCreateDisabledRule tests creating a disbaled notification +func (s *AccSuite) TestNotificationCreateDisabledRule() { + notificationResourceName := "rollbar_notification.webhook_notification" + // language=hcl + config := ` + resource "rollbar_notification" "webhook_notification" { + rule { + enabled = false + filters { + type = "environment" + operation = "eq" + value = "production" + } + filters { + type = "framework" + operation = "eq" + value = 13 + } + trigger = "new_item" + } + channel = "webhook" + config { + url = "https://www.rollbar.com" + format = "json" + } +} + ` + resource.ParallelTest(s.T(), resource.TestCase{ + PreCheck: func() { s.preCheck() }, + Providers: s.providers, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + s.checkResourceStateSanity(notificationResourceName), + resource.TestCheckResourceAttr(notificationResourceName, "channel", "webhook"), + resource.TestCheckResourceAttr(notificationResourceName, "rule.0.filters.0.type", "environment"), + resource.TestCheckResourceAttr(notificationResourceName, "rule.0.filters.1.type", "framework"), + resource.TestCheckResourceAttr(notificationResourceName, "rule.0.trigger", "new_item"), + resource.TestCheckResourceAttr(notificationResourceName, "rule.0.enabled", "false"), resource.TestCheckResourceAttr(notificationResourceName, "config.0.url", "https://www.rollbar.com"), resource.TestCheckResourceAttr(notificationResourceName, "config.0.format", "json"), ), @@ -87,12 +136,12 @@ func (s *AccSuite) TestNotificationCreate() { // TestNotificationUpdate tests updating a notification func (s *AccSuite) TestNotificationUpdate() { - s.T().Skip("unauthorized") notificationResourceName := "rollbar_notification.webhook_notification" // language=hcl config1 := ` resource "rollbar_notification" "webhook_notification" { rule { + enabled = true filters { type = "environment" operation = "eq" @@ -115,6 +164,7 @@ func (s *AccSuite) TestNotificationUpdate() { config2 := ` resource "rollbar_notification" "webhook_notification" { rule { + enabled = false filters { type = "environment" operation = "eq" @@ -147,6 +197,7 @@ func (s *AccSuite) TestNotificationUpdate() { resource.TestCheckResourceAttr(notificationResourceName, "rule.0.filters.0.type", "environment"), resource.TestCheckResourceAttr(notificationResourceName, "rule.0.filters.1.type", "framework"), resource.TestCheckResourceAttr(notificationResourceName, "rule.0.trigger", "new_item"), + resource.TestCheckResourceAttr(notificationResourceName, "rule.0.enabled", "true"), resource.TestCheckResourceAttr(notificationResourceName, "config.0.url", "https://www.rollbar.com"), resource.TestCheckResourceAttr(notificationResourceName, "config.0.format", "json"), ), @@ -159,6 +210,7 @@ func (s *AccSuite) TestNotificationUpdate() { resource.TestCheckResourceAttr(notificationResourceName, "rule.0.filters.0.type", "environment"), resource.TestCheckResourceAttr(notificationResourceName, "rule.0.filters.1.type", "framework"), resource.TestCheckResourceAttr(notificationResourceName, "rule.0.trigger", "new_item"), + resource.TestCheckResourceAttr(notificationResourceName, "rule.0.enabled", "false"), resource.TestCheckResourceAttr(notificationResourceName, "config.0.url", "https://www.rollbar.com"), resource.TestCheckResourceAttr(notificationResourceName, "config.0.format", "xml"), ), @@ -168,7 +220,6 @@ func (s *AccSuite) TestNotificationUpdate() { } func (s *AccSuite) TestNotificationCreateSpecialEmail() { - s.T().Skip("unauthorized") notificationResourceName := "rollbar_notification.email_notification" // language=hcl config := ` diff --git a/rollbar/test2/resource_service_link_test.go b/rollbar/test2/resource_service_link_test.go index 33f7ed00..dd718d57 100644 --- a/rollbar/test2/resource_service_link_test.go +++ b/rollbar/test2/resource_service_link_test.go @@ -40,7 +40,6 @@ func init() { // TestServiceLinkCreate tests creating a service link func (s *AccSuite) TestServiceLinkCreate() { - s.T().Skip("unauthorized") serviceLinkResourceName := "rollbar_service_link.service_link" // language=hcl tmpl := ` @@ -70,7 +69,6 @@ func (s *AccSuite) TestServiceLinkCreate() { // TestServiceLinkUpdate tests updating a service link func (s *AccSuite) TestServiceLinkUpdate() { - s.T().Skip("unauthorized") serviceLinkResourceName := "rollbar_service_link.service_link" // language=hcl tmpl1 := `