-
Notifications
You must be signed in to change notification settings - Fork 777
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
Changes from 7 commits
3e44908
8d8dc63
4173066
b0c87d3
f58a09b
37bc9a1
ce1bc09
55aea1c
c8677ff
f909018
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"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, | ||
}, | ||
"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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
package github | ||
|
||
import ( | ||
"fmt" | ||
"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 := "terraform" | ||
owner := "hashicorp" | ||
retrieveBy := "latest" | ||
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", regexp.MustCompile(`hashicorp/terraform`)), | ||
resource.TestMatchResourceAttr("data.github_release.test", "tarball_url", regexp.MustCompile(`hashicorp/terraform/tarball`)), | ||
), | ||
}, | ||
}, | ||
}) | ||
|
||
} | ||
|
||
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`"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing a leading character here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! I'll add that in |
||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccGithubReleaseDataSource_fetchByIdExisting(t *testing.T) { | ||
repo := "terraform" | ||
owner := "hashicorp" | ||
retrieveBy := "id" | ||
id := int64(23055013) | ||
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", regexp.MustCompile(`hashicorp/terraform`)), | ||
resource.TestMatchResourceAttr("data.github_release.test", "tarball_url", regexp.MustCompile(`hashicorp/terraform/tarball`)), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccGithubReleaseDataSource_fetchByTagNoTagReturnsError(t *testing.T) { | ||
repo := "terraform" | ||
owner := "hashicorp" | ||
retrieveBy := "tag" | ||
id := int64(23055013) | ||
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 := "terraform" | ||
owner := "hashicorp" | ||
retrieveBy := "tag" | ||
tag := "v0.12.20" | ||
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", regexp.MustCompile(`hashicorp/terraform`)), | ||
resource.TestMatchResourceAttr("data.github_release.test", "tarball_url", regexp.MustCompile(`hashicorp/terraform/tarball`)), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The convention within this repository I've observed so far has been to not hard-code values such as the repository and tag as was done in this test. I think this test is stable but would like to see an attempt to obtain these values from the environment before proceeding with the hard-coded defaults. See here for prior art. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for referring to this. I was unsure how to proceed since we don't have an associated resource to create / delete a release. Have a look at my changes - adding another environment variable with the tag and sourcing it from the template repo. In future, if added, I think it would be good to manage this release test object via a release resource as well, making it fully isolated. |
||
|
||
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("one of: `latest`, `id`, `tag` must be set for `retrieve_by`"), | ||
}, | ||
}, | ||
}) | ||
|
||
} | ||
|
||
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) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
--- | ||
layout: "github" | ||
page_title: "GitHub: github_release" | ||
description: |- | ||
Get information on a GitHub release. | ||
--- | ||
|
||
# github\_user | ||
|
||
Use this data source to retrieve information about a GitHub release in a specified repository. | ||
|
||
## Example Usage | ||
To retrieve the latest release that is present in a repository: | ||
```hcl | ||
data "github_release" "example" { | ||
repository = "example-repository" | ||
owner = "example-owner" | ||
retrieve_by = "latest" | ||
} | ||
``` | ||
To retrieve a specific release from a repository based on it's ID: | ||
```hcl | ||
data "github_release" "example" { | ||
repository = "example-repository" | ||
owner = "example-owner" | ||
retrieve_by = "id" | ||
id = 12345 | ||
} | ||
``` | ||
Finally, to retrieve a release based on it's tag: | ||
```hcl | ||
data "github_release" "example" { | ||
repository = "example-repository" | ||
owner = "example-owner" | ||
retrieve_by = "tag" | ||
release_tag = "v1.0.0" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
* `repository` - (Required) Name of the repository to retrieve the release from. | ||
|
||
* `owner` - (Required) Owner of the repository. | ||
|
||
* `retrieve_by` - (Required) Describes how to fetch the release. Valid values are `id`, `tag`, `latest`. | ||
|
||
* `release_id` - (Optional) ID of the release to retrieve. Must be specified when `retrieve_by` = `id`. | ||
|
||
* `release_tag` - (Optional) Tag of the release to retrieve. Must be specified when `retrieve_by` = `tag`. | ||
|
||
|
||
## Attributes Reference | ||
|
||
* `release_tag` - Tag of release | ||
* `release_id` - ID of release | ||
* `target_commitish` - Commitish value that determines where the Git release is created from | ||
* `name` - Name of release | ||
* `body` - Contents of the description (body) of a release | ||
* `draft` - (`Boolean`) indicates whether the release is a draft | ||
* `prerelease` - (`Boolean`) indicates whether the release is a prerelease | ||
* `created_at` - Date of release creation | ||
* `published_at` - Date of release publishing | ||
* `url` - Base URL of the release | ||
* `html_url` - URL directing to detailed information on the release | ||
* `asserts_url` - URL of any associated assets with the release | ||
* `upload_url` - URL that can be used to upload Assets to the release | ||
* `zipball_url` - Download URL of a specific release in `zip` format | ||
* `tarball_url` - Download URL of a specific release in `tar.gz` format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: to keep this within some margins, I would extract the third arguments here into their own variables above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good shout, will update this.