Skip to content

Commit

Permalink
Merge pull request #277 from ahmet2mir/project-template-support
Browse files Browse the repository at this point in the history
Adding support for project templates
  • Loading branch information
nicholasklick authored Sep 21, 2020
2 parents 5b1a050 + 0e0a69e commit 05a262e
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 4 deletions.
8 changes: 8 additions & 0 deletions docs/resources/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ The following arguments are supported:

* `push_rules` (Optional) Push rules for the project (documented below).

* `template_name` - (Optional) When used without use_custom_template, name of a built-in project template. When used with use_custom_template, name of a custom project template. This option is mutually exclusive with `template_project_id`.

* `template_project_id` - (Optional) When used with use_custom_template, project ID of a custom project template. This is preferable to using template_name since template_name may be ambiguous (enterprise edition). This option is mutually exclusive with `template_name`.

* `use_custom_template` - (Optional) Use either custom instance or group (with group_with_project_templates_id) project template (enterprise edition).

* `group_with_project_templates_id` - (Optional) For group-level custom templates, specifies ID of group from which all the custom project templates are sourced. Leave empty for instance-level templates. Requires use_custom_template to be true (enterprise edition).

## Attributes Reference

The following additional attributes are exported:
Expand Down
36 changes: 36 additions & 0 deletions gitlab/resource_gitlab_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,26 @@ var resourceGitLabProjectSchema = map[string]*schema.Schema{
},
},
},
"template_name": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"template_project_id"},
ForceNew: true,
},
"template_project_id": {
Type: schema.TypeInt,
Optional: true,
ConflictsWith: []string{"template_name"},
ForceNew: true,
},
"use_custom_template": {
Type: schema.TypeBool,
Optional: true,
},
"group_with_project_templates_id": {
Type: schema.TypeInt,
Optional: true,
},
}

func resourceGitlabProject() *schema.Resource {
Expand Down Expand Up @@ -342,6 +362,22 @@ func resourceGitlabProjectCreate(d *schema.ResourceData, meta interface{}) error
options.ImportURL = gitlab.String(v.(string))
}

if v, ok := d.GetOk("template_name"); ok {
options.TemplateName = gitlab.String(v.(string))
}

if v, ok := d.GetOk("template_project_id"); ok {
options.TemplateProjectID = gitlab.Int(v.(int))
}

if v, ok := d.GetOk("use_custom_template"); ok {
options.UseCustomTemplate = gitlab.Bool(v.(bool))
}

if v, ok := d.GetOk("group_with_project_templates_id"); ok {
options.GroupWithProjectTemplatesID = gitlab.Int(v.(int))
}

log.Printf("[DEBUG] create gitlab project %q", *options.Name)

project, _, err := client.Projects.CreateProject(options)
Expand Down
148 changes: 145 additions & 3 deletions gitlab/resource_gitlab_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,74 @@ max_file_size = 123
Config: testAccGitlabProjectConfigPushRules(rInt, `author_email_regex = "foo_author"`),
ExpectError: regexp.MustCompile(regexp.QuoteMeta("Project push rules are not supported in your version of GitLab")),
},
// Create a project using template name
{
Config: testAccGitlabProjectConfigTemplateName(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabProjectExists("gitlab_project.template-name", &received),
testAccCheckGitlabProjectDefaultBranch(&received, &testAccGitlabProjectExpectedAttributes{
DefaultBranch: "master",
}),
func(state *terraform.State) error {
client := testAccProvider.Meta().(*gitlab.Client)

projectID := state.RootModule().Resources["gitlab_project.template-name"].Primary.ID

_, _, err := client.RepositoryFiles.GetFile(projectID, ".ruby-version", &gitlab.GetFileOptions{Ref: gitlab.String("master")}, nil)
if err != nil {
return fmt.Errorf("failed to get '.ruby-version' file from template project: %w", err)
}

return nil
},
),
},
// Create a project using custom template name
{
Config: testAccGitlabProjectConfigTemplateNameCustom(rInt),
SkipFunc: isRunningInCE,
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabProjectExists("gitlab_project.template-name-custom", &received),
testAccCheckGitlabProjectDefaultBranch(&received, &testAccGitlabProjectExpectedAttributes{
DefaultBranch: "master",
}),
func(state *terraform.State) error {
client := testAccProvider.Meta().(*gitlab.Client)

projectID := state.RootModule().Resources["gitlab_project.template-name-custom"].Primary.ID

_, _, err := client.RepositoryFiles.GetFile(projectID, "Gemfile", &gitlab.GetFileOptions{Ref: gitlab.String("master")}, nil)
if err != nil {
return fmt.Errorf("failed to get 'Gemfile' file from template project: %w", err)
}

return nil
},
),
},
// Create a project using custom template project id
{
Config: testAccGitlabProjectConfigTemplateProjectID(rInt),
SkipFunc: isRunningInCE,
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabProjectExists("gitlab_project.template-id", &received),
testAccCheckGitlabProjectDefaultBranch(&received, &testAccGitlabProjectExpectedAttributes{
DefaultBranch: "master",
}),
func(state *terraform.State) error {
client := testAccProvider.Meta().(*gitlab.Client)

projectID := state.RootModule().Resources["gitlab_project.template-id"].Primary.ID

_, _, err := client.RepositoryFiles.GetFile(projectID, "Rakefile", &gitlab.GetFileOptions{Ref: gitlab.String("master")}, nil)
if err != nil {
return fmt.Errorf("failed to get 'Rakefile' file from template project: %w", err)
}

return nil
},
),
},
// Update to original project config
{
Config: testAccGitlabProjectConfig(rInt),
Expand All @@ -224,7 +292,7 @@ func TestAccGitlabProject_initializeWithReadme(t *testing.T) {
Config: testAccGitlabProjectConfigInitializeWithReadme(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabProjectExists("gitlab_project.foo", &project),
testAccCheckGitlabProjectInitializeWithReadme(&project, &testAccGitlabProjectExpectedAttributes{
testAccCheckGitlabProjectDefaultBranch(&project, &testAccGitlabProjectExpectedAttributes{
DefaultBranch: "master",
}),
),
Expand Down Expand Up @@ -437,6 +505,22 @@ func TestAccGitlabProject_importURL(t *testing.T) {
})
}

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

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckMutualExclusiveNameAndID(rInt),
SkipFunc: isRunningInCE,
ExpectError: regexp.MustCompile(regexp.QuoteMeta(`"template_project_id": conflicts with template_name`)),
},
},
})
}

