Skip to content

Commit

Permalink
Merge pull request #356 from dmwgroup/gh-144-releases-data-source
Browse files Browse the repository at this point in the history
GH-144 - New Data Source: Github release
  • Loading branch information
Jeremy Udit authored Feb 20, 2020
2 parents 8e28b5c + f909018 commit 7be5e1a
Show file tree
Hide file tree
Showing 6 changed files with 398 additions and 0 deletions.
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`

Export an environment variable corresponding to `GITHUB_TEMPLATE_REPOSITORY=test-repo-template`.

Expand All @@ -109,3 +110,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

0 comments on commit 7be5e1a

Please sign in to comment.