Skip to content

Commit da8bba8

Browse files
authored
Add resource for project freeze periods (#516)
1 parent 0c64a2b commit da8bba8

File tree

5 files changed

+358
-1
lines changed

5 files changed

+358
-1
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# gitlab_project_freeze_period
2+
3+
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).
4+
5+
## Example Usage
6+
7+
```hcl
8+
resource "gitlab_project_freeze_period" "schedule" {
9+
project_id = gitlab_project.foo.id
10+
freeze_start = "0 23 * * 5"
11+
freeze_end = "0 7 * * 1"
12+
cron_timezone = "UTC"
13+
}
14+
```
15+
16+
## Argument Reference
17+
18+
The following arguments are supported:
19+
20+
* `project_id` - (Required, string) The id of the project to add the schedule to.
21+
22+
* `freeze_start` - (Required,string) Start of the Freeze Period in cron format (e.g. `0 1 * * *`).
23+
24+
* `freeze_end` - (Required, string) End of the Freeze Period in cron format (e.g. `0 2 * * *`).
25+
26+
* `cron_timezone` - (Optional, string) The timezone.
27+
28+
## Import
29+
30+
GitLab project freeze periods can be imported using an id made up of `project_id:freeze_period_id`, e.g.
31+
32+
33+
```
34+
$ terraform import gitlab_project_freeze_period.schedule "12345:1337"
35+
```

