Skip to content

Commit f60dc34

Browse files
Merge pull request #358 from lukemgriffith/mirrorConfig
feature: add project mirror resources to provider
2 parents 1ed76d5 + 279b653 commit f60dc34

File tree

5 files changed

+433
-0
lines changed

5 files changed

+433
-0
lines changed

gitlab/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ func Provider() terraform.ResourceProvider {
8888
"gitlab_project_share_group": resourceGitlabProjectShareGroup(),
8989
"gitlab_group_cluster": resourceGitlabGroupCluster(),
9090
"gitlab_group_ldap_link": resourceGitlabGroupLdapLink(),
91+
"gitlab_project_mirror": resourceGitlabProjectMirror(),
9192
},
9293

9394
ConfigureFunc: providerConfigure,
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package gitlab
2+
3+
import (
4+
"log"
5+
"strconv"
6+
"strings"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
9+
"github.com/xanzy/go-gitlab"
10+
)
11+
12+
func resourceGitlabProjectMirror() *schema.Resource {
13+
return &schema.Resource{
14+
Create: resourceGitlabProjectMirrorCreate,
15+
Read: resourceGitlabProjectMirrorRead,
16+
Update: resourceGitlabProjectMirrorUpdate,
17+
Delete: resourceGitlabProjectMirrorDelete,
18+
Importer: &schema.ResourceImporter{
19+
State: schema.ImportStatePassthrough,
20+
},
21+
22+
Schema: map[string]*schema.Schema{
23+
"project": {
24+
Type: schema.TypeString,
25+
ForceNew: true,
26+
Required: true,
27+
},
28+
"mirror_id": {
29+
Type: schema.TypeInt,
30+
Computed: true,
31+
},
32+
"url": {
33+
Type: schema.TypeString,
34+
ForceNew: true,
35+
Required: true,
36+
},
37+
"enabled": {
38+
Type: schema.TypeBool,
39+
Optional: true,
40+
Default: true,
41+
},
42+
"only_protected_branches": {
43+
Type: schema.TypeBool,
44+
Optional: true,
45+
Default: true,
46+
},
47+
"keep_divergent_refs": {
48+
Type: schema.TypeBool,
49+
Optional: true,
50+
Default: true,
51+
},
52+
},
53+
}
54+
}
55+
56+
func resourceGitlabProjectMirrorCreate(d *schema.ResourceData, meta interface{}) error {
57+
client := meta.(*gitlab.Client)
58+
59+
projectID := d.Get("project").(string)
60+
URL := d.Get("url").(string)
61+
enabled := d.Get("enabled").(bool)
62+
onlyProtectedBranches := d.Get("only_protected_branches").(bool)
63+
keepDivergentRefs := d.Get("keep_divergent_refs").(bool)
64+
65+
options := &gitlab.AddProjectMirrorOptions{
66+
URL: &URL,
67+
Enabled: &enabled,
68+
OnlyProtectedBranches: &onlyProtectedBranches,
69+
KeepDivergentRefs: &keepDivergentRefs,
70+
}
71+
72+
log.Printf("[DEBUG] create gitlab project mirror for project %v", projectID)
73+
74+
mirror, _, err := client.ProjectMirrors.AddProjectMirror(projectID, options)
75+
if err != nil {
76+
return err
77+
}
78+
d.Set("mirror_id", mirror.ID)
79+
80+
mirrorID := strconv.Itoa(mirror.ID)
81+
d.SetId(buildTwoPartID(&projectID, &mirrorID))
82+
return resourceGitlabProjectMirrorRead(d, meta)
83+
}
84+
85+
func resourceGitlabProjectMirrorUpdate(d *schema.ResourceData, meta interface{}) error {
86+
client := meta.(*gitlab.Client)
87+
88+
mirrorID := d.Get("mirror_id").(int)
89+
projectID := d.Get("project").(string)
90+
enabled := d.Get("enabled").(bool)
91+
onlyProtectedBranches := d.Get("only_protected_branches").(bool)
92+
keepDivergentRefs := d.Get("keep_divergent_refs").(bool)
93+
94+
options := gitlab.EditProjectMirrorOptions{
95+
Enabled: &enabled,
96+
OnlyProtectedBranches: &onlyProtectedBranches,
97+
KeepDivergentRefs: &keepDivergentRefs,
98+
}
99+
log.Printf("[DEBUG] update gitlab project mirror %v for %s", mirrorID, projectID)
100+
101+
_, _, err := client.ProjectMirrors.EditProjectMirror(projectID, mirrorID, &options)
102+
if err != nil {
103+
return err
104+
}
105+
return resourceGitlabProjectMirrorRead(d, meta)
106+
}
107+
108+
// Documented remote mirrors API does not support a delete method, instead mirror is disabled.
109+
func resourceGitlabProjectMirrorDelete(d *schema.ResourceData, meta interface{}) error {
110+
client := meta.(*gitlab.Client)
111+
112+
enabled := false
113+
114+
mirrorID := d.Get("mirror_id").(int)
115+
projectID := d.Get("project").(string)
116+
onlyProtectedBranches := d.Get("only_protected_branches").(bool)
117+
keepDivergentRefs := d.Get("keep_divergent_refs").(bool)
118+
119+
options := gitlab.EditProjectMirrorOptions{
120+
Enabled: &enabled,
121+
OnlyProtectedBranches: &onlyProtectedBranches,
122+
KeepDivergentRefs: &keepDivergentRefs,
123+
}
124+
log.Printf("[DEBUG] Disable gitlab project mirror %v for %s", mirrorID, projectID)
125+
126+
_, _, err := client.ProjectMirrors.EditProjectMirror(projectID, mirrorID, &options)
127+
128+
return err
129+
}
130+
131+
func resourceGitlabProjectMirrorRead(d *schema.ResourceData, meta interface{}) error {
132+
client := meta.(*gitlab.Client)
133+
134+
ids := strings.Split(d.Id(), ":")
135+
projectID := ids[0]
136+
mirrorID := ids[1]
137+
integerMirrorID, err := strconv.Atoi(mirrorID)
138+
if err != nil {
139+
return err
140+
}
141+
log.Printf("[DEBUG] read gitlab project mirror %s id %v", projectID, mirrorID)
142+
143+
mirrors, _, err := client.ProjectMirrors.ListProjectMirror(projectID)
144+
145+
if err != nil {
146+
return err
147+
}
148+
149+
var mirror *gitlab.ProjectMirror
150+
found := false
151+
152+
for _, m := range mirrors {
153+
log.Printf("[DEBUG] project mirror found %v", m.ID)
154+
if m.ID == integerMirrorID {
155+
mirror = m
156+
found = true
157+
}
158+
}
159+
160+
if !found {
161+
d.SetId("")
162+
return nil
163+
}
164+
165+
resourceGitlabProjectMirrorSetToState(d, mirror, &projectID)
166+
return nil
167+
}
168+
169+
func resourceGitlabProjectMirrorSetToState(d *schema.ResourceData, projectMirror *gitlab.ProjectMirror, projectID *string) {
170+
d.Set("enabled", projectMirror.Enabled)
171+
d.Set("mirror_id", projectMirror.ID)
172+
d.Set("keep_divergent_refs", projectMirror.KeepDivergentRefs)
173+
d.Set("only_protected_branches", projectMirror.OnlyProtectedBranches)
174+
d.Set("project", projectID)
175+
d.Set("url", projectMirror.URL)
176+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package gitlab
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"strconv"
7+
"strings"
8+
"testing"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
11+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
12+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
13+
"github.com/xanzy/go-gitlab"
14+
)
15+
16+
func TestAccGitlabProjectMirror_basic(t *testing.T) {
17+
var hook gitlab.ProjectMirror
18+
rInt := acctest.RandInt()
19+
20+
resource.Test(t, resource.TestCase{
21+
PreCheck: func() { testAccPreCheck(t) },
22+
Providers: testAccProviders,
23+
CheckDestroy: testAccCheckGitlabProjectMirrorDestroy,
24+
Steps: []resource.TestStep{
25+
// Create a project and hook with default options
26+
{
27+
Config: testAccGitlabProjectMirrorConfig(rInt),
28+
Check: resource.ComposeTestCheckFunc(
29+
testAccCheckGitlabProjectMirrorExists("gitlab_project_mirror.foo", &hook),
30+
testAccCheckGitlabProjectMirrorAttributes(&hook, &testAccGitlabProjectMirrorExpectedAttributes{
31+
URL: fmt.Sprintf("https://example.com/hook-%d", rInt),
32+
Enabled: true,
33+
OnlyProtectedBranches: true,
34+
KeepDivergentRefs: true,
35+
}),
36+
),
37+
},
38+
// Update the project hook to toggle all the values to their inverse
39+
{
40+
Config: testAccGitlabProjectMirrorUpdateConfig(rInt),
41+
Check: resource.ComposeTestCheckFunc(
42+
testAccCheckGitlabProjectMirrorExists("gitlab_project_mirror.foo", &hook),
43+
testAccCheckGitlabProjectMirrorAttributes(&hook, &testAccGitlabProjectMirrorExpectedAttributes{
44+
URL: fmt.Sprintf("https://example.com/hook-%d", rInt),
45+
Enabled: false,
46+
OnlyProtectedBranches: false,
47+
KeepDivergentRefs: false,
48+
}),
49+
),
50+
},
51+
// Update the project hook to toggle the options back
52+
{
53+
Config: testAccGitlabProjectMirrorConfig(rInt),
54+
Check: resource.ComposeTestCheckFunc(
55+
testAccCheckGitlabProjectMirrorExists("gitlab_project_mirror.foo", &hook),
56+
testAccCheckGitlabProjectMirrorAttributes(&hook, &testAccGitlabProjectMirrorExpectedAttributes{
57+
URL: fmt.Sprintf("https://example.com/hook-%d", rInt),
58+
Enabled: true,
59+
OnlyProtectedBranches: true,
60+
KeepDivergentRefs: true,
61+
}),
62+
),
63+
},
64+
},
65+
})
66+
}
67+
68+
func TestAccGitlabProjectMirror_import(t *testing.T) {
69+
rInt := acctest.RandInt()
70+
71+
resource.Test(t, resource.TestCase{
72+
PreCheck: func() { testAccPreCheck(t) },
73+
Providers: testAccProviders,
74+
CheckDestroy: testAccCheckGitlabProjectMirrorDestroy,
75+
Steps: []resource.TestStep{
76+
{
77+
Config: testAccGitlabProjectMirrorConfig(rInt),
78+
},
79+
{
80+
ResourceName: "gitlab_project_mirror.foo",
81+
ImportState: true,
82+
ImportStateVerify: true,
83+
},
84+
},
85+
})
86+
}
87+
88+
func testAccCheckGitlabProjectMirrorExists(n string, mirror *gitlab.ProjectMirror) resource.TestCheckFunc {
89+
return func(s *terraform.State) error {
90+
rs, ok := s.RootModule().Resources[n]
91+
if !ok {
92+
return fmt.Errorf("Not Found: %s", n)
93+
}
94+
95+
splitID := strings.Split(rs.Primary.ID, ":")
96+
97+
mirrorID, err := strconv.Atoi(splitID[len(splitID)-1])
98+
if err != nil {
99+
return err
100+
}
101+
repoName := rs.Primary.Attributes["project"]
102+
if repoName == "" {
103+
return fmt.Errorf("No project ID is set")
104+
}
105+
conn := testAccProvider.Meta().(*gitlab.Client)
106+
107+
mirrors, _, err := conn.ProjectMirrors.ListProjectMirror(repoName, nil)
108+
if err != nil {
109+
return err
110+
}
111+
112+
for _, m := range mirrors {
113+
if m.ID == mirrorID {
114+
*mirror = *m
115+
break
116+
}
117+
return errors.New("unable to find mirror.")
118+
}
119+
return nil
120+
}
121+
}
122+
123+
type testAccGitlabProjectMirrorExpectedAttributes struct {
124+
URL string
125+
Enabled bool
126+
OnlyProtectedBranches bool
127+
KeepDivergentRefs bool
128+
}
129+
130+
func testAccCheckGitlabProjectMirrorAttributes(mirror *gitlab.ProjectMirror, want *testAccGitlabProjectMirrorExpectedAttributes) resource.TestCheckFunc {
131+
return func(s *terraform.State) error {
132+
if mirror.URL != want.URL {
133+
return fmt.Errorf("got url %q; want %q", mirror.URL, want.URL)
134+
}
135+
136+
if mirror.Enabled != want.Enabled {
137+
return fmt.Errorf("got enabled %t; want %t", mirror.Enabled, want.Enabled)
138+
}
139+
if mirror.OnlyProtectedBranches != want.OnlyProtectedBranches {
140+
return fmt.Errorf("got only protected branches %t; want %t", mirror.OnlyProtectedBranches, want.OnlyProtectedBranches)
141+
}
142+
if mirror.KeepDivergentRefs != want.KeepDivergentRefs {
143+
return fmt.Errorf("got keep divergent refs %t; want %t", mirror.KeepDivergentRefs, want.KeepDivergentRefs)
144+
}
145+
return nil
146+
}
147+
}
148+
149+
func testAccCheckGitlabProjectMirrorDestroy(s *terraform.State) error {
150+
conn := testAccProvider.Meta().(*gitlab.Client)
151+
152+
for _, rs := range s.RootModule().Resources {
153+
if rs.Type != "gitlab_project" {
154+
continue
155+
}
156+
157+
gotRepo, resp, err := conn.Projects.GetProject(rs.Primary.ID, nil)
158+
if err == nil {
159+
if gotRepo != nil && fmt.Sprintf("%d", gotRepo.ID) == rs.Primary.ID {
160+
if gotRepo.MarkedForDeletionAt == nil {
161+
return fmt.Errorf("Repository still exists")
162+
}
163+
}
164+
}
165+
if resp.StatusCode != 404 {
166+
return err
167+
}
168+
return nil
169+
}
170+
return nil
171+
}
172+
173+
func testAccGitlabProjectMirrorConfig(rInt int) string {
174+
return fmt.Sprintf(`
175+
resource "gitlab_project" "foo" {
176+
name = "foo-%d"
177+
description = "Terraform acceptance tests"
178+
179+
# So that acceptance tests can be run in a gitlab organization
180+
# with no billing
181+
visibility_level = "public"
182+
}
183+
184+
resource "gitlab_project_mirror" "foo" {
185+
project = "${gitlab_project.foo.id}"
186+
url = "https://example.com/hook-%d"
187+
}
188+
`, rInt, rInt)
189+
}
190+
191+
func testAccGitlabProjectMirrorUpdateConfig(rInt int) string {
192+
return fmt.Sprintf(`
193+
resource "gitlab_project" "foo" {
194+
name = "foo-%d"
195+
description = "Terraform acceptance tests"
196+
197+
# So that acceptance tests can be run in a gitlab organization
198+
# with no billing
199+
visibility_level = "public"
200+
}
201+
202+
resource "gitlab_project_mirror" "foo" {
203+
project = "${gitlab_project.foo.id}"
204+
url = "https://example.com/hook-%d"
205+
enabled = false
206+
only_protected_branches = false
207+
keep_divergent_refs = false
208+
}
209+
`, rInt, rInt)
210+
}

0 commit comments

Comments
 (0)