diff --git a/docs/resources/service_emails_on_push.md b/docs/resources/service_emails_on_push.md new file mode 100644 index 000000000..840957467 --- /dev/null +++ b/docs/resources/service_emails_on_push.md @@ -0,0 +1,63 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gitlab_service_emails_on_push Resource - terraform-provider-gitlab" +subcategory: "" +description: |- + The gitlab_service_emails_on_push resource allows to manage the lifecycle of a project integration with Emails on Push Service. + Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/integrations.html#emails-on-push +--- + +# gitlab_service_emails_on_push (Resource) + +The `gitlab_service_emails_on_push` resource allows to manage the lifecycle of a project integration with Emails on Push Service. + +**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/integrations.html#emails-on-push) + +## Example Usage + +```terraform +resource "gitlab_project" "awesome_project" { + name = "awesome_project" + description = "My awesome project." + visibility_level = "public" +} + +resource "gitlab_service_emails_on_push" "emails" { + project = gitlab_project.awesome_project.id + recipients = "myrecipient@example.com myotherrecipient@example.com" +} +``` + + +## Schema + +### Required + +- `project` (String) ID or full-path of the project you want to activate integration on. +- `recipients` (String) Emails separated by whitespace. + +### Optional + +- `branches_to_be_notified` (String) Branches to send notifications for. Valid options are `all`, `default`, `protected`, `default_and_protected`. Notifications are always fired for tag pushes. +- `disable_diffs` (Boolean) Disable code diffs. +- `push_events` (Boolean) Enable notifications for push events. +- `send_from_committer_email` (Boolean) Send from committer. +- `tag_push_events` (Boolean) Enable notifications for tag push events. + +### Read-Only + +- `active` (Boolean) Whether the integration is active. +- `created_at` (String) The ISO8601 date/time that this integration was activated at in UTC. +- `id` (String) The ID of this resource. +- `slug` (String) The name of the integration in lowercase, shortened to 63 bytes, and with everything except 0-9 and a-z replaced with -. No leading / trailing -. Use in URLs, host names and domain names. +- `title` (String) Title of the integration. +- `updated_at` (String) The ISO8601 date/time that this integration was last updated at in UTC. + +## Import + +Import is supported using the following syntax: + +```shell +# You can import a gitlab_service_emails_on_push state using the project ID, e.g. +terraform import gitlab_service_emails_on_push.emails 1 +``` diff --git a/examples/resources/gitlab_service_emails_on_push/import.sh b/examples/resources/gitlab_service_emails_on_push/import.sh new file mode 100644 index 000000000..08eff280a --- /dev/null +++ b/examples/resources/gitlab_service_emails_on_push/import.sh @@ -0,0 +1,2 @@ +# You can import a gitlab_service_emails_on_push state using the project ID, e.g. +terraform import gitlab_service_emails_on_push.emails 1 diff --git a/examples/resources/gitlab_service_emails_on_push/resource.tf b/examples/resources/gitlab_service_emails_on_push/resource.tf new file mode 100644 index 000000000..b318e3664 --- /dev/null +++ b/examples/resources/gitlab_service_emails_on_push/resource.tf @@ -0,0 +1,10 @@ +resource "gitlab_project" "awesome_project" { + name = "awesome_project" + description = "My awesome project." + visibility_level = "public" +} + +resource "gitlab_service_emails_on_push" "emails" { + project = gitlab_project.awesome_project.id + recipients = "myrecipient@example.com myotherrecipient@example.com" +} diff --git a/internal/provider/resource_gitlab_service_emails_on_push.go b/internal/provider/resource_gitlab_service_emails_on_push.go new file mode 100644 index 000000000..64d8dfedd --- /dev/null +++ b/internal/provider/resource_gitlab_service_emails_on_push.go @@ -0,0 +1,183 @@ +package provider + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + gitlab "github.com/xanzy/go-gitlab" +) + +var validBranchesToBeNotified = []string{ + "all", "default", "protected", "default_and_protected", +} + +var _ = registerResource("gitlab_service_emails_on_push", func() *schema.Resource { + return &schema.Resource{ + Description: `The ` + "`gitlab_service_emails_on_push`" + ` resource allows to manage the lifecycle of a project integration with Emails on Push Service. + +**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/integrations.html#emails-on-push)`, + + CreateContext: resourceGitlabServiceEmailsOnPushCreate, + ReadContext: resourceGitlabServiceEmailsOnPushRead, + UpdateContext: resourceGitlabServiceEmailsOnPushCreate, + DeleteContext: resourceGitlabServiceEmailsOnPushDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "project": { + Description: "ID or full-path of the project you want to activate integration on.", + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "recipients": { + Description: "Emails separated by whitespace.", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "disable_diffs": { + Description: "Disable code diffs.", + Type: schema.TypeBool, + Optional: true, + }, + "send_from_committer_email": { + Description: "Send from committer.", + Type: schema.TypeBool, + Optional: true, + }, + "push_events": { + Description: "Enable notifications for push events.", + Type: schema.TypeBool, + Optional: true, + }, + "tag_push_events": { + Description: "Enable notifications for tag push events.", + Type: schema.TypeBool, + Optional: true, + }, + "branches_to_be_notified": { + Description: fmt.Sprintf("Branches to send notifications for. Valid options are %s. Notifications are always fired for tag pushes.", renderValueListForDocs(validBranchesToBeNotified)), + Type: schema.TypeString, + Optional: true, + Default: "all", + ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(validBranchesToBeNotified, false)), + }, + "title": { + Description: "Title of the integration.", + Type: schema.TypeString, + Computed: true, + }, + "created_at": { + Description: "The ISO8601 date/time that this integration was activated at in UTC.", + Type: schema.TypeString, + Computed: true, + }, + "updated_at": { + Description: "The ISO8601 date/time that this integration was last updated at in UTC.", + Type: schema.TypeString, + Computed: true, + }, + "slug": { + Description: "The name of the integration in lowercase, shortened to 63 bytes, and with everything except 0-9 and a-z replaced with -. No leading / trailing -. Use in URLs, host names and domain names.", + Type: schema.TypeString, + Computed: true, + }, + "active": { + Description: "Whether the integration is active.", + Type: schema.TypeBool, + Computed: true, + }, + }, + } +}) + +func resourceGitlabServiceEmailsOnPushCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*gitlab.Client) + + options := &gitlab.SetEmailsOnPushServiceOptions{ + Recipients: gitlab.String(d.Get("recipients").(string)), + } + if v, ok := d.GetOk("disable_diffs"); ok { + options.DisableDiffs = gitlab.Bool(v.(bool)) + } + if v, ok := d.GetOk("send_from_committer_email"); ok { + options.SendFromCommitterEmail = gitlab.Bool(v.(bool)) + } + if v, ok := d.GetOk("push_events"); ok { + options.PushEvents = gitlab.Bool(v.(bool)) + } + if v, ok := d.GetOk("tag_push_events"); ok { + options.TagPushEvents = gitlab.Bool(v.(bool)) + } + if v, ok := d.GetOk("branches_to_be_notified"); ok { + options.BranchesToBeNotified = gitlab.String(v.(string)) + } + + project := d.Get("project").(string) + log.Printf("[DEBUG] create gitlab emails on push service for project %s", project) + + _, err := client.Services.SetEmailsOnPushService(project, options, gitlab.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + d.SetId(project) + + return resourceGitlabServiceEmailsOnPushRead(ctx, d, meta) +} + +func resourceGitlabServiceEmailsOnPushRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*gitlab.Client) + project := d.Id() + + log.Printf("[DEBUG] read gitlab emails on push service for project %s", project) + + service, _, err := client.Services.GetEmailsOnPushService(project, gitlab.WithContext(ctx)) + if err != nil { + if is404(err) { + log.Printf("[DEBUG] gitlab emails on push service not found for project %s, removing from state", project) + d.SetId("") + return nil + } + return diag.FromErr(err) + } + + d.Set("project", project) + d.Set("recipients", service.Properties.Recipients) + d.Set("branches_to_be_notified", service.Properties.BranchesToBeNotified) + d.Set("disable_diffs", service.Properties.DisableDiffs) + d.Set("push_events", service.Properties.PushEvents) + d.Set("send_from_committer_email", service.Properties.SendFromCommitterEmail) + d.Set("tag_push_events", service.Properties.TagPushEvents) + d.Set("active", service.Active) + d.Set("slug", service.Slug) + d.Set("title", service.Title) + d.Set("created_at", service.CreatedAt.Format(time.RFC3339)) + if service.UpdatedAt != nil { + d.Set("updated_at", service.UpdatedAt.Format(time.RFC3339)) + } + + return nil +} + +func resourceGitlabServiceEmailsOnPushDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*gitlab.Client) + project := d.Id() + + log.Printf("[DEBUG] delete gitlab emails on push service for project %s", project) + + _, err := client.Services.DeleteEmailsOnPushService(project, gitlab.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + + return nil +} diff --git a/internal/provider/resource_gitlab_service_emails_on_push_test.go b/internal/provider/resource_gitlab_service_emails_on_push_test.go new file mode 100644 index 000000000..0be82e504 --- /dev/null +++ b/internal/provider/resource_gitlab_service_emails_on_push_test.go @@ -0,0 +1,148 @@ +//go:build acceptance +// +build acceptance + +package provider + +import ( + "fmt" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + gitlab "github.com/xanzy/go-gitlab" +) + +func TestAccGitlabServiceEmailsOnPush_basic(t *testing.T) { + testProject := testAccCreateProject(t) + + var emailsOnPushService gitlab.EmailsOnPushService + + var recipients1 = "mynumberonerecipient@example.com" + var recipients2 = "mynumbertworecipient@example.com" + var emailsOnPushResourceName = "gitlab_service_emails_on_push.this" + + resource.ParallelTest(t, resource.TestCase{ + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckGitlabServiceEmailsOnPushDestroy, + Steps: []resource.TestStep{ + // Create an Emails on Push service + { + Config: fmt.Sprintf(` + resource "gitlab_service_emails_on_push" "this" { + project = %[1]d + recipients = "%[2]s" + } + `, testProject.ID, recipients1), + Check: resource.ComposeTestCheckFunc( + testAccCheckGitlabServiceEmailsOnPushExists(emailsOnPushResourceName, &emailsOnPushService), + resource.TestCheckResourceAttr(emailsOnPushResourceName, "recipients", recipients1), + resource.TestCheckResourceAttr(emailsOnPushResourceName, "active", "true"), + resource.TestCheckResourceAttrWith(emailsOnPushResourceName, "created_at", func(value string) error { + expectedValue := emailsOnPushService.CreatedAt.Format(time.RFC3339) + if value != expectedValue { + return fmt.Errorf("should be equal to %s", expectedValue) + } + return nil + }), + ), + }, + // Verify import + { + ResourceName: "gitlab_service_emails_on_push.this", + ImportState: true, + ImportStateVerify: true, + }, + // Update the Emails on Push service + { + Config: fmt.Sprintf(` + resource "gitlab_service_emails_on_push" "this" { + project = %[1]d + recipients = "%[2]s" + } + `, testProject.ID, recipients2), + Check: resource.ComposeTestCheckFunc( + testAccCheckGitlabServiceEmailsOnPushExists(emailsOnPushResourceName, &emailsOnPushService), + resource.TestCheckResourceAttr(emailsOnPushResourceName, "recipients", recipients2), + resource.TestCheckResourceAttrWith(emailsOnPushResourceName, "created_at", func(value string) error { + expectedValue := emailsOnPushService.CreatedAt.Format(time.RFC3339) + if value != expectedValue { + return fmt.Errorf("should be equal to %s", expectedValue) + } + return nil + }), + resource.TestCheckResourceAttrWith(emailsOnPushResourceName, "updated_at", func(value string) error { + expectedValue := emailsOnPushService.UpdatedAt.Format(time.RFC3339) + if value != expectedValue { + return fmt.Errorf("should be equal to %s", expectedValue) + } + return nil + }), + ), + }, + // Verify import + { + ResourceName: "gitlab_service_emails_on_push.this", + ImportState: true, + ImportStateVerify: true, + }, + // Update the Emails on Push service to get back to previous settings + { + Config: fmt.Sprintf(` + resource "gitlab_service_emails_on_push" "this" { + project = %[1]d + recipients = "%[2]s" + } + `, testProject.ID, recipients1), + }, + // Verify import + { + ResourceName: "gitlab_service_emails_on_push.this", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckGitlabServiceEmailsOnPushExists(resourceIdentifier string, service *gitlab.EmailsOnPushService) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceIdentifier] + if !ok { + return fmt.Errorf("Not Found: %s", resourceIdentifier) + } + + project := rs.Primary.Attributes["project"] + if project == "" { + return fmt.Errorf("No project ID is set") + } + + emailsOnPushService, _, err := testGitlabClient.Services.GetEmailsOnPushService(project) + if err != nil { + return fmt.Errorf("Emails on Push service does not exist in project %s: %v", project, err) + } + *service = *emailsOnPushService + + return nil + } +} + +func testAccCheckGitlabServiceEmailsOnPushDestroy(s *terraform.State) error { + var project string + + for _, rs := range s.RootModule().Resources { + if rs.Type == "gitlab_service_emails_on_push" { + project = rs.Primary.ID + + emailsOnPushService, _, err := testGitlabClient.Services.GetEmailsOnPushService(project) + if err == nil { + if emailsOnPushService != nil && emailsOnPushService.Active != false { + return fmt.Errorf("[ERROR] Emails on Push Service %v still exists", project) + } + } else { + return err + } + } + } + return nil +}