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_app_installation_repository resource #690

Merged
merged 9 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
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,
Comment on lines +14 to +16
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 would we benefit from an Update function here as well? Or is creating a new App installation usually non-disruptive?

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}"
}
Comment on lines +23 to +32
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we get a test that exercises this configuration? Open to updates in HCL syntax as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

🤦🏾 I now see an earlier comment where I requested an example over an acceptance test. I'll give testing a shot and plan to move forward with this with just the example if the test does not pan out.

```

## 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