Skip to content

Commit

Permalink
provider/gitlab: Add gitlab_group resource
Browse files Browse the repository at this point in the history
This adds a gitlab_group resource.

This combined with #14483 will allow you to create projects in a
group.

The implementation of this is a little ugly as go-gitlab doesn't have a
function already present for EditGroup, so we hack it into being as part
of the implementation of resourceGitlabGroupUpdate
  • Loading branch information
richardc committed May 19, 2017
1 parent 0a986e4 commit 4a48ea3
Show file tree
Hide file tree
Showing 4 changed files with 381 additions and 0 deletions.
1 change: 1 addition & 0 deletions builtin/providers/gitlab/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func Provider() terraform.ResourceProvider {
},
},
ResourcesMap: map[string]*schema.Resource{
"gitlab_group": resourceGitlabGroup(),
"gitlab_project": resourceGitlabProject(),
"gitlab_project_hook": resourceGitlabProjectHook(),
},
Expand Down
153 changes: 153 additions & 0 deletions builtin/providers/gitlab/resource_gitlab_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package gitlab

import (
"fmt"
"log"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
gitlab "github.com/xanzy/go-gitlab"
)

func resourceGitlabGroup() *schema.Resource {
return &schema.Resource{
Create: resourceGitlabGroupCreate,
Read: resourceGitlabGroupRead,
Update: resourceGitlabGroupUpdate,
Delete: resourceGitlabGroupDelete,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"path": {
Type: schema.TypeString,
Required: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
"lfs_enabled": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
"request_access_enabled": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"visibility_level": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"private", "internal", "public"}, true),
Default: "private",
},
},
}
}

func resourceGitlabGroupCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
options := &gitlab.CreateGroupOptions{
Name: gitlab.String(d.Get("name").(string)),
LFSEnabled: gitlab.Bool(d.Get("lfs_enabled").(bool)),
RequestAccessEnabled: gitlab.Bool(d.Get("request_access_enabled").(bool)),
}

if v, ok := d.GetOk("path"); ok {
options.Path = gitlab.String(v.(string))
}

if v, ok := d.GetOk("description"); ok {
options.Description = gitlab.String(v.(string))
}

if v, ok := d.GetOk("visibility_level"); ok {
options.VisibilityLevel = stringToVisibilityLevel(v.(string))
}

log.Printf("[DEBUG] create gitlab group %q", options.Name)

group, _, err := client.Groups.CreateGroup(options)
if err != nil {
return err
}

d.SetId(fmt.Sprintf("%d", group.ID))

return resourceGitlabGroupRead(d, meta)
}

func resourceGitlabGroupRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
log.Printf("[DEBUG] read gitlab group %s", d.Id())

group, response, err := client.Groups.GetGroup(d.Id())
if err != nil {
if response.StatusCode == 404 {
log.Printf("[WARN] removing group %s from state because it no longer exists in gitlab", d.Id())
d.SetId("")
return nil
}

return err
}

d.Set("name", group.Name)
d.Set("path", group.Path)
d.Set("description", group.Description)
d.Set("lfs_enabled", group.LFSEnabled)
d.Set("request_access_enabled", group.RequestAccessEnabled)

return nil
}

func resourceGitlabGroupUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)

options := &gitlab.UpdateGroupOptions{}

if d.HasChange("name") {
options.Name = gitlab.String(d.Get("name").(string))
}

if d.HasChange("path") {
options.Path = gitlab.String(d.Get("path").(string))
}

if d.HasChange("description") {
options.Description = gitlab.String(d.Get("description").(string))
}

if d.HasChange("lfs_enabled") {
options.LFSEnabled = gitlab.Bool(d.Get("lfs_enabled").(bool))
}

if d.HasChange("request_access_enabled") {
options.RequestAccessEnabled = gitlab.Bool(d.Get("request_access_enabled").(bool))
}

if d.HasChange("visibility_level") {
options.VisibilityLevel = stringToVisibilityLevel(d.Get("visibility_level").(string))
}

log.Printf("[DEBUG] update gitlab group %s", d.Id())

_, _, err := client.Groups.UpdateGroup(d.Id(), options)
if err != nil {
return err
}

return resourceGitlabGroupRead(d, meta)
}

func resourceGitlabGroupDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
log.Printf("[DEBUG] Delete gitlab group %s", d.Id())

_, err := client.Groups.DeleteGroup(d.Id())
return err
}
171 changes: 171 additions & 0 deletions builtin/providers/gitlab/resource_gitlab_group_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package gitlab

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/xanzy/go-gitlab"
)

