Skip to content

Commit

Permalink
resource/repository: add create from template
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Udit committed Dec 19, 2019
1 parent 2c03b95 commit d6a569c
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 8 deletions.
84 changes: 77 additions & 7 deletions github/resource_github_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package github

import (
"context"
"errors"
"fmt"
"log"
"net/http"
Expand Down Expand Up @@ -137,6 +138,25 @@ func resourceGithubRepository() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"template": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"owner": {
Type: schema.TypeString,
Optional: true,
Default: false,
},
"repository": {
Type: schema.TypeString,
Optional: true,
Default: false,
},
},
},
},
},
}
}
Expand Down Expand Up @@ -174,20 +194,58 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("Cannot set the default branch on a new repository to something other than 'master'.")
}

orgName := meta.(*Organization).name
repoReq := resourceGithubRepositoryObject(d)
orgName := meta.(*Organization).name
repoName := repoReq.GetName()
ctx := context.Background()

log.Printf("[DEBUG] Creating repository: %s/%s", orgName, repoReq.GetName())
repo, _, err := client.Repositories.Create(ctx, orgName, repoReq)
if err != nil {
return err
log.Printf("[DEBUG] Creating repository: %s/%s", orgName, repoName)

if template, ok := d.GetOk("template"); ok {
templateConfigBlocks := template.([]interface{})
if len(templateConfigBlocks) > 1 {
return errors.New("cannot specify template more than once")
}

for _, templateConfigBlock := range templateConfigBlocks {
templateConfigMap, ok := templateConfigBlock.(map[string]interface{})
if !ok {
return errors.New("failed to unpack template configuration block")
}

templateRepo := templateConfigMap["repository"].(string)
templateRepoOwner := templateConfigMap["owner"].(string)
templateRepoReq := github.TemplateRepoRequest{
Name: &repoName,
Owner: &orgName,
Description: github.String(d.Get("description").(string)),
Private: github.Bool(d.Get("private").(bool)),
}

repo, _, err := client.Repositories.CreateFromTemplate(ctx,
templateRepoOwner,
templateRepo,
&templateRepoReq,
)

if err != nil {
return err
}

d.SetId(*repo.Name)
}
} else {
// Create without a repository template
repo, _, err := client.Repositories.Create(ctx, orgName, repoReq)
if err != nil {
return err
}
d.SetId(*repo.Name)
}
d.SetId(*repo.Name)

topics := repoReq.Topics
if len(topics) > 0 {
_, _, err = client.Repositories.ReplaceAllTopics(ctx, orgName, repoReq.GetName(), topics)
_, _, err = client.Repositories.ReplaceAllTopics(ctx, orgName, repoName, topics)
if err != nil {
return err
}
Expand Down Expand Up @@ -250,6 +308,18 @@ func resourceGithubRepositoryRead(d *schema.ResourceData, meta interface{}) erro
d.Set("http_clone_url", repo.CloneURL)
d.Set("archived", repo.Archived)
d.Set("topics", flattenStringList(repo.Topics))

if repo.TemplateRepository != nil {
d.Set("template", []interface{}{
map[string]interface{}{
"owner": repo.TemplateRepository.Owner.Login,
"repository": repo.TemplateRepository.Name,
},
})
} else {
d.Set("template", []interface{}{})
}

return nil
}

Expand Down
69 changes: 69 additions & 0 deletions github/resource_github_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,36 @@ func TestAccGithubRepository_autoInitForceNew(t *testing.T) {
})
}

func TestAccGithubRepository_createFromTemplate(t *testing.T) {
var repo github.Repository

rn := "github_repository.foo"
randString := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckGithubRepositoryDestroy,
Steps: []resource.TestStep{
{
Config: testAccGithubRepositoryCreateFromTemplate(randString),
Check: resource.ComposeTestCheckFunc(
testAccCheckGithubRepositoryExists(rn, &repo),
testAccCheckGithubRepositoryTemplateRepoAttribute(rn, &repo),
),
},
{
ResourceName: rn,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"auto_init",
},
},
},
})
}

func testAccCheckGithubRepositoryExists(n string, repo *github.Repository) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand All @@ -513,6 +543,17 @@ func testAccCheckGithubRepositoryExists(n string, repo *github.Repository) resou
}
}

func testAccCheckGithubRepositoryTemplateRepoAttribute(n string, repo *github.Repository) resource.TestCheckFunc {
return func(s *terraform.State) error {

if *repo.TemplateRepository.IsTemplate != true {
return fmt.Errorf("got repo %q; want %q", *repo.TemplateRepository, repo)
}

return nil
}
}

type testAccGithubRepositoryExpectedAttributes struct {
Name string
Description string
Expand Down Expand Up @@ -841,6 +882,34 @@ resource "github_repository" "foo" {
`, randString, randString)
}

func testAccGithubRepositoryCreateFromTemplate(randString string) string {
return fmt.Sprintf(`
resource "github_repository" "foo" {
name = "tf-acc-test-%s"
description = "Terraform acceptance tests %s"
homepage_url = "http://example.com/"
template {
# FIXME: Change this to something more suitable for CI runs
owner = "jcudit"
repository = "terraform-template-module"
}
# So that acceptance tests can be run in a github organization
# with no billing
private = false
has_issues = true
has_wiki = true
allow_merge_commit = true
allow_squash_merge = false
allow_rebase_merge = false
has_downloads = true
}
`, randString, randString)
}

func testAccGithubRepositoryConfigTopics(randString string, topicList string) string {
return fmt.Sprintf(`
resource "github_repository" "foo" {
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ require (
github.com/terraform-providers/terraform-provider-tls v1.2.0
golang.org/x/oauth2 v0.0.0-20190604054615-0f29369cfe45
)

go 1.13
15 changes: 14 additions & 1 deletion website/docs/r/repository.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ resource "github_repository" "example" {
description = "My awesome codebase"
private = true
template {
owner = "github"
repo = "terraform-module-template"
}
}
```

Expand Down Expand Up @@ -65,10 +70,18 @@ and after a correct reference has been created for the target branch inside the
initial repository creation and create the target branch inside of the repository prior to setting this attribute.

* `archived` - (Optional) Specifies if the repository should be archived. Defaults to `false`.
~> **NOTE** Currently, the API does not support unarchiving.

* `topics` - (Optional) The list of topics of the repository.

~> **NOTE** Currently, the API does not support unarchiving.
* `template` - (Optional) Use a template repository to create this resource. See [Template Repositories](#template-repositories) below for details.

### Template Repositories

`template` supports the following arguments:

* `owner`: The GitHub organization or user the template repository is owned by.
* `repository`: The name of the template repository.

## Attributes Reference

Expand Down

0 comments on commit d6a569c

Please sign in to comment.