Skip to content

Commit ef0ddea

Browse files
btyy77ccnuss
andauthored
Project mirroring (#512)
* Project mirroring * tabs->spaces * Remove props in the wrong test config * Duplicate ImportURL test and check props * Update Config Function * Updating docs * Personal Nit: Oxford comma * Actually reference the resource * s/mirrored/mirror <3 AccTests * s/mirror_target_builds/mirror_trigger_builds * Post create updates of mirror/mirror_trigger_builds * New Accepance Test to Explicitly Disable Mirroring * Set defaults, perhaps? * Formatting * Checks need to be on the newly created resource * Formatting 🤦 * FIx log statement * Set ImportURL in tandem with mirror params cc: @cnuss * Disable Mirror Tests in CE * Formatting Co-authored-by: Christian Nuss <[email protected]> Co-authored-by: @cnuss
1 parent a628ae8 commit ef0ddea

File tree

5 files changed

+180
-1
lines changed

5 files changed

+180
-1
lines changed

docs/resources/project.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ The following arguments are supported:
3434

3535
* `import_url` - (Optional) Git URL to a repository to be imported.
3636

37+
* `mirror` (Optional) Enables pull mirroring in a project. Default is `false`. For further information on mirroring,
38+
consult the [gitlab documentation](https://docs.gitlab.com/ee/user/project/repository/repository_mirroring.html#repository-mirroring).
39+
40+
* `mirror_trigger_builds` (Optional) Pull mirroring triggers builds. Default is `false`.
41+
3742
* `request_access_enabled` - Allow users to request member access.
3843

3944
* `issues_enabled` - (Optional) Enable issue tracking for the project.

docs/resources/project_mirror.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
This resource allows you to add a mirror target for the repository, all changes will be synced to the remote target.
44

5+
-> This is for *pushing* changes to a remote repository. *Pull Mirroring* can be configured using a combination of the
6+
`import_url`, `mirror`, and `mirror_trigger_builds` properties on the `gitlab_project` resource.
7+
8+
For further information on mirroring, consult the
9+
[gitlab documentation](https://docs.gitlab.com/ee/user/project/repository/repository_mirroring.html#repository-mirroring).
10+
511
## Example Usage
612

713
```hcl

gitlab/data_source_gitlab_projects.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ package gitlab
22

33
import (
44
"fmt"
5+
"log"
6+
57
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
68
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
79
"github.com/mitchellh/hashstructure"
810
"github.com/xanzy/go-gitlab"
9-
"log"
1011
)
1112

1213
// Schemas

gitlab/resource_gitlab_project.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,16 @@ var resourceGitLabProjectSchema = map[string]*schema.Schema{
275275
Default: "private",
276276
ValidateFunc: validation.StringInSlice([]string{"public", "private", "enabled", "disabled"}, true),
277277
},
278+
"mirror": {
279+
Type: schema.TypeBool,
280+
Optional: true,
281+
Default: false,
282+
},
283+
"mirror_trigger_builds": {
284+
Type: schema.TypeBool,
285+
Optional: true,
286+
Default: false,
287+
},
278288
}
279289

280290
func resourceGitlabProject() *schema.Resource {
@@ -321,6 +331,8 @@ func resourceGitlabProjectSetToState(d *schema.ResourceData, project *gitlab.Pro
321331
d.Set("remove_source_branch_after_merge", project.RemoveSourceBranchAfterMerge)
322332
d.Set("packages_enabled", project.PackagesEnabled)
323333
d.Set("pages_access_level", string(project.PagesAccessLevel))
334+
d.Set("mirror", project.Mirror)
335+
d.Set("mirror_trigger_builds", project.MirrorTriggerBuilds)
324336
}
325337

326338
func resourceGitlabProjectCreate(d *schema.ResourceData, meta interface{}) error {
@@ -344,6 +356,8 @@ func resourceGitlabProjectCreate(d *schema.ResourceData, meta interface{}) error
344356
SharedRunnersEnabled: gitlab.Bool(d.Get("shared_runners_enabled").(bool)),
345357
RemoveSourceBranchAfterMerge: gitlab.Bool(d.Get("remove_source_branch_after_merge").(bool)),
346358
PackagesEnabled: gitlab.Bool(d.Get("packages_enabled").(bool)),
359+
Mirror: gitlab.Bool(d.Get("mirror").(bool)),
360+
MirrorTriggerBuilds: gitlab.Bool(d.Get("mirror_trigger_builds").(bool)),
347361
}
348362

349363
if v, ok := d.GetOk("path"); ok {
@@ -574,6 +588,20 @@ func resourceGitlabProjectUpdate(d *schema.ResourceData, meta interface{}) error
574588
options.PagesAccessLevel = stringToAccessControlValue(d.Get("pages_access_level").(string))
575589
}
576590

591+
if d.HasChange("mirror") {
592+
// It appears that GitLab API requires that import_url is also set when `mirror` is updated/changed
593+
// Ref: https://github.com/gitlabhq/terraform-provider-gitlab/pull/449#discussion_r549729230
594+
options.ImportURL = gitlab.String(d.Get("import_url").(string))
595+
options.Mirror = gitlab.Bool(d.Get("mirror").(bool))
596+
}
597+
598+
if d.HasChange("mirror_trigger_builds") {
599+
// It appears that GitLab API requires that import_url is also set when `mirror_trigger_builds` is updated/changed
600+
// Ref: https://github.com/gitlabhq/terraform-provider-gitlab/pull/449#discussion_r549729230
601+
options.ImportURL = gitlab.String(d.Get("import_url").(string))
602+
options.MirrorTriggerBuilds = gitlab.Bool(d.Get("mirror_trigger_builds").(bool))
603+
}
604+
577605
if *options != (gitlab.EditProjectOptions{}) {
578606
log.Printf("[DEBUG] update gitlab project %s", d.Id())
579607
_, _, err := client.Projects.EditProject(d.Id(), options)

gitlab/resource_gitlab_project_test.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,113 @@ func TestAccGitlabProject_importURL(t *testing.T) {
509509
})
510510
}
511511

512+
type testAccGitlabProjectMirroredExpectedAttributes struct {
513+
Mirror bool
514+
MirrorTriggerBuilds bool
515+
}
516+
517+
func testAccCheckGitlabProjectMirroredAttributes(project *gitlab.Project, want *testAccGitlabProjectMirroredExpectedAttributes) resource.TestCheckFunc {
518+
return func(s *terraform.State) error {
519+
if project.Mirror != want.Mirror {
520+
return fmt.Errorf("got mirror %t; want %t", project.Mirror, want.Mirror)
521+
}
522+
523+
if project.MirrorTriggerBuilds != want.MirrorTriggerBuilds {
524+
return fmt.Errorf("got mirror_trigger_builds %t; want %t", project.MirrorTriggerBuilds, want.MirrorTriggerBuilds)
525+
}
526+
return nil
527+
}
528+
}
529+
530+
func TestAccGitlabProject_importURLMirrored(t *testing.T) {
531+
// Since we do some manual setup in this test, we need to handle the test skip first.
532+
if os.Getenv(resource.TestEnvVar) == "" {
533+
t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", resource.TestEnvVar))
534+
}
535+
536+
client := testAccProvider.Meta().(*gitlab.Client)
537+
var mirror gitlab.Project
538+
rInt := acctest.RandInt()
539+
540+
// Create a base project for importing.
541+
baseProject, _, err := client.Projects.CreateProject(&gitlab.CreateProjectOptions{
542+
Name: gitlab.String(fmt.Sprintf("base-%d", rInt)),
543+
Visibility: gitlab.Visibility(gitlab.PublicVisibility),
544+
})
545+
if err != nil {
546+
t.Fatalf("failed to create base project: %v", err)
547+
}
548+
549+
defer client.Projects.DeleteProject(baseProject.ID)
550+
551+
// Add a file to the base project, for later verifying the import.
552+
_, _, err = client.RepositoryFiles.CreateFile(baseProject.ID, "foo.txt", &gitlab.CreateFileOptions{
553+
Branch: gitlab.String("master"),
554+
CommitMessage: gitlab.String("add file"),
555+
Content: gitlab.String(""),
556+
})
557+
if err != nil {
558+
t.Fatalf("failed to commit file to base project: %v", err)
559+
}
560+
561+
resource.Test(t, resource.TestCase{
562+
PreCheck: func() { testAccPreCheck(t) },
563+
Providers: testAccProviders,
564+
CheckDestroy: testAccCheckGitlabProjectDestroy,
565+
Steps: []resource.TestStep{
566+
{
567+
// First, import, as mirrored
568+
Config: testAccGitlabProjectConfigImportURLMirror(rInt, baseProject.HTTPURLToRepo),
569+
SkipFunc: isRunningInCE,
570+
Check: resource.ComposeTestCheckFunc(
571+
testAccCheckGitlabProjectExists("gitlab_project.imported", &mirror),
572+
resource.TestCheckResourceAttr("gitlab_project.imported", "import_url", baseProject.HTTPURLToRepo),
573+
testAccCheckGitlabProjectMirroredAttributes(&mirror, &testAccGitlabProjectMirroredExpectedAttributes{
574+
Mirror: true,
575+
MirrorTriggerBuilds: true,
576+
}),
577+
578+
func(state *terraform.State) error {
579+
projectID := state.RootModule().Resources["gitlab_project.imported"].Primary.ID
580+
581+
_, _, err := client.RepositoryFiles.GetFile(projectID, "foo.txt", &gitlab.GetFileOptions{Ref: gitlab.String("master")}, nil)
582+
if err != nil {
583+
return fmt.Errorf("failed to get file from imported project: %w", err)
584+
}
585+
586+
return nil
587+
},
588+
),
589+
},
590+
{
591+
// Second, disable mirroring, using the original ImportURL acceptance test
592+
Config: testAccGitlabProjectConfigImportURLMirrorDisabled(rInt, baseProject.HTTPURLToRepo),
593+
SkipFunc: isRunningInCE,
594+
Check: resource.ComposeTestCheckFunc(
595+
testAccCheckGitlabProjectExists("gitlab_project.imported", &mirror),
596+
resource.TestCheckResourceAttr("gitlab_project.imported", "import_url", baseProject.HTTPURLToRepo),
597+
testAccCheckGitlabProjectMirroredAttributes(&mirror, &testAccGitlabProjectMirroredExpectedAttributes{
598+
Mirror: false,
599+
MirrorTriggerBuilds: false,
600+
}),
601+
602+
// Ensure the test file still is as expected
603+
func(state *terraform.State) error {
604+
projectID := state.RootModule().Resources["gitlab_project.imported"].Primary.ID
605+
606+
_, _, err := client.RepositoryFiles.GetFile(projectID, "foo.txt", &gitlab.GetFileOptions{Ref: gitlab.String("master")}, nil)
607+
if err != nil {
608+
return fmt.Errorf("failed to get file from imported project: %w", err)
609+
}
610+
611+
return nil
612+
},
613+
),
614+
},
615+
},
616+
})
617+
}
618+
512619
func TestAccGitlabProjec_templateMutualExclusiveNameAndID(t *testing.T) {
513620
rInt := acctest.RandInt()
514621

@@ -838,6 +945,38 @@ resource "gitlab_project" "imported" {
838945
`, rInt, importURL)
839946
}
840947

948+
func testAccGitlabProjectConfigImportURLMirror(rInt int, importURL string) string {
949+
return fmt.Sprintf(`
950+
resource "gitlab_project" "imported" {
951+
name = "imported-%d"
952+
default_branch = "master"
953+
import_url = "%s"
954+
mirror = true
955+
mirror_trigger_builds = true
956+
957+
# So that acceptance tests can be run in a gitlab organization
958+
# with no billing
959+
visibility_level = "public"
960+
}
961+
`, rInt, importURL)
962+
}
963+
964+
func testAccGitlabProjectConfigImportURLMirrorDisabled(rInt int, importURL string) string {
965+
return fmt.Sprintf(`
966+
resource "gitlab_project" "imported" {
967+
name = "imported-%d"
968+
default_branch = "master"
969+
import_url = "%s"
970+
mirror = false
971+
mirror_trigger_builds = false
972+
973+
# So that acceptance tests can be run in a gitlab organization
974+
# with no billing
975+
visibility_level = "public"
976+
}
977+
`, rInt, importURL)
978+
}
979+
841980
func testAccGitlabProjectConfigPushRules(rInt int, pushRules string) string {
842981
return fmt.Sprintf(`
843982
resource "gitlab_project" "foo" {

0 commit comments

Comments
 (0)