├── .github ├── CODEOWNERS └── workflows │ └── main.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── README.tfdoc.hcl ├── examples ├── README.md └── organization │ ├── README.md │ ├── main.tf │ └── provider.tf ├── go.mod ├── go.sum ├── main.tf ├── outputs.tf ├── test ├── README.md ├── github_organization_test.go └── organization │ ├── main.tf │ ├── outputs.tf │ ├── provider.tf │ └── variables.tf ├── variables.tf └── versions.tf /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @mariux @mineiros-io/terraform-service-catalog 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI/CD Pipeline 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | concurrency: 12 | group: terraform-github-organization 13 | cancel-in-progress: false 14 | 15 | jobs: 16 | pre-commit: 17 | runs-on: ubuntu-latest 18 | name: Static Analysis 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | 23 | - name: Run pre-commit 24 | run: make test/docker/pre-commit 25 | 26 | unit-tests: 27 | needs: pre-commit 28 | runs-on: ubuntu-latest 29 | name: Unit Tests 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v2 33 | 34 | - name: Check for Terraform file changes 35 | uses: getsentry/paths-filter@v2 36 | id: changes 37 | with: 38 | token: ${{ github.token }} 39 | filters: | 40 | terraform: 41 | - '**/*.tf' 42 | - '**/*.go' 43 | - 'go.mod' 44 | - 'go.sum' 45 | 46 | - name: Run Unit Tests 47 | if: steps.changes.outputs.terraform == 'true' 48 | run: make test/docker/unit-tests 49 | env: 50 | GITHUB_OWNER: ${{ secrets.TEST_GITHUB_ORGANIZATION }} 51 | GITHUB_TOKEN: ${{ secrets.TEST_GITHUB_TOKEN }} 52 | 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # Lock file 5 | .terraform.lock.hcl 6 | 7 | # .tfstate files 8 | *.tfstate 9 | *.tfstate.* 10 | 11 | # Crash log files 12 | crash.log 13 | 14 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 15 | # .tfvars files are managed as part of configuration and so should be included in 16 | # version control. 17 | # 18 | # example.tfvars 19 | 20 | # Ignore override files as they are usually used to override resources locally and so 21 | # are not checked in 22 | override.tf 23 | override.tf.json 24 | *_override.tf 25 | *_override.tf.json 26 | 27 | # Include override files you do wish to add to version control using negated pattern 28 | # 29 | # !example_override.tf 30 | 31 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 32 | # example: *tfplan* 33 | 34 | # Go best practices dictate that libraries should not include the vendor directory 35 | vendor 36 | 37 | # IntelliJ files 38 | .idea_modules 39 | *.iml 40 | *.iws 41 | *.ipr 42 | .idea/ 43 | build/ 44 | */build/ 45 | out/ 46 | .DS_STORE 47 | 48 | # local env 49 | .env 50 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/mineiros-io/pre-commit-hooks 3 | rev: v0.4.1 4 | hooks: 5 | - id: terraform-fmt 6 | - id: terraform-validate 7 | exclude: ^examples|.terraform/ 8 | - id: tflint 9 | - id: phony-targets 10 | - id: terradoc-validate 11 | - id: golangci-lint 12 | - id: terradoc-fmt 13 | - id: terradoc-generate 14 | # - id: terramate-generate 15 | - id: markdown-link-check 16 | args: ['-p'] # When adding the -p flag, markdown-link-check will always with an exit code 0, even if dead links are found 17 | verbose: true # Forces the output of the hook to be printed even when the hook passes. 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.9.0] 11 | 12 | ### BREAKING CHANGES 13 | 14 | - Drop support for Terraform GitHub Provider `4.x` 15 | - Require Terraform GitHub Provider version `5.3` and above to support `github_organization_settings` resource 16 | 17 | ### Added 18 | 19 | - Add support for organization settings by implementing the `github_organization_settings` resource 20 | 21 | ## [0.8.0] 22 | 23 | ### Added 24 | 25 | - Add support for Terraform GitHub Provider version `5.x` 26 | 27 | ## [0.7.0] 28 | 29 | ### BREAKING CHANGES 30 | 31 | We dropped support for Terraform pre 1.0 and GitHub Terraform Provider pre 4.0. 32 | In addition we changed to the `integrations/github` official GitHub Terraform Provider. 33 | This needs migration actions if you already used this module with the `hashicorp/github` provider and want to upgrade. 34 | 35 | #### Migration from previous versions 36 | 37 | To migrate from a previous version, please ensure that you are using the 38 | `integrations/github` official GitHub Terraform Provider. 39 | 40 | ```hcl 41 | terraform { 42 | required_version = "~> 1.0" 43 | 44 | required_providers { 45 | github = { 46 | source = "integrations/github" 47 | version = "~> 4.0" 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | Once you've updated the provider, a manual state migration is required to 54 | migrate existing resources to the new provider. 55 | The following command will replace the provider in the state. 56 | 57 | ```bash 58 | terraform state replace-provider registry.terraform.io/hashicorp/github registry.terraform.io/integrations/github 59 | ``` 60 | 61 | After you've migrated the state, please run 62 | `terrafrm init` to apply the changes to the resources. 63 | 64 | ### Added 65 | 66 | - Add support for Official GitHub Terraform Provider `integrations/github` 67 | 68 | ### Removed 69 | 70 | - Removed support for Terraform < 1.0 71 | - Removed support for GitHub Provider < 4.0 72 | - Removed compatibility to Hashicorp GitHub Terraform Provider `hashicorp/github` 73 | 74 | ## [0.6.0] 75 | 76 | ### Added 77 | 78 | - Add support for Terraform `v1` 79 | 80 | ## [0.5.0] 81 | 82 | ### Added 83 | 84 | - Add support for Terraform `v0.15` 85 | 86 | ## [0.4.1] 87 | 88 | ### Added 89 | 90 | - Add safeguard to validate if a GitHub user exists before trying to add it to the organization 91 | 92 | ## [0.4.0] 93 | 94 | ### Added 95 | 96 | - Add support for Github Provider `v4` 97 | 98 | ## [0.3.0] 99 | 100 | ### Added 101 | 102 | - Add support for Terraform `v0.14` 103 | 104 | ## [0.2.0] 105 | 106 | ### Added 107 | 108 | - Add support for Terraform `v0.13` 109 | - Add support for Terraform Github Provider `v3` 110 | - Prepare support for Terraform `v0.14` (needs terraform `v0.12.20` or above) 111 | 112 | ## [0.1.4] - 2020-06-23 113 | 114 | ### Added 115 | 116 | - Add `CHANGELOG.md`. 117 | 118 | ### Changed 119 | 120 | - Switch CI from SemaphoreCI to GitHub Actions. 121 | 122 | ## [0.1.3] - 2020-05-13 123 | 124 | ### Added 125 | 126 | - Work around a terraform issue in `module_depends_on` argument. 127 | 128 | ## [0.1.2] - 2020-05-05 129 | 130 | ### Change 131 | 132 | - New format for README.md and LICENSE. 133 | - Bump pre-commit hooks to `v0.1.4` and add new hooks. 134 | - Bump build-tools to `v0.5.3` 135 | 136 | ## [0.1.1] - 2020-04-18 137 | 138 | ### Added 139 | 140 | - Introduce new variables `all_members_team_name` and `all_members_team_visibility` 141 | for adding the possibility to create a team which contains all members of your organization. 142 | 143 | ## [0.1.0] - 2020-03-03 144 | 145 | ### Added 146 | 147 | - Added some more documentation. 148 | - Pre-commit hooks upgrade. 149 | 150 | ### Changed 151 | 152 | - Add variables and outputs to the existing example. 153 | 154 | ## [0.0.2] - 2020-01-12 155 | 156 | ### Added 157 | 158 | - Added pre-commit hooks. 159 | - Added automated unit tests. 160 | - Added CI configuration. 161 | - Added admins for adding members with admins/owner role. 162 | - Added projects to outputs. 163 | 164 | ### Changed 165 | 166 | - Changed members from complex object to list of usernames for adding normal members. 167 | 168 | ## [0.0.1] - 2020-01-06 169 | 170 | ### Added 171 | 172 | - This is the initial release of our GitHub Organization module with support 173 | for managing GitHub Organizations, Members and Blocked Users. 174 | 175 | [unreleased]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.9.0...HEAD 176 | [0.9.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.8.0...v0.9.0 177 | [0.8.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.7.0...v0.8.0 178 | [0.7.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.6.0...v0.7.0 179 | [0.6.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.5.0...v0.6.0 180 | [0.5.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.4.1...v0.5.0 181 | [0.4.1]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.4.0...v0.4.1 182 | [0.4.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.3.0...v0.4.0 183 | [0.3.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.2.0...v0.3.0 184 | [0.2.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.1.4...v0.2.0 185 | [0.1.4]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.1.3...v0.1.4 186 | [0.1.3]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.1.2...v0.1.3 187 | [0.1.2]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.1.1...v0.1.2 188 | [0.1.1]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.1.0...v0.1.1 189 | [0.1.0]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.0.2...v0.1.0 190 | [0.0.2]: https://github.com/mineiros-io/terraform-github-organization/compare/v0.0.1...v0.0.2 191 | [0.0.1]: https://github.com/mineiros-io/terraform-github-organization/releases/tag/v0.0.1 192 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | First and foremost, we’d like to express our gratitude to you for taking the time to contribute. 4 | We welcome and appreciate any and all contributions via 5 | [Pull Requests] along the [GitHub Flow]. 6 | 7 | 1. [Open a GitHub issue](#open-a-github-issue) 8 | 2. [Fork the repository on GitHub](#fork-the-repository-on-github) 9 | 3. [Install the pre-commit hooks](#install-the-pre-commit-hooks) 10 | 4. [Update the documentation](#update-the-documentation) 11 | 5. [Update the tests](#update-the-tests) 12 | 6. [Update the code](#update-the-code) 13 | 7. [Create a pull request](#create-a-pull-request) 14 | 8. [Merge and release](#merge-and-release) 15 | 16 | ## Open a GitHub issue 17 | 18 | For bug reports or requests, please submit your issue in the appropriate repository. 19 | 20 | We advise that you open an issue and ask the 21 | [CODEOWNERS] and community prior to starting a contribution. 22 | This is your chance to ask questions and receive feedback before 23 | writing (potentially wrong) code. We value the direct contact with our community 24 | a lot, so don't hesitate to ask any questions. 25 | 26 | ## Fork the repository on GitHub 27 | 28 | [Fork] the repository into your own GitHub account and [create a new branch] as 29 | described in the [GitHub Flow]. 30 | 31 | ## Install the pre-commit hooks 32 | 33 | If the repository you're working on ships with a 34 | [`.pre-commit-config.yaml`][pre-commit-file], 35 | make sure the necessary hooks have been installed before you begin working 36 | (e.g. a `pre-commit install`). 37 | 38 | ## Update the documentation 39 | 40 | We encourage you to update the documentation before writing any code (please see 41 | [Readme Driven Development]. This ensures the 42 | documentation stays up to date and allows you to think through the problem fully before you begin implementing any 43 | changes. 44 | 45 | ## Update the tests 46 | 47 | We also recommend updating the automated tests before updating any code 48 | (see [Test Driven Development](https://en.wikipedia.org/wiki/Test-driven_development)). 49 | 50 | That means that you should add or update a test case, run all tests and verify 51 | that the new test fails with a clear error message and then start implementing 52 | the code changes to get that test to pass. 53 | 54 | The test folder in every repository will have documentation on how to run the 55 | tests locally. 56 | 57 | ## Update the code 58 | 59 | At this point, make your code changes and constantly test again your new test case to make sure that everything working 60 | properly. Do [commit] early and often and make useful commit messages. 61 | 62 | If a backwards incompatible change cannot be avoided, please make sure to call that out when you submit a pull request, 63 | explaining why the change is absolutely necessary. 64 | 65 | ## Create a pull request 66 | 67 | [Create a pull request] with your changes. 68 | Please make sure to include the following: 69 | 70 | 1. A description of the change, including a link to your GitHub issue. 71 | 1. Any notes on backwards incompatibility or downtime. 72 | 73 | ## Merge and release 74 | 75 | The [CODEOWNERS] of the repository will review your code and provide feedback. 76 | If everything looks good, they will merge the code and release a new version while following the principles of [Semantic Versioning (SemVer)]. 77 | 78 | 79 | 80 | [Pull Requests]: https://github.com/mineiros-io/terraform-github-organization/pulls 81 | [pre-commit-file]: https://github.com/mineiros-io/terraform-github-organization/blob/main/.pre-commit-config.yaml 82 | 83 | [Github Flow]: https://guides.github.com/introduction/flow/ 84 | [CODEOWNERS]: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 85 | [Fork]: https://help.github.com/en/github/getting-started-with-github/fork-a-repo 86 | [create a new branch]: https://guides.github.com/introduction/flow/ 87 | [Readme Driven Development]: https://tom.preston-werner.com/2010/08/23/readme-driven-development.html 88 | [commit]: https://help.github.com/en/desktop/contributing-to-projects/committing-and-reviewing-changes-to-your-project 89 | [create a pull request]: https://help.github.com/articles/creating-a-pull-request/ 90 | [Semantic Versioning (SemVer)]: https://semver.org/ 91 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [2020] [Mineiros GmbH] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Set default shell to bash 2 | SHELL := /bin/bash -o pipefail 3 | 4 | BUILD_TOOLS_VERSION ?= v0.15.2 5 | BUILD_TOOLS_DOCKER_REPO ?= mineiros/build-tools 6 | BUILD_TOOLS_DOCKER_IMAGE ?= ${BUILD_TOOLS_DOCKER_REPO}:${BUILD_TOOLS_VERSION} 7 | 8 | # Some CI providers such as GitHub Actions, CircleCI, and TravisCI are setting 9 | # the CI environment variable to a non-empty value by default to indicate that 10 | # the current workflow is running in a Continuous Integration environment. 11 | # 12 | # If TF_IN_AUTOMATION is set to any non-empty value, Terraform adjusts its 13 | # output to avoid suggesting specific commands to run next. 14 | # https://www.terraform.io/docs/commands/environment-variables.html#tf_in_automation 15 | # 16 | # We are using GNU style quiet commands to disable set V to non-empty e.g. V=1 17 | # https://www.gnu.org/software/automake/manual/html_node/Debugging-Make-Rules.html 18 | # 19 | ifdef CI 20 | TF_IN_AUTOMATION ?= yes 21 | export TF_IN_AUTOMATION 22 | 23 | V ?= 1 24 | endif 25 | 26 | ifndef NOCOLOR 27 | GREEN := $(shell tput -Txterm setaf 2) 28 | YELLOW := $(shell tput -Txterm setaf 3) 29 | WHITE := $(shell tput -Txterm setaf 7) 30 | RESET := $(shell tput -Txterm sgr0) 31 | endif 32 | 33 | GIT_TOPLEVEl = $(shell git rev-parse --show-toplevel) 34 | 35 | # Generic docker run flags 36 | DOCKER_RUN_FLAGS += -v ${GIT_TOPLEVEl}:/build 37 | DOCKER_RUN_FLAGS += --rm 38 | DOCKER_RUN_FLAGS += -e TF_IN_AUTOMATION 39 | # If TF_VERSION is defined, TFSwitch will switch to the desired version on 40 | # container startup. If TF_VERSION is omitted, the default version installed 41 | # inside the docker image will be used. 42 | DOCKER_RUN_FLAGS += -e TF_VERSION 43 | 44 | # If SSH_AUTH_SOCK is set, we forward the SSH agent of the host system into 45 | # the docker container. This is useful when working with private repositories 46 | # and dependencies that might need to be cloned inside the container (e.g. 47 | # private Terraform modules). 48 | ifdef SSH_AUTH_SOCK 49 | DOCKER_SSH_FLAGS += -e SSH_AUTH_SOCK=/ssh-agent 50 | DOCKER_SSH_FLAGS += -v ${SSH_AUTH_SOCK}:/ssh-agent 51 | endif 52 | 53 | # If AWS_ACCESS_KEY_ID is defined, we are likely running inside an AWS provider 54 | # module. To enable AWS authentication inside the docker container, we inject 55 | # the relevant environment variables. 56 | ifdef AWS_ACCESS_KEY_ID 57 | DOCKER_AWS_FLAGS += -e AWS_ACCESS_KEY_ID 58 | DOCKER_AWS_FLAGS += -e AWS_SECRET_ACCESS_KEY 59 | DOCKER_AWS_FLAGS += -e AWS_SESSION_TOKEN 60 | endif 61 | 62 | # If GOOGLE_CREDENTIALS is defined, we are likely running inside a GCP provider 63 | # module. To enable GCP authentication inside the docker container, we inject 64 | # the relevant environment variables (service-account key file). 65 | ifdef GOOGLE_CREDENTIALS 66 | DOCKER_GCP_FLAGS += -e GOOGLE_CREDENTIALS 67 | DOCKER_GCP_FLAGS += -e TEST_GCP_PROJECT 68 | DOCKER_GCP_FLAGS += -e TEST_GCP_ORG_DOMAIN 69 | endif 70 | 71 | # If GITHUB_OWNER is defined, we are likely running inside a GitHub provider 72 | # module. To enable GitHub authentication inside the docker container, 73 | # we inject the relevant environment variables. 74 | ifdef GITHUB_OWNER 75 | DOCKER_GITHUB_FLAGS += -e GITHUB_TOKEN 76 | DOCKER_GITHUB_FLAGS += -e GITHUB_OWNER 77 | endif 78 | 79 | .PHONY: default 80 | default: help 81 | 82 | # Not exposed as a callable target by `make help`, since this is a one-time shot to simplify the development of this module. 83 | .PHONY: template/adjust 84 | template/adjust: FILTER = -path ./.git -prune -a -type f -o -type f -not -name Makefile 85 | template/adjust: 86 | @find . $(FILTER) -exec sed -i -e "s,terraform-module-template,$${PWD##*/},g" {} \; 87 | 88 | ## Run pre-commit hooks inside a build-tools docker container. 89 | .PHONY: test/docker/pre-commit 90 | test/docker/pre-commit: DOCKER_FLAGS += ${DOCKER_SSH_FLAGS} 91 | test/docker/pre-commit: DOCKER_FLAGS += -e NOCOLOR=1 92 | test/docker/pre-commit: 93 | $(call docker-run,make test/pre-commit) 94 | 95 | ## Run all Go tests inside a build-tools docker container. This is complementary to running 'go test ./test/...'. 96 | .PHONY: test/docker/unit-tests 97 | test/docker/unit-tests: DOCKER_FLAGS += ${DOCKER_SSH_FLAGS} 98 | test/docker/unit-tests: DOCKER_FLAGS += ${DOCKER_GITHUB_FLAGS} 99 | test/docker/unit-tests: DOCKER_FLAGS += ${DOCKER_AWS_FLAGS} 100 | test/docker/unit-tests: DOCKER_FLAGS += ${DOCKER_GCP_FLAGS} 101 | test/docker/unit-tests: DOCKER_FLAGS += $(shell env | grep ^TF_VAR_ | cut -d = -f 1 | xargs -i printf ' -e {}') 102 | test/docker/unit-tests: DOCKER_FLAGS += -e TF_DATA_DIR=.terratest 103 | test/docker/unit-tests: DOCKER_FLAGS += -e NOCOLOR=1 104 | test/docker/unit-tests: TEST ?= "TestUnit" 105 | test/docker/unit-tests: 106 | @echo "${YELLOW}[TEST] ${GREEN}Start Running Go Tests in Docker Container.${RESET}" 107 | $(call docker-run,make test/unit-tests) 108 | 109 | ## Run pre-commit hooks. 110 | .PHONY: test/pre-commit 111 | test/pre-commit: DOCKER_FLAGS += ${DOCKER_SSH_FLAGS} 112 | test/pre-commit: 113 | $(call quiet-command,pre-commit run -a) 114 | 115 | ## Run all unit tests. 116 | .PHONY: test/docker/unit-tests 117 | test/unit-tests: TEST ?= "TestUnit" 118 | test/unit-tests: 119 | @echo "${YELLOW}[TEST] ${GREEN}Start Running unit tests.${RESET}" 120 | $(call quiet-command,cd test ; go test -v -count 1 -timeout 45m -parallel 128 -run $(TEST)) 121 | 122 | ## Generate README.md with Terradoc 123 | .PHONY: terradoc 124 | terradoc: 125 | $(call quiet-command,terradoc generate -o README.md README.tfdoc.hcl) 126 | 127 | ## Generate shared configuration for tests 128 | .PHONY: terramate 129 | terramate: 130 | $(call quiet-command,terramate generate) 131 | 132 | ## Clean up cache and temporary files 133 | .PHONY: clean 134 | clean: 135 | $(call rm-command,.terraform) 136 | $(call rm-command,.terratest) 137 | $(call rm-command,.terraform.lock.hcl) 138 | $(call rm-command,*.tfplan) 139 | $(call rm-command,*/*/.terraform) 140 | $(call rm-command,*/*/.terratest) 141 | $(call rm-command,*/*/*.tfplan) 142 | $(call rm-command,*/*/.terraform.lock.hcl) 143 | 144 | ## Display help for all targets 145 | .PHONY: help 146 | help: 147 | @awk '/^.PHONY: / { \ 148 | msg = match(lastLine, /^## /); \ 149 | if (msg) { \ 150 | cmd = substr($$0, 9, 100); \ 151 | msg = substr(lastLine, 4, 1000); \ 152 | printf " ${GREEN}%-30s${RESET} %s\n", cmd, msg; \ 153 | } \ 154 | } \ 155 | { lastLine = $$0 }' $(MAKEFILE_LIST) 156 | 157 | # Define helper functions 158 | DOCKER_FLAGS += ${DOCKER_RUN_FLAGS} 159 | DOCKER_RUN_CMD = docker run ${DOCKER_FLAGS} ${BUILD_TOOLS_DOCKER_IMAGE} 160 | 161 | quiet-command = $(if ${V},${1},$(if ${2},@echo ${2} && ${1}, @${1})) 162 | docker-run = $(call quiet-command,${DOCKER_RUN_CMD} ${1} | cat,"${YELLOW}[DOCKER RUN] ${GREEN}${1}${RESET}") 163 | rm-command = $(call quiet-command,rm -rf ${1},"${YELLOW}[CLEAN] ${GREEN}${1}${RESET}") 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://mineiros.io/?ref=terraform-github-organization) 2 | 3 | [![Build Status](https://github.com/mineiros-io/terraform-github-organization/workflows/CI/CD%20Pipeline/badge.svg)](https://github.com/mineiros-io/terraform-github-organization/actions) 4 | [![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/mineiros-io/terraform-github-organization.svg?label=latest&sort=semver)](https://github.com/mineiros-io/terraform-github-organization/releases) 5 | [![Terraform Version](https://img.shields.io/badge/terraform-1.x-623CE4.svg?logo=terraform)](https://github.com/hashicorp/terraform/releases) 6 | [![Github Provider Version](https://img.shields.io/badge/GH-5.x-F8991D.svg?logo=terraform)](https://github.com/terraform-providers/terraform-provider-github/releases) 7 | [![Join Slack](https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack)](https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg) 8 | 9 | # terraform-github-organization 10 | 11 | A [Terraform] module that acts as a wrapper around the Terraform 12 | [GitHub provider](https://www.terraform.io/docs/providers/github/index.html) and offers a more convenient and tested way 13 | to manage GitHub Organizations following best practices. 14 | 15 | **_This module supports Terraform v1.x and is compatible with the Official Terraform GitHub Provider v5.x from `integrations/github`._** 16 | 17 | **Attention: This module is incompatible with the Hashicorp GitHub Provider! The latest version of this module supporting `hashicorp/github` provider is `~> 0.6.0`** 18 | 19 | 20 | - [GitHub as Code](#github-as-code) 21 | - [Module Features](#module-features) 22 | - [Getting Started](#getting-started) 23 | - [Module Argument Reference](#module-argument-reference) 24 | - [Top-level Arguments](#top-level-arguments) 25 | - [Module Outputs](#module-outputs) 26 | - [External Documentation](#external-documentation) 27 | - [Terraform Github Provider Documentation:](#terraform-github-provider-documentation) 28 | - [Module Versioning](#module-versioning) 29 | - [Backwards compatibility in `0.0.z` and `0.y.z` version](#backwards-compatibility-in-00z-and-0yz-version) 30 | - [About Mineiros](#about-mineiros) 31 | - [Reporting Issues](#reporting-issues) 32 | - [Contributing](#contributing) 33 | - [Makefile Targets](#makefile-targets) 34 | - [License](#license) 35 | 36 | ## GitHub as Code 37 | 38 | [GitHub as Code][github-as-code] is a commercial solution built on top of 39 | our open-source Terraform modules for GitHub. It helps our customers to 40 | manage their GitHub organization more efficiently by enabling anyone in 41 | their organization to **self-service** manage **on- and offboarding of users**, 42 | **repositories**, and settings such as **branch protections**, **secrets**, and more 43 | through code. GitHub as Code comes with **pre-configured GitHub Actions 44 | pipelines** for **change pre-view in Pull Requests**, **fully automated 45 | rollouts** and **rollbacks**. It's a comprehensive, ready-to-use blueprint 46 | maintained by our team of platform engineering experts and saves 47 | companies such as yours tons of time by building on top of a pre-configured 48 | solution instead of building and maintaining it yourself. 49 | 50 | For details please see [https://mineiros.io/github-as-code][github-as-code]. 51 | 52 | ## Module Features 53 | 54 | - **Standard Module Features**: 55 | Organization Members, 56 | Organization Owners (Admins), 57 | Organization Projects, 58 | Blocked Users, 59 | Manage Organization Settings 60 | 61 | 62 | - **Extended Module Features**: 63 | Change organization member roles without removing and re-inviting users, 64 | Rename projects without recreating (when providing unique ids), 65 | No need to import members/admins on first run, 66 | Create an all member team that contains every member of your organization 67 | 68 | ## Getting Started 69 | 70 | To quickly start managing your GitHub Organization with Terraform: 71 | 72 | ```hcl 73 | module "organization" { 74 | source = "mineiros-io/organization/github" 75 | version = "~> 0.9.0" 76 | 77 | all_members_team_name = "Mineiros" 78 | 79 | settings = { 80 | billing_email = "hello@mineiros.io" 81 | company = "Mineiros" 82 | blog = "https://blog.mineiros.io" 83 | email = "hello@mineiros.io" 84 | twitter_username = "mineirosio" 85 | location = "Berlin" 86 | name = "Terraform Tests" 87 | description = "This Organization is just used to run some Terraform tests for https://github.com/mineiros-io" 88 | has_organization_projects = true 89 | has_repository_projects = true 90 | default_repository_permission = "read" 91 | members_can_create_repositories = false 92 | members_can_create_public_repositories = false 93 | members_can_create_private_repositories = false 94 | members_can_create_internal_repositories = false 95 | members_can_create_pages = false 96 | members_can_create_public_pages = false 97 | members_can_create_private_pages = false 98 | members_can_fork_private_repositories = false 99 | web_commit_signoff_required = false 100 | advanced_security_enabled_for_new_repositories = false 101 | dependabot_alerts_enabled_for_new_repositories = false 102 | dependabot_security_updates_enabled_for_new_repositories = false 103 | dependency_graph_enabled_for_new_repositories = false 104 | secret_scanning_enabled_for_new_repositories = false 105 | secret_scanning_push_protection_enabled_for_new_repositories = false 106 | } 107 | 108 | 109 | members = [ 110 | "a-user", 111 | "b-user", 112 | ] 113 | 114 | admins = [ 115 | "a-admin", 116 | ] 117 | 118 | blocked_users = [ 119 | "blocked-user", 120 | "another-blocked-user", 121 | ] 122 | 123 | projects = [ 124 | { 125 | id = "project-a" 126 | name = "A Great Project" 127 | body = "This is a project created by Terraform" 128 | } 129 | ] 130 | } 131 | 132 | provider "github" {} 133 | 134 | terraform { 135 | required_version = "~> 1.0" 136 | 137 | required_providers { 138 | github = { 139 | source = "integrations/github" 140 | version = "~> 4.0" 141 | } 142 | } 143 | } 144 | ``` 145 | 146 | ## Module Argument Reference 147 | 148 | See [variables.tf] and [examples/] for details and use-cases. 149 | 150 | ### Top-level Arguments 151 | 152 | - [**`settings`**](#var-settings): *(Optional `object(settings)`)* 153 | 154 | A map of settings for the GitHub organization. 155 | 156 | Default is `{"fixed_response":{"content_type":"plain/text","message_body":"Nothing to see here!","status_code":418}}`. 157 | 158 | The `settings` object accepts the following attributes: 159 | 160 | - [**`billing_email`**](#attr-settings-billing_email): *(**Required** `string`)* 161 | 162 | The billing email address for the organization. 163 | 164 | - [**`email`**](#attr-settings-email): *(Optional `string`)* 165 | 166 | The email address for the organization. 167 | 168 | - [**`name`**](#attr-settings-name): *(Optional `string`)* 169 | 170 | The name for the organization. 171 | 172 | - [**`description`**](#attr-settings-description): *(Optional `string`)* 173 | 174 | The description for the organization. 175 | 176 | - [**`company_name`**](#attr-settings-company_name): *(Optional `string`)* 177 | 178 | The company name for the organization. 179 | 180 | - [**`blog`**](#attr-settings-blog): *(Optional `string`)* 181 | 182 | The blog URL for the organization. 183 | 184 | - [**`twitter_username`**](#attr-settings-twitter_username): *(Optional `string`)* 185 | 186 | The Twitter username for the organization. 187 | 188 | - [**`location`**](#attr-settings-location): *(Optional `string`)* 189 | 190 | The location for the organization. 191 | 192 | - [**`has_organization_projects`**](#attr-settings-has_organization_projects): *(Optional `bool`)* 193 | 194 | Whether or not organization projects are enabled for the organization. 195 | 196 | Default is `true`. 197 | 198 | - [**`has_repository_projects`**](#attr-settings-has_repository_projects): *(Optional `bool`)* 199 | 200 | Whether or not repository projects are enabled for the organization. 201 | 202 | Default is `true`. 203 | 204 | - [**`default_repository_permission`**](#attr-settings-default_repository_permission): *(Optional `string`)* 205 | 206 | The default permission for organization members to create new repositories. 207 | Can be one of `read`, `write`, `admin`, or `none`. 208 | 209 | - [**`members_can_create_repositories`**](#attr-settings-members_can_create_repositories): *(Optional `bool`)* 210 | 211 | Whether or not organization members can create new repositories. 212 | 213 | Default is `false`. 214 | 215 | - [**`members_can_create_public_repositories`**](#attr-settings-members_can_create_public_repositories): *(Optional `bool`)* 216 | 217 | Whether or not organization members can create new public repositories. 218 | 219 | Default is `true`. 220 | 221 | - [**`members_can_create_private_repositories`**](#attr-settings-members_can_create_private_repositories): *(Optional `bool`)* 222 | 223 | Whether or not organization members can create new private repositories. 224 | 225 | Default is `false`. 226 | 227 | - [**`members_can_create_internal_repositories`**](#attr-settings-members_can_create_internal_repositories): *(Optional `bool`)* 228 | 229 | Whether or not organization members can create new internal repositories. For Enterprise Organizations only. 230 | 231 | Default is `false`. 232 | 233 | - [**`members_can_create_pages`**](#attr-settings-members_can_create_pages): *(Optional `bool`)* 234 | 235 | Whether or not organization members can create new pages. 236 | 237 | Default is `false`. 238 | 239 | - [**`members_can_create_public_pages`**](#attr-settings-members_can_create_public_pages): *(Optional `bool`)* 240 | 241 | Whether or not organization members can create new public pages. 242 | 243 | Default is `false`. 244 | 245 | - [**`members_can_fork_private_repositories`**](#attr-settings-members_can_fork_private_repositories): *(Optional `bool`)* 246 | 247 | Whether or not organization members can fork private repositories. 248 | 249 | Default is `false`. 250 | 251 | - [**`web_commit_signoff_required`**](#attr-settings-web_commit_signoff_required): *(Optional `bool`)* 252 | 253 | Whether or not commit signatures are required for commits to the organization. 254 | 255 | Default is `false`. 256 | 257 | - [**`advanced_security_enabled_for_new_repositories`**](#attr-settings-advanced_security_enabled_for_new_repositories): *(Optional `bool`)* 258 | 259 | Whether or not advanced security is enabled for new repositories. 260 | 261 | Default is `false`. 262 | 263 | - [**`dependabot_alerts_enabled_for_new_repositories`**](#attr-settings-dependabot_alerts_enabled_for_new_repositories): *(Optional `bool`)* 264 | 265 | Whether or not dependabot alerts are enabled for new repositories. 266 | 267 | Default is `false`. 268 | 269 | - [**`dependabot_security_updates_enabled_for_new_repositories`**](#attr-settings-dependabot_security_updates_enabled_for_new_repositories): *(Optional `bool`)* 270 | 271 | Whether or not dependabot security updates are enabled for new repositories. 272 | 273 | Default is `false`. 274 | 275 | - [**`dependency_graph_enabled_for_new_repositories`**](#attr-settings-dependency_graph_enabled_for_new_repositories): *(Optional `bool`)* 276 | 277 | Whether or not dependency graph is enabled for new repositories. 278 | 279 | Default is `false`. 280 | 281 | - [**`secret_scanning_enabled_for_new_repositories`**](#attr-settings-secret_scanning_enabled_for_new_repositories): *(Optional `bool`)* 282 | 283 | Whether or not secret scanning is enabled for new repositories. 284 | 285 | Default is `false`. 286 | 287 | - [**`secret_scanning_push_protection_enabled_for_new_repositories`**](#attr-settings-secret_scanning_push_protection_enabled_for_new_repositories): *(Optional `bool`)* 288 | 289 | Whether or not secret scanning push protection is enabled for new repositories. 290 | 291 | Default is `false`. 292 | 293 | - [**`blocked_users`**](#var-blocked_users): *(Optional `set(string)`)* 294 | 295 | A list of usernames to be blocked from a GitHub organization. 296 | 297 | Default is `[]`. 298 | 299 | Example: 300 | 301 | ```hcl 302 | blocked_users = [ 303 | "blocked-user" 304 | ] 305 | ``` 306 | 307 | - [**`members`**](#var-members): *(Optional `set(string)`)* 308 | 309 | A list of users to be added to your organization with member role. 310 | When applied, an invitation will be sent to the user to become part of the organization. 311 | When destroyed, either the invitation will be cancelled or the user will be removed. 312 | 313 | Default is `[]`. 314 | 315 | Example: 316 | 317 | ```hcl 318 | members = [ 319 | "admin", 320 | "another-admin" 321 | ] 322 | ``` 323 | 324 | - [**`admins`**](#var-admins): *(Optional `set(string)`)* 325 | 326 | A list of users to be added to your organization with admin role. 327 | When applied, an invitation will be sent to the user to become part of the organization. 328 | When destroyed, either the invitation will be cancelled or the user will be removed. 329 | 330 | Default is `[]`. 331 | 332 | Example: 333 | 334 | ```hcl 335 | admins = [ 336 | "admin", 337 | "another-admin" 338 | ] 339 | ``` 340 | 341 | - [**`projects`**](#var-projects): *(Optional `list(project)`)* 342 | 343 | Create and manage projects for the GitHub organization. 344 | 345 | Default is `[]`. 346 | 347 | Example: 348 | 349 | ```hcl 350 | projects = [ 351 | { 352 | name = "Test Project" 353 | body = "This is a test project created by Terraform" 354 | }, 355 | { 356 | name = "Test Project without a body" 357 | } 358 | ] 359 | ``` 360 | 361 | - [**`all_members_team_name`**](#var-all_members_team_name): *(Optional `string`)* 362 | 363 | The name of the team that contains all members of the organization. 364 | 365 | - [**`all_members_team_visibility`**](#var-all_members_team_visibility): *(Optional `string`)* 366 | 367 | The level of privacy for the team. Must be one of `secret` or `closed`. 368 | 369 | Default is `"secret"`. 370 | 371 | - [**`catch_non_existing_members`**](#var-catch_non_existing_members): *(Optional `bool`)* 372 | 373 | Validates if the list of GitHub users are existing users on every run. Use carefully as it will trigger one additional API call for every given user on every iteration. 374 | 375 | Default is `false`. 376 | 377 | ## Module Outputs 378 | 379 | The following attributes are exported by the module: 380 | 381 | - [**`blocked_users`**](#output-blocked_users): *(`set(string)`)* 382 | 383 | A list of `github_organization_block` resource objects 384 | that describe all users that are blocked by the organization. 385 | 386 | - [**`memberships`**](#output-memberships): *(`list(membership)`)* 387 | 388 | A list of `github_membership` resource objects that describe 389 | all members of the organization. 390 | 391 | - [**`projects`**](#output-projects): *(`list(project)`)* 392 | 393 | A list of `github_organization_project` resource objects that 394 | describe all projects of the organization. 395 | 396 | - [**`all_members_team`**](#output-all_members_team): *(`object(all_members_team)`)* 397 | 398 | The outputs of the all members team that contains all members of your organization. 399 | 400 | - [**`settings`**](#output-settings): *(`object(all_members_team)`)* 401 | 402 | The outputs of the organization settings. 403 | 404 | ## External Documentation 405 | 406 | ### Terraform Github Provider Documentation: 407 | 408 | - https://www.terraform.io/docs/providers/github/index.html 409 | 410 | ## Module Versioning 411 | 412 | This Module follows the principles of [Semantic Versioning (SemVer)]. 413 | 414 | Given a version number `MAJOR.MINOR.PATCH`, we increment the: 415 | 416 | 1. `MAJOR` version when we make incompatible changes, 417 | 2. `MINOR` version when we add functionality in a backwards compatible manner, and 418 | 3. `PATCH` version when we make backwards compatible bug fixes. 419 | 420 | ### Backwards compatibility in `0.0.z` and `0.y.z` version 421 | 422 | - Backwards compatibility in versions `0.0.z` is **not guaranteed** when `z` is increased. (Initial development) 423 | - Backwards compatibility in versions `0.y.z` is **not guaranteed** when `y` is increased. (Pre-release) 424 | 425 | ## About Mineiros 426 | 427 | Mineiros is a [DevOps as a Service][homepage] company based in Berlin, Germany. 428 | We offer commercial support for all of our projects and encourage you to reach out 429 | if you have any questions or need help. Feel free to send us an email at [hello@mineiros.io] or join our [Community Slack channel][slack]. 430 | 431 | We can also help you with: 432 | 433 | - Terraform modules for all types of infrastructure such as VPCs, Docker clusters, databases, logging and monitoring, CI, etc. 434 | - Consulting & training on AWS, Terraform and DevOps 435 | 436 | ## Reporting Issues 437 | 438 | We use GitHub [Issues] to track community reported issues and missing features. 439 | 440 | ## Contributing 441 | 442 | Contributions are always encouraged and welcome! For the process of accepting changes, we use 443 | [Pull Requests]. If you'd like more information, please see our [Contribution Guidelines]. 444 | 445 | ## Makefile Targets 446 | 447 | This repository comes with a handy [Makefile]. 448 | Run `make help` to see details on each available target. 449 | 450 | ## License 451 | 452 | [![license][badge-license]][apache20] 453 | 454 | This module is licensed under the Apache License Version 2.0, January 2004. 455 | Please see [LICENSE] for full details. 456 | 457 | Copyright © 2021-2022 [Mineiros GmbH][homepage] 458 | 459 | 460 | 461 | 462 | [homepage]: https://mineiros.io/?ref=terraform-github-organization 463 | [github-as-code]: https://mineiros.io/github-as-code?ref=terraform-github-organization 464 | [hello@mineiros.io]: mailto:hello@mineiros.io 465 | [badge-build]: https://github.com/mineiros-io/terraform-github-organization/workflows/CI/CD%20Pipeline/badge.svg 466 | [badge-semver]: https://img.shields.io/github/v/tag/mineiros-io/terraform-github-organization.svg?label=latest&sort=semver 467 | [badge-license]: https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg 468 | [badge-terraform]: https://img.shields.io/badge/terraform-1.x-623CE4.svg?logo=terraform 469 | [badge-slack]: https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack 470 | [build-status]: https://github.com/mineiros-io/terraform-github-organization/actions 471 | [releases-github]: https://github.com/mineiros-io/terraform-github-organization/releases 472 | [badge-tf-gh]: https://img.shields.io/badge/GH-4.x-F8991D.svg?logo=terraform 473 | [releases-github-provider]: https://github.com/terraform-providers/terraform-provider-github/releases 474 | [releases-terraform]: https://github.com/hashicorp/terraform/releases 475 | [apache20]: https://opensource.org/licenses/Apache-2.0 476 | [slack]: https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg 477 | [terraform]: https://www.terraform.io 478 | [aws]: https://aws.amazon.com/ 479 | [semantic versioning (semver)]: https://semver.org/ 480 | [examples/example/main.tf]: https://github.com/mineiros-io/terraform-github-organization/blob/main/examples/example/main.tf 481 | [variables.tf]: https://github.com/mineiros-io/terraform-github-organization/blob/main/variables.tf 482 | [examples/]: https://github.com/mineiros-io/terraform-github-organization/blob/main/examples 483 | [issues]: https://github.com/mineiros-io/terraform-github-organization/issues 484 | [license]: https://github.com/mineiros-io/terraform-github-organization/blob/main/LICENSE 485 | [makefile]: https://github.com/mineiros-io/terraform-github-organization/blob/main/Makefile 486 | [pull requests]: https://github.com/mineiros-io/terraform-github-organization/pulls 487 | [contribution guidelines]: https://github.com/mineiros-io/terraform-github-organization/blob/main/CONTRIBUTING.md 488 | -------------------------------------------------------------------------------- /README.tfdoc.hcl: -------------------------------------------------------------------------------- 1 | header { 2 | image = "https://raw.githubusercontent.com/mineiros-io/brand/3bffd30e8bdbbde32c143e2650b2faa55f1df3ea/mineiros-primary-logo.svg" 3 | url = "https://mineiros.io/?ref=terraform-github-organization" 4 | 5 | badge "build" { 6 | image = "https://github.com/mineiros-io/terraform-github-organization/workflows/CI/CD%20Pipeline/badge.svg" 7 | url = "https://github.com/mineiros-io/terraform-github-organization/actions" 8 | text = "Build Status" 9 | } 10 | 11 | badge "semver" { 12 | image = "https://img.shields.io/github/v/tag/mineiros-io/terraform-github-organization.svg?label=latest&sort=semver" 13 | url = "https://github.com/mineiros-io/terraform-github-organization/releases" 14 | text = "GitHub tag (latest SemVer)" 15 | } 16 | 17 | badge "terraform" { 18 | image = "https://img.shields.io/badge/terraform-1.x-623CE4.svg?logo=terraform" 19 | url = "https://github.com/hashicorp/terraform/releases" 20 | text = "Terraform Version" 21 | } 22 | 23 | badge "tf-gh" { 24 | image = "https://img.shields.io/badge/GH-5.x-F8991D.svg?logo=terraform" 25 | url = "https://github.com/terraform-providers/terraform-provider-github/releases" 26 | text = "Github Provider Version" 27 | } 28 | 29 | badge "slack" { 30 | image = "https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack" 31 | url = "https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg" 32 | text = "Join Slack" 33 | } 34 | } 35 | 36 | section { 37 | title = "terraform-github-organization" 38 | toc = true 39 | content = <<-END 40 | A [Terraform] module that acts as a wrapper around the Terraform 41 | [GitHub provider](https://www.terraform.io/docs/providers/github/index.html) and offers a more convenient and tested way 42 | to manage GitHub Organizations following best practices. 43 | 44 | **_This module supports Terraform v1.x and is compatible with the Official Terraform GitHub Provider v5.x from `integrations/github`._** 45 | 46 | **Attention: This module is incompatible with the Hashicorp GitHub Provider! The latest version of this module supporting `hashicorp/github` provider is `~> 0.6.0`** 47 | END 48 | 49 | section { 50 | title = "GitHub as Code" 51 | content = <<-END 52 | [GitHub as Code][github-as-code] is a commercial solution built on top of 53 | our open-source Terraform modules for GitHub. It helps our customers to 54 | manage their GitHub organization more efficiently by enabling anyone in 55 | their organization to **self-service** manage **on- and offboarding of users**, 56 | **repositories**, and settings such as **branch protections**, **secrets**, and more 57 | through code. GitHub as Code comes with **pre-configured GitHub Actions 58 | pipelines** for **change pre-view in Pull Requests**, **fully automated 59 | rollouts** and **rollbacks**. It's a comprehensive, ready-to-use blueprint 60 | maintained by our team of platform engineering experts and saves 61 | companies such as yours tons of time by building on top of a pre-configured 62 | solution instead of building and maintaining it yourself. 63 | 64 | For details please see [https://mineiros.io/github-as-code][github-as-code]. 65 | END 66 | } 67 | 68 | section { 69 | title = "Module Features" 70 | content = <<-END 71 | - **Standard Module Features**: 72 | Organization Members, 73 | Organization Owners (Admins), 74 | Organization Projects, 75 | Blocked Users, 76 | Manage Organization Settings 77 | 78 | 79 | - **Extended Module Features**: 80 | Change organization member roles without removing and re-inviting users, 81 | Rename projects without recreating (when providing unique ids), 82 | No need to import members/admins on first run, 83 | Create an all member team that contains every member of your organization 84 | END 85 | } 86 | 87 | section { 88 | title = "Getting Started" 89 | content = <<-END 90 | To quickly start managing your GitHub Organization with Terraform: 91 | 92 | ```hcl 93 | module "organization" { 94 | source = "mineiros-io/organization/github" 95 | version = "~> 0.9.0" 96 | 97 | all_members_team_name = "Mineiros" 98 | 99 | settings = { 100 | billing_email = "hello@mineiros.io" 101 | company = "Mineiros" 102 | blog = "https://blog.mineiros.io" 103 | email = "hello@mineiros.io" 104 | twitter_username = "mineirosio" 105 | location = "Berlin" 106 | name = "Terraform Tests" 107 | description = "This Organization is just used to run some Terraform tests for https://github.com/mineiros-io" 108 | has_organization_projects = true 109 | has_repository_projects = true 110 | default_repository_permission = "read" 111 | members_can_create_repositories = false 112 | members_can_create_public_repositories = false 113 | members_can_create_private_repositories = false 114 | members_can_create_internal_repositories = false 115 | members_can_create_pages = false 116 | members_can_create_public_pages = false 117 | members_can_create_private_pages = false 118 | members_can_fork_private_repositories = false 119 | web_commit_signoff_required = false 120 | advanced_security_enabled_for_new_repositories = false 121 | dependabot_alerts_enabled_for_new_repositories = false 122 | dependabot_security_updates_enabled_for_new_repositories = false 123 | dependency_graph_enabled_for_new_repositories = false 124 | secret_scanning_enabled_for_new_repositories = false 125 | secret_scanning_push_protection_enabled_for_new_repositories = false 126 | } 127 | 128 | 129 | members = [ 130 | "a-user", 131 | "b-user", 132 | ] 133 | 134 | admins = [ 135 | "a-admin", 136 | ] 137 | 138 | blocked_users = [ 139 | "blocked-user", 140 | "another-blocked-user", 141 | ] 142 | 143 | projects = [ 144 | { 145 | id = "project-a" 146 | name = "A Great Project" 147 | body = "This is a project created by Terraform" 148 | } 149 | ] 150 | } 151 | 152 | provider "github" {} 153 | 154 | terraform { 155 | required_version = "~> 1.0" 156 | 157 | required_providers { 158 | github = { 159 | source = "integrations/github" 160 | version = "~> 4.0" 161 | } 162 | } 163 | } 164 | ``` 165 | END 166 | } 167 | 168 | section { 169 | title = "Module Argument Reference" 170 | content = <<-END 171 | See [variables.tf] and [examples/] for details and use-cases. 172 | END 173 | 174 | section { 175 | title = "Top-level Arguments" 176 | 177 | variable "settings" { 178 | type = object(settings) 179 | default = { 180 | fixed_response = { 181 | content_type = "plain/text" 182 | message_body = "Nothing to see here!" 183 | status_code = 418 184 | } 185 | } 186 | description = <<-END 187 | A map of settings for the GitHub organization. 188 | END 189 | 190 | 191 | attribute "billing_email" { 192 | type = string 193 | required = true 194 | description = <<-END 195 | The billing email address for the organization. 196 | END 197 | } 198 | 199 | attribute "email" { 200 | type = string 201 | description = <<-END 202 | The email address for the organization. 203 | END 204 | } 205 | 206 | attribute "name" { 207 | type = string 208 | description = <<-END 209 | The name for the organization. 210 | END 211 | } 212 | 213 | attribute "description" { 214 | type = string 215 | description = <<-END 216 | The description for the organization. 217 | END 218 | } 219 | 220 | attribute "company_name" { 221 | type = string 222 | description = <<-END 223 | The company name for the organization. 224 | END 225 | } 226 | 227 | attribute "blog" { 228 | type = string 229 | description = <<-END 230 | The blog URL for the organization. 231 | END 232 | } 233 | 234 | attribute "twitter_username" { 235 | type = string 236 | description = <<-END 237 | The Twitter username for the organization. 238 | END 239 | } 240 | 241 | attribute "location" { 242 | type = string 243 | description = <<-END 244 | The location for the organization. 245 | END 246 | } 247 | 248 | attribute "has_organization_projects" { 249 | type = bool 250 | default = true 251 | description = <<-END 252 | Whether or not organization projects are enabled for the organization. 253 | END 254 | } 255 | 256 | attribute "has_repository_projects" { 257 | type = bool 258 | default = true 259 | description = <<-END 260 | Whether or not repository projects are enabled for the organization. 261 | END 262 | } 263 | 264 | attribute "default_repository_permission" { 265 | type = string 266 | description = <<-END 267 | The default permission for organization members to create new repositories. 268 | Can be one of `read`, `write`, `admin`, or `none`. 269 | END 270 | } 271 | 272 | attribute "members_can_create_repositories" { 273 | type = bool 274 | default = false 275 | description = <<-END 276 | Whether or not organization members can create new repositories. 277 | END 278 | } 279 | 280 | attribute "members_can_create_public_repositories" { 281 | type = bool 282 | default = true 283 | description = <<-END 284 | Whether or not organization members can create new public repositories. 285 | END 286 | } 287 | 288 | attribute "members_can_create_private_repositories" { 289 | type = bool 290 | default = false 291 | description = <<-END 292 | Whether or not organization members can create new private repositories. 293 | END 294 | } 295 | 296 | attribute "members_can_create_internal_repositories" { 297 | type = bool 298 | default = false 299 | description = <<-END 300 | Whether or not organization members can create new internal repositories. For Enterprise Organizations only. 301 | END 302 | } 303 | 304 | attribute "members_can_create_pages" { 305 | type = bool 306 | default = false 307 | description = <<-END 308 | Whether or not organization members can create new pages. 309 | END 310 | } 311 | 312 | attribute "members_can_create_public_pages" { 313 | type = bool 314 | default = false 315 | description = <<-END 316 | Whether or not organization members can create new public pages. 317 | END 318 | } 319 | 320 | attribute "members_can_fork_private_repositories" { 321 | type = bool 322 | default = false 323 | description = <<-END 324 | Whether or not organization members can fork private repositories. 325 | END 326 | } 327 | 328 | attribute "web_commit_signoff_required" { 329 | type = bool 330 | default = false 331 | description = <<-END 332 | Whether or not commit signatures are required for commits to the organization. 333 | END 334 | } 335 | 336 | attribute "advanced_security_enabled_for_new_repositories" { 337 | type = bool 338 | default = false 339 | description = <<-END 340 | Whether or not advanced security is enabled for new repositories. 341 | END 342 | } 343 | 344 | attribute "dependabot_alerts_enabled_for_new_repositories" { 345 | type = bool 346 | default = false 347 | description = <<-END 348 | Whether or not dependabot alerts are enabled for new repositories. 349 | END 350 | } 351 | 352 | attribute "dependabot_security_updates_enabled_for_new_repositories" { 353 | type = bool 354 | default = false 355 | description = <<-END 356 | Whether or not dependabot security updates are enabled for new repositories. 357 | END 358 | } 359 | 360 | attribute "dependency_graph_enabled_for_new_repositories" { 361 | type = bool 362 | default = false 363 | description = <<-END 364 | Whether or not dependency graph is enabled for new repositories. 365 | END 366 | } 367 | 368 | attribute "secret_scanning_enabled_for_new_repositories" { 369 | type = bool 370 | default = false 371 | description = <<-END 372 | Whether or not secret scanning is enabled for new repositories. 373 | END 374 | } 375 | 376 | attribute "secret_scanning_push_protection_enabled_for_new_repositories" { 377 | type = bool 378 | default = false 379 | description = <<-END 380 | Whether or not secret scanning push protection is enabled for new repositories. 381 | END 382 | } 383 | } 384 | 385 | variable "blocked_users" { 386 | type = set(string) 387 | default = [] 388 | description = <<-END 389 | A list of usernames to be blocked from a GitHub organization. 390 | END 391 | readme_example = <<-END 392 | blocked_users = [ 393 | "blocked-user" 394 | ] 395 | END 396 | } 397 | 398 | variable "members" { 399 | type = set(string) 400 | default = [] 401 | description = <<-END 402 | A list of users to be added to your organization with member role. 403 | When applied, an invitation will be sent to the user to become part of the organization. 404 | When destroyed, either the invitation will be cancelled or the user will be removed. 405 | END 406 | readme_example = <<-END 407 | members = [ 408 | "admin", 409 | "another-admin" 410 | ] 411 | END 412 | } 413 | 414 | variable "admins" { 415 | type = set(string) 416 | default = [] 417 | description = <<-END 418 | A list of users to be added to your organization with admin role. 419 | When applied, an invitation will be sent to the user to become part of the organization. 420 | When destroyed, either the invitation will be cancelled or the user will be removed. 421 | END 422 | readme_example = <<-END 423 | admins = [ 424 | "admin", 425 | "another-admin" 426 | ] 427 | END 428 | } 429 | 430 | variable "projects" { 431 | type = list(project) 432 | default = [] 433 | description = <<-END 434 | Create and manage projects for the GitHub organization. 435 | END 436 | readme_example = <<-END 437 | projects = [ 438 | { 439 | name = "Test Project" 440 | body = "This is a test project created by Terraform" 441 | }, 442 | { 443 | name = "Test Project without a body" 444 | } 445 | ] 446 | END 447 | } 448 | 449 | variable "all_members_team_name" { 450 | type = string 451 | description = <<-END 452 | The name of the team that contains all members of the organization. 453 | END 454 | } 455 | 456 | variable "all_members_team_visibility" { 457 | type = string 458 | default = "secret" 459 | description = <<-END 460 | The level of privacy for the team. Must be one of `secret` or `closed`. 461 | END 462 | } 463 | 464 | variable "catch_non_existing_members" { 465 | type = bool 466 | default = false 467 | description = <<-END 468 | Validates if the list of GitHub users are existing users on every run. Use carefully as it will trigger one additional API call for every given user on every iteration. 469 | END 470 | } 471 | } 472 | } 473 | 474 | section { 475 | title = "Module Outputs" 476 | content = <<-END 477 | The following attributes are exported by the module: 478 | END 479 | 480 | output "blocked_users" { 481 | type = set(string) 482 | description = <<-END 483 | A list of `github_organization_block` resource objects 484 | that describe all users that are blocked by the organization. 485 | END 486 | } 487 | 488 | output "memberships" { 489 | type = list(membership) 490 | description = <<-END 491 | A list of `github_membership` resource objects that describe 492 | all members of the organization. 493 | END 494 | } 495 | 496 | output "projects" { 497 | type = list(project) 498 | description = <<-END 499 | A list of `github_organization_project` resource objects that 500 | describe all projects of the organization. 501 | END 502 | } 503 | 504 | output "all_members_team" { 505 | type = object(all_members_team) 506 | description = <<-END 507 | The outputs of the all members team that contains all members of your organization. 508 | END 509 | } 510 | 511 | output "settings" { 512 | type = object(all_members_team) 513 | description = <<-END 514 | The outputs of the organization settings. 515 | END 516 | } 517 | } 518 | 519 | section { 520 | title = "External Documentation" 521 | 522 | section { 523 | title = "Terraform Github Provider Documentation:" 524 | content = <<-END 525 | - https://www.terraform.io/docs/providers/github/index.html 526 | END 527 | } 528 | } 529 | 530 | section { 531 | title = "Module Versioning" 532 | content = <<-END 533 | This Module follows the principles of [Semantic Versioning (SemVer)]. 534 | 535 | Given a version number `MAJOR.MINOR.PATCH`, we increment the: 536 | 537 | 1. `MAJOR` version when we make incompatible changes, 538 | 2. `MINOR` version when we add functionality in a backwards compatible manner, and 539 | 3. `PATCH` version when we make backwards compatible bug fixes. 540 | END 541 | 542 | section { 543 | title = "Backwards compatibility in `0.0.z` and `0.y.z` version" 544 | content = <<-END 545 | - Backwards compatibility in versions `0.0.z` is **not guaranteed** when `z` is increased. (Initial development) 546 | - Backwards compatibility in versions `0.y.z` is **not guaranteed** when `y` is increased. (Pre-release) 547 | END 548 | } 549 | } 550 | 551 | section { 552 | title = "About Mineiros" 553 | content = <<-END 554 | Mineiros is a [DevOps as a Service][homepage] company based in Berlin, Germany. 555 | We offer commercial support for all of our projects and encourage you to reach out 556 | if you have any questions or need help. Feel free to send us an email at [hello@mineiros.io] or join our [Community Slack channel][slack]. 557 | 558 | We can also help you with: 559 | 560 | - Terraform modules for all types of infrastructure such as VPCs, Docker clusters, databases, logging and monitoring, CI, etc. 561 | - Consulting & training on AWS, Terraform and DevOps 562 | END 563 | } 564 | 565 | section { 566 | title = "Reporting Issues" 567 | content = <<-END 568 | We use GitHub [Issues] to track community reported issues and missing features. 569 | END 570 | } 571 | 572 | section { 573 | title = "Contributing" 574 | content = <<-END 575 | Contributions are always encouraged and welcome! For the process of accepting changes, we use 576 | [Pull Requests]. If you'd like more information, please see our [Contribution Guidelines]. 577 | END 578 | } 579 | 580 | section { 581 | title = "Makefile Targets" 582 | content = <<-END 583 | This repository comes with a handy [Makefile]. 584 | Run `make help` to see details on each available target. 585 | END 586 | } 587 | 588 | section { 589 | title = "License" 590 | content = <<-END 591 | [![license][badge-license]][apache20] 592 | 593 | This module is licensed under the Apache License Version 2.0, January 2004. 594 | Please see [LICENSE] for full details. 595 | 596 | Copyright © 2021-2022 [Mineiros GmbH][homepage] 597 | END 598 | } 599 | } 600 | 601 | references { 602 | ref "homepage" { 603 | value = "https://mineiros.io/?ref=terraform-github-organization" 604 | } 605 | ref "github-as-code" { 606 | value = "https://mineiros.io/github-as-code?ref=terraform-github-organization" 607 | } 608 | ref "hello@mineiros.io" { 609 | value = "mailto:hello@mineiros.io" 610 | } 611 | ref "badge-build" { 612 | value = "https://github.com/mineiros-io/terraform-github-organization/workflows/CI/CD%20Pipeline/badge.svg" 613 | } 614 | ref "badge-semver" { 615 | value = "https://img.shields.io/github/v/tag/mineiros-io/terraform-github-organization.svg?label=latest&sort=semver" 616 | } 617 | ref "badge-license" { 618 | value = "https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg" 619 | } 620 | ref "badge-terraform" { 621 | value = "https://img.shields.io/badge/terraform-1.x-623CE4.svg?logo=terraform" 622 | } 623 | ref "badge-slack" { 624 | value = "https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack" 625 | } 626 | ref "build-status" { 627 | value = "https://github.com/mineiros-io/terraform-github-organization/actions" 628 | } 629 | ref "releases-github" { 630 | value = "https://github.com/mineiros-io/terraform-github-organization/releases" 631 | } 632 | ref "badge-tf-gh" { 633 | value = "https://img.shields.io/badge/GH-4.x-F8991D.svg?logo=terraform" 634 | } 635 | ref "releases-github-provider" { 636 | value = "https://github.com/terraform-providers/terraform-provider-github/releases" 637 | } 638 | ref "releases-terraform" { 639 | value = "https://github.com/hashicorp/terraform/releases" 640 | } 641 | ref "apache20" { 642 | value = "https://opensource.org/licenses/Apache-2.0" 643 | } 644 | ref "slack" { 645 | value = "https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg" 646 | } 647 | ref "terraform" { 648 | value = "https://www.terraform.io" 649 | } 650 | ref "aws" { 651 | value = "https://aws.amazon.com/" 652 | } 653 | ref "semantic versioning (semver)" { 654 | value = "https://semver.org/" 655 | } 656 | ref "examples/example/main.tf" { 657 | value = "https://github.com/mineiros-io/terraform-github-organization/blob/main/examples/example/main.tf" 658 | } 659 | ref "variables.tf" { 660 | value = "https://github.com/mineiros-io/terraform-github-organization/blob/main/variables.tf" 661 | } 662 | ref "examples/" { 663 | value = "https://github.com/mineiros-io/terraform-github-organization/blob/main/examples" 664 | } 665 | ref "issues" { 666 | value = "https://github.com/mineiros-io/terraform-github-organization/issues" 667 | } 668 | ref "license" { 669 | value = "https://github.com/mineiros-io/terraform-github-organization/blob/main/LICENSE" 670 | } 671 | ref "makefile" { 672 | value = "https://github.com/mineiros-io/terraform-github-organization/blob/main/Makefile" 673 | } 674 | ref "pull requests" { 675 | value = "https://github.com/mineiros-io/terraform-github-organization/pulls" 676 | } 677 | ref "contribution guidelines" { 678 | value = "https://github.com/mineiros-io/terraform-github-organization/blob/main/CONTRIBUTING.md" 679 | } 680 | } 681 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | [][homepage] 2 | 3 | [![GitHub tag (latest SemVer)][badge-semver]][releases-github] 4 | [![license][badge-license]][apache20] 5 | [![Terraform Version][badge-terraform]][releases-terraform] 6 | [![Join Slack][badge-slack]][slack] 7 | 8 | # Examples for using this Mineiros module 9 | 10 | - [organization/] Create a public repository on github and set it up with access and webhooks. 11 | 12 | 13 | [organization/]: https://github.com/mineiros-io/terraform-github-organization/blob/main/examples/organization 14 | 15 | [homepage]: https://mineiros.io/?ref=terraform-github-organization 16 | 17 | [badge-license]: https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg 18 | [badge-terraform]: https://img.shields.io/badge/terraform-1.x-623CE4.svg?logo=terraform 19 | [badge-slack]: https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack 20 | [badge-semver]: https://img.shields.io/github/v/tag/mineiros-io/terraform-github-organization.svg?label=latest&sort=semver 21 | 22 | [releases-github]: https://github.com/mineiros-io/terraform-github-organization/releases 23 | [releases-terraform]: https://github.com/hashicorp/terraform/releases 24 | [apache20]: https://opensource.org/licenses/Apache-2.0 25 | [slack]: https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg 26 | -------------------------------------------------------------------------------- /examples/organization/README.md: -------------------------------------------------------------------------------- 1 | [][homepage] 2 | 3 | [![license][badge-license]][apache20] 4 | [![Terraform Version][badge-terraform]][releases-terraform] 5 | [![Join Slack][badge-slack]][slack] 6 | 7 | # Create a public repository on Github 8 | 9 | ## Usage 10 | 11 | The code in [main.tf] defines the following code to manage an organization 12 | and setting it up with members and admins and also creating an all-users team. 13 | In Addition it blocks two random users and sets up two projects. 14 | 15 | ```hcl 16 | module "organization" { 17 | source = "mineiros-io/organization/github" 18 | version = "~> 0.7.0" 19 | 20 | all_members_team_name = "everyone" 21 | all_members_team_visibility = "closed" 22 | 23 | members = [ 24 | "terraform-test-user-1", 25 | "terraform-test-user-2", 26 | ] 27 | 28 | admins = [ 29 | "terraform-test-admin", 30 | ] 31 | 32 | # randomly chosen users, sorry for blocking you guys! 33 | blocked_users = [ 34 | "Testuser1", 35 | "Testuser2", 36 | ] 37 | 38 | projects = [ 39 | { 40 | name = "Test Project" 41 | body = "This is a test project created by Terraform" 42 | }, 43 | { 44 | name = "Test Project without a body" 45 | } 46 | ] 47 | } 48 | ``` 49 | 50 | ## Running the example 51 | 52 | ### Cloning the repository 53 | 54 | ```bash 55 | git clone https://github.com/mineiros-io/terraform-github-organization.git 56 | cd terraform-github-organization/examples/organization 57 | ``` 58 | 59 | ### Initializing Terraform 60 | 61 | Run `terraform init` to initialize the example and download providers and the module. 62 | 63 | ### Planning the example 64 | 65 | Run `terraform plan` to see a plan of the changes. 66 | 67 | ### Applying the example 68 | 69 | Run `terraform apply` to create the resources. 70 | You will see a plan of the changes and Terraform will prompt you for approval to actually apply the changes. 71 | 72 | ### Destroying the example 73 | 74 | Run `terraform destroy` to destroy all resources again. 75 | 76 | 77 | 78 | [main.tf]: https://github.com/mineiros-io/terraform-github-organization/blob/main/examples/organization/main.tf 79 | 80 | [homepage]: https://mineiros.io/?ref=terraform-github-organization 81 | 82 | [badge-license]: https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg 83 | [badge-terraform]: https://img.shields.io/badge/terraform-1.x%20|0.15%20|0.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform 84 | [badge-slack]: https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack 85 | 86 | [releases-terraform]: https://github.com/hashicorp/terraform/releases 87 | [apache20]: https://opensource.org/licenses/Apache-2.0 88 | [slack]: https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg 89 | -------------------------------------------------------------------------------- /examples/organization/main.tf: -------------------------------------------------------------------------------- 1 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | # MANAGE A GITHUB ORGANIZATION 3 | # - manage blocked users 4 | # - manage projects 5 | # - manage memberships ( admins and members ) 6 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | # --------------------------------------------------------------------------------------------------------------------- 9 | # ENVIRONMENT VARIABLES: 10 | # --------------------------------------------------------------------------------------------------------------------- 11 | # You can provide your credentials via the 12 | # GITHUB_TOKEN and 13 | # GITHUB_OWNER, environment variables, 14 | # representing your Access Token and the organization, respectively. 15 | # --------------------------------------------------------------------------------------------------------------------- 16 | 17 | # --------------------------------------------------------------------------------------------------------------------- 18 | # EXAMPLE PROVIDER CONFIGURATION 19 | # --------------------------------------------------------------------------------------------------------------------- 20 | 21 | module "organization" { 22 | source = "mineiros-io/organization/github" 23 | version = "~> 0.9.0" 24 | 25 | all_members_team_name = "everyone" 26 | all_members_team_visibility = "closed" 27 | 28 | members = [ 29 | "terraform-test-user-1", 30 | "terraform-test-user-2", 31 | ] 32 | 33 | admins = [ 34 | "terraform-test-admin", 35 | ] 36 | 37 | # randomly chosen users, sorry for blocking you guys! 38 | blocked_users = [ 39 | "Testuser1", 40 | "Testuser2", 41 | ] 42 | 43 | projects = [ 44 | { 45 | name = "Test Project" 46 | body = "This is a test project created by Terraform" 47 | }, 48 | { 49 | name = "Test Project without a body" 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /examples/organization/provider.tf: -------------------------------------------------------------------------------- 1 | provider "github" {} 2 | 3 | terraform { 4 | required_version = "~> 1.0" 5 | 6 | required_providers { 7 | github = { 8 | source = "integrations/github" 9 | version = "~> 5.3" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mineiros-io/terraform-github-organization/v2 2 | 3 | go 1.13 4 | 5 | require github.com/gruntwork-io/terratest v0.30.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= 9 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 10 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 11 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 12 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 13 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 14 | github.com/Azure/azure-sdk-for-go v32.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 15 | github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 16 | github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 17 | github.com/Azure/azure-sdk-for-go v38.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 18 | github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 19 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 20 | github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= 21 | github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 22 | github.com/Azure/go-autorest/autorest v0.9.1/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 23 | github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= 24 | github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= 25 | github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= 26 | github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= 27 | github.com/Azure/go-autorest/autorest/adal v0.6.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= 28 | github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= 29 | github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= 30 | github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= 31 | github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= 32 | github.com/Azure/go-autorest/autorest/azure/auth v0.3.0/go.mod h1:CI4BQYBct8NS7BXNBBX+RchsFsUu5+oz+OSyR/ZIi7U= 33 | github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= 34 | github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= 35 | github.com/Azure/go-autorest/autorest/azure/cli v0.3.0/go.mod h1:rNYMNAefZMRowqCV0cVhr/YDW5dD7afFq9nXAXL4ykE= 36 | github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= 37 | github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= 38 | github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= 39 | github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= 40 | github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= 41 | github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 42 | github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 43 | github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= 44 | github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= 45 | github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= 46 | github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= 47 | github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= 48 | github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= 49 | github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= 50 | github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= 51 | github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= 52 | github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= 53 | github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 54 | github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= 55 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 56 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 57 | github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= 58 | github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= 59 | github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= 60 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 61 | github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 62 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 63 | github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 64 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 65 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 66 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 67 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 68 | github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= 69 | github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 70 | github.com/aws/aws-sdk-go v1.23.8/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 71 | github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 72 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 73 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 74 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 75 | github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 76 | github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= 77 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 78 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 79 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 80 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 81 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 82 | github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= 83 | github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= 84 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 85 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 86 | github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= 87 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 88 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 89 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 90 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 91 | github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 92 | github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 93 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 94 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 95 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 96 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 97 | github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 98 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 99 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 100 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 101 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 102 | github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= 103 | github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= 104 | github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= 105 | github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= 106 | github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 107 | github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 108 | github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 109 | github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= 110 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 111 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 112 | github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 113 | github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 114 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 115 | github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 116 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 117 | github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 118 | github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 119 | github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= 120 | github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= 121 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 122 | github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 123 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 124 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 125 | github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 126 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 127 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 128 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 129 | github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 130 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 131 | github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= 132 | github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 133 | github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 134 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 135 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 136 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 137 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 138 | github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= 139 | github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= 140 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 141 | github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= 142 | github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= 143 | github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= 144 | github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= 145 | github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= 146 | github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= 147 | github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 148 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 149 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 150 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 151 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 152 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 153 | github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 154 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 155 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 156 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 157 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 158 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 159 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 160 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 161 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 162 | github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 163 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 164 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 165 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 166 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 167 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 168 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 169 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 170 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 171 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 172 | github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= 173 | github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= 174 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 175 | github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 176 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 177 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 178 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 179 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 180 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 181 | github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 182 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 183 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 184 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 185 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 186 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 187 | github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 188 | github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 189 | github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= 190 | github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= 191 | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 192 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 193 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 194 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 195 | github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 196 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 197 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 198 | github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 199 | github.com/gruntwork-io/gruntwork-cli v0.5.1/go.mod h1:IBX21bESC1/LGoV7jhXKUnTQTZgQ6dYRsoj/VqxUSZQ= 200 | github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= 201 | github.com/gruntwork-io/terratest v0.23.0 h1:JmGeqO0r5zRLAV55T67NEmPZArz9lN3RKd0moAKhIT4= 202 | github.com/gruntwork-io/terratest v0.23.0/go.mod h1:+fVff0FQYuRzCF3LKpKF9ac+4w384LDcwLZt7O/KmEE= 203 | github.com/gruntwork-io/terratest v0.24.2 h1:ZL7s7ZaVPRds+HqtPFh8gXjFVpKRNAAbwyVPYx3lH50= 204 | github.com/gruntwork-io/terratest v0.24.2/go.mod h1:0MCPUGIgQaAXOmw0qRLqyIXs8q6yoNPB3aZt4SkdH0M= 205 | github.com/gruntwork-io/terratest v0.25.0 h1:4Sz8q5DVEqeCC+eAfN+apL/PnqsmurGsn+fGRnZGeKU= 206 | github.com/gruntwork-io/terratest v0.25.0/go.mod h1:0MCPUGIgQaAXOmw0qRLqyIXs8q6yoNPB3aZt4SkdH0M= 207 | github.com/gruntwork-io/terratest v0.30.0 h1:1USVQG4Rg7Fp5WLuTjgU6kt+o7GM0ZcllYcsKXGv7nI= 208 | github.com/gruntwork-io/terratest v0.30.0/go.mod h1:7dNmTD2zDKUEVqfmvcUU5c9mZi+986mcXNzhzqPYPg8= 209 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 210 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 211 | github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 212 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 213 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 214 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 215 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 216 | github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 217 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 218 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 219 | github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= 220 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 221 | github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 222 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 223 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 224 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 225 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 226 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 227 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 228 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 229 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 230 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 231 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 232 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 233 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 234 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 235 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 236 | github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= 237 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 238 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 239 | github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= 240 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 241 | github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 242 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 243 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 244 | github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= 245 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 246 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 247 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 248 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 249 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 250 | github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 251 | github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= 252 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= 253 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 254 | github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= 255 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 256 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 257 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 258 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 259 | github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 260 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 261 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 262 | github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 263 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 264 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 265 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 266 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 267 | github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 268 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 269 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 270 | github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 271 | github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 272 | github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 273 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 274 | github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 275 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 276 | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 277 | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 278 | github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= 279 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 280 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 281 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 282 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 283 | github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 284 | github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 285 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 286 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 287 | github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= 288 | github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= 289 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 290 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 291 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 292 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 293 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 294 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 295 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 296 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 297 | github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= 298 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 299 | github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= 300 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 301 | github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= 302 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 303 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 304 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 305 | github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= 306 | github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 307 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 308 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 309 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 310 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 311 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 312 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 313 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 314 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 315 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 316 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 317 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 318 | github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 319 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 320 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 321 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 322 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 323 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 324 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 325 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 326 | github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 327 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 328 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 329 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 330 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 331 | github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 332 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 333 | github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 334 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 335 | github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 336 | github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= 337 | github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= 338 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 339 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 340 | go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 341 | go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= 342 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 343 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 344 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 345 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 346 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 347 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 348 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 349 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 350 | golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 351 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 352 | golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 353 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 354 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 355 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 356 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0= 357 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 358 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 359 | golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 360 | golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 h1:nVJ3guKA9qdkEQ3TUdXI9QSINo2CUPM/cySEvw2w8I0= 361 | golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 362 | golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 363 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 364 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 365 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 366 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 367 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 368 | golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 369 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 370 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 371 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 372 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 373 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 374 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 375 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 376 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 377 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 378 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 379 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 380 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 381 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 382 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 383 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 384 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 385 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 386 | golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 387 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 388 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 389 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 390 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 391 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 392 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 393 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 394 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 395 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 396 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 397 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 398 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 399 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 400 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 401 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 402 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= 403 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 404 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 405 | golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 406 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= 407 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 408 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 409 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 410 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 411 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 412 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 413 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 414 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 415 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 416 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 417 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 418 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 419 | golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 420 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 421 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 422 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 423 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 424 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 425 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 426 | golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 427 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 428 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 429 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 430 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 431 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 432 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 433 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 434 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 435 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 436 | golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 437 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 438 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 439 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 440 | golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 441 | golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 442 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 443 | golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 h1:Hynbrlo6LbYI3H1IqXpkVDOcX/3HiPdhVEuyj5a59RM= 444 | golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 445 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 446 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 447 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50 h1:YvQ10rzcqWXLlJZ3XCUoO25savxmscf4+SC+ZqiCHhA= 448 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 449 | golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 450 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 451 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 452 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 453 | golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 454 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 455 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 456 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 457 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 458 | golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 459 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 460 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 461 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 462 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 463 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 464 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 465 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 466 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 467 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 468 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 469 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 470 | golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 471 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 472 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 473 | golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= 474 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 475 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 476 | golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 477 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 478 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 479 | golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 480 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 481 | golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 482 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 483 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 484 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 485 | gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= 486 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 487 | gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= 488 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 489 | google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= 490 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 491 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 492 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 493 | google.golang.org/api v0.9.1-0.20190821000710-329ecc3c9c34/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 494 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 495 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 496 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 497 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 498 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 499 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 500 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 501 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 502 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 503 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 504 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 505 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 506 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 507 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 508 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 509 | google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 510 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 511 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 512 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 513 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 514 | google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 515 | google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= 516 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 517 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 518 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 519 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 520 | gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 521 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 522 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 523 | gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= 524 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 525 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 526 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 527 | gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 528 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 529 | gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 530 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 531 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 532 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 533 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 534 | gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= 535 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 536 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 537 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 538 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 539 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 540 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 541 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 542 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 543 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 544 | k8s.io/api v0.0.0-20181110191121-a33c8200050f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= 545 | k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= 546 | k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= 547 | k8s.io/apimachinery v0.0.0-20190704094520-6f131bee5e2c/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= 548 | k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= 549 | k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= 550 | k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= 551 | k8s.io/client-go v0.0.0-20190704095228-386e588352a4/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= 552 | k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= 553 | k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= 554 | k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= 555 | k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= 556 | k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= 557 | k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= 558 | k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 559 | k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 560 | k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 561 | k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 562 | k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= 563 | k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= 564 | k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= 565 | k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= 566 | k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= 567 | k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 568 | k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 569 | modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= 570 | modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= 571 | modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= 572 | modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= 573 | modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= 574 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 575 | sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 576 | sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= 577 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= 578 | sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= 579 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 580 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= 581 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | # MANAGE A GITHUB ORGANIZATION 3 | # - manage memberships ( admins and members ) 4 | # - manage blocked users 5 | # - manage projects 6 | # - create the team "all" that contains every member of the organization 7 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | 9 | locals { 10 | admins = { for i in var.admins : lower(i) => "admin" } 11 | members = { for i in var.members : lower(i) => "member" } 12 | memberships = merge(local.admins, local.members) 13 | } 14 | 15 | # Safeguard for validating if a GitHub user exists on `terraform plan` 16 | data "github_user" "user" { 17 | for_each = var.catch_non_existing_members ? local.memberships : {} 18 | 19 | username = each.key 20 | } 21 | 22 | resource "github_membership" "membership" { 23 | for_each = local.memberships 24 | 25 | username = each.key 26 | role = each.value 27 | } 28 | 29 | resource "github_organization_block" "blocked_user" { 30 | for_each = var.blocked_users 31 | 32 | username = each.value 33 | } 34 | 35 | locals { 36 | projects = { for p in var.projects : lookup(p, "id", lower(p.name)) => merge({ 37 | body = null 38 | }, p) } 39 | } 40 | 41 | resource "github_organization_project" "project" { 42 | for_each = local.projects 43 | 44 | name = each.value.name 45 | body = each.value.body 46 | } 47 | 48 | resource "github_team" "all" { 49 | count = var.all_members_team_name != null ? 1 : 0 50 | 51 | name = var.all_members_team_name 52 | description = "This teams contains all members of our organization." 53 | privacy = var.all_members_team_visibility 54 | } 55 | 56 | resource "github_team_membership" "all" { 57 | for_each = var.all_members_team_name != null ? local.memberships : {} 58 | 59 | team_id = github_team.all[0].id 60 | username = each.key 61 | role = "member" 62 | } 63 | 64 | resource "github_organization_settings" "settings" { 65 | count = length(var.settings) > 0 ? 1 : 0 66 | 67 | billing_email = var.settings.billing_email 68 | company = try(var.settings.company, null) 69 | blog = try(var.settings.blog, null) 70 | email = try(var.settings.email, null) 71 | twitter_username = try(var.settings.twitter_username, null) 72 | location = try(var.settings.location, null) 73 | name = try(var.settings.name, null) 74 | description = try(var.settings.description, null) 75 | has_organization_projects = try(var.settings.has_organization_projects, true) 76 | has_repository_projects = try(var.settings.has_repository_projects, true) 77 | default_repository_permission = try(var.settings.default_repository_permission, "read") 78 | members_can_create_repositories = try(var.settings.members_can_create_repositories, false) 79 | members_can_create_public_repositories = try(var.settings.members_can_create_public_repositories, false) 80 | members_can_create_private_repositories = try(var.settings.members_can_create_private_repositories, false) 81 | members_can_create_internal_repositories = try(var.settings.members_can_create_internal_repositories, false) 82 | members_can_create_pages = try(var.settings.members_can_create_pages, false) 83 | members_can_create_public_pages = try(var.settings.members_can_create_public_pages, false) 84 | members_can_create_private_pages = try(var.settings.members_can_create_private_pages, false) 85 | members_can_fork_private_repositories = try(var.settings.members_can_fork_private_repositories, false) 86 | web_commit_signoff_required = try(var.settings.web_commit_signoff_required, false) 87 | advanced_security_enabled_for_new_repositories = try(var.settings.advanced_security_enabled_for_new_repositories, false) 88 | dependabot_alerts_enabled_for_new_repositories = try(var.settings.dependabot_alerts_enabled_for_new_repositories, false) 89 | dependabot_security_updates_enabled_for_new_repositories = try(var.settings.advanced_security_enabled_for_new_repositories, false) 90 | dependency_graph_enabled_for_new_repositories = try(var.settings.dependency_graph_enabled_for_new_repositories, false) 91 | secret_scanning_enabled_for_new_repositories = try(var.settings.secret_scanning_enabled_for_new_repositories, false) 92 | secret_scanning_push_protection_enabled_for_new_repositories = try(var.settings.secret_scanning_push_protection_enabled_for_new_repositories, false) 93 | } 94 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # OUTPUT CALCULATED VARIABLES (prefer full objects) 3 | # ------------------------------------------------------------------------------ 4 | 5 | output "all_members_team" { 6 | description = "The outputs of the all members team that contains all members of your organization." 7 | value = try(github_team.all[0], {}) 8 | } 9 | 10 | # ------------------------------------------------------------------------------ 11 | # OUTPUT ALL RESOURCES AS FULL OBJECTS 12 | # ------------------------------------------------------------------------------ 13 | 14 | output "blocked_users" { 15 | description = "The list of users that are blocked by the organiation." 16 | value = github_organization_block.blocked_user 17 | } 18 | 19 | output "memberships" { 20 | description = "A map of members and admins keyed by username." 21 | value = github_membership.membership 22 | } 23 | 24 | output "projects" { 25 | description = "A map of projects keyed by the id (default: project name)." 26 | value = github_organization_project.project 27 | } 28 | 29 | output "settings" { 30 | description = "The outputs of the organization settings." 31 | value = try(github_organization_settings.settings[0], {}) 32 | } 33 | 34 | # ------------------------------------------------------------------------------ 35 | # OUTPUT ALL INPUT VARIABLES 36 | # ------------------------------------------------------------------------------ 37 | 38 | # ------------------------------------------------------------------------------ 39 | # OUTPUT MODULE CONFIGURATION 40 | # ------------------------------------------------------------------------------ 41 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | [][homepage] 2 | 3 | [![license][badge-license]][apache20] 4 | [![Terraform Version][badge-terraform]][releases-terraform] 5 | [![Join Slack][badge-slack]][slack] 6 | 7 | # Tests 8 | 9 | This directory contains a number of automated tests that cover the functionality 10 | of the modules that ship with this repository. 11 | 12 | ## Introduction 13 | 14 | We are using [Terratest] for automated tests that are located in the 15 | [`test/` directory][Testdirectory]. Terratest deploys _real_ infrastructure 16 | (e.g., servers) in a _real_ environment (e.g., AWS). 17 | 18 | The basic usage pattern for writing automated tests with Terratest is to: 19 | 20 | 1. Write tests using Go's built-in [package testing]: you create a file ending 21 | in `_test.go` and run tests with the `go test` command. 22 | 2. Use Terratest to execute your _real_ IaC tools (e.g., Terraform, Packer, etc.) 23 | to deploy _real_ infrastructure (e.g., servers) in a _real_ environment (e.g., AWS). 24 | 3. Validate that the infrastructure works correctly in that environment by 25 | making HTTP requests, API calls, SSH connections, etc. 26 | 4. Undeploy everything at the end of the test. 27 | 28 | **Note #1**: Many of these tests create real resources in an AWS account. 29 | That means they cost money to run, especially if you don't clean up after 30 | yourself. Please be considerate of the resources you create and take extra care 31 | to clean everything up when you're done! 32 | 33 | **Note #2**: Never hit `CTRL + C` or cancel a build once tests are running or 34 | the cleanup tasks won't run! 35 | 36 | **Note #3**: We set `-timeout 45m` on all tests not because they necessarily 37 | take 45 minutes, but because Go has a default test timeout of 10 minutes, after 38 | which it does a `SIGQUIT`, preventing the tests from properly cleaning up after 39 | themselves. Therefore, we set a timeout of 45 minutes to make sure all tests 40 | have enough time to finish and cleanup. 41 | 42 | ## How to run the tests 43 | 44 | This repository comes with a [Makefile], that helps you to run the 45 | tests in a convenient way. 46 | Alternatively, you can also run the tests without Docker. 47 | 48 | ### Run the tests with Docker 49 | 50 | 1. Install [Docker] 51 | 2. Set your AWS credentials as environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` 52 | 3. Run `make docker-run-tests` 53 | 54 | ### Run the tests without Docker 55 | 56 | 1. Install the latest version of [Go]. 57 | 2. Install [Terraform]. 58 | 3. Set your AWS credentials as environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` 59 | 4. Install go dependencies: `go mod download` 60 | 5. Run all tests: `go test -v -count 1 -timeout 45m -parallel 128 ./test/...` 61 | 6. Run a specific test: `go test -count 1 -v -timeout 45m -parallel 128 test/example_test.go` 62 | 63 | 64 | 65 | [Makefile]: https://github.com/mineiros-io/terraform-github-organization/blob/main/Makefile 66 | [Testdirectory]: https://github.com/mineiros-io/terraform-github-organization/tree/main/test 67 | 68 | [homepage]: https://mineiros.io/?ref=terraform-github-organization 69 | [Terratest]: https://github.com/gruntwork-io/terratest 70 | [package testing]: https://golang.org/pkg/testing/ 71 | [Docker]: https://docs.docker.com/get-started/ 72 | [Go]: https://golang.org/ 73 | [Terraform]: https://www.terraform.io/downloads.html 74 | [badge-license]: https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg 75 | [badge-terraform]: https://img.shields.io/badge/terraform-1.x%20|0.15%20|0.14%20|%200.13%20|%200.12.20+-623CE4.svg?logo=terraform 76 | [badge-slack]: https://img.shields.io/badge/slack-@mineiros--community-f32752.svg?logo=slack 77 | 78 | [releases-terraform]: https://github.com/hashicorp/terraform/releases 79 | [apache20]: https://opensource.org/licenses/Apache-2.0 80 | [slack]: https://join.slack.com/t/mineiros-community/shared_invite/zt-ehidestg-aLGoIENLVs6tvwJ11w9WGg 81 | -------------------------------------------------------------------------------- /test/github_organization_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/random" 9 | 10 | "github.com/gruntwork-io/terratest/modules/terraform" 11 | ) 12 | 13 | var githubOrganization, githubToken string 14 | 15 | func init() { 16 | githubOrganization = os.Getenv("GITHUB_OWNER") 17 | githubToken = os.Getenv("GITHUB_TOKEN") 18 | 19 | if githubOrganization == "" { 20 | panic("Please set a github organization using the GITHUB_OWNER environment variable.") 21 | } 22 | 23 | if githubToken == "" { 24 | panic("Please set a github token using the GITHUB_TOKEN environment variable.") 25 | } 26 | } 27 | 28 | func TestGithubOrganization(t *testing.T) { 29 | t.Parallel() 30 | 31 | expectedProjects := []interface{}{ 32 | map[string]interface{}{ 33 | "name": fmt.Sprintf("test-project-%s", random.UniqueId()), 34 | "body": "This is a test project created by Terraform", 35 | }, 36 | map[string]interface{}{ 37 | "name": fmt.Sprintf("test-project-%s", random.UniqueId()), 38 | }, 39 | } 40 | 41 | expectedBlockedUsers := []string{ 42 | "Testuser1", 43 | "Testuser2", 44 | } 45 | 46 | expectedAdmins := []string{ 47 | "terraform-test-admin", 48 | } 49 | 50 | expectedMembers := []string{ 51 | "terraform-test-user-1", 52 | "terraform-test-user-2", 53 | } 54 | 55 | terraformOptions := &terraform.Options{ 56 | // The path to where your Terraform code is located 57 | TerraformDir: "organization", 58 | Upgrade: true, 59 | Vars: map[string]interface{}{ 60 | "blocked_users": expectedBlockedUsers, 61 | "admins": expectedAdmins, 62 | "members": expectedMembers, 63 | "projects": expectedProjects, 64 | }, 65 | } 66 | 67 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 68 | defer terraform.Destroy(t, terraformOptions) 69 | 70 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 71 | terraform.InitAndApply(t, terraformOptions) 72 | 73 | } 74 | -------------------------------------------------------------------------------- /test/organization/main.tf: -------------------------------------------------------------------------------- 1 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | # MANAGE A GITHUB ORGANIZATION 3 | # - manage blocked users 4 | # - manage projects 5 | # - manage memberships ( admins and members ) 6 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | module "organization" { 9 | source = "../.." 10 | 11 | all_members_team_name = var.all_members_team_name 12 | all_members_team_visibility = "closed" 13 | members = var.members 14 | admins = var.admins 15 | blocked_users = var.blocked_users 16 | projects = var.projects 17 | settings = var.settings 18 | } 19 | -------------------------------------------------------------------------------- /test/organization/outputs.tf: -------------------------------------------------------------------------------- 1 | output "all_outputs" { 2 | description = "All outputs exposed by this module." 3 | value = module.organization 4 | } 5 | 6 | output "blocked_users" { 7 | description = "A list of users that are blocked by the organiation." 8 | value = module.organization.blocked_users 9 | } 10 | 11 | output "memberships" { 12 | description = "A map of members and admins keyed by username." 13 | value = module.organization.memberships 14 | } 15 | 16 | output "projects" { 17 | description = "A map of projects keyed by the id (default: project name)." 18 | value = module.organization.projects 19 | } 20 | 21 | -------------------------------------------------------------------------------- /test/organization/provider.tf: -------------------------------------------------------------------------------- 1 | provider "github" {} 2 | 3 | terraform { 4 | required_version = "~> 1.0" 5 | 6 | required_providers { 7 | github = { 8 | source = "integrations/github" 9 | version = "~> 5.0" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/organization/variables.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # REQUIRED VARIABLES 3 | # These variables must be set when using this module. 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | # --------------------------------------------------------------------------------------------------------------------- 7 | # OPTIONAL VARIABLES 8 | # These variables have defaults, but may be overridden. 9 | # --------------------------------------------------------------------------------------------------------------------- 10 | 11 | variable "admins" { 12 | description = "A list of admins to add to the organization." 13 | type = set(string) 14 | default = [ 15 | "terraform-test-admin", 16 | ] 17 | } 18 | 19 | variable "all_members_team_name" { 20 | description = "The name of the team that contains all members of the organization." 21 | type = string 22 | default = "everyone" 23 | } 24 | 25 | variable "all_members_team_visibility" { 26 | description = "The level of privacy for the team. Must be one of `secret` or `closed`." 27 | type = string 28 | default = "secret" 29 | } 30 | 31 | variable "blocked_users" { 32 | description = "A list of users that should be blocked by the organization." 33 | type = set(string) 34 | 35 | # randomly chosen users, sorry for blocking you guys! 36 | default = [ 37 | "Testuser1", 38 | "Testuser2", 39 | ] 40 | } 41 | 42 | variable "members" { 43 | description = "A list of members to add to the organization." 44 | type = set(string) 45 | default = [ 46 | "terraform-test-user-1", 47 | "terraform-test-user-2", 48 | ] 49 | } 50 | 51 | variable "projects" { 52 | description = "A list of projects to add to the organization." 53 | type = any 54 | default = [ 55 | { 56 | name = "Test Project" 57 | body = "This is a test project created by Terraform" 58 | }, 59 | { 60 | name = "Test Project without a body" 61 | } 62 | ] 63 | } 64 | 65 | variable "settings" { 66 | description = "A map of settings to apply to the organization." 67 | type = any 68 | default = { 69 | billing_email = "hello@mineiros.io" 70 | company = "Mineiros" 71 | blog = "https://blog.mineiros.io" 72 | email = "hello@mineiros.io" 73 | twitter_username = "mineirosio" 74 | location = "Berlin" 75 | name = "Terraform Tests" 76 | description = "This Organization is just used to run some Terraform tests for https://github.com/mineiros-io" 77 | has_organization_projects = true 78 | has_repository_projects = true 79 | default_repository_permission = "read" 80 | members_can_create_repositories = false 81 | members_can_create_public_repositories = false 82 | members_can_create_private_repositories = false 83 | members_can_create_internal_repositories = false 84 | members_can_create_pages = false 85 | members_can_create_public_pages = false 86 | members_can_create_private_pages = false 87 | members_can_fork_private_repositories = false 88 | web_commit_signoff_required = false 89 | advanced_security_enabled_for_new_repositories = false 90 | dependabot_alerts_enabled_for_new_repositories = false 91 | dependabot_security_updates_enabled_for_new_repositories = false 92 | dependency_graph_enabled_for_new_repositories = false 93 | secret_scanning_enabled_for_new_repositories = false 94 | secret_scanning_push_protection_enabled_for_new_repositories = false 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # REQUIRED VARIABLES 3 | # These variables must be set when using this module. 4 | # --------------------------------------------------------------------------------------------------------------------- 5 | 6 | # --------------------------------------------------------------------------------------------------------------------- 7 | # OPTIONAL VARIABLES 8 | # These variables have defaults, but may be overridden. 9 | # --------------------------------------------------------------------------------------------------------------------- 10 | 11 | variable "all_members_team_name" { 12 | description = "(Optional) The name of the team that contains all members of the organization." 13 | type = string 14 | default = null 15 | } 16 | 17 | variable "all_members_team_visibility" { 18 | description = "(Optional) The level of privacy for the team. Must be one of 'secret' or 'closed'." 19 | type = string 20 | default = "secret" 21 | } 22 | 23 | variable "catch_non_existing_members" { 24 | description = "(Optional) Validates if the list of GitHub users are existing users on every run. Use carefully as it will trigger one additional API call for every given user on every iteration. Default is 'false'" 25 | type = bool 26 | default = false 27 | } 28 | 29 | variable "blocked_users" { 30 | description = "(Optional) A list of usernames to be blocked from a GitHub organization." 31 | type = set(string) 32 | 33 | # 34 | # Example: 35 | # 36 | # blocked_users = [ 37 | # "blocked-user" 38 | # ] 39 | # 40 | 41 | default = [] 42 | } 43 | 44 | variable "members" { 45 | type = set(string) 46 | description = "(Optional) A list of users to be added to your organization with member role. When applied, an invitation will be sent to the user to become part of the organization. When destroyed, either the invitation will be cancelled or the user will be removed." 47 | 48 | # 49 | # Example: 50 | # 51 | # members = [ 52 | # "admin", 53 | # "another-admin" 54 | # ] 55 | # 56 | 57 | default = [] 58 | } 59 | 60 | variable "admins" { 61 | type = set(string) 62 | description = "(Optional) A list of users to be added to your organization with admin role. When applied, an invitation will be sent to the user to become part of the organization. When destroyed, either the invitation will be cancelled or the user will be removed." 63 | 64 | # 65 | # Example: 66 | # 67 | # admins = [ 68 | # "admin", 69 | # "another-admin" 70 | # ] 71 | # 72 | 73 | default = [] 74 | } 75 | 76 | variable "projects" { 77 | type = any 78 | 79 | # We can't use a detailed type specification due to a terraform limitation. However, this might be changed in a future 80 | # Terraform version. See https://github.com/hashicorp/terraform/issues/19898 and https://github.com/hashicorp/terraform/issues/22449 81 | # 82 | # type = list(object({ 83 | # name = string 84 | # body = optional(string) 85 | # })) 86 | 87 | description = "(Optional) Create and manage projects for the GitHub organization." 88 | 89 | # 90 | # Example: 91 | # 92 | # projects = [ 93 | # { 94 | # name = "Test Project" 95 | # body = "This is a test project created by Terraform" 96 | # }, 97 | # { 98 | # name = "Test Project without a body" 99 | # } 100 | # ] 101 | # 102 | 103 | default = [] 104 | } 105 | 106 | variable "settings" { 107 | type = any 108 | description = "A map of settings for the GitHub organization." 109 | # 110 | # Example 111 | # settings = { 112 | # billing_email = "hello@mineiros.io" 113 | # company = "Mineiros" 114 | # blog = "https://blog.mineiros.io" 115 | # email = "hello@mineiros.io" 116 | # twitter_username = "mineirosio" 117 | # location = "Berlin" 118 | # name = "Terraform Tests" 119 | # description = "This Organization is just used to run some Terraform tests for https://github.com/mineiros-io" 120 | # has_organization_projects = true 121 | # has_repository_projects = true 122 | # default_repository_permission = "read" 123 | # members_can_create_repositories = false 124 | # members_can_create_public_repositories = false 125 | # members_can_create_private_repositories = false 126 | # members_can_create_internal_repositories = false 127 | # members_can_create_pages = false 128 | # members_can_create_public_pages = false 129 | # members_can_create_private_pages = false 130 | # members_can_fork_private_repositories = false 131 | # web_commit_signoff_required = false 132 | # advanced_security_enabled_for_new_repositories = false 133 | # dependabot_alerts_enabled_for_new_repositories = false 134 | # dependabot_security_updates_enabled_for_new_repositories = false 135 | # dependency_graph_enabled_for_new_repositories = false 136 | # secret_scanning_enabled_for_new_repositories = false 137 | # secret_scanning_push_protection_enabled_for_new_repositories = false 138 | # } 139 | # 140 | 141 | default = {} 142 | } 143 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # SET TERRAFORM AND PROVIDER REQUIREMENTS FOR RUNNING THIS MODULE 3 | # --------------------------------------------------------------------------------------------------------------------- 4 | 5 | terraform { 6 | required_version = "~> 1.0" 7 | 8 | required_providers { 9 | github = { 10 | source = "integrations/github" 11 | version = "~> 5.3" 12 | } 13 | } 14 | } 15 | --------------------------------------------------------------------------------