From 8130794cbff2e1d7f2ced97e217cc4aedbe293ab Mon Sep 17 00:00:00 2001 From: Byungjin Park Date: Mon, 14 Mar 2022 02:26:09 +0900 Subject: [PATCH] Migrate modules --- modules/org-organization/README.md | 58 ++++++++ modules/org-organization/main.tf | 53 ++++++++ modules/org-organization/outputs.tf | 49 +++++++ modules/org-organization/variables.tf | 22 +++ modules/org-organization/versions.tf | 12 ++ modules/org-team/README.md | 61 +++++++++ modules/org-team/main.tf | 42 ++++++ modules/org-team/outputs.tf | 54 ++++++++ modules/org-team/variables.tf | 46 +++++++ modules/org-team/versions.tf | 12 ++ modules/project/README.md | 56 ++++++++ modules/project/main.tf | 27 ++++ modules/project/outputs.tf | 52 +++++++ modules/project/variables.tf | 33 +++++ modules/project/versions.tf | 12 ++ modules/repository/README.md | 97 ++++++++++++++ modules/repository/collaborators.tf | 58 ++++++++ modules/repository/deploy-keys.tf | 15 +++ modules/repository/issue-labels.tf | 16 +++ modules/repository/main.tf | 51 +++++++ modules/repository/outputs.tf | 139 +++++++++++++++++++ modules/repository/teams.tf | 56 ++++++++ modules/repository/variables.tf | 186 ++++++++++++++++++++++++++ modules/repository/versions.tf | 12 ++ modules/webhook/README.md | 55 ++++++++ modules/webhook/main.tf | 36 +++++ modules/webhook/outputs.tf | 38 ++++++ modules/webhook/variables.tf | 47 +++++++ modules/webhook/versions.tf | 12 ++ 29 files changed, 1407 insertions(+) create mode 100644 modules/org-organization/README.md create mode 100644 modules/org-organization/main.tf create mode 100644 modules/org-organization/outputs.tf create mode 100644 modules/org-organization/variables.tf create mode 100644 modules/org-organization/versions.tf create mode 100644 modules/org-team/README.md create mode 100644 modules/org-team/main.tf create mode 100644 modules/org-team/outputs.tf create mode 100644 modules/org-team/variables.tf create mode 100644 modules/org-team/versions.tf create mode 100644 modules/project/README.md create mode 100644 modules/project/main.tf create mode 100644 modules/project/outputs.tf create mode 100644 modules/project/variables.tf create mode 100644 modules/project/versions.tf create mode 100644 modules/repository/README.md create mode 100644 modules/repository/collaborators.tf create mode 100644 modules/repository/deploy-keys.tf create mode 100644 modules/repository/issue-labels.tf create mode 100644 modules/repository/main.tf create mode 100644 modules/repository/outputs.tf create mode 100644 modules/repository/teams.tf create mode 100644 modules/repository/variables.tf create mode 100644 modules/repository/versions.tf create mode 100644 modules/webhook/README.md create mode 100644 modules/webhook/main.tf create mode 100644 modules/webhook/outputs.tf create mode 100644 modules/webhook/variables.tf create mode 100644 modules/webhook/versions.tf diff --git a/modules/org-organization/README.md b/modules/org-organization/README.md new file mode 100644 index 0000000..31d98ee --- /dev/null +++ b/modules/org-organization/README.md @@ -0,0 +1,58 @@ +# org-organization + +This module creates following resources. + +- `github_membership` (optional) +- `github_organization_block` (optional) + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.1 | +| [github](#requirement\_github) | = 4.13.0 | + +## Providers + +| Name | Version | +|------|---------| +| [github](#provider\_github) | 4.13.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_membership.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/membership) | resource | +| [github_organization_block.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/organization_block) | resource | +| [github_organization.after](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/data-sources/organization) | data source | +| [github_organization.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/data-sources/organization) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name](#input\_name) | (Required) The name of the organization. | `string` | n/a | yes | +| [blocked\_users](#input\_blocked\_users) | (Optional) A list of usernames to block from organization. | `set(string)` | `[]` | no | +| [members](#input\_members) | (Optional) A list of usernames to add users as `member` role. When applied, an invitation will be sent to the user to become a member of the organization. | `set(string)` | `[]` | no | +| [owners](#input\_owners) | (Optional) A list of usernames to add users as `admin` role. When applied, an invitation will be sent to the user to become an owner of the organization. | `set(string)` | `[]` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [all\_members](#output\_all\_members) | A list of all members of the organization. | +| [blocked\_users](#output\_blocked\_users) | A list of blocked usernames from organization. | +| [description](#output\_description) | The description of the organization. | +| [display\_name](#output\_display\_name) | The display name of the organization. | +| [id](#output\_id) | The ID of the organization. | +| [members](#output\_members) | A list of the members of the organization. | +| [name](#output\_name) | The name of the organization. | +| [owners](#output\_owners) | A list of the owners of the organization. | +| [plan](#output\_plan) | The billing plan of the organization. | +| [repositories](#output\_repositories) | A list of the repositories of the organization. | + diff --git a/modules/org-organization/main.tf b/modules/org-organization/main.tf new file mode 100644 index 0000000..8015d36 --- /dev/null +++ b/modules/org-organization/main.tf @@ -0,0 +1,53 @@ +data "github_organization" "this" { + name = var.name +} + +data "github_organization" "after" { + name = var.name + + depends_on = [ + github_membership.this + ] +} + +locals { + members = [ + for member in var.members : { + username = member + role = "member" + } + ] + owners = [ + for owner in var.owners : { + username = owner + role = "admin" + } + ] + membership = concat(local.members, local.owners) +} + + +################################################### +# Membership of GitHub Organization +################################################### + +resource "github_membership" "this" { + for_each = { + for member in local.membership : + member.username => member + } + + username = each.key + role = each.value.role +} + + +################################################### +# Blocked Users of GitHub Organization +################################################### + +resource "github_organization_block" "this" { + for_each = toset(var.blocked_users) + + username = each.key +} diff --git a/modules/org-organization/outputs.tf b/modules/org-organization/outputs.tf new file mode 100644 index 0000000..3d36f99 --- /dev/null +++ b/modules/org-organization/outputs.tf @@ -0,0 +1,49 @@ +output "name" { + description = "The name of the organization." + value = data.github_organization.this.login +} + +output "display_name" { + description = "The display name of the organization." + value = data.github_organization.this.name +} + +output "id" { + description = "The ID of the organization." + value = data.github_organization.this.id +} + +output "description" { + description = "The description of the organization." + value = data.github_organization.this.description +} + +output "plan" { + description = "The billing plan of the organization." + value = data.github_organization.this.plan +} + +output "owners" { + description = "A list of the owners of the organization." + value = var.owners +} + +output "members" { + description = "A list of the members of the organization." + value = var.members +} + +output "all_members" { + description = "A list of all members of the organization." + value = data.github_organization.after.members +} + +output "repositories" { + description = "A list of the repositories of the organization." + value = data.github_organization.this.repositories +} + +output "blocked_users" { + description = "A list of blocked usernames from organization." + value = var.blocked_users +} diff --git a/modules/org-organization/variables.tf b/modules/org-organization/variables.tf new file mode 100644 index 0000000..66ea54a --- /dev/null +++ b/modules/org-organization/variables.tf @@ -0,0 +1,22 @@ +variable "name" { + description = "(Required) The name of the organization." + type = string +} + +variable "owners" { + description = "(Optional) A list of usernames to add users as `admin` role. When applied, an invitation will be sent to the user to become an owner of the organization." + type = set(string) + default = [] +} + +variable "members" { + description = "(Optional) A list of usernames to add users as `member` role. When applied, an invitation will be sent to the user to become a member of the organization." + type = set(string) + default = [] +} + +variable "blocked_users" { + description = "(Optional) A list of usernames to block from organization." + type = set(string) + default = [] +} diff --git a/modules/org-organization/versions.tf b/modules/org-organization/versions.tf new file mode 100644 index 0000000..014c72a --- /dev/null +++ b/modules/org-organization/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 1.1" + + required_providers { + github = { + # source = "integrations/github" + # version = ">= 4.19" + source = "hashicorp/github" + version = "= 4.13.0" + } + } +} diff --git a/modules/org-team/README.md b/modules/org-team/README.md new file mode 100644 index 0000000..303f324 --- /dev/null +++ b/modules/org-team/README.md @@ -0,0 +1,61 @@ +# org-team + +This module creates following resources. + +- `github_team` +- `github_team_membership` (optional) + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.1 | +| [github](#requirement\_github) | = 4.13.0 | + +## Providers + +| Name | Version | +|------|---------| +| [github](#provider\_github) | 4.13.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_team.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/team) | resource | +| [github_team_membership.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/team_membership) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name](#input\_name) | (Required) The name of the team. | `string` | n/a | yes | +| [default\_maintainer\_enabled](#input\_default\_maintainer\_enabled) | (Optional) If true, adds the creating user as a default maintainer to the team. | `bool` | `false` | no | +| [description](#input\_description) | (Optional) A description of the team. | `string` | `"Managed by Terraform."` | no | +| [is\_secret](#input\_is\_secret) | (Optional) If true, team is only visible to the people on the team and people with owner permissions. | `bool` | `false` | no | +| [ldap\_group\_dn](#input\_ldap\_group\_dn) | (Optional) The LDAP Distinguished Name of the group where membership will be synchronized. Only available in GitHub Enterprise Server. | `string` | `null` | no | +| [maintainers](#input\_maintainers) | (Optional) A list of usernames to add users as `maintainer` role. When applied, the user will become a maintainer of the team. | `set(string)` | `[]` | no | +| [members](#input\_members) | (Optional) A list of usernames to add users as `member` role. When applied, the user will become a member of the team. | `set(string)` | `[]` | no | +| [parent\_id](#input\_parent\_id) | (Optional) The ID of the parent team, if this is a nested team. | `string` | `null` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [default\_maintainer\_enabled](#output\_default\_maintainer\_enabled) | Whether to add the creating user as a default maintainer. | +| [description](#output\_description) | The description of the team. | +| [id](#output\_id) | The ID of the team. | +| [is\_secret](#output\_is\_secret) | Whether to be only visible to the people on the team and people with owner permissions. | +| [ldap\_group\_dn](#output\_ldap\_group\_dn) | The LDAP Distinguished Name of the group where membership will be synchronized. | +| [maintainers](#output\_maintainers) | A list of the maintainers of the team. | +| [members](#output\_members) | A list of the members of the team. | +| [name](#output\_name) | The name of the team. | +| [node\_id](#output\_node\_id) | The Node ID of the team. | +| [parent\_id](#output\_parent\_id) | The ID of the parent team. | +| [slug](#output\_slug) | The slug of the team. | + diff --git a/modules/org-team/main.tf b/modules/org-team/main.tf new file mode 100644 index 0000000..7f37f47 --- /dev/null +++ b/modules/org-team/main.tf @@ -0,0 +1,42 @@ +resource "github_team" "this" { + name = var.name + description = try(var.description, null) + privacy = var.is_secret ? "secret" : "closed" + + parent_team_id = try(var.parent_id, null) + create_default_maintainer = var.default_maintainer_enabled + + ldap_dn = try(var.ldap_group_dn, null) +} + +locals { + members = [ + for member in var.members : { + username = member + role = "member" + } + ] + maintainers = [ + for maintainer in var.maintainers : { + username = maintainer + role = "maintainer" + } + ] + membership = concat(local.members, local.maintainers) +} + + +################################################### +# Membership of GitHub Organization Team +################################################### + +resource "github_team_membership" "this" { + for_each = { + for member in local.membership : + member.username => member + } + + team_id = github_team.this.id + username = each.key + role = each.value.role +} diff --git a/modules/org-team/outputs.tf b/modules/org-team/outputs.tf new file mode 100644 index 0000000..7f6eb7a --- /dev/null +++ b/modules/org-team/outputs.tf @@ -0,0 +1,54 @@ +output "id" { + description = "The ID of the team." + value = github_team.this.id +} + +output "node_id" { + description = "The Node ID of the team." + value = github_team.this.node_id +} + +output "slug" { + description = "The slug of the team." + value = github_team.this.slug +} + +output "name" { + description = "The name of the team." + value = github_team.this.name +} + +output "description" { + description = "The description of the team." + value = github_team.this.description +} + +output "is_secret" { + description = "Whether to be only visible to the people on the team and people with owner permissions." + value = var.is_secret +} + +output "parent_id" { + description = "The ID of the parent team." + value = github_team.this.parent_team_id +} + +output "ldap_group_dn" { + description = "The LDAP Distinguished Name of the group where membership will be synchronized." + value = var.ldap_group_dn +} + +output "default_maintainer_enabled" { + description = "Whether to add the creating user as a default maintainer." + value = github_team.this.create_default_maintainer +} + +output "maintainers" { + description = "A list of the maintainers of the team." + value = var.maintainers +} + +output "members" { + description = "A list of the members of the team." + value = var.members +} diff --git a/modules/org-team/variables.tf b/modules/org-team/variables.tf new file mode 100644 index 0000000..e93b41a --- /dev/null +++ b/modules/org-team/variables.tf @@ -0,0 +1,46 @@ +variable "name" { + description = "(Required) The name of the team." + type = string +} + +variable "description" { + description = "(Optional) A description of the team." + type = string + default = "Managed by Terraform." +} + +variable "is_secret" { + description = "(Optional) If true, team is only visible to the people on the team and people with owner permissions." + type = bool + default = false +} + +variable "parent_id" { + description = "(Optional) The ID of the parent team, if this is a nested team." + type = string + default = null +} + +variable "default_maintainer_enabled" { + description = "(Optional) If true, adds the creating user as a default maintainer to the team." + type = bool + default = false +} + +variable "ldap_group_dn" { + description = "(Optional) The LDAP Distinguished Name of the group where membership will be synchronized. Only available in GitHub Enterprise Server." + type = string + default = null +} + +variable "maintainers" { + description = "(Optional) A list of usernames to add users as `maintainer` role. When applied, the user will become a maintainer of the team." + type = set(string) + default = [] +} + +variable "members" { + description = "(Optional) A list of usernames to add users as `member` role. When applied, the user will become a member of the team." + type = set(string) + default = [] +} diff --git a/modules/org-team/versions.tf b/modules/org-team/versions.tf new file mode 100644 index 0000000..014c72a --- /dev/null +++ b/modules/org-team/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 1.1" + + required_providers { + github = { + # source = "integrations/github" + # version = ">= 4.19" + source = "hashicorp/github" + version = "= 4.13.0" + } + } +} diff --git a/modules/project/README.md b/modules/project/README.md new file mode 100644 index 0000000..8c943dc --- /dev/null +++ b/modules/project/README.md @@ -0,0 +1,56 @@ +# project + +This module creates following resources. + +- `github_repository_project` (optional) +- `github_organization_project` (optional) +- `github_project_column` (optional) + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.1 | +| [github](#requirement\_github) | = 4.13.0 | + +## Providers + +| Name | Version | +|------|---------| +| [github](#provider\_github) | 4.13.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_organization_project.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/organization_project) | resource | +| [github_project_column.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/project_column) | resource | +| [github_repository_project.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/repository_project) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name](#input\_name) | (Required) The name of the project. | `string` | n/a | yes | +| [columns](#input\_columns) | (Optional) A list of columns for the project. | `set(string)` | `[]` | no | +| [description](#input\_description) | (Optional) A description of the project. | `string` | `"Managed by Terraform."` | no | +| [level](#input\_level) | (Optional) Choose to create a project for organization or repository. Valid values are `ORGANIAZTION` and `REPOSITORY`. The default is `ORGANIZATION` level, so the project is managed by organization level. | `string` | `"ORGANIZATION"` | no | +| [repository](#input\_repository) | (Optional) The repository to create the project for. Only need when `level` is `REPOSITORY`. | `string` | `null` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [columns](#output\_columns) | A list of columns of the project. | +| [description](#output\_description) | The description of the team. | +| [id](#output\_id) | The ID of the project. | +| [level](#output\_level) | The level of the project. `REPOSITORY` or `ORGANIZATION`. | +| [name](#output\_name) | The name of the project. | +| [repository](#output\_repository) | The repository which the project is created. | +| [url](#output\_url) | The URL of the project. | + diff --git a/modules/project/main.tf b/modules/project/main.tf new file mode 100644 index 0000000..2207e7f --- /dev/null +++ b/modules/project/main.tf @@ -0,0 +1,27 @@ +resource "github_organization_project" "this" { + count = var.level == "ORGANIZATION" ? 1 : 0 + + name = var.name + body = var.description +} + +resource "github_repository_project" "this" { + count = var.level == "REPOSITORY" ? 1 : 0 + + repository = var.repository + + name = var.name + body = var.description +} + + +################################################### +# Columns for GitHub Project +################################################### + +resource "github_project_column" "this" { + for_each = toset(var.columns) + + project_id = try(github_repository_project.this[0].id, github_organization_project.this[0].id) + name = each.key +} diff --git a/modules/project/outputs.tf b/modules/project/outputs.tf new file mode 100644 index 0000000..f99bec5 --- /dev/null +++ b/modules/project/outputs.tf @@ -0,0 +1,52 @@ +output "id" { + description = "The ID of the project." + value = try( + github_repository_project.this[0].id, + github_organization_project.this[0].id + ) +} + +output "name" { + description = "The name of the project." + value = try( + github_repository_project.this[0].name, + github_organization_project.this[0].name + ) +} + +output "description" { + description = "The description of the team." + value = try( + github_repository_project.this[0].body, + github_organization_project.this[0].body + ) +} + +output "level" { + description = "The level of the project. `REPOSITORY` or `ORGANIZATION`." + value = var.level +} + +output "repository" { + description = "The repository which the project is created." + value = try(github_repository_project.this[0].repository, null) +} + +output "url" { + description = "The URL of the project." + value = try( + github_repository_project.this[0].url, + github_organization_project.this[0].url + ) +} + +output "columns" { + description = "A list of columns of the project." + value = { + for name, column in github_project_column.this : + name => { + id = column.id + name = name + } + } +} diff --git a/modules/project/variables.tf b/modules/project/variables.tf new file mode 100644 index 0000000..d981abb --- /dev/null +++ b/modules/project/variables.tf @@ -0,0 +1,33 @@ +variable "name" { + description = "(Required) The name of the project." + type = string +} + +variable "description" { + description = "(Optional) A description of the project." + type = string + default = "Managed by Terraform." +} + +variable "level" { + description = "(Optional) Choose to create a project for organization or repository. Valid values are `ORGANIAZTION` and `REPOSITORY`. The default is `ORGANIZATION` level, so the project is managed by organization level." + type = string + default = "ORGANIZATION" + + validation { + condition = contains(["REPOSITORY", "ORGANIZATION"], var.level) + error_message = "The level should be one of `REPOSITORY`, `ORGANIZATION`." + } +} + +variable "repository" { + description = "(Optional) The repository to create the project for. Only need when `level` is `REPOSITORY`." + type = string + default = null +} + +variable "columns" { + description = "(Optional) A list of columns for the project." + type = set(string) + default = [] +} diff --git a/modules/project/versions.tf b/modules/project/versions.tf new file mode 100644 index 0000000..014c72a --- /dev/null +++ b/modules/project/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 1.1" + + required_providers { + github = { + # source = "integrations/github" + # version = ">= 4.19" + source = "hashicorp/github" + version = "= 4.13.0" + } + } +} diff --git a/modules/repository/README.md b/modules/repository/README.md new file mode 100644 index 0000000..b5e0a6b --- /dev/null +++ b/modules/repository/README.md @@ -0,0 +1,97 @@ +# repository + +This module creates following resources. + +- `github_repository` +- `github_repository_collaborator` (optional) +- `github_team_repository` (optional) +- `github_repository_deploy_key` (optional) +- `github_issue_label` (optional) +- `github_branch_default` (optional) + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.1 | +| [github](#requirement\_github) | = 4.13.0 | + +## Providers + +| Name | Version | +|------|---------| +| [github](#provider\_github) | 4.13.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_branch_default.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/branch_default) | resource | +| [github_issue_label.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/issue_label) | resource | +| [github_repository.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/repository) | resource | +| [github_repository_collaborator.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/repository_collaborator) | resource | +| [github_repository_deploy_key.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/repository_deploy_key) | resource | +| [github_team_repository.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/team_repository) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name](#input\_name) | (Required) A name of the repository. | `string` | n/a | yes | +| [admin\_collaborators](#input\_admin\_collaborators) | (Optional) A list of users as collaborator with `admin` permission to the repository. You can use GitHub username. | `set(string)` | `[]` | no | +| [admin\_teams](#input\_admin\_teams) | (Optional) A list of teams with `admin` permission to the repository. You can use GitHub team id or the GitHub team slug. | `set(string)` | `[]` | no | +| [archive\_on\_destroy](#input\_archive\_on\_destroy) | (Optional) Set to `true` to archive the repository instead of deleting on destroy. | `bool` | `false` | no | +| [archived](#input\_archived) | (Optional) Specify if the repository should be archived. Defaults to `false`. NOTE: Currently, the API does not support unarchiving. | `bool` | `false` | no | +| [default\_branch](#input\_default\_branch) | (Optional) Set the default branch for the repository. Default is `main` branch. | `string` | `"main"` | no | +| [delete\_branch\_on\_merge](#input\_delete\_branch\_on\_merge) | (Optional) Automatically delete head branch after a pull request is merged. Defaults to true. | `bool` | `true` | no | +| [deploy\_keys](#input\_deploy\_keys) | (Optional) A list of deploy keys to grant access to the repository. A deploy key is a SSH key. Each member of `deploy_keys` block as defined below.
(Required) `name` - A name of deploy key.
(Optional) `key` - A SSH key. Begins with 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519', 'sk-ecdsa-sha2-nistp256@openssh.com', or 'sk-ssh-ed25519@openssh.com'.
(Optional) `writable` - Whether to allow write access to the repository. The key can be used to push to the repository if enabled. |
list(object({
name = string
key = string
writable = bool
}))
| `[]` | no | +| [description](#input\_description) | (Optional) A description of the repository. | `string` | `"Managed by Terraform."` | no | +| [features](#input\_features) | (Optional) A list of enabled features on the repository. Available features: `ISSUES`, `PROJECTS`, `WIKI`. | `set(string)` |
[
"ISSUES"
]
| no | +| [homepage](#input\_homepage) | (Optional) A URL of website describing the repository. | `string` | `null` | no | +| [is\_template](#input\_is\_template) | (Optional) Set to `true` if this is a template repository. | `bool` | `false` | no | +| [issue\_labels](#input\_issue\_labels) | (Optional) A list of issue labels for the repository. Each member of `issue_labels` block as defined below.
(Required) `name` - The name of the label.
(Required) `color` - A 6 character hex code, without the leading #, identifying the color of the label.
(Optional) `description` - A short description of the label. | `set(map(string))` | `[]` | no | +| [maintain\_collaborators](#input\_maintain\_collaborators) | (Optional) A list of users as collaborator with `maintain` permission to the repository. You can use GitHub username. | `set(string)` | `[]` | no | +| [maintain\_teams](#input\_maintain\_teams) | (Optional) A list of teams with `maintain` permission to the repository. You can use GitHub team id or the GitHub team slug. | `set(string)` | `[]` | no | +| [merge\_strategies](#input\_merge\_strategies) | (Optional) A list of allowed strategies for merging pull requests on the repository. Available strategies: `MERGE_COMMIT`, `SQUASH`, `REBASE`. | `set(string)` |
[
"SQUASH",
"REBASE"
]
| no | +| [read\_collaborators](#input\_read\_collaborators) | (Optional) A list of users as collaborator with `read` permission to the repository. You can use GitHub username. | `set(string)` | `[]` | no | +| [read\_teams](#input\_read\_teams) | (Optional) A list of teams with `read` permission to the repository. You can use GitHub team id or the GitHub team slug. | `set(string)` | `[]` | no | +| [template](#input\_template) | (Optional) Use a template repository, license or gitignore to create the repository.this resource. `template` block as defined below.
(Optional) `gitignore` - Choose which files not to track from a list of templates. Use the name of the template without the extension. For example, `Haskell`.
(Optional) `init_readme` - Set to `true` to produce an initial commit with README.md in the repository.
(Optional) `license` - A license tells others what they can and can't do with your code. Use the name of the license template without the extension. For example, `mit` or `mpl-2.0`.
(Optional) `repository` - Start this repository with a template repository's contents. The full name of the repository is required. A string of the form `owner/repository`. | `any` | `{}` | no | +| [topics](#input\_topics) | (Optional) A list of topics for the repository. | `set(string)` | `[]` | no | +| [triage\_collaborators](#input\_triage\_collaborators) | (Optional) A list of users as collaborator with `triage` permission to the repository. You can use GitHub username. | `set(string)` | `[]` | no | +| [triage\_teams](#input\_triage\_teams) | (Optional) A list of teams with `triage` permission to the repository. You can use GitHub team id or the GitHub team slug. | `set(string)` | `[]` | no | +| [visibility](#input\_visibility) | (Optional) Can be `public`, `private` or `internal`. `internal` visibility is only available if your organization is associated with an enterprise account using GitHub Enterprise Cloud or GitHub Enterprise Server 2.20+. | `string` | `"private"` | no | +| [write\_collaborators](#input\_write\_collaborators) | (Optional) A list of users as collaborator with `write` permission to the repository. You can use GitHub username. | `set(string)` | `[]` | no | +| [write\_teams](#input\_write\_teams) | (Optional) A list of teams with `write` permission to the repository. You can use GitHub team id or the GitHub team slug. | `set(string)` | `[]` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [archived](#output\_archived) | Whether the repository is archived. | +| [default\_branch](#output\_default\_branch) | The default branch of the repository. | +| [delete\_branch\_on\_merge](#output\_delete\_branch\_on\_merge) | Automatically delete head branch after a pull request is merged. | +| [deploy\_keys](#output\_deploy\_keys) | A list of deploy keys granted access to the repository. | +| [description](#output\_description) | The description of the repository. | +| [features](#output\_features) | A list of available features on the repository. | +| [full\_name](#output\_full\_name) | The full name of the repository. A string of the form `orgname/reponame` | +| [git\_clone\_url](#output\_git\_clone\_url) | The URL that can be provided to `git clone` to clone the repository anonymously via the git protocol. | +| [homepage](#output\_homepage) | A URL of the website for the repository. | +| [http\_clone\_url](#output\_http\_clone\_url) | The URL that can be provided to `git clone` to clone the repository anonymously via HTTPS. | +| [id](#output\_id) | The ID of the GitHub repository. | +| [is\_template](#output\_is\_template) | Whether this is a template repository. | +| [issue\_labels](#output\_issue\_labels) | A list of issue labels for the repository. | +| [merge\_strategies](#output\_merge\_strategies) | A list of available strategies for merging pull requests on the repository. | +| [name](#output\_name) | The name of the repository. | +| [node\_id](#output\_node\_id) | The node ID of the GitHub repository. This is GraphQL global node id for use with v4 API. | +| [permissions](#output\_permissions) | The access control list which manage individual and team access to the repository. | +| [ssh\_clone\_url](#output\_ssh\_clone\_url) | The URL that can be provided to `git clone` to clone the repository anonymously via SSH. | +| [template](#output\_template) | The template of the repository. | +| [topics](#output\_topics) | A list of topics for the repository. | +| [url](#output\_url) | The URL of the repository. | +| [visibility](#output\_visibility) | The visibility of the repository. Can be `public`, `private` or `internal`. | + diff --git a/modules/repository/collaborators.tf b/modules/repository/collaborators.tf new file mode 100644 index 0000000..1751bb7 --- /dev/null +++ b/modules/repository/collaborators.tf @@ -0,0 +1,58 @@ +locals { + read_collaborators = [ + for collaborator in var.read_collaborators : { + username = collaborator + permission = "pull" + } + ] + triage_collaborators = [ + for collaborator in var.triage_collaborators : { + username = collaborator + permission = "triage" + } + ] + write_collaborators = [ + for collaborator in var.write_collaborators : { + username = collaborator + permission = "push" + } + ] + maintain_collaborators = [ + for collaborator in var.maintain_collaborators : { + username = collaborator + permission = "maintain" + } + ] + admin_collaborators = [ + for collaborator in var.admin_collaborators : { + username = collaborator + permission = "admin" + } + ] + + collaborators = concat( + local.read_collaborators, + local.triage_collaborators, + local.write_collaborators, + local.maintain_collaborators, + local.admin_collaborators, + ) +} + + +################################################### +# Collaborators for GitHub Repository +################################################### + +resource "github_repository_collaborator" "this" { + for_each = { + for collaborator in local.collaborators : + collaborator.username => collaborator + } + + repository = github_repository.this.name + username = each.key + permission = each.value.permission + + permission_diff_suppression = true +} diff --git a/modules/repository/deploy-keys.tf b/modules/repository/deploy-keys.tf new file mode 100644 index 0000000..711c8b7 --- /dev/null +++ b/modules/repository/deploy-keys.tf @@ -0,0 +1,15 @@ +################################################### +# Deploy Keys for GitHub Repository +################################################### + +resource "github_repository_deploy_key" "this" { + for_each = { + for key in var.deploy_keys : + key.name => key + } + + repository = github_repository.this.name + title = try(each.key, md5(each.value.key)) + key = each.value.key + read_only = try(!each.value.writable, true) +} diff --git a/modules/repository/issue-labels.tf b/modules/repository/issue-labels.tf new file mode 100644 index 0000000..11eab60 --- /dev/null +++ b/modules/repository/issue-labels.tf @@ -0,0 +1,16 @@ +################################################### +# Issue Labels for GitHub Repository +################################################### + +resource "github_issue_label" "this" { + for_each = { + for label in var.issue_labels : + label.name => label + } + + repository = github_repository.this.name + + name = each.key + color = each.value.color + description = try(each.value.description, "Managed by Terraform.") +} diff --git a/modules/repository/main.tf b/modules/repository/main.tf new file mode 100644 index 0000000..d195f93 --- /dev/null +++ b/modules/repository/main.tf @@ -0,0 +1,51 @@ +resource "github_repository" "this" { + name = var.name + description = var.description + homepage_url = var.homepage + + visibility = var.visibility + is_template = var.is_template + archived = var.archived + archive_on_destroy = var.archive_on_destroy + + auto_init = try(var.template.init_readme, false) + license_template = try(var.template.license, null) + gitignore_template = try(var.template.gitignore, null) + + dynamic "template" { + for_each = try([var.template.repository], []) + + content { + owner = split("/", template.value)[0] + repository = split("/", template.value)[1] + } + } + + has_issues = contains(var.features, "ISSUES") + has_projects = contains(var.features, "PROJECTS") + has_wiki = contains(var.features, "WIKI") + + allow_merge_commit = contains(var.merge_strategies, "MERGE_COMMIT") + allow_squash_merge = contains(var.merge_strategies, "SQUASH") + allow_rebase_merge = contains(var.merge_strategies, "REBASE") + + delete_branch_on_merge = var.delete_branch_on_merge + + topics = var.topics + + lifecycle { + ignore_changes = [ + auto_init, + license_template, + gitignore_template, + template, + ] + } +} + +resource "github_branch_default" "this" { + count = var.default_branch != null ? 1 : 0 + + repository = github_repository.this.name + branch = var.default_branch +} diff --git a/modules/repository/outputs.tf b/modules/repository/outputs.tf new file mode 100644 index 0000000..11e332f --- /dev/null +++ b/modules/repository/outputs.tf @@ -0,0 +1,139 @@ +output "id" { + description = "The ID of the GitHub repository." + value = github_repository.this.repo_id +} + +output "node_id" { + description = "The node ID of the GitHub repository. This is GraphQL global node id for use with v4 API." + value = github_repository.this.node_id +} + +output "name" { + description = "The name of the repository." + value = github_repository.this.name +} + +output "full_name" { + description = "The full name of the repository. A string of the form `orgname/reponame`" + value = github_repository.this.full_name +} + +output "description" { + description = "The description of the repository." + value = github_repository.this.description +} + +output "homepage" { + description = "A URL of the website for the repository." + value = github_repository.this.homepage_url +} + +output "url" { + description = "The URL of the repository." + value = github_repository.this.html_url +} + +output "git_clone_url" { + description = "The URL that can be provided to `git clone` to clone the repository anonymously via the git protocol." + value = github_repository.this.git_clone_url +} + +output "http_clone_url" { + description = "The URL that can be provided to `git clone` to clone the repository anonymously via HTTPS." + value = github_repository.this.http_clone_url +} + +output "ssh_clone_url" { + description = "The URL that can be provided to `git clone` to clone the repository anonymously via SSH." + value = github_repository.this.ssh_clone_url +} + +output "visibility" { + description = "The visibility of the repository. Can be `public`, `private` or `internal`." + value = github_repository.this.visibility +} + +output "is_template" { + description = "Whether this is a template repository." + value = github_repository.this.is_template +} + +output "archived" { + description = "Whether the repository is archived." + value = github_repository.this.archived +} + +output "template" { + description = "The template of the repository." + value = var.template +} + +output "features" { + description = "A list of available features on the repository." + value = var.features +} + +output "merge_strategies" { + description = "A list of available strategies for merging pull requests on the repository." + value = var.merge_strategies +} + +output "delete_branch_on_merge" { + description = "Automatically delete head branch after a pull request is merged." + value = github_repository.this.delete_branch_on_merge +} + +output "topics" { + description = "A list of topics for the repository." + value = github_repository.this.topics +} + +output "issue_labels" { + description = "A list of issue labels for the repository." + value = [ + for label in github_issue_label.this : { + name = label.name + color = label.color + description = label.description + } + ] +} + +output "permissions" { + description = "The access control list which manage individual and team access to the repository." + value = { + read = { + teams = var.read_teams + collaborators = var.read_collaborators + } + triage = { + teams = var.triage_teams + collaborators = var.triage_collaborators + } + write = { + teams = var.write_teams + collaborators = var.write_collaborators + } + maintain = { + teams = var.maintain_teams + collaborators = var.maintain_collaborators + } + admin = { + teams = var.admin_teams + collaborators = var.admin_collaborators + } + } +} + +output "default_branch" { + description = "The default branch of the repository." + value = one(github_branch_default.this.*.branch) +} + +output "deploy_keys" { + description = "A list of deploy keys granted access to the repository." + value = { + for key in var.deploy_keys : + key.name => key + } +} diff --git a/modules/repository/teams.tf b/modules/repository/teams.tf new file mode 100644 index 0000000..77f533b --- /dev/null +++ b/modules/repository/teams.tf @@ -0,0 +1,56 @@ +locals { + read_teams = [ + for team in var.read_teams : { + team_id = team + permission = "pull" + } + ] + triage_teams = [ + for team in var.triage_teams : { + team_id = team + permission = "triage" + } + ] + write_teams = [ + for team in var.write_teams : { + team_id = team + permission = "push" + } + ] + maintain_teams = [ + for team in var.maintain_teams : { + team_id = team + permission = "maintain" + } + ] + admin_teams = [ + for team in var.admin_teams : { + team_id = team + permission = "admin" + } + ] + + teams = concat( + local.read_teams, + local.triage_teams, + local.write_teams, + local.maintain_teams, + local.admin_teams, + ) +} + + +################################################### +# Teams for GitHub Repository +################################################### + +resource "github_team_repository" "this" { + for_each = { + for team in local.teams : + team.team_id => team + } + + repository = github_repository.this.name + team_id = each.key + permission = each.value.permission +} diff --git a/modules/repository/variables.tf b/modules/repository/variables.tf new file mode 100644 index 0000000..7bc3ce0 --- /dev/null +++ b/modules/repository/variables.tf @@ -0,0 +1,186 @@ +variable "name" { + description = "(Required) A name of the repository." + type = string +} + +variable "description" { + description = "(Optional) A description of the repository." + type = string + default = "Managed by Terraform." +} + +variable "homepage" { + description = "(Optional) A URL of website describing the repository." + type = string + default = null +} + +variable "visibility" { + description = "(Optional) Can be `public`, `private` or `internal`. `internal` visibility is only available if your organization is associated with an enterprise account using GitHub Enterprise Cloud or GitHub Enterprise Server 2.20+." + type = string + default = "private" +} + +variable "is_template" { + description = "(Optional) Set to `true` if this is a template repository." + type = bool + default = false +} + +variable "archived" { + description = "(Optional) Specify if the repository should be archived. Defaults to `false`. NOTE: Currently, the API does not support unarchiving." + type = bool + default = false +} + +variable "archive_on_destroy" { + description = "(Optional) Set to `true` to archive the repository instead of deleting on destroy." + type = bool + default = false +} + +# INFO: https://github.com/github/gitignore +# INFO: https://github.com/github/choosealicense.com/tree/gh-pages/_licenses +variable "template" { + description = < +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.1 | +| [github](#requirement\_github) | = 4.13.0 | + +## Providers + +| Name | Version | +|------|---------| +| [github](#provider\_github) | 4.13.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_organization_webhook.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/organization_webhook) | resource | +| [github_repository_webhook.this](https://registry.terraform.io/providers/hashicorp/github/4.13.0/docs/resources/repository_webhook) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [url](#input\_url) | (Required) The URL of the webhook. | `string` | n/a | yes | +| [content\_type](#input\_content\_type) | (Optional) The content type for the webhook payload. Valid values are either `FORM` or `JSON`. | `string` | `"JSON"` | no | +| [enabled](#input\_enabled) | (Optional) Whether to activate the webhook should receive events. | `bool` | `true` | no | +| [events](#input\_events) | (Optional) A list of events which should trigger the webhook. Default is for only `push` event. | `set(string)` |
[
"push"
]
| no | +| [repositories](#input\_repositories) | (Optional) A list of repositories to create the webhook for. Create an organization-level webhook if you provide `*`. | `set(string)` |
[
"*"
]
| no | +| [secret](#input\_secret) | (Optional) The shared secret for the webhook. | `string` | `""` | no | +| [ssl\_enabled](#input\_ssl\_enabled) | (Optional) Whether to verify SSL certificates when delivering payloads. Default is true. | `bool` | `true` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [content\_type](#output\_content\_type) | The content type of the webhook payload. | +| [enabled](#output\_enabled) | Whether the webhook is enabled. | +| [events](#output\_events) | A list of events which trigger the webhook. | +| [repositories](#output\_repositories) | A list of repositories which the webhook is for. | +| [ssl\_enabled](#output\_ssl\_enabled) | Whether SSL verification is enabled. | +| [url](#output\_url) | The URL of the webhook. | + diff --git a/modules/webhook/main.tf b/modules/webhook/main.tf new file mode 100644 index 0000000..e368ac0 --- /dev/null +++ b/modules/webhook/main.tf @@ -0,0 +1,36 @@ +locals { + is_organization = contains(var.repositories, "*") + repositories = local.is_organization ? [] : var.repositories +} + +resource "github_organization_webhook" "this" { + count = local.is_organization ? 1 : 0 + + events = var.events + active = var.enabled + + configuration { + url = var.url + content_type = lower(var.content_type) + insecure_ssl = !var.ssl_enabled + + secret = var.secret + } +} + +resource "github_repository_webhook" "this" { + for_each = local.repositories + + repository = each.key + + events = var.events + active = var.enabled + + configuration { + url = var.url + content_type = lower(var.content_type) + insecure_ssl = !var.ssl_enabled + + secret = var.secret + } +} diff --git a/modules/webhook/outputs.tf b/modules/webhook/outputs.tf new file mode 100644 index 0000000..1c940e0 --- /dev/null +++ b/modules/webhook/outputs.tf @@ -0,0 +1,38 @@ +output "url" { + description = "The URL of the webhook." + value = var.url +} + +output "content_type" { + description = "The content type of the webhook payload." + value = try( + upper(github_organization_webhook.this[0].configuration[0].content_type), + upper(values(github_repository_webhook.this)[0].configuration[0].content_type), + ) +} + +output "ssl_enabled" { + description = "Whether SSL verification is enabled." + value = try( + !github_organization_webhook.this[0].configuration[0].insecure_ssl, + !values(github_repository_webhook.this)[0].configuration[0].insecure_ssl, + ) +} + +output "repositories" { + description = "A list of repositories which the webhook is for." + value = local.is_organization ? ["*"] : local.repositories +} + +output "events" { + description = "A list of events which trigger the webhook." + value = try( + github_organization_webhook.this[0].events, + values(github_repository_webhook.this)[0].events, + ) +} + +output "enabled" { + description = "Whether the webhook is enabled." + value = var.enabled +} diff --git a/modules/webhook/variables.tf b/modules/webhook/variables.tf new file mode 100644 index 0000000..a75b34e --- /dev/null +++ b/modules/webhook/variables.tf @@ -0,0 +1,47 @@ +variable "url" { + description = "(Required) The URL of the webhook." + type = string +} + +variable "content_type" { + description = "(Optional) The content type for the webhook payload. Valid values are either `FORM` or `JSON`." + type = string + default = "JSON" + + validation { + condition = contains(["FORM", "JSON"], var.content_type) + error_message = "Available content-type: `FORM`, `JSON`." + } +} + +variable "ssl_enabled" { + description = "(Optional) Whether to verify SSL certificates when delivering payloads. Default is true." + type = bool + default = true +} + +variable "secret" { + description = "(Optional) The shared secret for the webhook." + type = string + default = "" + sensitive = true +} + +variable "repositories" { + description = "(Optional) A list of repositories to create the webhook for. Create an organization-level webhook if you provide `*`." + type = set(string) + default = ["*"] +} + +# INFO: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads +variable "events" { + description = "(Optional) A list of events which should trigger the webhook. Default is for only `push` event." + type = set(string) + default = ["push"] +} + +variable "enabled" { + description = "(Optional) Whether to activate the webhook should receive events." + type = bool + default = true +} diff --git a/modules/webhook/versions.tf b/modules/webhook/versions.tf new file mode 100644 index 0000000..014c72a --- /dev/null +++ b/modules/webhook/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 1.1" + + required_providers { + github = { + # source = "integrations/github" + # version = ">= 4.19" + source = "hashicorp/github" + version = "= 4.13.0" + } + } +}