diff --git a/.envrc b/.envrc index ea9c614..cdc6862 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,7 @@ +# +# https://direnv.net/ +# + pre-commit install + +source_env_if_exists .envrc.private diff --git a/.gitignore b/.gitignore index f8a3f27..9068df4 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,7 @@ **/.CFUserTextEncoding **/.Trash/ **/$RECYCLE.BIN/ + +## direnv +/.envrc.private +/.direnv/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 41443eb..9eaa44b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,19 +1,33 @@ repos: - # Pre-commit + # Pre-commit hooks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 # Get the latest from https://github.com/pre-commit/pre-commit-hooks/releases + rev: v4.5.0 # See the release notes at https://github.com/pre-commit/pre-commit-hooks/releases hooks: - id: end-of-file-fixer + name: end of file fixer + description: Let's be sure that a new line has been added to the end of the file. - id: trailing-whitespace + name: trailing whitespace + description: Automatically remove trailing whitespace before committing. - id: check-merge-conflict + name: check merge conflict + description: Check for files that contain merge conflict strings. stages: [commit] - id: check-executables-have-shebangs + name: check executables have shebangs + description: Checks that non-binary executables have a proper shebang. stages: [commit] - id: detect-private-key + name: detect private key + description: Checks for the existence of private keys. stages: [commit] - id: check-symlinks + name: check symlinks + description: Checks for symlinks which do not point to anything. stages: [commit] - id: mixed-line-ending + name: mixed line ending + description: Replaces or checks mixed line ending. stages: [commit] - id: check-yaml name: check yaml @@ -24,17 +38,25 @@ repos: # Terraform - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.75.0 # Get the latest from: https://github.com/antonbabenko/pre-commit-terraform/releases + rev: v1.88.0 # See the release notes at https://github.com/antonbabenko/pre-commit-terraform/releases hooks: - id: terraform_fmt + name: terraform fmt + description: Checks if the terraform code format is valid. stages: [commit] - id: terraform_tflint + name: terraform tflint + description: Automatic terraform linting. stages: [commit] exclude: (examples) - id: terraform_validate + name: terraform validate + description: Terraform code validator. stages: [commit] exclude: (examples) - id: terraform_docs + name: terraform docs + description: Generates terraform documentation. args: - --args=--config=.terraform-docs.yml stages: [commit] diff --git a/.terraform-docs.yml b/.terraform-docs.yml index ef5c3ec..7c1fc71 100644 --- a/.terraform-docs.yml +++ b/.terraform-docs.yml @@ -1,11 +1,15 @@ --- formatter: markdown table -version: ">= 0.16.0, < 1.0.0" +version: ">= 0.17.0, < 1.0.0" output: file: README.md mode: inject + template: |- + + {{ .Content }} + sort: enabled: true diff --git a/.tflint.hcl b/.tflint.hcl new file mode 100644 index 0000000..24e529f --- /dev/null +++ b/.tflint.hcl @@ -0,0 +1,23 @@ +config { + format = "compact" + module = false + force = false +} + +# Enable all rules, always. The bundled plugin uses only recommended. +plugin "terraform" { + enabled = true + preset = "all" +} + +# Enforces module version pinning. +rule "terraform_module_pinned_source" { + enabled = true + style = "semver" +} + +# Enforces naming conventions. +rule "terraform_naming_convention" { + enabled = true + format = "snake_case" +} diff --git a/.tool-versions b/.tool-versions index 9609d85..6396e99 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ -terraform 1.3.1 -terraform-docs 0.16.0 -tflint 0.41.0 -pre-commit 2.20.0 +terraform 1.5.7 +terraform-docs 0.17.0 +tflint 0.50.3 +pre-commit 3.6.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 61c4603..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,148 +0,0 @@ -# Contributing - -First, we are glad you are interested in contributing to our project. -Below you will find the information you need to get started. - -## Repository structure - -The below diagram shows a typical terraform module repo structure. To not reinvent the wheel, we adopted the [schema](https://www.terraform.io/language/modules/develop/structure) proposed by Terraform team. - -``` -. -├── README.md -├── main.tf -├── variables.tf -├── outputs.tf -├── ... -├── modules/ -│ ├── nestedA/ -│ │ ├── README.md -│ │ ├── variables.tf -│ │ ├── main.tf -│ │ ├── outputs.tf -│ ├── nestedB/ -│ ├── .../ -├── examples/ -│ ├── exampleA/ -│ │ ├── main.tf -│ ├── exampleB/ -│ ├── .../ -``` - -## Tools - -For local development, you need a few things: - -- [asdf](https://asdf-vm.com/) - which manages multiple runtime versions; -- [direnv](https://direnv.net/) - which augments existing shells with a new feature that can load and unload environment variables. - -All these tools must be installed and configured according to their official documentation. - -### asdf - -The config file `.tool-versions` is located in the root directory. The structure is very straightforward. - -```shell -terraform 1.2.9 -terraform-docs 0.16.0 -tflint 0.40.0 -pre-commit 2.20.0 -``` - -The full packages list can be found in the [.tool-versions](.tool-versions) file. - -To install required tools in proper versions, run the command as in the example below - -```shell -% asdf install -terraform 1.2.9 is already installed -pre-commit 2.20.0 is already installed -terraform-docs 0.16.0 is already installed -tflint 0.40.0 is already installed -``` -**Notice**: the output will vary; this is just an example. - -**Important**: Please keep in mind the versions or tools themselves might change, so it is advised to rerun `asdf install` command after pulling from git. - -After the installation process, all the tools will be installed. You can verify this by executing - -```shell -% terraform --version -Terraform v1.2.9 -on darwin_amd64 -``` - -in the project directory. - -More information and examples can be found in the ASDF project [documentation](https://asdf-vm.com/manage/plugins.html). - -### direnv - -The direnv config files `.envrc` might be present in many directories. -Therefore, you must approve each of them by entering a particular directory whenever their contents change. - -**Notice**: The descriptive error will pop up if you forget to do so. - -To allow direnv to load its config run: - -```shell -% direnv allow -direnv: loading .envrc -direnv: export ~PATH -``` -**Notice**: output will vary depending on directory in which you run it. - -### Pre-commit hooks - -The repository has `pre-commit` hooks configured: - -```yaml -repos: - # Pre-commit - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 # Get the latest from https://github.com/pre-commit/pre-commit-hooks/releases - hooks: - - id: end-of-file-fixer - - id: trailing-whitespace - - id: check-merge-conflict - stages: [commit] - - id: check-executables-have-shebangs - stages: [commit] - - id: detect-private-key - stages: [commit] - - id: check-symlinks - stages: [commit] - - id: mixed-line-ending - stages: [commit] - - id: check-yaml - name: check yaml - description: checks yaml files for parseable syntax. - entry: check-yaml - language: python - types: [yaml] - - # Terraform - - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.75.0 # Get the latest from: https://github.com/antonbabenko/pre-commit-terraform/releases - hooks: - - id: terraform_fmt - stages: [commit] - - id: terraform_tflint - stages: [commit] - exclude: (examples) - - id: terraform_validate - stages: [commit] - exclude: (examples) - - id: terraform_docs - args: - - --args=--config=.terraform-docs.yml - stages: [commit] -``` - -The full hooks list can be found in the [.pre-commit-config.yaml](.pre-commit-config.yaml) file. - -**Important**: We're using **GitHub Actions** to trigger `pre-commit` checks on the **Pull Request**. The configuration file can be found in the in the [static-code-analysis.yml](.github/workflows/static-code-analysis.yml) file. - -## Versioning - -The module should be tagged using SemVer and a changelog. Use the [semantic commits](https://www.conventionalcommits.org/en/v1.0.0/) so that we can auto-generate the changelog. diff --git a/README.md b/README.md index 2d21467..b8c5c32 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Meet **OPSd**. The unique and effortless way of managing cloud infrastructure. Visit our website [www.opsd.io](https://www.opsd.io) for more details. -# terraform-github +# terraform-module-github-repository ## Introduction @@ -13,14 +13,19 @@ A terraform module responsible for creating GitHub repositories from the templat ## Usage ``` +data "github_team" "terraformers" { + slug = "terraformers" +} + module "terraform-github" { - source = "github.com/opsd-io/terraform-github" - version = ">= 0.1.0" + source = "../../terraform-module-github-repository" + + # Assign maintainers github team to the repo + maintainers_team_id = data.github_team.terraformers.id # Setup basic repository settings - repository_name = "test_repo" - repository_description = "Brief description of the test_repo project." - repository_visibility = "public" + repository_name = "test-repo" + repository_description = "Created by terraform." } ``` @@ -28,6 +33,48 @@ module "terraform-github" { You can find more example [here](examples). +Before you start, you need to create a [GitHub token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) or use an existing one. + +Next, set the environment variable. + +```bash +export GITHUB_TOKEN="ghp_your_github_token" +``` + +Now, you need to initialize terraform. + +```shell +terraform init +``` + +Execute plan command. + +```shell +terraform plan +``` + +and verify what will be created. + +The last step is to create the repo + +```shell +terrafrorm apply +``` + +**IMPORTANT**: Please double-check the command output. The vital section can be seen in the example `Plan: 6 to add, 0 to change, 0 to destroy`. Ensure that you understand the changes you are making. + +Next, you will be asked + +```shell +Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: +``` + +Type `yes` to approve and let the magic happen. + ## Related modules No related modules. @@ -37,14 +84,14 @@ No related modules. | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3.1 | -| [github](#requirement\_github) | >= 5.3.0 | +| [terraform](#requirement\_terraform) | >= 1.5.7 | +| [github](#requirement\_github) | 6.2.0 | ## Providers | Name | Version | |------|---------| -| [github](#provider\_github) | >= 5.3.0 | +| [github](#provider\_github) | 6.2.0 | ## Modules @@ -54,27 +101,35 @@ No modules. | Name | Type | |------|------| -| [github_branch_protection_v3.main](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/branch_protection_v3) | resource | -| [github_issue_label.breaking](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/issue_label) | resource | -| [github_issue_label.chore](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/issue_label) | resource | -| [github_issue_label.skip_changelog](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/issue_label) | resource | -| [github_repository.main](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository) | resource | -| [github_repository_tag_protection.main](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_tag_protection) | resource | +| [github_branch_protection_v3.main](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/branch_protection_v3) | resource | +| [github_issue_label.breaking](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/issue_label) | resource | +| [github_issue_label.chore](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/issue_label) | resource | +| [github_issue_label.skip_changelog](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/issue_label) | resource | +| [github_repository.main](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/repository) | resource | +| [github_repository_collaborator.admins](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/repository_collaborator) | resource | +| [github_repository_collaborator.maintainers](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/repository_collaborator) | resource | +| [github_repository_tag_protection.main](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/repository_tag_protection) | resource | +| [github_team_repository.admins](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/team_repository) | resource | +| [github_team_repository.maintainers](https://registry.terraform.io/providers/integrations/github/6.2.0/docs/resources/team_repository) | resource | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [admin\_teams](#input\_admin\_teams) | A set of the repository admin teams IDs. | `set(string)` | `[]` | no | +| [admins](#input\_admins) | A set of users with an admin privileges. | `set(string)` | `[]` | no | +| [maintainer\_teams](#input\_maintainer\_teams) | A set of the repository admin teams IDs. | `set(string)` | `[]` | no | +| [maintainers](#input\_maintainers) | A set of users with maintain privileges. | `set(string)` | `[]` | no | | [repository\_default\_branch](#input\_repository\_default\_branch) | The default branch name. | `string` | `"main"` | no | | [repository\_delete\_branch\_on\_merge](#input\_repository\_delete\_branch\_on\_merge) | Automatically delete head branch after a pull request is merged. | `bool` | `true` | no | -| [repository\_description](#input\_repository\_description) | Brief description of the project. | `string` | `"test_repo desc"` | no | +| [repository\_description](#input\_repository\_description) | Brief description of the project. | `string` | n/a | yes | | [repository\_has\_issues](#input\_repository\_has\_issues) | Enable the GitHub Issues on the repository. | `bool` | `true` | no | | [repository\_has\_projects](#input\_repository\_has\_projects) | Enable the GitHub Project on the repository. | `bool` | `false` | no | | [repository\_has\_wiki](#input\_repository\_has\_wiki) | Enable the GitHub Wiki on the repository. | `bool` | `false` | no | -| [repository\_name](#input\_repository\_name) | The name of the repository. | `string` | `"test_repo"` | no | -| [repository\_require\_code\_owner\_reviews](#input\_repository\_require\_code\_owner\_reviews) | Require code owners review before PR can be merged | `bool` | `true` | no | -| [repository\_require\_conversation\_resolution](#input\_repository\_require\_conversation\_resolution) | Resolve all the comments before PR can be merged | `bool` | `true` | no | -| [repository\_required\_approving\_review\_count](#input\_repository\_required\_approving\_review\_count) | Require N aprovales before PR can be merged | `number` | `1` | no | +| [repository\_name](#input\_repository\_name) | The name of the repository. | `string` | n/a | yes | +| [repository\_require\_code\_owner\_reviews](#input\_repository\_require\_code\_owner\_reviews) | Require code owners review before PR can be merged. | `bool` | `true` | no | +| [repository\_require\_conversation\_resolution](#input\_repository\_require\_conversation\_resolution) | Resolve all the comments before PR can be merged. | `bool` | `true` | no | +| [repository\_required\_approving\_review\_count](#input\_repository\_required\_approving\_review\_count) | Require N aprovales before PR can be merged. | `number` | `1` | no | | [repository\_tag\_protection\_pattern](#input\_repository\_tag\_protection\_pattern) | The pattern of the tag to protect. | `string` | `"v*"` | no | | [repository\_template\_owner](#input\_repository\_template\_owner) | The GitHub organization or user the template repository is owned by. | `string` | `"opsd-io"` | no | | [repository\_template\_repository](#input\_repository\_template\_repository) | Name of the (template) repository from which to create the new repository. | `string` | `"terraform-module-template"` | no | diff --git a/examples/create_repo_from_template/.tool-versions b/examples/create_repo_from_template/.tool-versions deleted file mode 100644 index 843e1f5..0000000 --- a/examples/create_repo_from_template/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -terraform 1.3.1 diff --git a/examples/create_repo_from_template/README.md b/examples/create_repo_from_template/README.md deleted file mode 100644 index 4684824..0000000 --- a/examples/create_repo_from_template/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# Create GitHub repo from the tempate - -Before you start, you need to create a [GitHub token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) or use an existing one. - -Next, set the environment variable. - -```bash -export GITHUB_TOKEN="ghp_your_github_token" -``` - -Now, you need to initialize terraform. - -```shell -terraform init -``` - -Execute plan command. - -```shell -terraform plan -``` - -and verify what will be created. - -The last step is to create the repo - -```shell -terrafrorm apply -``` - -**IMPORTANT**: Please double-check the command output. The vital section can be seen in the example `Plan: 6 to add, 0 to change, 0 to destroy`. Ensure that you understand the changes you are making. - -Next, you will be asked - -```shell -Do you want to perform these actions? - Terraform will perform the actions described above. - Only 'yes' will be accepted to approve. - - Enter a value: -``` - -Type `yes` to approve and let the magic happen. - - -## Requirements - -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | >= 1.3.1 | -| [github](#requirement\_github) | >= 5.3.0 | - -## Providers - -No providers. - -## Modules - -| Name | Source | Version | -|------|--------|---------| -| [terraform-github](#module\_terraform-github) | ../../ | n/a | - -## Resources - -No resources. - -## Inputs - -No inputs. - -## Outputs - -No outputs. - diff --git a/examples/create_repo_from_template/main.tf b/examples/create_repo_from_template/main.tf index e14593f..8441276 100644 --- a/examples/create_repo_from_template/main.tf +++ b/examples/create_repo_from_template/main.tf @@ -1,10 +1,17 @@ -module "terraform-github" { - source = "../../" +data "github_team" "terraformers" { + slug = "terraformers" +} + +module "example" { + source = "github.com/opsd-io/terraform-module-github-repository" + + # Assign maintainers github team to the repo + maintainers_team_id = data.github_team.terraformers.id # Setup basic repository settings repository_name = "test_repo" repository_description = "Brief description of the test_repo project." - repository_visibility = "public" + repository_visibility = "private" # Enabling/disabling repository features repository_has_issues = true diff --git a/examples/create_repo_from_template/override.tf b/examples/create_repo_from_template/override.tf new file mode 100644 index 0000000..c3d7d62 --- /dev/null +++ b/examples/create_repo_from_template/override.tf @@ -0,0 +1,5 @@ +# Make sure we're using working version (from local directory, not git). + +module "example" { + source = "./../.." +} diff --git a/examples/create_repo_from_template/versions.tf b/examples/create_repo_from_template/terraform.tf similarity index 55% rename from examples/create_repo_from_template/versions.tf rename to examples/create_repo_from_template/terraform.tf index 68faccc..627eeb7 100644 --- a/examples/create_repo_from_template/versions.tf +++ b/examples/create_repo_from_template/terraform.tf @@ -1,9 +1,12 @@ terraform { - required_version = ">= 1.3.1" + required_version = ">= 1.5.7" + required_providers { github = { source = "integrations/github" - version = ">= 5.3.0" + version = "6.2.0" } } } + +provider "github" {} diff --git a/main.tf b/main.tf index 629d121..a98fa48 100644 --- a/main.tf +++ b/main.tf @@ -1,6 +1,12 @@ -# Create repo from the template -provider "github" { - owner = "opsd-io" +terraform { + required_version = ">= 1.5.7" + + required_providers { + github = { + source = "integrations/github" + version = "6.2.0" + } + } } resource "github_repository" "main" { @@ -19,7 +25,38 @@ resource "github_repository" "main" { owner = var.repository_template_owner repository = var.repository_template_repository } +} + +resource "github_repository_collaborator" "admins" { + for_each = var.admins + + username = each.key + repository = github_repository.main.name + permission = "admin" +} + +resource "github_repository_collaborator" "maintainers" { + for_each = var.maintainers + + username = each.key + repository = github_repository.main.name + permission = "maintain" +} + +resource "github_team_repository" "admins" { + for_each = var.admin_teams + + team_id = each.key + repository = github_repository.main.name + permission = "admin" +} +resource "github_team_repository" "maintainers" { + for_each = var.maintainer_teams + + team_id = each.key + repository = github_repository.main.name + permission = "maintain" } # Protect the main branch. diff --git a/outputs.tf b/outputs.tf index 93b9094..e69de29 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,3 +0,0 @@ -# output "database_name" { -# value = postgresql_database.main.name -# } diff --git a/variables.tf b/variables.tf index 979b41d..73e5958 100644 --- a/variables.tf +++ b/variables.tf @@ -1,13 +1,11 @@ variable "repository_name" { description = "The name of the repository." type = string - default = "test_repo" } variable "repository_description" { description = "Brief description of the project." type = string - default = "test_repo desc" } variable "repository_visibility" { @@ -53,19 +51,19 @@ variable "repository_template_repository" { } variable "repository_require_conversation_resolution" { - description = "Resolve all the comments before PR can be merged" + description = "Resolve all the comments before PR can be merged." type = bool default = true } variable "repository_require_code_owner_reviews" { - description = "Require code owners review before PR can be merged" + description = "Require code owners review before PR can be merged." type = bool default = true } variable "repository_required_approving_review_count" { - description = "Require N aprovales before PR can be merged" + description = "Require N aprovales before PR can be merged." type = number default = 1 } @@ -81,3 +79,27 @@ variable "repository_default_branch" { type = string default = "main" } + +variable "admins" { + description = "A set of users with an admin privileges." + type = set(string) + default = [] +} + +variable "maintainers" { + description = "A set of users with maintain privileges." + type = set(string) + default = [] +} + +variable "admin_teams" { + description = "A set of the repository admin teams IDs." + type = set(string) + default = [] +} + +variable "maintainer_teams" { + description = "A set of the repository admin teams IDs." + type = set(string) + default = [] +} diff --git a/versions.tf b/versions.tf deleted file mode 100644 index 6209a15..0000000 --- a/versions.tf +++ /dev/null @@ -1,17 +0,0 @@ -terraform { - required_version = ">= 1.3.1" - required_providers { - # azurerm = { - # source = "hashicorp/azurerm" - # version = ">= 3.22.0" - # } - # aws = { - # source = "hashicorp/aws" - # version = ">= 4.30.0" - # } - github = { - source = "integrations/github" - version = ">= 5.3.0" - } - } -}