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

GH-144 - New Data Source: Github release #356

Merged
merged 10 commits into from
Feb 20, 2020
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ In the organization you are using above, create the following test repositories:
* Create a `test-branch` branch
* `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)
* Create a release on the repository with `tag = v1.0`

### 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
Expand All @@ -107,3 +108,5 @@ the acceptance tests do real things (and will trigger some notifications for thi

Additionally the user exported as `GITHUB_TEST_USER` should have a public email address configured in their profile; this should be exported
as `GITHUB_TEST_USER_EMAIL` and the Github name exported as `GITHUB_TEST_USER_NAME` (this could be different to your GitHub login).

Finally, export the ID of the release created in the template repository as `GITHUB_TEMPLATE_REPOSITORY_RELEASE_ID`
156 changes: 156 additions & 0 deletions github/data_source_github_release.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package github

import (
"context"
"fmt"
"github.com/hashicorp/terraform/helper/validation"
"log"
"strconv"
"strings"

"github.com/google/go-github/v28/github"
"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceGithubRelease() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubReleaseRead,

Schema: map[string]*schema.Schema{
"repository": {
Type: schema.TypeString,
Required: true,
},
"owner": {
Type: schema.TypeString,
Required: true,
},
"retrieve_by": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
"latest",
"id",
"tag",
}, false),
},
"release_tag": {
Type: schema.TypeString,
Optional: true,
},
"release_id": {
Type: schema.TypeInt,
Optional: true,
},
"target_commitish": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"body": {
Type: schema.TypeString,
Computed: true,
},
"draft": {
Type: schema.TypeBool,
Computed: true,
},
"prerelease": {
Type: schema.TypeBool,
Computed: true,
},
"created_at": {
Type: schema.TypeString,
Computed: true,
},
"published_at": {
Type: schema.TypeString,
Computed: true,
},
"url": {
Type: schema.TypeString,
Computed: true,
},
"html_url": {
Type: schema.TypeString,
Computed: true,
},
"asserts_url": {
Type: schema.TypeString,
Computed: true,
},
"upload_url": {
Type: schema.TypeString,
Computed: true,
},
"zipball_url": {
Type: schema.TypeString,
Computed: true,
},
"tarball_url": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceGithubReleaseRead(d *schema.ResourceData, meta interface{}) error {
repository := d.Get("repository").(string)
owner := d.Get("owner").(string)

client := meta.(*Organization).client
ctx := context.Background()

var err error
var release *github.RepositoryRelease

switch retrieveBy := strings.ToLower(d.Get("retrieve_by").(string)); retrieveBy {
case "latest":
log.Printf("[INFO] Refreshing GitHub latest release from repository %s", repository)
release, _, err = client.Repositories.GetLatestRelease(ctx, owner, repository)
case "id":
releaseID := int64(d.Get("release_id").(int))
if releaseID == 0 {
return fmt.Errorf("`release_id` must be set when `retrieve_by` = `id`")
}

log.Printf("[INFO] Refreshing GitHub release by id %d from repository %s", releaseID, repository)
release, _, err = client.Repositories.GetRelease(ctx, owner, repository, releaseID)
case "tag":
tag := d.Get("release_tag").(string)
if tag == "" {
return fmt.Errorf("`release_tag` must be set when `retrieve_by` = `tag`")
}

log.Printf("[INFO] Refreshing GitHub release by tag %s from repository %s", tag, repository)
release, _, err = client.Repositories.GetReleaseByTag(ctx, owner, repository, tag)
default:
return fmt.Errorf("one of: `latest`, `id`, `tag` must be set for `retrieve_by`")
}

if err != nil {
return err
}

d.SetId(strconv.FormatInt(release.GetID(), 10))
d.Set("release_tag", release.GetTagName())
d.Set("target_commitish", release.GetTargetCommitish())
d.Set("name", release.GetName())
d.Set("body", release.GetBody())
d.Set("draft", release.GetDraft())
d.Set("prerelease", release.GetPrerelease())
d.Set("created_at", release.GetCreatedAt())
d.Set("published_at", release.GetPublishedAt())
d.Set("url", release.GetURL())
d.Set("html_url", release.GetHTMLURL())
d.Set("asserts_url", release.GetAssetsURL())
d.Set("upload_url", release.GetUploadURL())
d.Set("zipball_url", release.GetZipballURL())
d.Set("tarball_url", release.GetTarballURL())

return nil
}
166 changes: 166 additions & 0 deletions github/data_source_github_release_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package github

import (
"fmt"
"os"
"regexp"
"strconv"
"testing"

"github.com/hashicorp/terraform/helper/resource"
)

func TestAccGithubReleaseDataSource_fetchByLatestNoReleaseReturnsError(t *testing.T) {
repo := "nonExistentRepo"
owner := "no-user"
retrieveBy := "latest"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckGithubReleaseDataSourceConfig(repo, owner, retrieveBy, "", 0),
ExpectError: regexp.MustCompile(`Not Found`),
},
},
})
}

func TestAccGithubReleaseDataSource_latestExisting(t *testing.T) {
repo := os.Getenv("GITHUB_TEMPLATE_REPOSITORY")
owner := os.Getenv("GITHUB_ORGANIZATION")
retrieveBy := "latest"
expectedUrl := regexp.MustCompile(fmt.Sprintf("%s/%s", owner, repo))
expectedTarball := regexp.MustCompile(fmt.Sprintf("%s/%s/tarball", owner, repo))
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckGithubReleaseDataSourceConfig(repo, owner, retrieveBy, "", 0),
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("data.github_release.test", "url", expectedUrl),
resource.TestMatchResourceAttr("data.github_release.test", "tarball_url", expectedTarball),
),
},
},
})
}

func TestAccGithubReleaseDataSource_fetchByIdWithNoIdReturnsError(t *testing.T) {
retrieveBy := "id"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckGithubReleaseDataSourceConfig("", "", retrieveBy, "", 0),
ExpectError: regexp.MustCompile("`release_id` must be set when `retrieve_by` = `id`"),
},
},
})
}

func TestAccGithubReleaseDataSource_fetchByIdExisting(t *testing.T) {
repo := os.Getenv("GITHUB_TEMPLATE_REPOSITORY")
owner := os.Getenv("GITHUB_ORGANIZATION")
retrieveBy := "id"
expectedUrl := regexp.MustCompile(fmt.Sprintf("%s/%s", owner, repo))
expectedTarball := regexp.MustCompile(fmt.Sprintf("%s/%s/tarball", owner, repo))
id, _ := strconv.ParseInt(os.Getenv("GITHUB_TEMPLATE_REPOSITORY_RELEASE_ID"), 10, 64)
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckGithubReleaseDataSourceConfig(repo, owner, retrieveBy, "", id),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.github_release.test", "release_id", strconv.FormatInt(id, 10)),
resource.TestMatchResourceAttr("data.github_release.test", "url", expectedUrl),
resource.TestMatchResourceAttr("data.github_release.test", "tarball_url", expectedTarball),
),
},
},
})
}

func TestAccGithubReleaseDataSource_fetchByTagNoTagReturnsError(t *testing.T) {
repo := os.Getenv("GITHUB_TEMPLATE_REPOSITORY")
owner := os.Getenv("GITHUB_ORGANIZATION")
retrieveBy := "tag"
id := int64(0)
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckGithubReleaseDataSourceConfig(repo, owner, retrieveBy, "", id),
ExpectError: regexp.MustCompile("`release_tag` must be set when `retrieve_by` = `tag`"),
},
},
})
}

func TestAccGithubReleaseDataSource_fetchByTagExisting(t *testing.T) {
repo := os.Getenv("GITHUB_TEMPLATE_REPOSITORY")
owner := os.Getenv("GITHUB_ORGANIZATION")
retrieveBy := "tag"
tag := "v1.0"
expectedUrl := regexp.MustCompile(fmt.Sprintf("%s/%s", owner, repo))
expectedTarball := regexp.MustCompile(fmt.Sprintf("%s/%s/tarball", owner, repo))
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckGithubReleaseDataSourceConfig(repo, owner, retrieveBy, tag, 0),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.github_release.test", "release_tag", tag),
resource.TestMatchResourceAttr("data.github_release.test", "url", expectedUrl),
resource.TestMatchResourceAttr("data.github_release.test", "tarball_url", expectedTarball),
),
},
},
})
}

func TestAccGithubReleaseDataSource_invalidRetrieveMethodReturnsError(t *testing.T) {
retrieveBy := "not valid"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckGithubReleaseDataSourceConfig("", "", retrieveBy, "", 0),
ExpectError: regexp.MustCompile(`expected retrieve_by to be one of \[latest id tag]`),
},
},
})

}

func testAccCheckGithubReleaseDataSourceConfig(repo, owner, retrieveBy, tag string, id int64) string {
return fmt.Sprintf(`
data "github_release" "test" {
repository = "%s"
owner = "%s"
retrieve_by = "%s"
release_tag = "%s"
release_id = %d
}
`, repo, owner, retrieveBy, tag, id)
}
1 change: 1 addition & 0 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func Provider() terraform.ResourceProvider {
DataSourcesMap: map[string]*schema.Resource{
"github_collaborators": dataSourceGithubCollaborators(),
"github_ip_ranges": dataSourceGithubIpRanges(),
"github_release": dataSourceGithubRelease(),
"github_repositories": dataSourceGithubRepositories(),
"github_repository": dataSourceGithubRepository(),
"github_team": dataSourceGithubTeam(),
Expand Down
3 changes: 3 additions & 0 deletions github/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ func testAccPreCheck(t *testing.T) {
if v := os.Getenv("GITHUB_TEMPLATE_REPOSITORY"); v == "" {
t.Fatal("GITHUB_TEMPLATE_REPOSITORY must be set for acceptance tests")
}
if v := os.Getenv("GITHUB_TEMPLATE_REPOSITORY_RELEASE_ID"); v == "" {
t.Fatal("GITHUB_TEMPLATE_REPOSITORY_RELEASE_ID must be set for acceptance tests")
}
}

func TestProvider_individual(t *testing.T) {
Expand Down
Loading