func TestAccGitlabGroup_basic(t *testing.T) {
var group gitlab.Group
rInt := acctest.RandInt()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckGitlabGroupDestroy,
Steps: []resource.TestStep{
// Create a group
{
Config: testAccGitlabGroupConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabGroupExists("gitlab_group.foo", &group),
testAccCheckGitlabGroupAttributes(&group, &testAccGitlabGroupExpectedAttributes{
Name: fmt.Sprintf("foo-name-%d", rInt),
Path: fmt.Sprintf("foo-path-%d", rInt),
Description: "Terraform acceptance tests",
LFSEnabled: true,
}),
),
},
// Update the group to change the description
{
Config: testAccGitlabGroupUpdateConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabGroupExists("gitlab_group.foo", &group),
testAccCheckGitlabGroupAttributes(&group, &testAccGitlabGroupExpectedAttributes{
Name: fmt.Sprintf("bar-name-%d", rInt),
Path: fmt.Sprintf("bar-path-%d", rInt),
Description: "Terraform acceptance tests! Updated description",
RequestAccessEnabled: true,
}),
),
},
// Update the group to put the anem and description back
{
Config: testAccGitlabGroupConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabGroupExists("gitlab_group.foo", &group),
testAccCheckGitlabGroupAttributes(&group, &testAccGitlabGroupExpectedAttributes{
Name: fmt.Sprintf("foo-name-%d", rInt),
Path: fmt.Sprintf("foo-path-%d", rInt),
Description: "Terraform acceptance tests",
LFSEnabled: true,
}),
),
},
},
})
}

func testAccCheckGitlabGroupExists(n string, group *gitlab.Group) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not Found: %s", n)
}

groupID := rs.Primary.ID
if groupID == "" {
return fmt.Errorf("No group ID is set")
}
conn := testAccProvider.Meta().(*gitlab.Client)

gotGroup, _, err := conn.Groups.GetGroup(groupID)
if err != nil {
return err
}
*group = *gotGroup
return nil
}
}

type testAccGitlabGroupExpectedAttributes struct {
Name string
Path string
Description string
LFSEnabled bool
RequestAccessEnabled bool
}

func testAccCheckGitlabGroupAttributes(group *gitlab.Group, want *testAccGitlabGroupExpectedAttributes) resource.TestCheckFunc {
return func(s *terraform.State) error {
if group.Name != want.Name {
return fmt.Errorf("got repo %q; want %q", group.Name, want.Name)
}

if group.Path != want.Path {
return fmt.Errorf("got path %q; want %q", group.Path, want.Path)
}

if group.Description != want.Description {
return fmt.Errorf("got description %q; want %q", group.Description, want.Description)
}

if group.LFSEnabled != want.LFSEnabled {
return fmt.Errorf("got lfs_enabled %t; want %t", group.LFSEnabled, want.LFSEnabled)
}

if group.RequestAccessEnabled != want.RequestAccessEnabled {
return fmt.Errorf("got request_access_enabled %t; want %t", group.RequestAccessEnabled, want.RequestAccessEnabled)
}

return nil
}
}

func testAccCheckGitlabGroupDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*gitlab.Client)

for _, rs := range s.RootModule().Resources {
if rs.Type != "gitlab_group" {
continue
}

group, resp, err := conn.Groups.GetGroup(rs.Primary.ID)
if err == nil {
if group != nil && fmt.Sprintf("%d", group.ID) == rs.Primary.ID {
return fmt.Errorf("Group still exists")
}
}
if resp.StatusCode != 404 {
return err
}
return nil
}
return nil
}

func testAccGitlabGroupConfig(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_group" "foo" {
name = "foo-name-%d"
path = "foo-path-%d"
description = "Terraform acceptance tests"
# So that acceptance tests can be run in a gitlab organization
# with no billing
visibility_level = "public"
}
`, rInt, rInt)
}

func testAccGitlabGroupUpdateConfig(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_group" "foo" {
name = "bar-name-%d"
path = "bar-path-%d"
description = "Terraform acceptance tests! Updated description"
lfs_enabled = false
request_access_enabled = true
# So that acceptance tests can be run in a gitlab organization
# with no billing
visibility_level = "public"
}
`, rInt, rInt)
}
56 changes: 56 additions & 0 deletions website/source/docs/providers/gitlab/r/group.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
layout: "gitlab"
page_title: "GitLab: gitlab_group"
sidebar_current: "docs-gitlab-resource-group"
description: |-
Creates and manages GitLab groups
---

# gitlab\_group

This resource allows you to create and manage GitLab groups.
Note your provider will need to be configured with admin-level access for this resource to work.

## Example Usage

```hcl
resource "gitlab_group" "example" {
name = "example"
path = "example"
description = "An example group"
}
// Create a project in the example group
resource "gitlab_project" "example" {
name = "example"
description = "An example project"
namespace_id = "${gitlab_group.example.id}"
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of this group.

* `path` - (Required) The url of the hook to invoke.

* `description` - (Optional) The description of the group.

* `lfs_enabled` - (Optional) Boolean, defaults to true. Whether to enable LFS
support for projects in this group.

* `request_access_enabled` - (Optional) Boolean, defaults to false. Whether to
enable users to request access to the group.

* `visibility_level` - (Optional) Set to `public` to create a public group.
Valid values are `private`, `internal`, `public`.
Groups are created as private by default.

## Attributes Reference

The resource exports the following attributes:

* `id` - The unique id assigned to the group by the GitLab server. Serves as a
namespace id where one is needed.

0 comments on commit 4a48ea3

Please sign in to comment.