Skip to content

Commit

Permalink
Add resource for project freeze periods (#516)
Browse files Browse the repository at this point in the history
  • Loading branch information
zk-kb4 authored Jan 28, 2021
1 parent 0c64a2b commit da8bba8
Show file tree
Hide file tree
Showing 5 changed files with 358 additions and 1 deletion.
35 changes: 35 additions & 0 deletions docs/resources/project_freeze_period.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# gitlab_project_freeze_period

This resource allows you to create and manage freeze periods. For further information on freeze periods, consult the [gitlab documentation](https://docs.gitlab.com/ee/api/freeze_periods.html#create-a-freeze-period).

## Example Usage

```hcl
resource "gitlab_project_freeze_period" "schedule" {
project_id = gitlab_project.foo.id
freeze_start = "0 23 * * 5"
freeze_end = "0 7 * * 1"
cron_timezone = "UTC"
}
```

## Argument Reference

The following arguments are supported:

* `project_id` - (Required, string) The id of the project to add the schedule to.

* `freeze_start` - (Required,string) Start of the Freeze Period in cron format (e.g. `0 1 * * *`).

* `freeze_end` - (Required, string) End of the Freeze Period in cron format (e.g. `0 2 * * *`).

* `cron_timezone` - (Optional, string) The timezone.

## Import

GitLab project freeze periods can be imported using an id made up of `project_id:freeze_period_id`, e.g.


```
$ terraform import gitlab_project_freeze_period.schedule "12345:1337"
```
1 change: 1 addition & 0 deletions gitlab/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func Provider() terraform.ResourceProvider {
"gitlab_project_level_mr_approvals": resourceGitlabProjectLevelMRApprovals(),
"gitlab_project_approval_rule": resourceGitlabProjectApprovalRule(),
"gitlab_instance_variable": resourceGitlabInstanceVariable(),
"gitlab_project_freeze_period": resourceGitlabProjectFreezePeriod(),
"gitlab_group_share_group": resourceGitlabGroupShareGroup(),
},
}
Expand Down
154 changes: 154 additions & 0 deletions gitlab/resource_gitlab_project_freeze_period.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package gitlab

import (
"fmt"
"log"
"net/http"
"strconv"

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

func resourceGitlabProjectFreezePeriod() *schema.Resource {
return &schema.Resource{
Create: resourceGitlabProjectFreezePeriodCreate,
Read: resourceGitlabProjectFreezePeriodRead,
Update: resourceGitlabProjectFreezePeriodUpdate,
Delete: resourceGitlabProjectFreezePeriodDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"project_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"freeze_start": {
Type: schema.TypeString,
Required: true,
},
"freeze_end": {
Type: schema.TypeString,
Required: true,
},
"cron_timezone": {
Type: schema.TypeString,
Optional: true,
Default: "UTC",
},
},
}
}

func resourceGitlabProjectFreezePeriodCreate(d *schema.ResourceData, meta interface{}) error {
projectID := d.Get("project_id").(string)

options := gitlab.CreateFreezePeriodOptions{
FreezeStart: gitlab.String(d.Get("freeze_start").(string)),
FreezeEnd: gitlab.String(d.Get("freeze_end").(string)),
CronTimezone: gitlab.String(d.Get("cron_timezone").(string)),
}

log.Printf("[DEBUG] Project %s create gitlab project-level freeze period %+v", projectID, options)

client := meta.(*gitlab.Client)
FreezePeriod, _, err := client.FreezePeriods.CreateFreezePeriodOptions(projectID, &options)
if err != nil {
return err
}

FreezePeriodIDString := fmt.Sprintf("%d", FreezePeriod.ID)
d.SetId(buildTwoPartID(&projectID, &FreezePeriodIDString))

return resourceGitlabProjectFreezePeriodRead(d, meta)
}

func resourceGitlabProjectFreezePeriodRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
projectID, freezePeriodID, err := projectIDAndFreezePeriodIDFromID(d.Id())
if err != nil {
return err
}

log.Printf("[DEBUG] read gitlab FreezePeriod %s/%d", projectID, freezePeriodID)

freezePeriod, resp, err := client.FreezePeriods.GetFreezePeriod(projectID, freezePeriodID)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
log.Printf("[DEBUG] project freeze period for %s not found so removing it from state", d.Id())
d.SetId("")
return nil
}
return err
}

d.Set("freeze_start", freezePeriod.FreezeStart)
d.Set("freeze_end", freezePeriod.FreezeEnd)
d.Set("cron_timezone", freezePeriod.CronTimezone)
d.Set("project_id", projectID)

return nil
}

func resourceGitlabProjectFreezePeriodUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
projectID, freezePeriodID, err := projectIDAndFreezePeriodIDFromID(d.Id())
options := &gitlab.UpdateFreezePeriodOptions{}

if err != nil {
return fmt.Errorf("%s cannot be converted to int", d.Id())
}

if d.HasChange("freeze_start") {
options.FreezeStart = gitlab.String(d.Get("freeze_start").(string))
}

if d.HasChange("freeze_end") {
options.FreezeEnd = gitlab.String(d.Get("freeze_end").(string))
}

if d.HasChange("cron_timezone") {
options.CronTimezone = gitlab.String(d.Get("cron_timezone").(string))
}

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

_, _, err = client.FreezePeriods.UpdateFreezePeriodOptions(projectID, freezePeriodID, options)
if err != nil {
return err
}

return resourceGitlabProjectFreezePeriodRead(d, meta)
}

func resourceGitlabProjectFreezePeriodDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
projectID, freezePeriodID, err := projectIDAndFreezePeriodIDFromID(d.Id())
log.Printf("[DEBUG] Delete gitlab FreezePeriod %s", d.Id())

