Terraform GitHub Providerで遊んでみた

この記事は`FLINTERS Advent Calendar 2022`の4日目です。
先月FLINTERSに入社したwakye5815です、今回はTerraformRegistryを散策していたところGithub Providerなる面白そうなものを見つけたので遊んでみた機能の紹介になります。

# GitHub Providerとは
GitHub RestAPI,GraphQLを用いてGitHubのリポジトリ設定などをコード化するためのTerraform Providerです。
公式のGithub Integrationから提供、[Github Providerリポジトリ](https://registry.terraform.io/providers/integrations/github/latest/docs)を見る限り現在(2022/12時点)ある程度活発に開発されているようです。

とりあえず環境を構築していきます。
# 環境構築
``` terraform
terraform {
  required_providers {
    github = {
      source  = "integrations/github"
      version = "5.9.1"
    }
  }
}

provider "github" {
  token = var.token
}
```
providerのtokenにはOAuth、Personal Access Tokenのいずれかで発行したtokenを参照します。

``` terraform
provider "github" {
  app_auth {
    id              = var.app_id
    installation_id = var.app_installation_id
    pem_file        = var.app_pem_file
  }
}
```
上記のようにGitHub Appsを用いた認証も可能のようですが今回はPersonal Access Tokenを用いて動作確認をしています。


※この記事は下記のversionで確認された内容になります。
Github Provider -> 5.9.1
Terraform -> 1.3.5

# 触ってみる
導入ができたところでよく使いそうな設定を試しに定義してみました。

## リポジトリ作成、デフォルトブランチ設定
``` terraform
resource "github_repository" "sample_repository" {
  name        = "Sample"
  description = "This is sample repository"
  visibility  = "public"
  auto_init   = true
}

resource "github_branch" "development" {
  repository = github_repository.sample_repository.name
  branch     = "development"
}

resource "github_branch_default" "default" {
  repository = github_repository.sample_repository.name
  branch     = github_branch.development.branch
}
```
publicなリポジトリの定義、developmentブランチを作成後defaultとしてdevelopmentブランチを指定しています。
github_repository.auto_initはmainブランチに初期コミットをしてくれるオプションです、github_branchを定義するにはコミットが存在しないとエラーになるため指定をしています。

## ブランチ保護
``` terraform
resource "github_branch_protection" "main_and_development" {
  for_each      = toset(["main", "development"])
  repository_id = github_repository.sample_repository.node_id
  pattern       = each.value

  required_pull_request_reviews {
    dismiss_stale_reviews           = true
    required_approving_review_count = 1
  }

  allows_deletions                = false
  allows_force_pushes             = false
}
```
main,developmentブランチの保護設定です。PRのレビューを必須に、ブランチ削除、強制pushに対して制限をします。
patternでmatchできない複数ブランチに対して同じ設定をGUIで行うのは少々辛いですが今回terraformによって解決できたのでこれは嬉しいです。

``` terraform
resource "github_branch_protection" "feature" {
  repository_id = github_repository.sample_repository.node_id
  pattern       = "feature*"

  allows_deletions                = true
  allows_force_pushes             = true
}
```
featureブランチの保護設定です。ブランチ削除、強制pushを許可しています。

## リポジトリにユーザー招待
``` terraform
locals {
  collaborator_usernames = []
}
resource "github_repository_collaborator" "default" {
  for_each   = toset(local.collaborator_usernames)
  repository = github_repository.sample_repository.name
  username   = each.value
  permission = "push"
}
```
リポジトリに対してユーザー追加、権限設定を行います。
github_repository_collaboratorの新規作成がapplyされるとinvitationメールが送信されます。
organizationを採用しているならば[membership](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/membership)teamを採用しているならば[team_members](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_members)、[team_membership](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_membership)などの権限管理リソースもあるようです。
## 全体
``` terraform
terraform {
  required_providers {
    github = {
      source  = "integrations/github"
      version = "5.9.1"
    }
  }
}

provider "github" {
  token = var.token
}

resource "github_repository" "sample_repository" {
  name        = "Sample"
  description = "This is sample repository"
  visibility  = "public"
  auto_init   = true
}

resource "github_branch" "development" {
  repository = github_repository.sample_repository.name
  branch     = "development"
}

resource "github_branch_default" "default" {
  repository = github_repository.sample_repository.name
  branch     = github_branch.development.branch
}

resource "github_branch_protection" "main_and_development" {
  for_each      = ["main", "development"]
  repository_id = github_repository.sample_repository.node_id
  pattern       = each.value

  required_pull_request_reviews {
    dismiss_stale_reviews           = true
    required_approving_review_count = 1
  }

  allows_deletions                = false
  allows_force_pushes             = false
}

resource "github_branch_protection" "feature" {
  repository_id = github_repository.sample_repository.node_id
  pattern       = "feature*"

  allows_deletions                = true
  allows_force_pushes             = true
}

locals {
  collaborator_usernames = []
}

resource "github_repository_collaborator" "default" {
  for_each   = toset(local.collaborator_usernames)
  repository = github_repository.sample_repository.name
  username   = each.value
  permission = "push"
}
```

# 感想
個人的にはGUIでやりたくない設定があらかたできるので設定の可視化、ヒューマンエラーの抑制が見込めてとても良さそうな印象です。
当然ですがこのterraform化したGithub管理コードのリポジトリ管理をterraform化して完璧にやるには`while(true) {print("このterraform化したGithub管理コードのリポジトリ管理をterraform化して、")}`になってしまうので手動部分は消せないと思いますが十分効果がありそうです。

上記では触れませんでしたが膨れ上がりがちなGithubActionsのsecret管理もresourceとして提供されているのでGUIでぺたぺたコピペせずに済んで嬉しいですね。

https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret

次回5日目の記事は@takat0-h0rikosh1さんの記事になります！

https://qiita.com/advent-calendar/2022/flinters

# 引用
公式ドキュメント
https://registry.terraform.io/providers/integrations/github/latest/docs