From 9daf40cf4180fdf3f5f6b171b51f5d5ca48a907a Mon Sep 17 00:00:00 2001 From: "Jeremy T. Bouse" Date: Sun, 13 Feb 2022 14:27:41 -0500 Subject: [PATCH] execute github/init Signed-off-by: Jeremy T. Bouse --- .build-harness | 176 ++++++++++++++++++++++ .github/CODEOWNERS | 25 +++ .github/ISSUE_TEMPLATE/bug_report.md | 37 +++++ .github/ISSUE_TEMPLATE/config.yml | 18 +++ .github/ISSUE_TEMPLATE/feature_request.md | 36 +++++ .github/ISSUE_TEMPLATE/question.md | 0 .github/PULL_REQUEST_TEMPLATE.md | 13 ++ .github/auto-release.yml | 54 +++++++ .github/mergify.yml | 65 ++++++++ .github/renovate.json | 12 ++ .github/workflows/auto-context.yml | 57 +++++++ .github/workflows/auto-format.yml | 88 +++++++++++ .github/workflows/auto-release.yml | 26 ++++ .github/workflows/chatops.yml | 37 +++++ .github/workflows/validate-codeowners.yml | 27 ++++ README.md | 34 ++++- docs/terraform.md | 34 ++++- 17 files changed, 737 insertions(+), 2 deletions(-) create mode 100644 .build-harness create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/auto-release.yml create mode 100644 .github/mergify.yml create mode 100644 .github/renovate.json create mode 100644 .github/workflows/auto-context.yml create mode 100644 .github/workflows/auto-format.yml create mode 100644 .github/workflows/auto-release.yml create mode 100644 .github/workflows/chatops.yml create mode 100644 .github/workflows/validate-codeowners.yml diff --git a/.build-harness b/.build-harness new file mode 100644 index 0000000..49edaae --- /dev/null +++ b/.build-harness @@ -0,0 +1,176 @@ +# +# This is a shim installed automatically by the build-harness +# https://github.com/cloudposse/build-harness +# + +# templates/Makefile.build-harness includes this Makefile +# and this Makefile includes templates/Makefile.build-harness +# to support different modes of invocation. Use a guard variable +# to prevent infinite recursive includes +ifeq ($(BUILD_HARNESS_TEMPLATES_MAKEFILE_GUARD),) +BUILD_HARNESS_TEMPLATES_MAKEFILE_GUARD := included + +export SHELL = /bin/bash +export PWD = $(shell pwd) +export BUILD_HARNESS_ORG ?= ugns +export BUILD_HARNESS_PROJECT ?= build-harness +export BUILD_HARNESS_DOCKER_IMAGE ?= $(BUILD_HARNESS_ORG)/$(BUILD_HARNESS_PROJECT) +export BUILD_HARNESS_BRANCH ?= main +export BUILD_HARNESS_CLONE_URL ?= https://github.com/$(BUILD_HARNESS_ORG)/$(BUILD_HARNESS_PROJECT).git + +# Resolves BUILD_HARNESS_PATH to BUILD_HARNESS_PATH_LOCAL when BUILD_HARNESS_PATH does not exist +BUILD_HARNESS_PATH ?= $(shell until [ -d "$(BUILD_HARNESS_PROJECT)" ] || [ "`pwd`" == '/' ]; do cd ..; done; pwd)/$(BUILD_HARNESS_PROJECT) +BUILD_HARNESS_PATH_LOCAL := $(PWD)/$(BUILD_HARNESS_PROJECT) +export BUILD_HARNESS_PATH := $(or $(wildcard $(BUILD_HARNESS_PATH)),$(BUILD_HARNESS_PATH_LOCAL)) +# It is kind of expensive to figure out the Docker SHA tag, so we just define the command here, and only call it when needed +# With the ":=" syntax, it stores the current value of BUILD_HARNESS_PATH, so this has to come after that has been set with ":=" +export BUILD_HARNESS_DOCKER_SHA_TAG_CMD := git -C "$(BUILD_HARNESS_PATH)" log -n 1 --format=sha-%h 2>/dev/null || echo latest + +# Toggles the auto-init feature +BUILD_HARNESS_AUTO_INIT ?= false + +# Macro to clone/install BUILD_HARNESS_PROJECT +define harness_install +curl --retry 5 --fail --silent --retry-delay 1 \ + https://raw.githubusercontent.com/$(BUILD_HARNESS_ORG)/$(BUILD_HARNESS_PROJECT)/$(BUILD_HARNESS_BRANCH)/bin/install.sh | \ + bash -s "$(BUILD_HARNESS_ORG)" "$(BUILD_HARNESS_PROJECT)" "$(BUILD_HARNESS_BRANCH)" +endef + +# Macro to auto-init the BUILD_HARNESS_PROJECT with the `include` directive +# Tests if BUILD_HARNESS_PROJECT does not yet exist, or if it does exist but the +# checkout does not match BUILD_HARNESS_BRANCH +define harness_auto_init +if [[ \ + -f "/build-harness/Makefile" || -f "/$(BUILD_HARNESS_PROJECT)/Makefile" \ +]]; then \ + echo "[.build-harness]: In $(BUILD_HARNESS_PROJECT) docker container, skipping auto-init" ;\ +elif grep -q docker /proc/1/cgroup 2>/dev/null; then \ + echo "[.build-harness]: In unknown docker container, skipping auto-init" ;\ +elif [[ \ + "$(BUILD_HARNESS_PATH)" != "$(BUILD_HARNESS_PATH_LOCAL)" && \ + -f "$(BUILD_HARNESS_PATH)/Makefile" \ +]]; then \ + echo "[.build-harness]: Using external $(BUILD_HARNESS_PATH), skipping auto-init" ;\ +elif [[ \ + "$(BUILD_HARNESS_PATH)" == "$(BUILD_HARNESS_PATH_LOCAL)" && \ + -f "$(BUILD_HARNESS_PATH)/Makefile" && \ + "$$(git -C '$(BUILD_HARNESS_PATH_LOCAL)' ls-remote '$(BUILD_HARNESS_CLONE_URL)' '$(BUILD_HARNESS_BRANCH)' | cut -f1)" == "$$(git -C '$(BUILD_HARNESS_PATH_LOCAL)' rev-parse HEAD)" \ +]]; then \ + echo "[.build-harness]: Clone of $(BUILD_HARNESS_PROJECT) is up-to-date, skipping auto-init" ;\ +else \ + $(harness_install) ;\ +fi +endef + +-include $(if $(findstring true,$(BUILD_HARNESS_AUTO_INIT)),$(shell $(harness_auto_init) >&2)) $(BUILD_HARNESS_PATH)/Makefile + +.PHONY : init +## Init build-harness +init:: + @ $(harness_install) + +.PHONY : clean +## Clean build-harness +clean:: + @ if [ -d "$(BUILD_HARNESS_PATH)" ]; then \ + if [ -d build-harness ] && [ $$(stat -f -c %i "$(BUILD_HARNESS_PATH)") == $$(stat -f -c %i build-harness) ]; then \ + rm -rf build-harness; \ + else \ + echo Not removing build harness from "$(BUILD_HARNESS_PATH)" because it appears to be shared.; \ + echo If you are sure you want to delete it, run: ; \ + echo ' rm -rf "$(BUILD_HARNESS_PATH)"'; \ + fi; \ + fi + +.PHONY: build-harness/shell builder build-harness/shell/pull builder/pull builder/build + +build-harness/shell/pull builder/pull builder/build: BUILD_HARNESS_DOCKER_SHA_TAG ?= $(shell $(BUILD_HARNESS_DOCKER_SHA_TAG_CMD)) +build-harness/shell/pull builder/pull: + docker pull $(BUILD_HARNESS_DOCKER_IMAGE):$(BUILD_HARNESS_DOCKER_SHA_TAG) + @[[ "$(BUILD_HARNESS_DOCKER_SHA_TAG)" == "latest" ]] || docker pull $(BUILD_HARNESS_DOCKER_IMAGE):latest + +builder/build: export DOCKER_IMAGE_NAME = $(BUILD_HARNESS_DOCKER_IMAGE):$(BUILD_HARNESS_DOCKER_SHA_TAG) +builder/build: + @$(MAKE) --no-print-directory docker/build + +DEFAULT_DOCKER_ENVS := AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN TERM AWS_PROFILE AWS_REGION \ + AWS_DEFAULT_PROFILE AWS_DEFAULT_REGION +EXTRA_DOCKER_ENVS ?= AWS_CONFIG_FILE AWS_SHARED_CREDENTIALS_FILE +DOCKER_ENVS ?= $(DEFAULT_DOCKER_ENVS) $(EXTRA_DOCKER_ENVS) + +## Start a shell inside of the `build-harness` docker container with `make build-harness/shell` or `make builder` +## Run `make` targets inside the build-harness shell by setting `TARGETS` or `TARGET`, e.g. +## make builder TARGETS="github/init readme" +build-harness/shell builder tester: MOUNT_HOME ?= $(shell [ -d "$$HOME" ] && printf -- "-e HOME -v \"%s\":\"%s\"" "$$HOME" "$$HOME") +build-harness/shell builder tester: TARGETS ?= $(TARGET) +build-harness/shell builder tester: ARGS := $(if $(TARGETS),$(TARGETS),-l || true) +build-harness/shell builder tester: ENTRYPOINT := $(if $(TARGETS),/usr/bin/make,/bin/bash) +build-harness/shell builder pr/pre-commit: RUNNER_DOCKER_TAG ?= $(shell $(BUILD_HARNESS_DOCKER_SHA_TAG_CMD)) +build-harness/shell builder pr/pre-commit: RUNNER_DOCKER_IMAGE ?= $(BUILD_HARNESS_DOCKER_IMAGE) +build-harness/shell builder: build-harness/runner + @exit 0 + +.PHONY: build-harness/shell-slim builder-slim pr/auto-format pr/auto-format/host pr/readme pr/readme/host pr/pre-commit tf14-upgrade + +build-harness/shell-slim builder-slim pr/auto-format pr/readme tf14-upgrade: RUNNER_DOCKER_IMAGE ?= $(BUILD_HARNESS_DOCKER_IMAGE) + +build-harness/shell-slim builder-slim tf14-upgrade pr/auto-format pr/readme: RUNNER_DOCKER_SHA_TAG ?= $(shell $(BUILD_HARNESS_DOCKER_SHA_TAG_CMD)) +build-harness/shell-slim builder-slim tf14-upgrade pr/auto-format pr/readme: RUNNER_DOCKER_TAG ?= \ + $(shell docker inspect --type=image $(RUNNER_DOCKER_IMAGE):$(RUNNER_DOCKER_SHA_TAG) >/dev/null 2>&1 && \ + echo "$(RUNNER_DOCKER_SHA_TAG) " || echo "slim-$(RUNNER_DOCKER_SHA_TAG)") + +build-harness/shell-slim builder-slim: TARGETS ?= $(TARGET) +build-harness/shell-slim builder-slim: ARGS := $(if $(TARGETS),$(TARGETS),-l || true) +build-harness/shell-slim builder-slim: ENTRYPOINT := $(if $(TARGETS),/usr/bin/make,/bin/bash) +build-harness/shell-slim builder-slim: build-harness/runner + +pr/auto-format pr/readme pr/pre-commit tf14-upgrade : ENTRYPOINT := /usr/bin/make + +pr/auto-format pr/auto-format/host: ARGS := terraform/fmt readme +pr/readme pr/readme/host: ARGS := readme/deps readme +pr/auto-format pr/readme: build-harness/runner +pr/auto-format/host pr/readme/host: + $(MAKE) $(ARGS) + +pr/pre-commit: ARGS := pre-commit/run +pr/pre-commit: build-harness/runner + +tf14-upgrade: export TERRAFORM_FORCE_README := true +tf14-upgrade: ARGS := github/init terraform/v14-rewrite +tf14-upgrade: build-harness/runner + +.PHONY: tester tester/pull + +tester tester/pull: TEST_HARNESS_DOCKER_IMAGE ?= cloudposse/test-harness +tester tester/pull: TEST_HARNESS_DOCKER_TAG ?= latest +tester: RUNNER_DOCKER_IMAGE ?= $(TEST_HARNESS_DOCKER_IMAGE) +tester: RUNNER_DOCKER_TAG ?= $(TEST_HARNESS_DOCKER_TAG) +tester: build-harness/runner + +tester/pull: + docker pull $(TEST_HARNESS_DOCKER_IMAGE):$(TEST_HARNESS_DOCKER_TAG) + + +.PHONY: build-harness/runner + +build-harness/runner: + $(info Starting $(RUNNER_DOCKER_IMAGE):$(RUNNER_DOCKER_TAG)) + docker run --name build-harness \ + --rm -it \ + -e PACKAGES_PREFER_HOST=true \ + $(addprefix -e ,$(DOCKER_ENVS)) \ + $(MOUNT_HOME) \ + -v $(CURDIR):/opt \ + --workdir /opt \ + --entrypoint $(ENTRYPOINT) \ + $(RUNNER_DOCKER_IMAGE):$(RUNNER_DOCKER_TAG) $(ARGS) + +.PHONY: reset-owner +reset-owner: + @if [[ -n $$(find . -xdev -user 0 -print) ]]; then \ + printf "\n* To reset ownership on files, run:\n sudo find . -xdev -user 0 -exec chown $$USER {} \;\n\n" ; \ + else \ + printf "\n* No root-owned files found\n\n" ; \ + fi + +endif diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..9e0a825 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,25 @@ +# Use this file to define individuals or teams that are responsible for code in a repository. +# Read more: +# +# Order is important: the last matching pattern has the highest precedence + +# These owners will be the default owners for everything +* @ugns/engineering @ugns/contributors + +# Cloud Posse must review any changes to Makefiles +**/Makefile @ugns/engineering +**/Makefile.* @ugns/engineering + +# Cloud Posse must review any changes to GitHub actions +.github/* @ugns/engineering + +# Cloud Posse must review any changes to standard context definition, +# but some changes can be rubber-stamped. +**/*.tf @ugns/engineering @ugns/contributors @ugns/approvers +README.yaml @ugns/engineering @ugns/contributors @ugns/approvers +README.md @ugns/engineering @ugns/contributors @ugns/approvers +docs/*.md @ugns/engineering @ugns/contributors @ugns/approvers + +# Cloud Posse Admins must review all changes to CODEOWNERS or the mergify configuration +.github/mergify.yml @ugns/admins +.github/CODEOWNERS @ugns/admins diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..f3df96b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,37 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'bug' +assignees: '' + +--- + +Found a bug? Maybe our [Slack Community](https://slack.cloudposse.com) can help. + +[![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + +## Describe the Bug +A clear and concise description of what the bug is. + +## Expected Behavior +A clear and concise description of what you expected to happen. + +## Steps to Reproduce +Steps to reproduce the behavior: +1. Go to '...' +2. Run '....' +3. Enter '....' +4. See error + +## Screenshots +If applicable, add screenshots or logs to help explain your problem. + +## Environment (please complete the following information): + +Anything that will help us triage the bug will help. Here are some ideas: + - OS: [e.g. Linux, OSX, WSL, etc] + - Version [e.g. 10.15] + +## Additional Context +Add any other context about the problem here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..76ae6d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,18 @@ +blank_issues_enabled: false + +contact_links: + + - name: Community Slack Team + url: https://cloudposse.com/slack/ + about: |- + Please ask and answer questions here. + + - name: Office Hours + url: https://cloudposse.com/office-hours/ + about: |- + Join us every Wednesday for FREE Office Hours (lunch & learn). + + - name: DevOps Accelerator Program + url: https://cloudposse.com/accelerate/ + about: |- + Own your infrastructure in record time. We build it. You drive it. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..39a8686 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,36 @@ +--- +name: Feature Request +about: Suggest an idea for this project +title: '' +labels: 'feature request' +assignees: '' + +--- + +Have a question? Please checkout our [Slack Community](https://slack.cloudposse.com) or visit our [Slack Archive](https://archive.sweetops.com/). + +[![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + +## Describe the Feature + +A clear and concise description of what the bug is. + +## Expected Behavior + +A clear and concise description of what you expected to happen. + +## Use Case + +Is your feature request related to a problem/challenge you are trying to solve? Please provide some additional context of why this feature or capability will be valuable. + +## Describe Ideal Solution + +A clear and concise description of what you want to happen. If you don't know, that's okay. + +## Alternatives Considered + +Explain what alternative solutions or features you've considered. + +## Additional Context + +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..e69de29 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4b8f32d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +## what +* Describe high-level what changed as a result of these commits (i.e. in plain-english, what do these changes mean?) +* Use bullet points to be concise and to the point. + +## why +* Provide the justifications for the changes (e.g. business case). +* Describe why these changes were made (e.g. why do these commits fix the problem?) +* Use bullet points to be concise and to the point. + +## references +* Link to any supporting github issues or helpful documentation to add some context (e.g. stackoverflow). +* Use `closes #123`, if this PR closes a GitHub issue `#123` + diff --git a/.github/auto-release.yml b/.github/auto-release.yml new file mode 100644 index 0000000..b45efb7 --- /dev/null +++ b/.github/auto-release.yml @@ -0,0 +1,54 @@ +name-template: 'v$RESOLVED_VERSION' +tag-template: '$RESOLVED_VERSION' +version-template: '$MAJOR.$MINOR.$PATCH' +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + - 'enhancement' + patch: + labels: + - 'auto-update' + - 'patch' + - 'fix' + - 'bugfix' + - 'bug' + - 'hotfix' + - 'no-release' + default: 'minor' + +categories: +- title: '🚀 Enhancements' + labels: + - 'enhancement' + - 'patch' +- title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - 'hotfix' +- title: '🤖 Automatic Updates' + labels: + - 'auto-update' + +change-template: | +
+ $TITLE @$AUTHOR (#$NUMBER) + + $BODY +
+ +template: | + $CHANGES + +replacers: +# Remove irrelevant information from Renovate bot +- search: '/(?<=---\s)\s*^#.*(Renovate configuration|Configuration)(?:.|\n)*?This PR has been generated .*/gm' + replace: '' +# Remove Renovate bot banner image +- search: '/\[!\[[^\]]*Renovate\][^\]]*\](\([^)]*\))?\s*\n+/gm' + replace: '' diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 0000000..7e9a71d --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,65 @@ +# https://docs.mergify.io/conditions.html +# https://docs.mergify.io/actions.html +pull_request_rules: +- name: "approve automated PRs that have passed checks" + conditions: + - "author~=^(undergridbot|renovate\\[bot\\])$" + - "base=master" + - "-closed" + - "head~=^(auto-update|renovate)/.*" + - "check-success=test/bats" + - "check-success=test/readme" + - "check-success=test/terratest" + - "check-success=validate-codeowners" + actions: + review: + type: "APPROVE" + bot_account: "undergrid-mergebot" + message: "We've automatically approved this PR because the checks from the automated Pull Request have passed." + +- name: "merge automated PRs when approved and tests pass" + conditions: + - "author~=^(undergridbot|renovate\\[bot\\])$" + - "base=master" + - "-closed" + - "head~=^(auto-update|renovate)/.*" + - "check-success=test/bats" + - "check-success=test/readme" + - "check-success=test/terratest" + - "check-success=validate-codeowners" + - "#approved-reviews-by>=1" + - "#changes-requested-reviews-by=0" + - "#commented-reviews-by=0" + actions: + merge: + method: "squash" + +- name: "delete the head branch after merge" + conditions: + - "merged" + actions: + delete_head_branch: {} + +- name: "ask to resolve conflict" + conditions: + - "conflict" + - "-closed" + actions: + comment: + message: "This pull request is now in conflict. Could you fix it @{{author}}? 🙏" + +- name: "remove outdated reviews" + conditions: + - "base=master" + actions: + dismiss_reviews: + changes_requested: true + approved: true + message: "This Pull Request has been updated, so we're dismissing all reviews." + +- name: "close Pull Requests without files changed" + conditions: + - "#files=0" + actions: + close: + message: "This pull request has been automatically closed by Mergify because there are no longer any changes." diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..ae4f0aa --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,12 @@ +{ + "extends": [ + "config:base", + ":preserveSemverRanges" + ], + "labels": ["auto-update"], + "enabledManagers": ["terraform"], + "terraform": { + "ignorePaths": ["**/context.tf", "examples/**"] + } +} + diff --git a/.github/workflows/auto-context.yml b/.github/workflows/auto-context.yml new file mode 100644 index 0000000..f8a59cf --- /dev/null +++ b/.github/workflows/auto-context.yml @@ -0,0 +1,57 @@ +name: "auto-context" +on: + schedule: + # Update context.tf nightly + - cron: '0 3 * * *' + +jobs: + update: + if: github.event_name == 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Update context.tf + shell: bash + id: update + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + if [[ -f context.tf ]]; then + echo "Discovered existing context.tf! Fetching most recent version to see if there is an update." + curl -o context.tf -fsSL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf + if git diff --no-patch --exit-code context.tf; then + echo "No changes detected! Exiting the job..." + else + echo "context.tf file has changed. Update examples and rebuild README.md." + make init + make github/init/context.tf + make readme/build + echo "::set-output name=create_pull_request::true" + fi + else + echo "This module has not yet been updated to support the context.tf pattern! Please update in order to support automatic updates." + fi + + - name: Create Pull Request + if: steps.update.outputs.create_pull_request == 'true' + uses: ugns/actions/github/create-pull-request@1.0.0 + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + committer: 'undergridbot <97003863+undergridbot@users.noreply.github.com>' + author: 'undergridbot <97003863+undergridbot@users.noreply.github.com>' + commit-message: Update context.tf from origin source + title: Update context.tf + body: |- + ## what + This is an auto-generated PR that updates the `context.tf` file to the latest version from `cloudposse/terraform-null-label` + + ## why + To support all the features of the `context` interface. + + branch: auto-update/context.tf + base: master + delete-branch: true + labels: | + auto-update + context diff --git a/.github/workflows/auto-format.yml b/.github/workflows/auto-format.yml new file mode 100644 index 0000000..5d1830a --- /dev/null +++ b/.github/workflows/auto-format.yml @@ -0,0 +1,88 @@ +name: Auto Format +on: + pull_request_target: + types: [opened, synchronize] + +jobs: + auto-format: + runs-on: ubuntu-latest + container: ugns/build-harness:latest + steps: + # Checkout the pull request branch + # "An action in a workflow run can’t trigger a new workflow run. For example, if an action pushes code using + # the repository’s GITHUB_TOKEN, a new workflow will not run even when the repository contains + # a workflow configured to run when push events occur." + # However, using a personal access token will cause events to be triggered. + # We need that to ensure a status gets posted after the auto-format commit. + # We also want to trigger tests if the auto-format made no changes. + - uses: actions/checkout@v2 + if: github.event.pull_request.state == 'open' + name: Privileged Checkout + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + # Check out the PR commit, not the merge commit + # Use `ref` instead of `sha` to enable pushing back to `ref` + ref: ${{ github.event.pull_request.head.ref }} + + # Do all the formatting stuff + - name: Auto Format + if: github.event.pull_request.state == 'open' + shell: bash + env: + GITHUB_TOKEN: "${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}" + run: make BUILD_HARNESS_PATH=/build-harness PACKAGES_PREFER_HOST=true -f /build-harness/templates/Makefile.build-harness pr/auto-format/host + + # Commit changes (if any) to the PR branch + - name: Commit changes to the PR branch + if: github.event.pull_request.state == 'open' + shell: bash + id: commit + env: + SENDER: ${{ github.event.sender.login }} + run: | + set -x + output=$(git diff --name-only) + + if [ -n "$output" ]; then + echo "Changes detected. Pushing to the PR branch" + git config --global user.name 'undergridbot' + git config --global user.email '97003863+undergridbot@users.noreply.github.com' + git add -A + git commit -m "Auto Format" + # Prevent looping by not pushing changes in response to changes from undergridbot + [[ $SENDER == "undergridbot" ]] || git push + # Set status to fail, because the push should trigger another status check, + # and we use success to indicate the checks are finished. + printf "::set-output name=%s::%s\n" "changed" "true" + exit 1 + else + printf "::set-output name=%s::%s\n" "changed" "false" + echo "No changes detected" + fi + + - name: Auto Test + uses: ugns/actions/github/repository-dispatch@1.0.0 + # match users by ID because logins (user names) are inconsistent, + # for example in the REST API Renovate Bot is `renovate[bot]` but + # in GraphQL it is just `renovate`, plus there is a non-bot + # user `renovate` with ID 1832810. + # Mergify bot: 37929162 + # Renovate bot: 29139614 + # UnderGrid bot: 97003863 + # Need to use space separators to prevent "21" from matching "112144" + if: > + contains(' 37929162 29139614 97003863', format(' {0} ', github.event.pull_request.user.id)) + && steps.commit.outputs.changed == 'false' && github.event.pull_request.state == 'open' + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + repository: ugns/actions + event-type: test-command + client-payload: |- + { "slash_command":{"args": {"unnamed": {"all": "all", "arg1": "all"}}}, + "pull_request": ${{ toJSON(github.event.pull_request) }}, + "github":{"payload":{"repository": ${{ toJSON(github.event.repository) }}, + "comment": {"id": ""} + } + } + } diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 0000000..3a38fae --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -0,0 +1,26 @@ +name: auto-release + +on: + push: + branches: + - main + - master + - production + +jobs: + publish: + runs-on: ubuntu-latest + steps: + # Get PR from merged commit to master + - uses: actions-ecosystem/action-get-merged-pull-request@v1 + id: get-merged-pull-request + with: + github_token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + # Drafts your next Release notes as Pull Requests are merged into "main" + - uses: release-drafter/release-drafter@v5 + with: + publish: ${{ !contains(steps.get-merged-pull-request.outputs.labels, 'no-release') }} + prerelease: false + config-name: auto-release.yml + env: + GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} diff --git a/.github/workflows/chatops.yml b/.github/workflows/chatops.yml new file mode 100644 index 0000000..2d98a38 --- /dev/null +++ b/.github/workflows/chatops.yml @@ -0,0 +1,37 @@ +name: chatops +on: + issue_comment: + types: [created] + +jobs: + default: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: "Handle common commands" + uses: ugns/actions/github/slash-command-dispatch@1.0.0 + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + reaction-token: ${{ secrets.GITHUB_TOKEN }} + repository: ugns/actions + commands: rebuild-readme, terraform-fmt + permission: triage + issue-type: pull-request + + test: + runs-on: ubuntu-latest + steps: + - name: "Checkout commit" + uses: actions/checkout@v2 + - name: "Run tests" + uses: ugns/actions/github/slash-command-dispatch@1.0.0 + with: + token: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }} + reaction-token: ${{ secrets.GITHUB_TOKEN }} + repository: ugns/actions + commands: test + permission: triage + issue-type: pull-request + reactions: false + + diff --git a/.github/workflows/validate-codeowners.yml b/.github/workflows/validate-codeowners.yml new file mode 100644 index 0000000..c5193b6 --- /dev/null +++ b/.github/workflows/validate-codeowners.yml @@ -0,0 +1,27 @@ +name: Validate Codeowners +on: + workflow_dispatch: + + pull_request: + +jobs: + validate-codeowners: + runs-on: ubuntu-latest + steps: + - name: "Checkout source code at current commit" + uses: actions/checkout@v2 + - uses: mszostok/codeowners-validator@v0.5.0 + if: github.event.pull_request.head.repo.full_name == github.repository + name: "Full check of CODEOWNERS" + with: + # For now, remove "files" check to allow CODEOWNERS to specify non-existent + # files so we can use the same CODEOWNERS file for Terraform and non-Terraform repos + # checks: "files,syntax,owners,duppatterns" + checks: "syntax,owners,duppatterns" + # GitHub access token is required only if the `owners` check is enabled + github_access_token: "${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}" + - uses: mszostok/codeowners-validator@v0.5.0 + if: github.event.pull_request.head.repo.full_name != github.repository + name: "Syntax check of CODEOWNERS" + with: + checks: "syntax,duppatterns" diff --git a/README.md b/README.md index 5a087f0..4ca7a8f 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,7 @@ Available targets: | [caa\_record](#module\_caa\_record) | UGNS/route53-caa/aws | 0.1.0 | | [mta\_sts](#module\_mta\_sts) | ugns/route53-mta-sts/aws | 0.1.0 | | [ses](#module\_ses) | ugns/route53-ses/aws | 0.1.0 | +| [this](#module\_this) | cloudposse/label/null | 0.25.0 | | [website](#module\_website) | cloudposse/s3-website/aws | 0.17.11 | | [www-website](#module\_www-website) | cloudposse/s3-website/aws | 0.17.11 | @@ -182,7 +183,38 @@ Available targets: ## Inputs -No inputs. +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [additional\_dkim](#input\_additional\_dkim) | Additional DKIM TXT records to add | `map(string)` | `{}` | no | +| [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no | +| [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | +| [caa\_issuers](#input\_caa\_issuers) | List of Certificate authories authorized to issue certificates | `list(string)` |
[
"amazon.com"
]
| no | +| [caa\_report\_recipient](#input\_caa\_report\_recipient) | Recipient of CAA reports | `string` | `"hostmaster"` | no | +| [comment](#input\_comment) | Hosted Zone comment | `string` | n/a | yes | +| [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
| no | +| [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | +| [dmarc\_additional\_rua](#input\_dmarc\_additional\_rua) | SMTP DMARC Reporting additional RUA | `string` | `""` | no | +| [dmarc\_domain](#input\_dmarc\_domain) | SMTP DMARC Reporting domain, defaults to current domain | `string` | `""` | no | +| [dmarc\_mailbox](#input\_dmarc\_mailbox) | SMTP DMARC Reporting mailbox, defaults to noreply-dmarc-support | `string` | `""` | no | +| [dmarc\_version](#input\_dmarc\_version) | SMTP DMARC Reporting version, defaults to DMARC1 | `string` | `""` | no | +| [domain\_name](#input\_domain\_name) | Hosted Zone domain name | `string` | n/a | yes | +| [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | +| [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | +| [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | +| [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | +| [mta\_sts\_mode](#input\_mta\_sts\_mode) | MTA Strict Transport Security mode, defaults to testing | `string` | `"testing"` | no | +| [mx\_records](#input\_mx\_records) | List of MX Records | `list(string)` | `[]` | no | +| [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | +| [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no | +| [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | +| [tenant](#input\_tenant) | ID element \_(Rarely used, not included by default)\_. A customer identifier, indicating who this instance of a resource is for | `string` | `null` | no | +| [tls\_report\_recipient](#input\_tls\_report\_recipient) | Recipient of SMTP TLS Reports | `string` | `"smtp-tls-reports"` | no | ## Outputs diff --git a/docs/terraform.md b/docs/terraform.md index bd2ca8a..37974b6 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -20,6 +20,7 @@ | [caa\_record](#module\_caa\_record) | UGNS/route53-caa/aws | 0.1.0 | | [mta\_sts](#module\_mta\_sts) | ugns/route53-mta-sts/aws | 0.1.0 | | [ses](#module\_ses) | ugns/route53-ses/aws | 0.1.0 | +| [this](#module\_this) | cloudposse/label/null | 0.25.0 | | [website](#module\_website) | cloudposse/s3-website/aws | 0.17.11 | | [www-website](#module\_www-website) | cloudposse/s3-website/aws | 0.17.11 | @@ -31,7 +32,38 @@ ## Inputs -No inputs. +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [additional\_dkim](#input\_additional\_dkim) | Additional DKIM TXT records to add | `map(string)` | `{}` | no | +| [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no | +| [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | +| [caa\_issuers](#input\_caa\_issuers) | List of Certificate authories authorized to issue certificates | `list(string)` |
[
"amazon.com"
]
| no | +| [caa\_report\_recipient](#input\_caa\_report\_recipient) | Recipient of CAA reports | `string` | `"hostmaster"` | no | +| [comment](#input\_comment) | Hosted Zone comment | `string` | n/a | yes | +| [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
| no | +| [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | +| [dmarc\_additional\_rua](#input\_dmarc\_additional\_rua) | SMTP DMARC Reporting additional RUA | `string` | `""` | no | +| [dmarc\_domain](#input\_dmarc\_domain) | SMTP DMARC Reporting domain, defaults to current domain | `string` | `""` | no | +| [dmarc\_mailbox](#input\_dmarc\_mailbox) | SMTP DMARC Reporting mailbox, defaults to noreply-dmarc-support | `string` | `""` | no | +| [dmarc\_version](#input\_dmarc\_version) | SMTP DMARC Reporting version, defaults to DMARC1 | `string` | `""` | no | +| [domain\_name](#input\_domain\_name) | Hosted Zone domain name | `string` | n/a | yes | +| [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | +| [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | +| [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | +| [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | +| [mta\_sts\_mode](#input\_mta\_sts\_mode) | MTA Strict Transport Security mode, defaults to testing | `string` | `"testing"` | no | +| [mx\_records](#input\_mx\_records) | List of MX Records | `list(string)` | `[]` | no | +| [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | +| [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no | +| [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | +| [tenant](#input\_tenant) | ID element \_(Rarely used, not included by default)\_. A customer identifier, indicating who this instance of a resource is for | `string` | `null` | no | +| [tls\_report\_recipient](#input\_tls\_report\_recipient) | Recipient of SMTP TLS Reports | `string` | `"smtp-tls-reports"` | no | ## Outputs