Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
## 2.3.0 (Unreleased)

FEATURES:

* **New Resource:** `github_repository_prereceive_hook` ([#252](https://github.com/terraform-providers/terraform-provider-github/issues/252))

## 2.2.0 (June 28, 2019)

FEATURES:
Expand Down
37 changes: 19 additions & 18 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,25 @@ func Provider() terraform.ResourceProvider {
},

ResourcesMap: map[string]*schema.Resource{
"github_branch_protection": resourceGithubBranchProtection(),
"github_issue_label": resourceGithubIssueLabel(),
"github_membership": resourceGithubMembership(),
"github_organization_block": resourceOrganizationBlock(),
"github_organization_project": resourceGithubOrganizationProject(),
"github_organization_webhook": resourceGithubOrganizationWebhook(),
"github_project_column": resourceGithubProjectColumn(),
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
"github_repository_project": resourceGithubRepositoryProject(),
"github_repository_webhook": resourceGithubRepositoryWebhook(),
"github_repository": resourceGithubRepository(),
"github_team_membership": resourceGithubTeamMembership(),
"github_team_repository": resourceGithubTeamRepository(),
"github_team": resourceGithubTeam(),
"github_user_gpg_key": resourceGithubUserGpgKey(),
"github_user_invitation_accepter": resourceGithubUserInvitationAccepter(),
"github_user_ssh_key": resourceGithubUserSshKey(),
"github_branch_protection": resourceGithubBranchProtection(),
"github_issue_label": resourceGithubIssueLabel(),
"github_membership": resourceGithubMembership(),
"github_organization_block": resourceOrganizationBlock(),
"github_organization_project": resourceGithubOrganizationProject(),
"github_organization_webhook": resourceGithubOrganizationWebhook(),
"github_project_column": resourceGithubProjectColumn(),
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
"github_repository_project": resourceGithubRepositoryProject(),
"github_repository_webhook": resourceGithubRepositoryWebhook(),
"github_repository_prereceive_hook": resourceGithubRepositoryPreReceiveHook(),
"github_repository": resourceGithubRepository(),
"github_team_membership": resourceGithubTeamMembership(),
"github_team_repository": resourceGithubTeamRepository(),
"github_team": resourceGithubTeam(),
"github_user_gpg_key": resourceGithubUserGpgKey(),
"github_user_invitation_accepter": resourceGithubUserInvitationAccepter(),
"github_user_ssh_key": resourceGithubUserSshKey(),
},

DataSourcesMap: map[string]*schema.Resource{
Expand Down
165 changes: 165 additions & 0 deletions github/resource_github_repository_prereceive_hook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package github

import (
"context"
"fmt"
"strconv"

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

func resourceGithubRepositoryPreReceiveHook() *schema.Resource {
return &schema.Resource{
Create: resourceGithubRepositoryPreReceiveHookCreate,
Read: resourceGithubRepositoryPreReceiveHookRead,
Update: resourceGithubRepositoryPreReceiveHookCreate,
Delete: resourceGithubRepositoryPreReceiveHookDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"repository": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"enforcement": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"enabled", "disabled", "testing"}, false),
},
"config_url": {
Type: schema.TypeString,
Optional: true,
},
},
}
}

func fetchGitHubRepositoryPreReceiveHookByName(meta interface{}, repoName, hookName string) (*github.PreReceiveHook, error) {
ctx := context.Background()
client := meta.(*Organization).client
orgName := meta.(*Organization).name

opt := &github.ListOptions{
PerPage: 100,
}

var hook *github.PreReceiveHook

for {
hooks, resp, err := client.Repositories.ListPreReceiveHooks(ctx, orgName, repoName, opt)
if err != nil {
return nil, err
}

for _, h := range hooks {
n := *h.Name
if n == hookName {
hook = h
break
}
}

if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}

if *hook.ID <= 0 {
return nil, fmt.Errorf("No pre-receive hook with name %s found on %s/%s", hookName, orgName, repoName)
}

return hook, nil
}

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

repoName := d.Get("repository").(string)
hookName := d.Get("name").(string)

hook, err := fetchGitHubRepositoryPreReceiveHookByName(meta, repoName, hookName)
if err != nil {
return err
}

enforcement := d.Get("enforcement").(string)
hook.Enforcement = &enforcement

if v, ok := d.GetOk("config_url"); ok {
configURL := v.(string)
hook.ConfigURL = &configURL
}

ctx := context.Background()
client := meta.(*Organization).client
orgName := meta.(*Organization).name
_, _, err = client.Repositories.UpdatePreReceiveHook(ctx, orgName, repoName, *hook.ID, hook)
if err != nil {
return err
}

d.SetId(fmt.Sprintf("%s/%s/%s", orgName, repoName, strconv.FormatInt(*hook.ID, 10)))

return resourceGithubRepositoryPreReceiveHookRead(d, meta)
}

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

repoName := d.Get("repository").(string)
hookName := d.Get("name").(string)

