Skip to content

Commit

Permalink
Add tag protection
Browse files Browse the repository at this point in the history
  • Loading branch information
bilby91 committed May 7, 2019
1 parent 7b87573 commit 4859ef1
Show file tree
Hide file tree
Showing 5 changed files with 320 additions and 1 deletion.
1 change: 1 addition & 0 deletions gitlab/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func Provider() terraform.ResourceProvider {

ResourcesMap: map[string]*schema.Resource{
"gitlab_branch_protection": resourceGitlabBranchProtection(),
"gitlab_tag_protection": resourceGitlabTagProtection(),
"gitlab_group": resourceGitlabGroup(),
"gitlab_project": resourceGitlabProject(),
"gitlab_label": resourceGitlabLabel(),
Expand Down
121 changes: 121 additions & 0 deletions gitlab/resource_gitlab_tag_protection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package gitlab

import (
"log"
"net/url"

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

func resourceGitlabTagProtection() *schema.Resource {
acceptedAccessLevels := make([]string, 0, len(accessLevelID))

for k := range accessLevelID {
acceptedAccessLevels = append(acceptedAccessLevels, k)
}
return &schema.Resource{
Create: resourceGitlabTagProtectionCreate,
Read: resourceGitlabTagProtectionRead,
Delete: resourceGitlabTagProtectionDelete,
Schema: map[string]*schema.Schema{
"project": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"tag": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
},
"create_access_level": {
Type: schema.TypeString,
ValidateFunc: validateValueFunc(acceptedAccessLevels),
Required: true,
ForceNew: true,
},
},
}
}

func resourceGitlabTagProtectionCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
project := d.Get("project").(string)
tag := gitlab.String(d.Get("tag").(string))
createAccessLevel := accessLevelID[d.Get("create_access_level").(string)]

options := &gitlab.ProtectRepositoryTagsOptions{
Name: tag,
CreateAccessLevel: &createAccessLevel,
}

log.Printf("[DEBUG] create gitlab tag protection on %v for project %s", options.Name, project)

tp, _, err := client.ProtectedTags.ProtectRepositoryTags(project, options)
if err != nil {
// Remove existing tag protection
_, err = client.ProtectedTags.UnprotectRepositoryTags(project, url.PathEscape(*tag))
if err != nil {
return err
}
// Reprotect tag with updated values
tp, _, err = client.ProtectedTags.ProtectRepositoryTags(project, options)
if err != nil {
return err
}
}

d.SetId(buildTwoPartID(&project, &tp.Name))

return resourceGitlabTagProtectionRead(d, meta)
}

func resourceGitlabTagProtectionRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
project, tag, err := projectAndTagFromID(d.Id())
if err != nil {
return err
}

log.Printf("[DEBUG] read gitlab tag protection for project %s, tag %s", project, tag)

pt, response, err := client.ProtectedTags.GetProtectedTag(project, url.PathEscape(tag))
if err != nil {
if response.StatusCode == 404 {
log.Printf("[WARN] removing project tag protection %s from state because it no longer exists in gitlab", tag)
d.SetId("")
return nil
}

return err
}

d.Set("project", project)
d.Set("tag", pt.Name)
d.Set("create_access_level", pt.CreateAccessLevels[0].AccessLevel)

d.SetId(buildTwoPartID(&project, &pt.Name))

return nil
}

func resourceGitlabTagProtectionDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
project := d.Get("project").(string)
tag := d.Get("tag").(string)

log.Printf("[DEBUG] Delete gitlab protected tag %s for project %s", tag, project)

_, err := client.ProtectedTags.UnprotectRepositoryTags(project, url.PathEscape(tag))
return err
}

func projectAndTagFromID(id string) (string, string, error) {
project, tag, err := parseTwoPartID(id)

if err != nil {
log.Printf("[WARN] cannot get group member id from input: %v", id)
}
return project, tag, err
}
166 changes: 166 additions & 0 deletions gitlab/resource_gitlab_tag_protection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
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 TestAccGitlabTagProtection_basic(t *testing.T) {

var pt gitlab.ProtectedTag
rInt := acctest.RandInt()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckGitlabTagProtectionDestroy,
Steps: []resource.TestStep{
// Create a project and Tag Protection with default options
{
Config: testAccGitlabTagProtectionConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabTagProtectionExists("gitlab_tag_protection.TagProtect", &pt),
testAccCheckGitlabTagProtectionAttributes(&pt, &testAccGitlabTagProtectionExpectedAttributes{
Name: fmt.Sprintf("TagProtect-%d", rInt),
CreateAccessLevel: accessLevel[gitlab.DeveloperPermissions],
}),
),
},
// Update the Tag Protection
{
Config: testAccGitlabTagProtectionUpdateConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabTagProtectionExists("gitlab_tag_protection.TagProtect", &pt),
testAccCheckGitlabTagProtectionAttributes(&pt, &testAccGitlabTagProtectionExpectedAttributes{
Name: fmt.Sprintf("TagProtect-%d", rInt),
CreateAccessLevel: accessLevel[gitlab.MasterPermissions],
}),
),
},
// Update the Tag Protection to get back to initial settings
{
Config: testAccGitlabTagProtectionConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabTagProtectionExists("gitlab_tag_protection.TagProtect", &pt),
testAccCheckGitlabTagProtectionAttributes(&pt, &testAccGitlabTagProtectionExpectedAttributes{
Name: fmt.Sprintf("TagProtect-%d", rInt),
CreateAccessLevel: accessLevel[gitlab.DeveloperPermissions],
}),
),
},
},
})
}

