Skip to content

Commit

Permalink
Merge pull request integrations#309 from terraform-providers/template…
Browse files Browse the repository at this point in the history
…-repos

resource/repository: add create from template
  • Loading branch information
Jeremy Udit authored Jan 14, 2020
2 parents 8ec0b28 + 75cf578 commit 2d57cfa
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 16 deletions.
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,22 @@ testing. It will need to have the following scopes selected:
Once the token has been created, it must be exported in your environment as `GITHUB_TOKEN`.

### GitHub organization
If you do not have an organization already that you are comfortable running tests again, you will need to [create one](https://help.github.com/en/articles/creating-a-new-organization-from-scratch). The free "Team for Open Source" org type is fine for these tests. The name of the
If you do not have an organization already that you are comfortable running tests against, you will need to [create one](https://help.github.com/en/articles/creating-a-new-organization-from-scratch). The free "Team for Open Source" org type is fine for these tests. The name of the
organization must then be exported in your environment as `GITHUB_ORGANIZATION`.

### Test repository
In the organization you are using above, create a test repository named `test-repo`. Make sure the repository is configured as follows:
* The description should be `Test description, used in GitHub Terraform provider acceptance test.`
* The website url should be `http://www.example.com`
* Create two topics within the repo named `test-topic` and `second-test-topic`
* In the repo settings, make sure all features and merge button options are enabled.
### Test repositories
In the organization you are using above, create the following test repositories:

* `test-repo`
* The description should be `Test description, used in GitHub Terraform provider acceptance test.`
* The website url should be `http://www.example.com`
* Create two topics within the repo named `test-topic` and `second-test-topic`
* In the repo settings, make sure all features and merge button options are enabled.
* `test-repo-template`
* Configure the repository to be a [Template repository](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-template-repository)

### GitHub users
Export your github username (the one you used to create the personal access token above) as `GITHUB_TEST_USER`. You will need to export a
different github username as `GITHUB_TEST_COLLABORATOR`. Please note that these usernames cannot be the same as each other, and both of them
must be real github usernames. The collaborator user does not need to be added as a collaborator to your test repo or organization, but as
the acceptance tests do real things (and will trigger some notifications for this user), you should probably make sure the person you specify knows that you're doing this just to be nice.
the acceptance tests do real things (and will trigger some notifications for this user), you should probably make sure the person you specify knows that you're doing this just to be nice.
3 changes: 3 additions & 0 deletions github/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ func testAccPreCheck(t *testing.T) {
if v := os.Getenv("GITHUB_TEST_COLLABORATOR"); v == "" {
t.Fatal("GITHUB_TEST_COLLABORATOR must be set for acceptance tests")
}
if v := os.Getenv("GITHUB_TEMPLATE_REPOSITORY"); v == "" {
t.Fatal("GITHUB_TEMPLATE_REPOSITORY must be set for acceptance tests")
}
}

func TestProvider_individual(t *testing.T) {
Expand Down
80 changes: 73 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,24 @@ func resourceGithubRepository() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"template": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"owner": {
Type: schema.TypeString,
Required: true,
},
"repository": {
Type: schema.TypeString,
Required: true,
},
},
},
},
},
}
}
Expand Down Expand Up @@ -174,20 +193,55 @@ 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{})

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 +304,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
72 changes: 72 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,37 @@ resource "github_repository" "foo" {
`, randString, randString)
}

func testAccGithubRepositoryCreateFromTemplate(randString string) string {

owner := os.Getenv("GITHUB_ORGANIZATION")
repository := os.Getenv("GITHUB_TEMPLATE_REPOSITORY")

return fmt.Sprintf(`
resource "github_repository" "foo" {
name = "tf-acc-test-%s"
description = "Terraform acceptance tests %s"
homepage_url = "http://example.com/"
template {
owner = "%s"
repository = "%s"
}
# 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, owner, repository)
}

func testAccGithubRepositoryConfigTopics(randString string, topicList string) string {
return fmt.Sprintf(`
resource "github_repository" "foo" {
Expand Down
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 2d57cfa

Please sign in to comment.