From e975fff1147087c3e88347020d81678c2f3149f5 Mon Sep 17 00:00:00 2001 From: Thomas Boerger Date: Mon, 30 Oct 2023 16:27:28 +0100 Subject: [PATCH] chore: add terraform scripts for membership management --- .editorconfig | 24 +++++ .github/settings.yml | 1 + .github/workflows/general.yml | 67 ++++++++++++++ .gitignore | 4 + .terraform-version | 1 + Gemfile | 13 ++- README.md | 27 +++++- Rakefile | 6 ++ bin/terraform | 14 +++ flake.nix | 2 + terraform/.terraform.lock.hcl | 24 +++++ terraform/members.tf | 6 ++ terraform/repositories.tf | 28 ++++++ terraform/secrets.tf | 0 terraform/teams.tf | 43 +++++++++ terraform/terraform.tf | 20 +++++ terraform/variables.tf | 164 ++++++++++++++++++++++++++++++++++ 17 files changed, 438 insertions(+), 6 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/workflows/general.yml create mode 100644 .terraform-version create mode 100644 Rakefile create mode 100755 bin/terraform create mode 100644 terraform/.terraform.lock.hcl create mode 100644 terraform/members.tf create mode 100644 terraform/repositories.tf create mode 100644 terraform/secrets.tf create mode 100644 terraform/teams.tf create mode 100644 terraform/terraform.tf create mode 100644 terraform/variables.tf diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6e89695 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,24 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +[Makefile] +indent_style = tab +indent_size = 4 + +[*.{html,tmpl,py,go}] +indent_style = tab +indent_size = 4 + +[*.{yml,yaml,toml,json,css,less,js,vue,rb,nix}] +indent_style = space +indent_size = 2 + +[*.sh] +indent_style = space +indent_size = 4 diff --git a/.github/settings.yml b/.github/settings.yml index c49cd28..7c37b9b 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -88,6 +88,7 @@ branches: restrictions: apps: - renovate + - promhippie users: [] teams: - admins diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml new file mode 100644 index 0000000..0718ec9 --- /dev/null +++ b/.github/workflows/general.yml @@ -0,0 +1,67 @@ +--- +name: general + +"on": + workflow_dispatch: + schedule: + - cron: "0 5 * * *" + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + terraform: + runs-on: ubuntu-latest + + steps: + - name: Checkout source + id: source + uses: actions/checkout@v3 + + - name: Setup terraform + id: terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_version: latest + + - name: Terraform format + id: fmt + run: bin/terraform fmt -no-color -check + + - name: Terraform init + id: init + env: + GITHUB_TOKEN: ${{ secrets.INFRA_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: bin/terraform init -no-color -input=false + + - name: Terraform validate + id: validate + env: + GITHUB_TOKEN: ${{ secrets.INFRA_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: bin/terraform validate -no-color + + - name: Terraform plan + id: plan + env: + GITHUB_TOKEN: ${{ secrets.INFRA_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: bin/terraform plan -no-color -input=false + + - name: Terraform apply + id: apply + env: + GITHUB_TOKEN: ${{ secrets.INFRA_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' + run: bin/terraform apply -no-color -input=false -auto-approve + +... diff --git a/.gitignore b/.gitignore index 92b2793..4bea233 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ .direnv +.terraform + +*.retry +*.tfvars diff --git a/.terraform-version b/.terraform-version new file mode 100644 index 0000000..94fe62c --- /dev/null +++ b/.terraform-version @@ -0,0 +1 @@ +1.5.4 diff --git a/Gemfile b/Gemfile index a61be16..c5bce1f 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,10 @@ -source "https://rubygems.org" -gem "octokit", "~> 7.0" -gem "faraday-retry", "~> 2.2" +# frozen_string_literal: true + +source 'https://rubygems.org' +gem 'faraday-retry', '~> 2.2' +gem 'octokit', '~> 7.0' + +group :development, :test do + gem 'rake', '~> 13.0' + gem 'rubocop', '~> 1.28' +end diff --git a/README.md b/README.md index d109fc9..e4a75ed 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,32 @@ # Promhippie +[![General Workflow](https://github.com/promhippie/.github/actions/workflows/general.yml/badge.svg)](https://github.com/promhippie/.github/actions/workflows/general.yml) [![Join the Matrix chat at https://matrix.to/#/#webhippie:matrix.org](https://img.shields.io/badge/matrix-%23webhippie%3Amatrix.org-7bc9a4.svg)](https://matrix.to/#/#webhippie:matrix.org) + TBD +## Development + +TBD + +## Security + +If you find a security issue please contact +[thomas@webhippie.de](mailto:thomas@webhippie.de) first. + +## Contributing + +Fork -> Patch -> Push -> Pull Request + +## Authors + +* [Thomas Boerger](https://github.com/tboerger) + ## License -MIT +Apache-2.0 -## Author +## Copyright -[Thomas Boerger](https://github.com/tboerger) +```console +Copyright (c) 2018 Thomas Boerger +``` diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..c1c1d50 --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require 'rubocop/rake_task' +RuboCop::RakeTask.new(:rubocop) + +task default: %i[rubocop] diff --git a/bin/terraform b/bin/terraform new file mode 100755 index 0000000..fba7ce4 --- /dev/null +++ b/bin/terraform @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ -L "$0" ]; then + ROOT=$(cd "$(dirname "$(readlink -e "$0")")/../terraform" || exit; pwd) +else + ROOT=$(cd "$(dirname "$0")/../terraform" || exit; pwd) +fi + +if ! which terraform >/dev/null; then + echo "Failed to detect terraform!" + exit 1 +fi + +terraform -chdir="${ROOT}" "$@" diff --git a/flake.nix b/flake.nix index 2d477c9..38f06a3 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,9 @@ { devShell = pkgs.mkShell { buildInputs = with pkgs; [ + terraform ruby_3_2 + shellcheck ]; }; } diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl new file mode 100644 index 0000000..e4179d4 --- /dev/null +++ b/terraform/.terraform.lock.hcl @@ -0,0 +1,24 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/integrations/github" { + version = "5.32.0" + constraints = "~> 5.32.0" + hashes = [ + "h1:2+ykRJOPosx0nlqrGPFcBLiP5rNurpP4miwbQMBFPYI=", + "zh:06a406a6563d0fc73789196316b01f40c2a65fdb3f92d2797c0bd9f9a3ac0b6b", + "zh:0981f5ee76d5a8dd8f72c759a7f62e25a5746a7da444df267bd744fa06af96c7", + "zh:09eacf97e95990f2ce8b1d8f8372a6e0d234783d8f162a65b83154fd951a35c7", + "zh:106ce76c23b5cf7108e35bebf1f7e8de0a50470c1331002e0eb9e09f2774643d", + "zh:13d58278002d7e6ebe0af9403b898d1cd6cae47924b2c060f3d6b55f22f348ee", + "zh:1f03341962decdae3509900ba54f041bb7dd28c37086762add54765ad035d6bd", + "zh:2d9559d2475fceca464332a2c4fa54f2d6e678d5bf2436d5caa04c14c9dacbe7", + "zh:3c12c7c1530609f0bad246e33fd306fb928ca6629e817300bbd60e386f6e89bb", + "zh:44a8bb19d6428de8ac6619316e9ada44efda541a495b5e338c4421c9c2b4bfdd", + "zh:47fae24fea27c9c740b2d8129d6447251d30e09335b06b26b098a1a9e6ecf668", + "zh:7b2b41851a7a35792d5bbef4afda53f3b26ad7075887923203a2e144f6c0ec61", + "zh:9d8137e0b10bd3cbb1bedd8c8dac3be6e77e02af0a37b2de292cdc59626664d1", + "zh:a864c30878fddd475bb96b4eb23aa7fc44cc6d4563109a6e4ff4ff1269f4b590", + "zh:bf4f04484151799e5c2a4e1333fa2b53cff0d6a0a489b8798c65bf6cb8719119", + ] +} diff --git a/terraform/members.tf b/terraform/members.tf new file mode 100644 index 0000000..23ffd95 --- /dev/null +++ b/terraform/members.tf @@ -0,0 +1,6 @@ +resource "github_membership" "general" { + for_each = { for row in var.members : row.name => row } + + username = each.value.name + role = each.value.role +} diff --git a/terraform/repositories.tf b/terraform/repositories.tf new file mode 100644 index 0000000..80354fe --- /dev/null +++ b/terraform/repositories.tf @@ -0,0 +1,28 @@ +data "github_repositories" "available" { + query = "org:promhippie" +} + +locals { + repository_labels = flatten([ + for repository in data.github_repositories.available.names : [ + for index, label in var.labels : [ + { + name = "${repository}-${label.name}" + repository = repository + label = label.name + description = label.description + color = label.color + } + ] + ] + ]) +} + +resource "github_issue_label" "general" { + for_each = { for row in local.repository_labels : row.name => row } + + repository = each.value.repository + name = each.value.label + description = each.value.description + color = each.value.color +} diff --git a/terraform/secrets.tf b/terraform/secrets.tf new file mode 100644 index 0000000..e69de29 diff --git a/terraform/teams.tf b/terraform/teams.tf new file mode 100644 index 0000000..1e597a4 --- /dev/null +++ b/terraform/teams.tf @@ -0,0 +1,43 @@ +locals { + team_repositories = flatten([ + for repository in data.github_repositories.available.names : [ + for index, team in var.teams : [ + { + name = "${team.name}-${repository}" + team = team.name + repository = repository + permission = team.permission + } + ] + ] + ]) +} + +resource "github_team" "general" { + for_each = { for row in var.teams : row.name => row } + + name = each.value.name + privacy = each.value.privacy +} + +resource "github_team_members" "general" { + for_each = { for row in var.teams : row.name => row } + team_id = github_team.general[each.value.name].id + + dynamic "members" { + for_each = each.value.members + + content { + username = members.value.name + role = members.value.role + } + } +} + +resource "github_team_repository" "general" { + for_each = { for row in local.team_repositories : row.name => row } + + team_id = github_team.general[each.value.team].id + repository = each.value.repository + permission = each.value.permission +} diff --git a/terraform/terraform.tf b/terraform/terraform.tf new file mode 100644 index 0000000..41c5e0f --- /dev/null +++ b/terraform/terraform.tf @@ -0,0 +1,20 @@ +terraform { + backend "s3" { + bucket = "promhippie-terraform" + key = "github" + region = "eu-central-1" + } + + required_providers { + github = { + source = "integrations/github" + version = "~> 5.32.0" + } + } + + required_version = ">= 1.0" +} + +provider "github" { + owner = "promhippie" +} diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..92049c5 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,164 @@ +variable "members" { + default = [ + { + name = "bothippie" + role = "admin" + }, + { + name = "tboerger" + role = "admin" + }, + ] +} + +variable "teams" { + default = [ + { + name = "admins" + privacy = "closed" + permission = "admin" + members = [ + { + name = "bothippie" + role = "maintainer" + }, + { + name = "tboerger" + role = "maintainer" + }, + ] + }, + { + name = "bots" + privacy = "closed" + permission = "admin" + members = [ + { + name = "bothippie" + role = "maintainer" + }, + ] + }, + { + name = "members" + privacy = "closed" + permission = "maintain" + members = [ + { + name = "tboerger" + role = "maintainer" + }, + ] + }, + ] +} + +variable "labels" { + default = [ + { + name = "bug" + color = "fc2929" + description = "Something isn't working" + }, + { + name = "duplicate" + color = "cccccc" + description = "This issue or pull request already exists" + }, + { + name = "enhancement" + color = "84b6eb" + description = "New feature or request" + }, + { + name = "good first issue" + color = "7057ff" + description = "Good for newcomers" + }, + { + name = "help wanted" + color = "159818" + description = "Extra attention is needed" + }, + { + name = "invalid" + color = "e6e6e6" + description = "This doesn't seem right" + }, + { + name = "question" + color = "cc317c" + description = "Further information is requested" + }, + { + name = "renovate" + color = "1d76db" + description = "Automated action from Renovate" + }, + { + name = "wontfix" + color = "5319e7" + description = "This will not be worked on" + }, + { + name = "hacktoberfest" + color = "d4c5f9" + description = "Contribution at Hacktoberfest appreciated" + }, + { + name = "ready" + color = "ededed" + description = "This is ready to be worked on" + }, + { + name = "in progress" + color = "ededed" + description = "This is currently worked on" + }, + { + name = "infra" + color = "006b75" + description = "Related to the infrastructure" + }, + { + name = "lint" + color = "fbca04" + description = "Related to linting tools" + }, + { + name = "poc" + color = "c2e0c6" + description = "Proof of concept for new feature" + }, + { + name = "rebase" + color = "ffa8a5" + description = "Branch requires a rebase" + }, + { + name = "third-party" + color = "e99695" + description = "Depends on third-party tool or library" + }, + { + name = "translation" + color = "b60205" + description = "Change or issue related to translations" + }, + { + name = "ci" + color = "b60105" + description = "Related to Continous Integration" + }, + { + name = "docs" + color = "b60305" + description = "Related to documentation" + }, + { + name = "outdated" + color = "cccccc" + description = "This is out of scope and outdated" + }, + ] +}