hook, err := fetchGitHubRepositoryPreReceiveHookByName(meta, repoName, hookName)
if err != nil {
return err
}

d.Set("enforcement", hook.Enforcement)

if _, ok := d.GetOk("config_url"); ok {
d.Set("config_url", hook.ConfigURL)
}

return nil
}

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

repoName := d.Get("repository").(string)
hookName := d.Get("name").(string)

hook, err := fetchGitHubRepositoryPreReceiveHookByName(meta, repoName, hookName)
if err != nil {
return err
}

disabled := "disabled"
hook.Enforcement = &disabled

ctx := context.Background()
client := meta.(*Organization).client
orgName := meta.(*Organization).name
_, _, err = client.Repositories.UpdatePreReceiveHook(ctx, orgName, repoName, *hook.ID, hook)
if err != nil {
return err
}

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

import (
"context"
"fmt"
"strconv"
"strings"
"testing"

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

func TestAccGithubRepositoryPreReceiveHook_basic(t *testing.T) {
randString := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
enforcement := "enabled"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccGithubRepositoryPreReceiveHookConfig_basic(randString),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitHubPreReceiveHookEnforcement("github_repository_prereceive_hook.foo", enforcement),
resource.TestCheckResourceAttr(
"github_repository_prereceive_hook.foo", "enforcement", enforcement),
resource.TestCheckResourceAttrSet(
"github_repository_prereceive_hook.foo", "id"),
),
},
},
})
}

func testAccCheckGitHubPreReceiveHookEnforcement(n string, enforcement string) resource.TestCheckFunc {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not required as we should be checking what's in state matches reality. This can be accomplished using an import state verifier

{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},

Copy link
Author

Choose a reason for hiding this comment

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

This is a check against the API; not state? I don't have an importer for this resource. I can skip validating against the API entirely though if that's preferred (I copied this pattern from the webhook tests).

return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]

if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No hook ID is set")
}

id := strings.Split(rs.Primary.ID, "/")
orgName, repoName, i := id[0], id[1], id[2]

hookID, err := strconv.ParseInt(i, 10, 64)
if err != nil {
return err
}

org := testAccProvider.Meta().(*Organization)
client := org.client

hook, _, err := client.Repositories.GetPreReceiveHook(context.TODO(), orgName, repoName, hookID)

if err != nil {
return err
}

if *hook.Enforcement != enforcement {
return fmt.Errorf("Enforcement set to %s instead of %s", *hook.Enforcement, enforcement)
}

return nil
}
}

func testAccGithubRepositoryPreReceiveHookConfig_basic(randString string) string {
return fmt.Sprintf(`
resource "github_repository" "foo" {
name = "foo-%s"
description = "Terraform acceptance tests"
homepage_url = "http://example.com/"
# So that acceptance tests can be run in a github organization
# with no billing
private = false
has_issues = true
has_wiki = true
has_downloads = true
}
resource "github_repository_prereceive_hook" "foo" {
name = "require-code-review"
repository = "${github_repository.foo.name}"
enforcement = "enabled"
}
`, randString)
}
41 changes: 41 additions & 0 deletions website/docs/r/repository_prereceive_hook.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
layout: "github"
page_title: "GitHub: github_repository_prereceive_hook"
sidebar_current: "docs-github-resource-repository-prereceive-hook"
description: |-
Creates and manages repository pre-recieve hooks within a GitHub Enterprise organization
---

# github_repository_prereceive_hook

This resource allows you to create and manage [pre-receive hooks](https://developer.github.com/enterprise/2.17/v3/enterprise-admin/repo_pre_receive_hooks/) for
repositories within your GitHub Enterprise organizations.

~> **NOTE** Pre-recieve hooks are only available on GitHub Enterprise.

## Example Usage

```hcl
resource "github_repository" "repo" {
name = "foo"
description = "Terraform acceptance tests"
}

resource "github_repository_prereceive_hook" "reviews" {
name = "require-code-review"
repository = "${github_repository.repo.name}"
enforcement = "enabled"
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of the pre-receive hook.

* `repository` - (Required) The repository of the pre-receive hook.

* `enforcement` - (Required) The state of enforcement for the hook on this repository. Available keys are `enabled`, `disabled`, and `testing`.

* `config_url` - (Optional) URL for the endpoint where enforcement is set.
3 changes: 3 additions & 0 deletions website/github.erb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
<li<%= sidebar_current("docs-github-resource-repository-deploy-key") %>>
<a href="/docs/providers/github/r/repository_deploy_key.html">github_repository_deploy_key</a>
</li>
<li<%= sidebar_current("docs-github-resource-repository-prereceive-hook") %>>
<a href="/docs/providers/github/r/repository_prereceive_hook.html">github_repository_prereceive_hook</a>
</li>
<li<%= sidebar_current("docs-github-resource-repository-project") %>>
<a href="/docs/providers/github/r/repository_project.html">github_repository_project</a>
</li>
Expand Down