func testAccCheckGitlabTagProtectionExists(n string, pt *gitlab.ProtectedTag) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not Found: %s", n)
}
project, tag, err := projectAndTagFromID(rs.Primary.ID)
if err != nil {
return fmt.Errorf("Error in Splitting Project and Tag Ids")
}

conn := testAccProvider.Meta().(*gitlab.Client)

pts, _, err := conn.ProtectedTags.ListProtectedTags(project, nil)
if err != nil {
return err
}
for _, gotpt := range pts {
if gotpt.Name == tag {
*pt = *gotpt
return nil
}
}
return fmt.Errorf("Protected Tag does not exist")
}
}

type testAccGitlabTagProtectionExpectedAttributes struct {
Name string
CreateAccessLevel string
}

func testAccCheckGitlabTagProtectionAttributes(pt *gitlab.ProtectedTag, want *testAccGitlabTagProtectionExpectedAttributes) resource.TestCheckFunc {
return func(s *terraform.State) error {
if pt.Name != want.Name {
return fmt.Errorf("got name %q; want %q", pt.Name, want.Name)
}

if pt.CreateAccessLevels[0].AccessLevel != accessLevelID[want.CreateAccessLevel] {
return fmt.Errorf("got Create access levels %q; want %q", pt.CreateAccessLevels[0].AccessLevel, accessLevelID[want.CreateAccessLevel])
}

return nil
}
}

func testAccCheckGitlabTagProtectionDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*gitlab.Client)
var project string
var tag string
for _, rs := range s.RootModule().Resources {
if rs.Type == "gitlab_project" {
project = rs.Primary.ID
} else if rs.Type == "gitlab_tag_protection" {
tag = rs.Primary.ID
}
}

pt, response, err := conn.ProtectedTags.GetProtectedTag(project, tag)
if err == nil {
if pt != nil {
return fmt.Errorf("project tag protection %s still exists", tag)
}
}
if response.StatusCode != 404 {
return err
}
return nil
}

func testAccGitlabTagProtectionConfig(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_project" "foo" {
name = "foo-%d"
description = "Terraform acceptance tests"
# So that acceptance tests can be run in a gitlab organization
# with no billing
visibility_level = "public"
}
resource "gitlab_tag_protection" "TagProtect" {
project = "${gitlab_project.foo.id}"
tag = "TagProtect-%d"
create_access_level = "developer"
}
`, rInt, rInt)
}

func testAccGitlabTagProtectionUpdateConfig(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_project" "foo" {
name = "foo-%d"
description = "Terraform acceptance tests"
# So that acceptance tests can be run in a gitlab organization
# with no billing
visibility_level = "public"
}
resource "gitlab_tag_protection" "TagProtect" {
project = "${gitlab_project.foo.id}"
tag = "TagProtect-%d"
create_access_level = "maintainer"
}
`, rInt, rInt)
}
2 changes: 1 addition & 1 deletion website/docs/r/branch_protection.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: |-

# gitlab\_branch_protection

This resource allows you to protect a specific branch by an access level so that the user with less access level cannot Merge/Push to the branch.
This resource allows you to protect a specific branch by an access level so that the user with less access level cannot Merge/Push to the branch. GitLab EE features to protect by group or user are not supported.

## Example Usage

Expand Down
31 changes: 31 additions & 0 deletions website/docs/r/tag_protection.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
layout: "gitlab"
page_title: "GitLab: gitlab_tag_protection"
sidebar_current: "docs-gitlab-resource-tag_protection"
description: |-
Protects a tag by assigning access levels to it
---

# gitlab\_tag\_protection

This resource allows you to protect a specific tag or wildcard by an access level so that the user with less access level cannot Create the tags.

## Example Usage

```hcl
resource "gitlab_tag_protection" "TagProtect" {
project = "12345"
tag = "TagProtected"
create_access_level = "developer"
}
```

## Argument Reference

The following arguments are supported:

* `project` - (Required) The id of the project.

* `tag` - (Required) Name of the tag or wildcard.

* `create_access_level` - (Required) One of five levels of access to the project.

0 comments on commit 4859ef1

Please sign in to comment.