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

Add github_branch data and resource #364

Merged
merged 24 commits into from
May 1, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
29c18ba
add github_repository_branch data and resource
cornfeedhobo Feb 25, 2020
7a77eb4
rename github_repository_branch to github_branch and adjust tests to …
cornfeedhobo Mar 4, 2020
09505f2
nit
cornfeedhobo Mar 4, 2020
dd1cb11
Trigger travis
cornfeedhobo Mar 4, 2020
3f9891f
Trigger travis
cornfeedhobo Mar 24, 2020
793f674
Merge branch 'master' into add-github_repository_branch
cornfeedhobo Mar 25, 2020
34759ab
add github_branch documentation
cornfeedhobo Mar 27, 2020
399eaac
revert go.sum change.
cornfeedhobo Mar 27, 2020
5fa3cbb
remove sha attribute
cornfeedhobo Apr 1, 2020
9a856d8
fix importing
cornfeedhobo Apr 1, 2020
b826d09
Merge branch 'master' into add-github_repository_branch
cornfeedhobo Apr 2, 2020
a26f674
include doc links
cornfeedhobo Apr 2, 2020
fea50d9
fix broken doc link
cornfeedhobo Apr 2, 2020
0eac1ce
Merge branch 'master' into add-github_repository_branch
cornfeedhobo Apr 2, 2020
4f600b5
clean up github_branch:
cornfeedhobo Apr 7, 2020
d2fc48e
review
cornfeedhobo Apr 10, 2020
89b1e1e
review
cornfeedhobo Apr 10, 2020
a3e87a0
review
cornfeedhobo Apr 10, 2020
57fb500
Merge branch 'master' into add-github_repository_branch
cornfeedhobo Apr 25, 2020
15abf85
fix client references for github v3 client
cornfeedhobo Apr 25, 2020
1b768ac
fix util call
cornfeedhobo Apr 25, 2020
12be2ab
nit
cornfeedhobo Apr 25, 2020
6550ac2
Merge branch 'master' into add-github_repository_branch
cornfeedhobo Apr 30, 2020
62fcc4d
fix import id when specifying source_branch
cornfeedhobo Apr 30, 2020
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
69 changes: 69 additions & 0 deletions github/data_source_github_branch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package github

import (
"context"
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func dataSourceGithubBranch() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubBranchRead,

Schema: map[string]*schema.Schema{
"repository": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"branch": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"etag": {
Type: schema.TypeString,
Computed: true,
},
"ref": {
Type: schema.TypeString,
Computed: true,
},
"sha": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceGithubBranchRead(d *schema.ResourceData, meta interface{}) error {
err := checkOrganization(meta)
if err != nil {
return err
}

client := meta.(*Organization).client
cornfeedhobo marked this conversation as resolved.
Show resolved Hide resolved
orgName := meta.(*Organization).name
repoName := d.Get("repository").(string)
branchName := d.Get("branch").(string)
branchRefName := "refs/heads/" + branchName

log.Printf("[DEBUG] Reading GitHub branch reference %s/%s (%s)",
orgName, repoName, branchRefName)
ref, resp, err := client.Git.GetRef(
context.TODO(), orgName, repoName, branchRefName)
if err != nil {
return fmt.Errorf("Error reading GitHub branch reference %s/%s (%s): %s",
orgName, repoName, branchRefName, err)
}

d.SetId(buildTwoPartID(&repoName, &branchName))
cornfeedhobo marked this conversation as resolved.
Show resolved Hide resolved
d.Set("etag", resp.Header.Get("ETag"))
d.Set("ref", *ref.Ref)
d.Set("sha", *ref.Object.SHA)

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

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccGithubBranchDataSource_basic(t *testing.T) {

var (
name = "main"
repo = "test-repo"
rn = "data.github_branch." + name
)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckGithubBranchDataSourceConfig(name, repo, "master"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(rn, "repository", repo),
resource.TestCheckResourceAttr(rn, "branch", "master"),
resource.TestCheckResourceAttrSet(rn, "etag"),
resource.TestCheckResourceAttrSet(rn, "ref"),
resource.TestCheckResourceAttrSet(rn, "sha"),
),
},
{
Config: testAccCheckGithubBranchDataSourceConfig(name, repo, "master"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(rn, "repository", repo),
resource.TestCheckResourceAttr(rn, "branch", "master"),
resource.TestCheckResourceAttrSet(rn, "etag"),
resource.TestCheckResourceAttrSet(rn, "ref"),
resource.TestCheckResourceAttrSet(rn, "sha"),
),
},
Comment on lines +32 to +41
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a duplicate of the block above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jcudit Yes. My understanding is that this checks for drift, essentially making sure my state doesn't accidentally drift between runs. This helped me catch an error with where I was setting etag.

{
Config: testAccCheckGithubBranchDataSourceConfig(name, repo, "test-branch"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(rn, "repository", repo),
resource.TestCheckResourceAttr(rn, "branch", "test-branch"),
resource.TestCheckResourceAttrSet(rn, "etag"),
resource.TestCheckResourceAttrSet(rn, "ref"),
resource.TestCheckResourceAttrSet(rn, "sha"),
),
},
{
Config: testAccCheckGithubBranchDataSourceConfig(name, repo, "test-branch"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(rn, "repository", repo),
resource.TestCheckResourceAttr(rn, "branch", "test-branch"),
resource.TestCheckResourceAttrSet(rn, "etag"),
resource.TestCheckResourceAttrSet(rn, "ref"),
resource.TestCheckResourceAttrSet(rn, "sha"),
),
},
Comment on lines +53 to +61
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a duplicate of the block above?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

same answer as above.

},
})

}

