Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/repository: add create from template #309

Merged
merged 3 commits into from
Jan 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much for updating these instructions! ❤️


### 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,
jcudit marked this conversation as resolved.
Show resolved Hide resolved
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