gitlab/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func Provider() terraform.ResourceProvider {
9595
"gitlab_project_level_mr_approvals": resourceGitlabProjectLevelMRApprovals(),
9696
"gitlab_project_approval_rule": resourceGitlabProjectApprovalRule(),
9797
"gitlab_instance_variable": resourceGitlabInstanceVariable(),
98+
"gitlab_project_freeze_period": resourceGitlabProjectFreezePeriod(),
9899
"gitlab_group_share_group": resourceGitlabGroupShareGroup(),
99100
},
100101
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package gitlab
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"net/http"
7+
"strconv"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
10+
gitlab "github.com/xanzy/go-gitlab"
11+
)
12+
13+
func resourceGitlabProjectFreezePeriod() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceGitlabProjectFreezePeriodCreate,
16+
Read: resourceGitlabProjectFreezePeriodRead,
17+
Update: resourceGitlabProjectFreezePeriodUpdate,
18+
Delete: resourceGitlabProjectFreezePeriodDelete,
19+
Importer: &schema.ResourceImporter{
20+
State: schema.ImportStatePassthrough,
21+
},
22+
Schema: map[string]*schema.Schema{
23+
"project_id": {
24+
Type: schema.TypeString,
25+
Required: true,
26+
ForceNew: true,
27+
},
28+
"freeze_start": {
29+
Type: schema.TypeString,
30+
Required: true,
31+
},
32+
"freeze_end": {
33+
Type: schema.TypeString,
34+
Required: true,
35+
},
36+
"cron_timezone": {
37+
Type: schema.TypeString,
38+
Optional: true,
39+
Default: "UTC",
40+
},
41+
},
42+
}
43+
}
44+
45+
func resourceGitlabProjectFreezePeriodCreate(d *schema.ResourceData, meta interface{}) error {
46+
projectID := d.Get("project_id").(string)
47+
48+
options := gitlab.CreateFreezePeriodOptions{
49+
FreezeStart: gitlab.String(d.Get("freeze_start").(string)),
50+
FreezeEnd: gitlab.String(d.Get("freeze_end").(string)),
51+
CronTimezone: gitlab.String(d.Get("cron_timezone").(string)),
52+
}
53+
54+
log.Printf("[DEBUG] Project %s create gitlab project-level freeze period %+v", projectID, options)
55+
56+
client := meta.(*gitlab.Client)
57+
FreezePeriod, _, err := client.FreezePeriods.CreateFreezePeriodOptions(projectID, &options)
58+
if err != nil {
59+
return err
60+
}
61+
62+
FreezePeriodIDString := fmt.Sprintf("%d", FreezePeriod.ID)
63+
d.SetId(buildTwoPartID(&projectID, &FreezePeriodIDString))
64+
65+
return resourceGitlabProjectFreezePeriodRead(d, meta)
66+
}
67+
68+
func resourceGitlabProjectFreezePeriodRead(d *schema.ResourceData, meta interface{}) error {
69+
client := meta.(*gitlab.Client)
70+
projectID, freezePeriodID, err := projectIDAndFreezePeriodIDFromID(d.Id())
71+
if err != nil {
72+
return err
73+
}
74+
75+
log.Printf("[DEBUG] read gitlab FreezePeriod %s/%d", projectID, freezePeriodID)
76+
77+
freezePeriod, resp, err := client.FreezePeriods.GetFreezePeriod(projectID, freezePeriodID)
78+
if err != nil {
79+
if resp != nil && resp.StatusCode == http.StatusNotFound {
80+
log.Printf("[DEBUG] project freeze period for %s not found so removing it from state", d.Id())
81+
d.SetId("")
82+
return nil
83+
}
84+
return err
85+
}
86+
87+
d.Set("freeze_start", freezePeriod.FreezeStart)
88+
d.Set("freeze_end", freezePeriod.FreezeEnd)
89+
d.Set("cron_timezone", freezePeriod.CronTimezone)
90+
d.Set("project_id", projectID)
91+
92+
return nil
93+
}
94+
95+
func resourceGitlabProjectFreezePeriodUpdate(d *schema.ResourceData, meta interface{}) error {
96+
client := meta.(*gitlab.Client)
97+
projectID, freezePeriodID, err := projectIDAndFreezePeriodIDFromID(d.Id())
98+
options := &gitlab.UpdateFreezePeriodOptions{}
99+
100+
if err != nil {
101+
return fmt.Errorf("%s cannot be converted to int", d.Id())
102+
}
103+
104+
if d.HasChange("freeze_start") {
105+
options.FreezeStart = gitlab.String(d.Get("freeze_start").(string))
106+
}
107+
108+
if d.HasChange("freeze_end") {
109+
options.FreezeEnd = gitlab.String(d.Get("freeze_end").(string))
110+
}
111+
112+
if d.HasChange("cron_timezone") {
113+
options.CronTimezone = gitlab.String(d.Get("cron_timezone").(string))
114+
}
115+
116+
log.Printf("[DEBUG] update gitlab FreezePeriod %s", d.Id())
117+
118+
_, _, err = client.FreezePeriods.UpdateFreezePeriodOptions(projectID, freezePeriodID, options)
119+
if err != nil {
120+
return err
121+
}
122+
123+
return resourceGitlabProjectFreezePeriodRead(d, meta)
124+
}
125+
126+
func resourceGitlabProjectFreezePeriodDelete(d *schema.ResourceData, meta interface{}) error {
127+
client := meta.(*gitlab.Client)
128+
projectID, freezePeriodID, err := projectIDAndFreezePeriodIDFromID(d.Id())
129+
log.Printf("[DEBUG] Delete gitlab FreezePeriod %s", d.Id())
130+
131+
if err != nil {
132+
return fmt.Errorf("%s cannot be converted to int", d.Id())
133+
}
134+
135+
if _, err = client.FreezePeriods.DeleteFreezePeriod(projectID, freezePeriodID); err != nil {
136+
return fmt.Errorf("failed to delete pipeline schedule %q: %w", d.Id(), err)
137+
}
138+
139+
return nil
140+
}
141+
142+
func projectIDAndFreezePeriodIDFromID(id string) (string, int, error) {
143+
project, freezePeriodIDString, err := parseTwoPartID(id)
144+
if err != nil {
145+
return "", 0, err
146+
}
147+
148+
freezePeriodID, err := strconv.Atoi(freezePeriodIDString)
149+
if err != nil {
150+
return "", 0, fmt.Errorf("failed to get freezePeriodId: %v", err)
151+
}
152+
153+
return project, freezePeriodID, nil
154+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package gitlab
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
10+
gitlab "github.com/xanzy/go-gitlab"
11+
)
12+
13+
func TestAccGitlabProjectFreezePeriod_basic(t *testing.T) {
14+
var schedule gitlab.FreezePeriod
15+
rInt := acctest.RandInt()
16+
17+
resource.Test(t, resource.TestCase{
18+
PreCheck: func() { testAccPreCheck(t) },
19+
Providers: testAccProviders,
20+
CheckDestroy: testAccCheckGitlabProjectDestroy,
21+
Steps: []resource.TestStep{
22+
// Create a project and freeze period with default options
23+
{
24+
Config: testAccGitlabProjectFreezePeriodConfig(rInt),
25+
Check: resource.ComposeTestCheckFunc(
26+
testAccCheckGitlabProjectFreezePeriodExists("gitlab_project_freeze_period.schedule", &schedule),
27+
testAccCheckGitlabProjectFreezePeriodAttributes(&schedule, &testAccGitlabProjectFreezePeriodExpectedAttributes{
28+
FreezeStart: "0 23 * * 5",
29+
FreezeEnd: "0 7 * * 1",
30+
CronTimezone: "UTC",
31+
}),
32+
),
33+
},
34+
// Update the freeze period to change the parameters
35+
{
36+
Config: testAccGitlabProjectFreezePeriodUpdateConfig(rInt),
37+
Check: resource.ComposeTestCheckFunc(
38+
testAccCheckGitlabProjectFreezePeriodExists("gitlab_project_freeze_period.schedule", &schedule),
39+
testAccCheckGitlabProjectFreezePeriodAttributes(&schedule, &testAccGitlabProjectFreezePeriodExpectedAttributes{
40+
FreezeStart: "0 20 * * 6",
41+
FreezeEnd: "0 7 * * 3",
42+
CronTimezone: "EST",
43+
}),
44+
),
45+
},
46+
// Update the freeze period to get back to initial settings
47+
{
48+
Config: testAccGitlabProjectFreezePeriodConfig(rInt),
49+
Check: resource.ComposeTestCheckFunc(
50+
testAccCheckGitlabProjectFreezePeriodExists("gitlab_project_freeze_period.schedule", &schedule),
51+
testAccCheckGitlabProjectFreezePeriodAttributes(&schedule, &testAccGitlabProjectFreezePeriodExpectedAttributes{
52+
FreezeStart: "0 23 * * 5",
53+
FreezeEnd: "0 7 * * 1",
54+
CronTimezone: "UTC",
55+
}),
56+
),
57+
},
58+
},
59+
})
60+
}
61+
62+
func TestAccGitlabProjectFreezePeriod_import(t *testing.T) {
63+
rInt := acctest.RandInt()
64+
65+
resource.Test(t, resource.TestCase{
66+
PreCheck: func() { testAccPreCheck(t) },
67+
Providers: testAccProviders,
68+
CheckDestroy: testAccCheckGitlabProjectDestroy,
69+
Steps: []resource.TestStep{
70+
{
71+
Config: testAccGitlabProjectFreezePeriodConfig(rInt),
72+
},
73+
{
74+
ResourceName: "gitlab_project_freeze_period.schedule",
75+
ImportState: true,
76+
ImportStateVerify: true,
77+
},
78+
},
79+
})
80+
}
81+
82+
func testAccCheckGitlabProjectFreezePeriodExists(n string, freezePeriod *gitlab.FreezePeriod) resource.TestCheckFunc {
83+
return func(s *terraform.State) error {
84+
rs, ok := s.RootModule().Resources[n]
85+
if !ok {
86+
return fmt.Errorf("Not Found: %s", n)
87+
}
88+
89+
projectID, freezePeriodID, err := projectIDAndFreezePeriodIDFromID(rs.Primary.ID)
90+
if err != nil {
91+
return err
92+
}
93+
94+
conn := testAccProvider.Meta().(*gitlab.Client)
95+
gotFreezePeriod, _, err := conn.FreezePeriods.GetFreezePeriod(projectID, freezePeriodID)
96+
if err != nil {
97+
return err
98+
}
99+
100+
*freezePeriod = *gotFreezePeriod
101+
102+
return nil
103+
}
104+
}
105+
106+
type testAccGitlabProjectFreezePeriodExpectedAttributes struct {
107+
FreezeStart string
108+
FreezeEnd string
109+
CronTimezone string
110+
}
111+
112+
func testAccCheckGitlabProjectFreezePeriodAttributes(freezePeriod *gitlab.FreezePeriod, want *testAccGitlabProjectFreezePeriodExpectedAttributes) resource.TestCheckFunc {
113+
return func(s *terraform.State) error {
114+
if freezePeriod.FreezeStart != want.FreezeStart {
115+
return fmt.Errorf("got freeze_start %q; want %q", freezePeriod.FreezeStart, want.FreezeStart)
116+
}
117+
if freezePeriod.FreezeEnd != want.FreezeEnd {
118+
return fmt.Errorf("got freeze_end %q; want %q", freezePeriod.FreezeEnd, want.FreezeEnd)
119+
}
120+
121+
if freezePeriod.CronTimezone != want.CronTimezone {
122+
return fmt.Errorf("got cron_timezone %q; want %q", freezePeriod.CronTimezone, want.CronTimezone)
123+
}
124+
125+
return nil
126+
}
127+
}
128+
129+
func testAccGitlabProjectFreezePeriodConfig(rInt int) string {
130+
return fmt.Sprintf(`
131+
resource "gitlab_project" "foo" {
132+
name = "foo-%d"
133+
description = "Terraform acceptance tests"
134+
135+
# So that acceptance tests can be run in a gitlab organization
136+
# with no billing
137+
visibility_level = "public"
138+
}
139+
140+
resource "gitlab_project_freeze_period" "schedule" {
141+
project_id = gitlab_project.foo.id
142+
freeze_start = "0 23 * * 5"
143+
freeze_end = "0 7 * * 1"
144+
cron_timezone = "UTC"
145+
}
146+
`, rInt)
147+
}
148+
149+
func testAccGitlabProjectFreezePeriodUpdateConfig(rInt int) string {
150+
return fmt.Sprintf(`
151+
resource "gitlab_project" "foo" {
152+
name = "foo-%d"
153+
description = "Terraform acceptance tests"
154+
155+
# So that acceptance tests can be run in a gitlab organization
156+
# with no billing
157+
visibility_level = "public"
158+
}
159+
160+
resource "gitlab_project_freeze_period" "schedule" {
161+
project_id = gitlab_project.foo.id
162+
freeze_start = "0 20 * * 6"
163+
freeze_end = "0 7 * * 3"
164+
cron_timezone = "EST"
165+
}
166+
`, rInt)
167+
}

gitlab/resource_gitlab_project_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,7 @@ func testAccGitlabProjectConfigDefaultBranchSkipFunc(project *gitlab.Project, de
866866
return func() (bool, error) {
867867
conn := testAccProvider.Meta().(*gitlab.Client)
868868

869+
// Commit data
869870
commitMessage := "Initial Commit"
870871
commitFile := "file.txt"
871872
commitFileAction := gitlab.FileCreate
@@ -876,7 +877,6 @@ func testAccGitlabProjectConfigDefaultBranchSkipFunc(project *gitlab.Project, de
876877
Content: &commitMessage,
877878
},
878879
}
879-
880880
options := &gitlab.CreateCommitOptions{
881881
Branch: &defaultBranch,
882882
CommitMessage: &commitMessage,

0 commit comments

Comments
 (0)