func testAccCheckGithubBranchDataSourceConfig(name, repo, branch string) string {
return fmt.Sprintf(`
data "github_branch" "%s" {
repository = "%s"
branch = "%s"
}
`, name, repo, branch)
}
4 changes: 3 additions & 1 deletion github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func Provider() terraform.ResourceProvider {

ResourcesMap: map[string]*schema.Resource{
"github_actions_secret": resourceGithubActionsSecret(),
"github_branch": resourceGithubBranch(),
"github_branch_protection": resourceGithubBranchProtection(),
"github_issue_label": resourceGithubIssueLabel(),
"github_membership": resourceGithubMembership(),
Expand All @@ -69,6 +70,8 @@ func Provider() terraform.ResourceProvider {
},

DataSourcesMap: map[string]*schema.Resource{
"github_actions_public_key": dataSourceGithubActionsPublicKey(),
cornfeedhobo marked this conversation as resolved.
Show resolved Hide resolved
"github_branch": dataSourceGithubBranch(),
"github_collaborators": dataSourceGithubCollaborators(),
"github_ip_ranges": dataSourceGithubIpRanges(),
"github_membership": dataSourceGithubMembership(),
Expand All @@ -77,7 +80,6 @@ func Provider() terraform.ResourceProvider {
"github_repository": dataSourceGithubRepository(),
"github_team": dataSourceGithubTeam(),
"github_user": dataSourceGithubUser(),
"github_actions_public_key": dataSourceGithubActionsPublicKey(),
},
}

Expand Down
202 changes: 202 additions & 0 deletions github/resource_github_branch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package github

import (
"context"
"fmt"
"log"
"net/http"
"strings"

"github.com/google/go-github/v29/github"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceGithubBranch() *schema.Resource {
return &schema.Resource{
Create: resourceGithubBranchCreate,
Read: resourceGithubBranchRead,
Delete: resourceGithubBranchDelete,
Importer: &schema.ResourceImporter{
State: resourceGithubBranchImport,
},

Schema: map[string]*schema.Schema{
"repository": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"branch": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"source_branch": {
Type: schema.TypeString,
Default: "master",
Optional: true,
ForceNew: true,
},
"source_sha": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},
"etag": {
Type: schema.TypeString,
Computed: true,
},
"ref": {
Type: schema.TypeString,
Computed: true,
},
"sha": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceGithubBranchCreate(d *schema.ResourceData, meta interface{}) error {
err := checkOrganization(meta)
if err != nil {
return err
}

ctx := context.Background()
if !d.IsNewResource() {
ctx = context.WithValue(ctx, ctxId, d.Id())
}

client := meta.(*Organization).client
cornfeedhobo marked this conversation as resolved.
Show resolved Hide resolved
orgName := meta.(*Organization).name
repoName := d.Get("repository").(string)
branchName := d.Get("branch").(string)
branchRefName := "refs/heads/" + branchName
sourceBranchName := d.Get("source_branch").(string)
sourceBranchRefName := "refs/heads/" + sourceBranchName

if _, hasSourceSHA := d.GetOk("source_sha"); !hasSourceSHA {
log.Printf("[DEBUG] Querying GitHub branch reference %s/%s (%s) to derive source_sha",
orgName, repoName, sourceBranchRefName)
ref, _, err := client.Git.GetRef(ctx, orgName, repoName, sourceBranchRefName)
if err != nil {
return fmt.Errorf("Error querying GitHub branch reference %s/%s (%s): %s",
orgName, repoName, sourceBranchRefName, err)
}
d.Set("source_sha", *ref.Object.SHA)
}
sourceBranchSHA := d.Get("source_sha").(string)

log.Printf("[DEBUG] Creating GitHub branch reference %s/%s (%s)",
orgName, repoName, branchRefName)
_, _, err = client.Git.CreateRef(ctx, orgName, repoName, &github.Reference{
Ref: &branchRefName,
Object: &github.GitObject{SHA: &sourceBranchSHA},
})
if err != nil {
return fmt.Errorf("Error creating GitHub branch reference %s/%s (%s): %s",
orgName, repoName, branchRefName, err)
}

d.SetId(buildTwoPartID(&repoName, &branchName))
cornfeedhobo marked this conversation as resolved.
Show resolved Hide resolved

return resourceGithubBranchRead(d, meta)
}

func resourceGithubBranchRead(d *schema.ResourceData, meta interface{}) error {
err := checkOrganization(meta)
if err != nil {
return err
}

ctx := context.WithValue(context.Background(), ctxId, d.Id())
if !d.IsNewResource() {
ctx = context.WithValue(ctx, ctxEtag, d.Get("etag").(string))
}

client := meta.(*Organization).client
cornfeedhobo marked this conversation as resolved.
Show resolved Hide resolved
orgName := meta.(*Organization).name
repoName, branchName, err := parseTwoPartID(d.Id(), "repository", "branch")
if err != nil {
return err
}
branchRefName := "refs/heads/" + branchName

log.Printf("[DEBUG] Querying GitHub branch reference %s/%s (%s)",
orgName, repoName, branchRefName)
ref, resp, err := client.Git.GetRef(ctx, orgName, repoName, branchRefName)
if err != nil {
if ghErr, ok := err.(*github.ErrorResponse); ok {
if ghErr.Response.StatusCode == http.StatusNotModified {
return nil
}
if ghErr.Response.StatusCode == http.StatusNotFound {
log.Printf("[WARN] Removing branch %s/%s (%s) from state because it no longer exists in Github",
orgName, repoName, branchName)
d.SetId("")
return nil
}
}
return fmt.Errorf("Error querying GitHub branch reference %s/%s (%s): %s",
orgName, repoName, branchRefName, err)
}

d.SetId(buildTwoPartID(&repoName, &branchName))
d.Set("etag", resp.Header.Get("ETag"))
d.Set("repository", repoName)
d.Set("branch", branchName)
d.Set("ref", *ref.Ref)
d.Set("sha", *ref.Object.SHA)

return nil
}

func resourceGithubBranchDelete(d *schema.ResourceData, meta interface{}) error {
err := checkOrganization(meta)
if err != nil {
return err
}

ctx := context.WithValue(context.Background(), ctxId, d.Id())

client := meta.(*Organization).client
orgName := meta.(*Organization).name
repoName, branchName, err := parseTwoPartID(d.Id(), "repository", "branch")
if err != nil {
return err
}
branchRefName := "refs/heads/" + branchName

log.Printf("[DEBUG] Deleting GitHub branch reference %s/%s (%s)",
orgName, repoName, branchRefName)
_, err = client.Git.DeleteRef(ctx, orgName, repoName, branchRefName)
if err != nil {
return fmt.Errorf("Error deleting GitHub branch reference %s/%s (%s): %s",
orgName, repoName, branchRefName, err)
}

return nil
}

func resourceGithubBranchImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
repoName, branchName, err := parseTwoPartID(d.Id(), "repository", "branch")
cornfeedhobo marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}

sourceBranch := "master"
if strings.Contains(branchName, ":") {
branchName, sourceBranch, err = parseTwoPartID(branchName, "branch", "source_branch")
if err != nil {
return nil, err
}
d.SetId(buildTwoPartID(&repoName, &branchName))
cornfeedhobo marked this conversation as resolved.
Show resolved Hide resolved
}

d.Set("source_branch", sourceBranch)

return []*schema.ResourceData{d}, resourceGithubBranchRead(d, meta)
}
Loading