Skip to content

Commit

Permalink
Add github_app_installation_repository resource
Browse files Browse the repository at this point in the history
  • Loading branch information
k24dizzle committed Mar 8, 2021
1 parent 00a960a commit b2c7400
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 0 deletions.
35 changes: 35 additions & 0 deletions examples/app_installation_repository/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# App Installation Example

This example gives an application installation access to a
specific repository in the same organization.

To complete this demo, first [install an application in your
github organization](https://docs.github.com/en/github/customizing-your-github-workflow/installing-an-app-in-your-organization). To use the full scope of this
resource, make sure you install the application only on select repositories
in the organization (instead of all repositories).

This will allow you to use this resource to manage which repositories
the app installation has access to.

After you have installed the application, locate the installation id of the
application by visiting `https://github.com/organizations/{ORG_NAME}/settings/installations`
and configuring the app you'd like to install.
The ID should be located in the URL on the configure page.

This example will create a repository in the specified organization.
It will also add the created repository to the app installation.

Alternatively, you may use variables passed via command line:

```console
export GITHUB_ORG=
export GITHUB_TOKEN=
export INSTALLATION_ID=
```

```console
terraform apply \
-var "organization=${GITHUB_ORG}" \
-var "github_token=${GITHUB_TOKEN}" \
-var "installation_id=${INSTALLATION_ID}" \
```
9 changes: 9 additions & 0 deletions examples/app_installation_repository/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
resource "github_repository" "app_installation_example" {
name = "appinstallationexample"
description = "A repository to install an application in."
}

resource "github_app_installation_repository" "test"{
repository = github_repository.app_installation_example.name
installation_id = var.installation_id
}
Empty file.
4 changes: 4 additions & 0 deletions examples/app_installation_repository/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
provider "github" {
organization = var.organization
token = var.github_token
}
14 changes: 14 additions & 0 deletions examples/app_installation_repository/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
variable "installation_id" {
description = "ID of an app installation in an organization"
type = string
}

variable "organization" {
description = "GitHub organization used to configure the provider"
type = string
}

variable "github_token" {
description = "GitHub access token used to configure the provider"
type = string
}
1 change: 1 addition & 0 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func Provider() terraform.ResourceProvider {
ResourcesMap: map[string]*schema.Resource{
"github_actions_organization_secret": resourceGithubActionsOrganizationSecret(),
"github_actions_secret": resourceGithubActionsSecret(),
"github_app_installation_repository": resourceGithubAppInstallationRepository(),
"github_branch": resourceGithubBranch(),
"github_branch_protection": resourceGithubBranchProtection(),
"github_branch_protection_v3": resourceGithubBranchProtectionV3(),
Expand Down
146 changes: 146 additions & 0 deletions github/resource_github_app_installation_repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package github

import (
"context"
"log"
"strconv"

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

func resourceGithubAppInstallationRepository() *schema.Resource {
return &schema.Resource{
Create: resourceGithubAppInstallationRepositoryCreate,
Read: resourceGithubAppInstallationRepositoryRead,
Delete: resourceGithubAppInstallationRepositoryDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"installation_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"repository": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"repo_id": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}

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

installationIDString := d.Get("installation_id").(string)
installationID, err := strconv.ParseInt(installationIDString, 10, 64)
if err != nil {
return unconvertibleIdErr(installationIDString, err)
}

client := meta.(*Owner).v3client
owner := meta.(*Owner).name
ctx := context.Background()
repoName := d.Get("repository").(string)
repo, _, err := client.Repositories.Get(ctx, owner, repoName)
if err != nil {
return err
}
repoID := repo.GetID()

log.Printf("[DEBUG] Creating app installation repository association: %s:%s",
installationIDString, repoName)

_, _, err = client.Apps.AddRepository(ctx, installationID, repoID)
if err != nil {
return err
}

d.SetId(buildTwoPartID(installationIDString, repoName))
return resourceGithubAppInstallationRepositoryRead(d, meta)
}

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

client := meta.(*Owner).v3client
installationIDString, repoName, err := parseTwoPartID(d.Id(), "installation_id", "repository")
if err != nil {
return err
}

installationID, err := strconv.ParseInt(installationIDString, 10, 64)
if err != nil {
return unconvertibleIdErr(installationIDString, err)
}

ctx := context.WithValue(context.Background(), ctxId, d.Id())
opt := &github.ListOptions{PerPage: maxPerPage}

for {
repos, resp, err := client.Apps.ListUserRepos(ctx, installationID, opt)
if err != nil {
return err
}

log.Printf("[DEBUG] Found %d repos, checking if any matches %s", len(repos), repoName)
for _, r := range repos {
if r.GetName() == repoName {
d.Set("installation_id", installationIDString)
d.Set("repository", repoName)
d.Set("repo_id", r.GetID())
return nil
}
}

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

log.Printf("[WARN] Removing app installation repository association %s from state because it no longer exists in GitHub",
d.Id())
d.SetId("")
return nil
}

func resourceGithubAppInstallationRepositoryDelete(d *schema.ResourceData, meta interface{}) error {
err := checkOrganization(meta)
if err != nil {
return err
}
installationIDString := d.Get("installation_id").(string)
installationID, err := strconv.ParseInt(installationIDString, 10, 64)
if err != nil {
return unconvertibleIdErr(installationIDString, err)
}

client := meta.(*Owner).v3client
ctx := context.Background()

repoName := d.Get("repository").(string)
repoID := d.Get("repo_id").(int)
log.Printf("[DEBUG] Deleting app installation repository association: %s:%s",
installationIDString, repoName)

_, err = client.Apps.RemoveRepository(ctx, installationID, int64(repoID))
if err != nil {
return err
}
return nil
}
49 changes: 49 additions & 0 deletions website/docs/r/app_installation_repository.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
layout: "github"
page_title: "GitHub: github_app_installation_repository"
description: |-
Manages the associations between app installations and repositories.
---

# github_app_installation_repository

This resource manages relationships between app installations and repositories
in your GitHub organization.

Creating this resource installs a particular app on a particular repository.

The app installation and the repository must both belong to the same
organization on GitHub. Note: you can review your organization's installations
by the following the instructions at this
[link](https://docs.github.com/en/github/setting-up-and-managing-organizations-and-teams/reviewing-your-organizations-installed-integrations).

## Example Usage

```hcl
# Create a repository.
resource "github_repository" "some_repo" {
name = "some-repo"
}
resource "github_app_installation_repository" "some_app_repo" {
# The installation id of the app (in the organization).
installation_id = "1234567"
repository = "${github_repository.some_repo.name}"
}
```

## Argument Reference

The following arguments are supported:

* `installation_id` - (Required) The GitHub app installation id.
* `repository` - (Required) The repository to install the app on.

## Import

GitHub App Installation Repository can be imported
using an ID made up of `installation_id:repository`, e.g.

```
$ terraform import github_app_installation_repository.terraform_repo 1234567:terraform
```
3 changes: 3 additions & 0 deletions website/github.erb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
<li>
<a href="/docs/providers/github/r/actions_secret.html">github_actions_secret</a>
</li>
<li>
<a href="/docs/providers/github/r/app_installation_repository.html">github_app_installation_repository</a>
</li>
<li>
<a href="/docs/providers/github/r/branch.html">github_branch</a>
</li>
Expand Down

0 comments on commit b2c7400

Please sign in to comment.