if err != nil {
return fmt.Errorf("%s cannot be converted to int", d.Id())
}

if _, err = client.FreezePeriods.DeleteFreezePeriod(projectID, freezePeriodID); err != nil {
return fmt.Errorf("failed to delete pipeline schedule %q: %w", d.Id(), err)
}

return nil
}

func projectIDAndFreezePeriodIDFromID(id string) (string, int, error) {
project, freezePeriodIDString, err := parseTwoPartID(id)
if err != nil {
return "", 0, err
}

freezePeriodID, err := strconv.Atoi(freezePeriodIDString)
if err != nil {
return "", 0, fmt.Errorf("failed to get freezePeriodId: %v", err)
}

return project, freezePeriodID, nil
}
167 changes: 167 additions & 0 deletions gitlab/resource_gitlab_project_freeze_period_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package gitlab

import (
"fmt"
"testing"

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

func TestAccGitlabProjectFreezePeriod_basic(t *testing.T) {
var schedule gitlab.FreezePeriod
rInt := acctest.RandInt()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckGitlabProjectDestroy,
Steps: []resource.TestStep{
// Create a project and freeze period with default options
{
Config: testAccGitlabProjectFreezePeriodConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabProjectFreezePeriodExists("gitlab_project_freeze_period.schedule", &schedule),
testAccCheckGitlabProjectFreezePeriodAttributes(&schedule, &testAccGitlabProjectFreezePeriodExpectedAttributes{
FreezeStart: "0 23 * * 5",
FreezeEnd: "0 7 * * 1",
CronTimezone: "UTC",
}),
),
},
// Update the freeze period to change the parameters
{
Config: testAccGitlabProjectFreezePeriodUpdateConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabProjectFreezePeriodExists("gitlab_project_freeze_period.schedule", &schedule),
testAccCheckGitlabProjectFreezePeriodAttributes(&schedule, &testAccGitlabProjectFreezePeriodExpectedAttributes{
FreezeStart: "0 20 * * 6",
FreezeEnd: "0 7 * * 3",
CronTimezone: "EST",
}),
),
},
// Update the freeze period to get back to initial settings
{
Config: testAccGitlabProjectFreezePeriodConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabProjectFreezePeriodExists("gitlab_project_freeze_period.schedule", &schedule),
testAccCheckGitlabProjectFreezePeriodAttributes(&schedule, &testAccGitlabProjectFreezePeriodExpectedAttributes{
FreezeStart: "0 23 * * 5",
FreezeEnd: "0 7 * * 1",
CronTimezone: "UTC",
}),
),
},
},
})
}

func TestAccGitlabProjectFreezePeriod_import(t *testing.T) {
rInt := acctest.RandInt()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckGitlabProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccGitlabProjectFreezePeriodConfig(rInt),
},
{
ResourceName: "gitlab_project_freeze_period.schedule",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

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

projectID, freezePeriodID, err := projectIDAndFreezePeriodIDFromID(rs.Primary.ID)
if err != nil {
return err
}

conn := testAccProvider.Meta().(*gitlab.Client)
gotFreezePeriod, _, err := conn.FreezePeriods.GetFreezePeriod(projectID, freezePeriodID)
if err != nil {
return err
}

*freezePeriod = *gotFreezePeriod

return nil
}
}

type testAccGitlabProjectFreezePeriodExpectedAttributes struct {
FreezeStart string
FreezeEnd string
CronTimezone string
}

func testAccCheckGitlabProjectFreezePeriodAttributes(freezePeriod *gitlab.FreezePeriod, want *testAccGitlabProjectFreezePeriodExpectedAttributes) resource.TestCheckFunc {
return func(s *terraform.State) error {
if freezePeriod.FreezeStart != want.FreezeStart {
return fmt.Errorf("got freeze_start %q; want %q", freezePeriod.FreezeStart, want.FreezeStart)
}
if freezePeriod.FreezeEnd != want.FreezeEnd {
return fmt.Errorf("got freeze_end %q; want %q", freezePeriod.FreezeEnd, want.FreezeEnd)
}

if freezePeriod.CronTimezone != want.CronTimezone {
return fmt.Errorf("got cron_timezone %q; want %q", freezePeriod.CronTimezone, want.CronTimezone)
}

return nil
}
}

func testAccGitlabProjectFreezePeriodConfig(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_project_freeze_period" "schedule" {
project_id = gitlab_project.foo.id
freeze_start = "0 23 * * 5"
freeze_end = "0 7 * * 1"
cron_timezone = "UTC"
}
`, rInt)
}

func testAccGitlabProjectFreezePeriodUpdateConfig(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_project_freeze_period" "schedule" {
project_id = gitlab_project.foo.id
freeze_start = "0 20 * * 6"
freeze_end = "0 7 * * 3"
cron_timezone = "EST"
}
`, rInt)
}
2 changes: 1 addition & 1 deletion gitlab/resource_gitlab_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ func testAccGitlabProjectConfigDefaultBranchSkipFunc(project *gitlab.Project, de
return func() (bool, error) {
conn := testAccProvider.Meta().(*gitlab.Client)

// Commit data
commitMessage := "Initial Commit"
commitFile := "file.txt"
commitFileAction := gitlab.FileCreate
Expand All @@ -876,7 +877,6 @@ func testAccGitlabProjectConfigDefaultBranchSkipFunc(project *gitlab.Project, de
Content: &commitMessage,
},
}

options := &gitlab.CreateCommitOptions{
Branch: &defaultBranch,
CommitMessage: &commitMessage,
Expand Down

0 comments on commit da8bba8

Please sign in to comment.