func testAccCheckGitlabProjectExists(n string, project *gitlab.Project) resource.TestCheckFunc {
return func(s *terraform.State) error {
var err error
Expand Down Expand Up @@ -506,10 +590,10 @@ func testAccCheckAggregateGitlabProject(expected, received *gitlab.Project) reso
return resource.ComposeAggregateTestCheckFunc(checks...)
}

func testAccCheckGitlabProjectInitializeWithReadme(project *gitlab.Project, want *testAccGitlabProjectExpectedAttributes) resource.TestCheckFunc {
func testAccCheckGitlabProjectDefaultBranch(project *gitlab.Project, want *testAccGitlabProjectExpectedAttributes) resource.TestCheckFunc {
return func(s *terraform.State) error {
if project.DefaultBranch != want.DefaultBranch {
return fmt.Errorf("got description %q; want %q", project.DefaultBranch, want.DefaultBranch)
return fmt.Errorf("got default branch %q; want %q", project.DefaultBranch, want.DefaultBranch)
}

return nil
Expand Down Expand Up @@ -765,3 +849,61 @@ resource "gitlab_project" "foo" {
}
`, rInt, pushRules)
}

func testAccGitlabProjectConfigTemplateName(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_project" "template-name" {
name = "template-name-%d"
path = "template-name.%d"
description = "Terraform acceptance tests"
template_name = "rails"
default_branch = "master"
}
`, rInt, rInt)
}

// 2020-09-07: Currently Gitlab (version 13.3.6 ) doesn't allow in admin API
// ability to set a group as instance level templates.
// To test resource_gitlab_project_test template features we add
// group, project myrails and admin settings directly in scripts/start-gitlab.sh
// Once Gitlab add admin template in API we could manage group/project/settings
// directly in tests like TestAccGitlabProject_basic.
func testAccGitlabProjectConfigTemplateNameCustom(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_project" "template-name-custom" {
name = "template-name-custom-%d"
path = "template-name-custom.%d"
description = "Terraform acceptance tests"
template_name = "myrails"
use_custom_template = true
default_branch = "master"
}
`, rInt, rInt)
}

func testAccGitlabProjectConfigTemplateProjectID(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_project" "template-id" {
name = "template-id-%d"
path = "template-id.%d"
description = "Terraform acceptance tests"
template_project_id = 999
use_custom_template = true
default_branch = "master"
}
`, rInt, rInt)
}

func testAccCheckMutualExclusiveNameAndID(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_project" "template-mutual-exclusive" {
name = "template-mutual-exclusive-%d"
path = "template-mutual-exclusive.%d"
description = "Terraform acceptance tests"
template_name = "rails"
template_project_id = 999
use_custom_template = true
default_branch = "master"
}
`, rInt, rInt)
}
28 changes: 27 additions & 1 deletion scripts/start-gitlab.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,30 @@ echo "Creating access token"
) |
docker exec -i gitlab gitlab-rails console


# 2020-09-07: Currently Gitlab (version 13.3.6 ) doesn't allow in admin API
# ability to set a group as instance level templates.
# To test resource_gitlab_project_test template features we add
# group, project myrails and admin settings directly in scripts/start-gitlab.sh
# Once Gitlab add admin template in API we could manage group/project/settings
# directly in tests like TestAccGitlabProject_basic.
# Works on CE too
echo
echo "Creating an instance level template group with a simple template based on rails"
(
echo -n 'group_template = Group.new('
echo -n 'name: :terraform, '
echo -n 'path: :terraform);'
echo -n 'group_template.save!;'
echo -n 'application_settings = ApplicationSetting.find_by "";'
echo -n 'application_settings.custom_project_templates_group_id = group_template.id;'
echo -n 'application_settings.save!;'
echo -n 'attrs = {'
echo -n 'name: :myrails, '
echo -n 'path: :myrails, '
echo -n 'namespace_id: group_template.id, '
echo -n 'template_name: :rails, '
echo -n 'id: 999};'
echo -n 'project = ::Projects::CreateService.new(User.find_by_username("root"), attrs).execute;'
echo -n 'project.saved?;'
) |
docker exec -i gitlab gitlab-rails console

0 comments on commit 05a262e

Please sign in to comment.