diff --git a/docs/data-sources/group_hook.md b/docs/data-sources/group_hook.md new file mode 100644 index 000000000..16b72c810 --- /dev/null +++ b/docs/data-sources/group_hook.md @@ -0,0 +1,59 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gitlab_group_hook Data Source - terraform-provider-gitlab" +subcategory: "" +description: |- + The gitlab_group_hook data source allows to retrieve details about a hook in a group. + Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/groups.html#get-group-hook +--- + +# gitlab_group_hook (Data Source) + +The `gitlab_group_hook` data source allows to retrieve details about a hook in a group. + +**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#get-group-hook) + +## Example Usage + +```terraform +data "gitlab_group" "example" { + id = "foo/bar/baz" +} + +data "gitlab_group_hook" "example" { + group = data.gitlab_group.example.id + hook_id = 1 +} +``` + + +## Schema + +### Required + +- `group` (String) The ID or full path of the group. +- `hook_id` (Number) The id of the group hook. + +### Read-Only + +- `confidential_issues_events` (Boolean) Invoke the hook for confidential issues events. +- `confidential_note_events` (Boolean) Invoke the hook for confidential notes events. +- `deployment_events` (Boolean) Invoke the hook for deployment events. +- `enable_ssl_verification` (Boolean) Enable ssl verification when invoking the hook. +- `group_id` (Number) The id of the group for the hook. +- `id` (String) The ID of this resource. +- `issues_events` (Boolean) Invoke the hook for issues events. +- `job_events` (Boolean) Invoke the hook for job events. +- `merge_requests_events` (Boolean) Invoke the hook for merge requests. +- `note_events` (Boolean) Invoke the hook for notes events. +- `pipeline_events` (Boolean) Invoke the hook for pipeline events. +- `push_events` (Boolean) Invoke the hook for push events. +- `push_events_branch_filter` (String) Invoke the hook for push events on matching branches only. +- `releases_events` (Boolean) Invoke the hook for releases events. +- `subgroup_events` (Boolean) Invoke the hook for subgroup events. +- `tag_push_events` (Boolean) Invoke the hook for tag push events. +- `token` (String) A token to present when invoking the hook. The token is not available for imported resources. +- `url` (String) The url of the hook to invoke. +- `wiki_page_events` (Boolean) Invoke the hook for wiki page events. + + diff --git a/docs/data-sources/group_hooks.md b/docs/data-sources/group_hooks.md new file mode 100644 index 000000000..b79b11693 --- /dev/null +++ b/docs/data-sources/group_hooks.md @@ -0,0 +1,66 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gitlab_group_hooks Data Source - terraform-provider-gitlab" +subcategory: "" +description: |- + The gitlab_group_hooks data source allows to retrieve details about hooks in a group. + Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/groups.html#list-group-hooks +--- + +# gitlab_group_hooks (Data Source) + +The `gitlab_group_hooks` data source allows to retrieve details about hooks in a group. + +**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#list-group-hooks) + +## Example Usage + +```terraform +data "gitlab_group" "example" { + id = "foo/bar/baz" +} + +data "gitlab_group_hooks" "examples" { + group = data.gitlab_group.example.id +} +``` + + +## Schema + +### Required + +- `group` (String) The ID or full path of the group. + +### Read-Only + +- `hooks` (List of Object) The list of hooks. (see [below for nested schema](#nestedatt--hooks)) +- `id` (String) The ID of this resource. + + +### Nested Schema for `hooks` + +Read-Only: + +- `confidential_issues_events` (Boolean) +- `confidential_note_events` (Boolean) +- `deployment_events` (Boolean) +- `enable_ssl_verification` (Boolean) +- `group` (String) +- `group_id` (Number) +- `hook_id` (Number) +- `issues_events` (Boolean) +- `job_events` (Boolean) +- `merge_requests_events` (Boolean) +- `note_events` (Boolean) +- `pipeline_events` (Boolean) +- `push_events` (Boolean) +- `push_events_branch_filter` (String) +- `releases_events` (Boolean) +- `subgroup_events` (Boolean) +- `tag_push_events` (Boolean) +- `token` (String) +- `url` (String) +- `wiki_page_events` (Boolean) + + diff --git a/docs/resources/group_hook.md b/docs/resources/group_hook.md new file mode 100644 index 000000000..6e200fb5f --- /dev/null +++ b/docs/resources/group_hook.md @@ -0,0 +1,90 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gitlab_group_hook Resource - terraform-provider-gitlab" +subcategory: "" +description: |- + The gitlab_group_hook resource allows to manage the lifecycle of a group hook. + Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/groups.html#hooks +--- + +# gitlab_group_hook (Resource) + +The `gitlab_group_hook` resource allows to manage the lifecycle of a group hook. + +**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#hooks) + +## Example Usage + +```terraform +resource "gitlab_group_hook" "example" { + group = "example/hooked" + url = "https://example.com/hook/example" + merge_requests_events = true +} + +# Setting all attributes +resource "gitlab_group_hook" "all_attributes" { + group = 1 + url = "http://example.com" + token = "supersecret" + enable_ssl_verification = false + push_events = true + push_events_branch_filter = "devel" + issues_events = false + confidential_issues_events = false + merge_requests_events = true + tag_push_events = true + note_events = true + confidential_note_events = true + job_events = true + pipeline_events = true + wiki_page_events = true + deployment_events = true + releases_events = true + subgroup_events = true +} +``` + + +## Schema + +### Required + +- `group` (String) The ID or full path of the group. +- `url` (String) The url of the hook to invoke. + +### Optional + +- `confidential_issues_events` (Boolean) Invoke the hook for confidential issues events. +- `confidential_note_events` (Boolean) Invoke the hook for confidential notes events. +- `deployment_events` (Boolean) Invoke the hook for deployment events. +- `enable_ssl_verification` (Boolean) Enable ssl verification when invoking the hook. +- `issues_events` (Boolean) Invoke the hook for issues events. +- `job_events` (Boolean) Invoke the hook for job events. +- `merge_requests_events` (Boolean) Invoke the hook for merge requests. +- `note_events` (Boolean) Invoke the hook for notes events. +- `pipeline_events` (Boolean) Invoke the hook for pipeline events. +- `push_events` (Boolean) Invoke the hook for push events. +- `push_events_branch_filter` (String) Invoke the hook for push events on matching branches only. +- `releases_events` (Boolean) Invoke the hook for releases events. +- `subgroup_events` (Boolean) Invoke the hook for subgroup events. +- `tag_push_events` (Boolean) Invoke the hook for tag push events. +- `token` (String, Sensitive) A token to present when invoking the hook. The token is not available for imported resources. +- `wiki_page_events` (Boolean) Invoke the hook for wiki page events. + +### Read-Only + +- `group_id` (Number) The id of the group for the hook. +- `hook_id` (Number) The id of the group hook. +- `id` (String) The ID of this resource. + +## Import + +Import is supported using the following syntax: + +```shell +# A GitLab Group Hook can be imported using a key composed of `:`, e.g. +terraform import gitlab_group_hook.example "12345:1" + +# NOTE: the `token` resource attribute is not available for imported resources as this information cannot be read from the GitLab API. +``` diff --git a/examples/data-sources/gitlab_group_hook/data-source.tf b/examples/data-sources/gitlab_group_hook/data-source.tf new file mode 100644 index 000000000..718902f9b --- /dev/null +++ b/examples/data-sources/gitlab_group_hook/data-source.tf @@ -0,0 +1,8 @@ +data "gitlab_group" "example" { + id = "foo/bar/baz" +} + +data "gitlab_group_hook" "example" { + group = data.gitlab_group.example.id + hook_id = 1 +} diff --git a/examples/data-sources/gitlab_group_hooks/data-source.tf b/examples/data-sources/gitlab_group_hooks/data-source.tf new file mode 100644 index 000000000..2e1cf9d7b --- /dev/null +++ b/examples/data-sources/gitlab_group_hooks/data-source.tf @@ -0,0 +1,7 @@ +data "gitlab_group" "example" { + id = "foo/bar/baz" +} + +data "gitlab_group_hooks" "examples" { + group = data.gitlab_group.example.id +} diff --git a/examples/resources/gitlab_group_hook/import.sh b/examples/resources/gitlab_group_hook/import.sh new file mode 100644 index 000000000..ea0f7db64 --- /dev/null +++ b/examples/resources/gitlab_group_hook/import.sh @@ -0,0 +1,4 @@ +# A GitLab Group Hook can be imported using a key composed of `:`, e.g. +terraform import gitlab_group_hook.example "12345:1" + +# NOTE: the `token` resource attribute is not available for imported resources as this information cannot be read from the GitLab API. diff --git a/examples/resources/gitlab_group_hook/resource.tf b/examples/resources/gitlab_group_hook/resource.tf new file mode 100644 index 000000000..f47f3c983 --- /dev/null +++ b/examples/resources/gitlab_group_hook/resource.tf @@ -0,0 +1,27 @@ +resource "gitlab_group_hook" "example" { + group = "example/hooked" + url = "https://example.com/hook/example" + merge_requests_events = true +} + +# Setting all attributes +resource "gitlab_group_hook" "all_attributes" { + group = 1 + url = "http://example.com" + token = "supersecret" + enable_ssl_verification = false + push_events = true + push_events_branch_filter = "devel" + issues_events = false + confidential_issues_events = false + merge_requests_events = true + tag_push_events = true + note_events = true + confidential_note_events = true + job_events = true + pipeline_events = true + wiki_page_events = true + deployment_events = true + releases_events = true + subgroup_events = true +} diff --git a/internal/provider/data_source_gitlab_group_hook.go b/internal/provider/data_source_gitlab_group_hook.go new file mode 100644 index 000000000..ed060c1e4 --- /dev/null +++ b/internal/provider/data_source_gitlab_group_hook.go @@ -0,0 +1,39 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/xanzy/go-gitlab" +) + +var _ = registerDataSource("gitlab_group_hook", func() *schema.Resource { + return &schema.Resource{ + Description: `The ` + "`gitlab_group_hook`" + ` data source allows to retrieve details about a hook in a group. + +**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#get-group-hook)`, + + ReadContext: dataSourceGitlabGroupHookRead, + Schema: datasourceSchemaFromResourceSchema(gitlabGroupHookSchema(), []string{"group", "hook_id"}, nil), + } +}) + +func dataSourceGitlabGroupHookRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*gitlab.Client) + group := d.Get("group").(string) + hookID := d.Get("hook_id").(int) + + hook, _, err := client.Groups.GetGroupHook(group, hookID, gitlab.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(fmt.Sprintf("%s:%d", group, hookID)) + stateMap := gitlabGroupHookToStateMap(group, hook) + if err := setStateMapInResourceData(stateMap, d); err != nil { + return diag.FromErr(err) + } + return nil +} diff --git a/internal/provider/data_source_gitlab_group_hook_test.go b/internal/provider/data_source_gitlab_group_hook_test.go new file mode 100644 index 000000000..26d5ac074 --- /dev/null +++ b/internal/provider/data_source_gitlab_group_hook_test.go @@ -0,0 +1,37 @@ +//go:build acceptance +// +build acceptance + +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceGitlabGroupHook_basic(t *testing.T) { + testAccCheckEE(t) + + testGroup := testAccCreateGroups(t, 1)[0] + testHook := testAccCreateGroupHooks(t, testGroup.ID, 1)[0] + + resource.ParallelTest(t, resource.TestCase{ + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(` + data "gitlab_group_hook" "this" { + group = "%s" + hook_id = %d + } + `, testGroup.FullPath, testHook.ID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.gitlab_group_hook.this", "hook_id", fmt.Sprintf("%d", testHook.ID)), + resource.TestCheckResourceAttr("data.gitlab_group_hook.this", "group_id", fmt.Sprintf("%d", testGroup.ID)), + resource.TestCheckResourceAttr("data.gitlab_group_hook.this", "url", testHook.URL), + ), + }, + }, + }) +} diff --git a/internal/provider/data_source_gitlab_group_hooks.go b/internal/provider/data_source_gitlab_group_hooks.go new file mode 100644 index 000000000..486bb13ce --- /dev/null +++ b/internal/provider/data_source_gitlab_group_hooks.go @@ -0,0 +1,69 @@ +package provider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/xanzy/go-gitlab" +) + +var _ = registerDataSource("gitlab_group_hooks", func() *schema.Resource { + return &schema.Resource{ + Description: `The ` + "`gitlab_group_hooks`" + ` data source allows to retrieve details about hooks in a group. + +**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#list-group-hooks)`, + + ReadContext: dataSourceGitlabGroupHooksRead, + Schema: map[string]*schema.Schema{ + "group": { + Description: "The ID or full path of the group.", + Type: schema.TypeString, + Required: true, + }, + "hooks": { + Description: "The list of hooks.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: datasourceSchemaFromResourceSchema(gitlabGroupHookSchema(), nil, nil), + }, + }, + }, + } +}) + +func dataSourceGitlabGroupHooksRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*gitlab.Client) + + group := d.Get("group").(string) + options := gitlab.ListGroupHooksOptions{ + PerPage: 20, + Page: 1, + } + + var hooks []*gitlab.GroupHook + for options.Page != 0 { + paginatedHooks, resp, err := client.Groups.ListGroupHooks(group, &options, gitlab.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + + hooks = append(hooks, paginatedHooks...) + options.Page = resp.NextPage + } + + d.SetId(group) + if err := d.Set("hooks", flattenGitlabGroupHooks(group, hooks)); err != nil { + return diag.Errorf("failed to set hooks to state: %v", err) + } + + return nil +} + +func flattenGitlabGroupHooks(group string, hooks []*gitlab.GroupHook) (values []map[string]interface{}) { + for _, hook := range hooks { + values = append(values, gitlabGroupHookToStateMap(group, hook)) + } + return values +} diff --git a/internal/provider/data_source_gitlab_group_hooks_test.go b/internal/provider/data_source_gitlab_group_hooks_test.go new file mode 100644 index 000000000..d50182d2b --- /dev/null +++ b/internal/provider/data_source_gitlab_group_hooks_test.go @@ -0,0 +1,36 @@ +//go:build acceptance +// +build acceptance + +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceGitlabGroupHooks_basic(t *testing.T) { + testAccCheckEE(t) + + testGroup := testAccCreateGroups(t, 1)[0] + testHooks := testAccCreateGroupHooks(t, testGroup.ID, 25) + + resource.ParallelTest(t, resource.TestCase{ + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(` + data "gitlab_group_hooks" "this" { + group = "%s" + } + `, testGroup.FullPath), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.gitlab_group_hooks.this", "hooks.#", fmt.Sprintf("%d", len(testHooks))), + resource.TestCheckResourceAttr("data.gitlab_group_hooks.this", "hooks.0.url", testHooks[0].URL), + resource.TestCheckResourceAttr("data.gitlab_group_hooks.this", "hooks.1.url", testHooks[1].URL), + ), + }, + }, + }) +} diff --git a/internal/provider/helper_test.go b/internal/provider/helper_test.go index 5d524c987..fc77a7bd7 100644 --- a/internal/provider/helper_test.go +++ b/internal/provider/helper_test.go @@ -249,6 +249,22 @@ func testAccCreateSubGroups(t *testing.T, parentGroup *gitlab.Group, n int) []*g return groups } +func testAccCreateGroupHooks(t *testing.T, gid interface{}, n int) []*gitlab.GroupHook { + t.Helper() + + var hooks []*gitlab.GroupHook + for i := 0; i < n; i++ { + hook, _, err := testGitlabClient.Groups.AddGroupHook(gid, &gitlab.AddGroupHookOptions{ + URL: gitlab.String(fmt.Sprintf("https://%s.com", acctest.RandomWithPrefix("acctest"))), + }) + if err != nil { + t.Fatalf("could not create group hook: %v", err) + } + hooks = append(hooks, hook) + } + return hooks +} + // testAccCreateBranches is a test helper for creating a specified number of branches. // It assumes the project will be destroyed at the end of the test and will not cleanup created branches. func testAccCreateBranches(t *testing.T, project *gitlab.Project, n int) []*gitlab.Branch { diff --git a/internal/provider/resource_gitlab_group_hook.go b/internal/provider/resource_gitlab_group_hook.go new file mode 100644 index 000000000..ad124f2b6 --- /dev/null +++ b/internal/provider/resource_gitlab_group_hook.go @@ -0,0 +1,167 @@ +package provider + +import ( + "context" + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + gitlab "github.com/xanzy/go-gitlab" +) + +var _ = registerResource("gitlab_group_hook", func() *schema.Resource { + return &schema.Resource{ + Description: `The ` + "`" + `gitlab_group_hook` + "`" + ` resource allows to manage the lifecycle of a group hook. + +**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#hooks)`, + + CreateContext: resourceGitlabGroupHookCreate, + ReadContext: resourceGitlabGroupHookRead, + UpdateContext: resourceGitlabGroupHookUpdate, + DeleteContext: resourceGitlabGroupHookDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Schema: gitlabGroupHookSchema(), + } +}) + +func resourceGitlabGroupHookCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*gitlab.Client) + group := d.Get("group").(string) + options := &gitlab.AddGroupHookOptions{ + URL: gitlab.String(d.Get("url").(string)), + PushEvents: gitlab.Bool(d.Get("push_events").(bool)), + PushEventsBranchFilter: gitlab.String(d.Get("push_events_branch_filter").(string)), + IssuesEvents: gitlab.Bool(d.Get("issues_events").(bool)), + ConfidentialIssuesEvents: gitlab.Bool(d.Get("confidential_issues_events").(bool)), + MergeRequestsEvents: gitlab.Bool(d.Get("merge_requests_events").(bool)), + TagPushEvents: gitlab.Bool(d.Get("tag_push_events").(bool)), + NoteEvents: gitlab.Bool(d.Get("note_events").(bool)), + ConfidentialNoteEvents: gitlab.Bool(d.Get("confidential_note_events").(bool)), + JobEvents: gitlab.Bool(d.Get("job_events").(bool)), + PipelineEvents: gitlab.Bool(d.Get("pipeline_events").(bool)), + WikiPageEvents: gitlab.Bool(d.Get("wiki_page_events").(bool)), + DeploymentEvents: gitlab.Bool(d.Get("deployment_events").(bool)), + ReleasesEvents: gitlab.Bool(d.Get("releases_events").(bool)), + SubGroupEvents: gitlab.Bool(d.Get("subgroup_events").(bool)), + EnableSSLVerification: gitlab.Bool(d.Get("enable_ssl_verification").(bool)), + } + + if v, ok := d.GetOk("token"); ok { + options.Token = gitlab.String(v.(string)) + } + + log.Printf("[DEBUG] create gitlab group hook %q", *options.URL) + + hook, _, err := client.Groups.AddGroupHook(group, options, gitlab.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(resourceGitlabGroupHookBuildID(group, hook.ID)) + d.Set("token", options.Token) + + return resourceGitlabGroupHookRead(ctx, d, meta) +} + +func resourceGitlabGroupHookRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + group, hookID, err := resourceGitlabGroupHookParseID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + log.Printf("[DEBUG] read gitlab group hook %s/%d", group, hookID) + + client := meta.(*gitlab.Client) + hook, _, err := client.Groups.GetGroupHook(group, hookID, gitlab.WithContext(ctx)) + if err != nil { + if is404(err) { + log.Printf("[DEBUG] gitlab group hook not found %s/%d, removing from state", group, hookID) + d.SetId("") + return nil + } + return diag.FromErr(err) + } + + stateMap := gitlabGroupHookToStateMap(group, hook) + if err = setStateMapInResourceData(stateMap, d); err != nil { + return diag.FromErr(err) + } + return nil +} + +func resourceGitlabGroupHookUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + group, hookID, err := resourceGitlabGroupHookParseID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + client := meta.(*gitlab.Client) + options := &gitlab.EditGroupHookOptions{ + URL: gitlab.String(d.Get("url").(string)), + PushEvents: gitlab.Bool(d.Get("push_events").(bool)), + PushEventsBranchFilter: gitlab.String(d.Get("push_events_branch_filter").(string)), + IssuesEvents: gitlab.Bool(d.Get("issues_events").(bool)), + ConfidentialIssuesEvents: gitlab.Bool(d.Get("confidential_issues_events").(bool)), + MergeRequestsEvents: gitlab.Bool(d.Get("merge_requests_events").(bool)), + TagPushEvents: gitlab.Bool(d.Get("tag_push_events").(bool)), + NoteEvents: gitlab.Bool(d.Get("note_events").(bool)), + ConfidentialNoteEvents: gitlab.Bool(d.Get("confidential_note_events").(bool)), + JobEvents: gitlab.Bool(d.Get("job_events").(bool)), + PipelineEvents: gitlab.Bool(d.Get("pipeline_events").(bool)), + WikiPageEvents: gitlab.Bool(d.Get("wiki_page_events").(bool)), + DeploymentEvents: gitlab.Bool(d.Get("deployment_events").(bool)), + ReleasesEvents: gitlab.Bool(d.Get("releases_events").(bool)), + SubGroupEvents: gitlab.Bool(d.Get("subgroup_events").(bool)), + EnableSSLVerification: gitlab.Bool(d.Get("enable_ssl_verification").(bool)), + } + + if d.HasChange("token") { + options.Token = gitlab.String(d.Get("token").(string)) + } + + log.Printf("[DEBUG] update gitlab group hook %s", d.Id()) + + _, _, err = client.Groups.EditGroupHook(group, hookID, options, gitlab.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + + return resourceGitlabGroupHookRead(ctx, d, meta) +} + +func resourceGitlabGroupHookDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + group, hookID, err := resourceGitlabGroupHookParseID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + log.Printf("[DEBUG] Delete gitlab group hook %s/%d", group, hookID) + + client := meta.(*gitlab.Client) + _, err = client.Groups.DeleteGroupHook(group, hookID, gitlab.WithContext(ctx)) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceGitlabGroupHookBuildID(group string, agentID int) string { + return fmt.Sprintf("%s:%d", group, agentID) +} + +func resourceGitlabGroupHookParseID(id string) (string, int, error) { + groupID, rawHookID, err := parseTwoPartID(id) + if err != nil { + return "", 0, err + } + + hookID, err := strconv.Atoi(rawHookID) + if err != nil { + return "", 0, err + } + + return groupID, hookID, nil +} diff --git a/internal/provider/resource_gitlab_group_hook_test.go b/internal/provider/resource_gitlab_group_hook_test.go new file mode 100644 index 000000000..b3885435b --- /dev/null +++ b/internal/provider/resource_gitlab_group_hook_test.go @@ -0,0 +1,113 @@ +//go:build acceptance +// +build acceptance + +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccGitlabGroupHook_basic(t *testing.T) { + testAccCheckEE(t) + + testGroup := testAccCreateGroups(t, 1)[0] + + resource.ParallelTest(t, resource.TestCase{ + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckGitlabGroupHookDestroy, + Steps: []resource.TestStep{ + // Create a Group Hook with required attributes only + { + Config: fmt.Sprintf(` + resource "gitlab_group_hook" "this" { + group = "%s" + url = "http://example.com" + } + `, testGroup.FullPath), + }, + // Verify Import + { + ResourceName: "gitlab_group_hook.this", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"token"}, + }, + // Update Group Hook to set all attributes + { + Config: fmt.Sprintf(` + resource "gitlab_group_hook" "this" { + group = "%s" + url = "http://example.com" + + token = "supersecret" + enable_ssl_verification = false + push_events = true + push_events_branch_filter = "devel" + issues_events = false + confidential_issues_events = false + merge_requests_events = true + tag_push_events = true + note_events = true + confidential_note_events = true + job_events = true + pipeline_events = true + wiki_page_events = true + deployment_events = true + releases_events = true + subgroup_events = true + } + `, testGroup.FullPath), + }, + // Verify Import + { + ResourceName: "gitlab_group_hook.this", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"token"}, + }, + // Update Group Hook to defaults again + { + Config: fmt.Sprintf(` + resource "gitlab_group_hook" "this" { + group = "%s" + url = "http://example.com" + } + `, testGroup.FullPath), + }, + // Verify Import + { + ResourceName: "gitlab_group_hook.this", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"token"}, + }, + }, + }) +} + +func testAccCheckGitlabGroupHookDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "gitlab_group_hook" { + continue + } + + group, hookID, err := resourceGitlabGroupHookParseID(rs.Primary.ID) + if err != nil { + return err + } + + _, _, err = testGitlabClient.Groups.GetGroupHook(group, hookID) + if err == nil { + return fmt.Errorf("Group Hook %d in group %s still exists", hookID, group) + } + if !is404(err) { + return err + } + return nil + } + return nil +} diff --git a/internal/provider/schema_gitlab_group_hook.go b/internal/provider/schema_gitlab_group_hook.go new file mode 100644 index 000000000..2b012d99e --- /dev/null +++ b/internal/provider/schema_gitlab_group_hook.go @@ -0,0 +1,150 @@ +package provider + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/xanzy/go-gitlab" +) + +func gitlabGroupHookSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "group": { + Description: "The ID or full path of the group.", + Type: schema.TypeString, + Required: true, + }, + "group_id": { + Description: "The id of the group for the hook.", + Type: schema.TypeInt, + Computed: true, + }, + "hook_id": { + Description: "The id of the group hook.", + Type: schema.TypeInt, + Computed: true, + }, + "url": { + Description: "The url of the hook to invoke.", + Type: schema.TypeString, + Required: true, + }, + "token": { + Description: "A token to present when invoking the hook. The token is not available for imported resources.", + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + "push_events": { + Description: "Invoke the hook for push events.", + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "push_events_branch_filter": { + Description: "Invoke the hook for push events on matching branches only.", + Type: schema.TypeString, + Optional: true, + }, + "issues_events": { + Description: "Invoke the hook for issues events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "confidential_issues_events": { + Description: "Invoke the hook for confidential issues events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "merge_requests_events": { + Description: "Invoke the hook for merge requests.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "tag_push_events": { + Description: "Invoke the hook for tag push events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "note_events": { + Description: "Invoke the hook for notes events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "confidential_note_events": { + Description: "Invoke the hook for confidential notes events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "job_events": { + Description: "Invoke the hook for job events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "pipeline_events": { + Description: "Invoke the hook for pipeline events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "wiki_page_events": { + Description: "Invoke the hook for wiki page events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "deployment_events": { + Description: "Invoke the hook for deployment events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "releases_events": { + Description: "Invoke the hook for releases events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "subgroup_events": { + Description: "Invoke the hook for subgroup events.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "enable_ssl_verification": { + Description: "Enable ssl verification when invoking the hook.", + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + } +} + +func gitlabGroupHookToStateMap(group string, hook *gitlab.GroupHook) map[string]interface{} { + stateMap := make(map[string]interface{}) + stateMap["group"] = group + stateMap["group_id"] = hook.GroupID + stateMap["hook_id"] = hook.ID + stateMap["url"] = hook.URL + stateMap["push_events"] = hook.PushEvents + stateMap["push_events_branch_filter"] = hook.PushEventsBranchFilter + stateMap["issues_events"] = hook.IssuesEvents + stateMap["confidential_issues_events"] = hook.ConfidentialIssuesEvents + stateMap["merge_requests_events"] = hook.MergeRequestsEvents + stateMap["tag_push_events"] = hook.TagPushEvents + stateMap["note_events"] = hook.NoteEvents + stateMap["confidential_note_events"] = hook.ConfidentialNoteEvents + stateMap["job_events"] = hook.JobEvents + stateMap["pipeline_events"] = hook.PipelineEvents + stateMap["wiki_page_events"] = hook.WikiPageEvents + stateMap["deployment_events"] = hook.DeploymentEvents + stateMap["releases_events"] = hook.ReleasesEvents + stateMap["subgroup_events"] = hook.SubGroupEvents + stateMap["enable_ssl_verification"] = hook.EnableSSLVerification + return stateMap +}