diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml index 168011c..eb1d555 100644 --- a/.github/workflows/pr-title.yml +++ b/.github/workflows/pr-title.yml @@ -1,52 +1,29 @@ -name: 'Validate PR title' +name: Validate PR title on: pull_request_target: - types: - - opened - - edited - - synchronize + types: [opened, edited, synchronize] + +permissions: + pull-requests: read jobs: - main: - name: Validate PR title + validate: runs-on: ubuntu-latest steps: - # Please look up the latest version from - # https://github.com/amannn/action-semantic-pull-request/releases - - uses: amannn/action-semantic-pull-request@v3.4.6 + - uses: amannn/action-semantic-pull-request@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - # Configure which types are allowed. - # Default: https://github.com/commitizen/conventional-commit-types types: | fix feat docs ci chore - # Configure that a scope must always be provided. + style + revert requireScope: false - # Configure additional validation for the subject based on a regex. - # This example ensures the subject starts with an uppercase character. - subjectPattern: ^[A-Z].+$ - # If `subjectPattern` is configured, you can use this property to override - # the default error message that is shown when the pattern doesn't match. - # The variables `subject` and `title` can be used within the message. - subjectPatternError: | - The subject "{subject}" found in the pull request title "{title}" - didn't match the configured pattern. Please ensure that the subject - starts with an uppercase character. - # For work-in-progress PRs you can typically use draft pull requests - # from Github. However, private repositories on the free plan don't have - # this option and therefore this action allows you to opt-in to using the - # special "[WIP]" prefix to indicate this state. This will avoid the - # validation of the PR title and the pull request checks remain pending. - # Note that a second check will be reported if this is enabled. - wip: true - # When using "Squash and merge" on a PR with only one commit, GitHub - # will suggest using that commit message instead of the PR title for the - # merge commit, and it's easy to commit this by mistake. Enable this option - # to also validate the commit message for one commit PRs. + subjectPattern: ^[a-z].+$ + subjectPatternError: "The subject must start with a lowercase character." validateSingleCommit: false diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml deleted file mode 100644 index 956986a..0000000 --- a/.github/workflows/pre-commit.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Pre-Commit - -on: - pull_request: - branches: - - main - - master - -env: - TERRAFORM_DOCS_VERSION: v0.16.0 - -jobs: - collectInputs: - name: Collect workflow inputs - runs-on: ubuntu-latest - outputs: - directories: ${{ steps.dirs.outputs.directories }} - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Get root directories - id: dirs - uses: clowdhaus/terraform-composite-actions/directories@v1.3.0 - - preCommitMinVersions: - name: Min TF pre-commit - needs: collectInputs - runs-on: ubuntu-latest - strategy: - matrix: - directory: ${{ fromJson(needs.collectInputs.outputs.directories) }} - steps: - - run: git config --global url."https://".insteadOf git:// - - name: Checkout - uses: actions/checkout@v3 - - - name: Terraform min/max versions - id: minMax - uses: clowdhaus/terraform-min-max@v1.0.3 - with: - directory: ${{ matrix.directory }} - - - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} - # Run only validate pre-commit check on min version supported - if: ${{ matrix.directory != '.' }} - uses: clowdhaus/terraform-composite-actions/pre-commit@v1.3.0 - with: - terraform-version: ${{ steps.minMax.outputs.minVersion }} - args: 'terraform_validate --color=always --show-diff-on-failure --files ${{ matrix.directory }}/*' - - - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} - # Run only validate pre-commit check on min version supported - if: ${{ matrix.directory == '.' }} - uses: clowdhaus/terraform-composite-actions/pre-commit@v1.3.0 - with: - terraform-version: ${{ steps.minMax.outputs.minVersion }} - args: 'terraform_validate --color=always --show-diff-on-failure --files $(ls *.tf)' - - #preCommitMaxVersion: - # name: Max TF pre-commit - # runs-on: ubuntu-latest - # needs: collectInputs - # steps: - # - run: git config --global url."https://".insteadOf git:// - # - name: Checkout - # uses: actions/checkout@v3 - # with: - # ref: ${{ github.event.pull_request.head.ref }} - # repository: ${{github.event.pull_request.head.repo.full_name}} -# - # - name: Terraform min/max versions - # id: minMax - # uses: clowdhaus/terraform-min-max@v1.0.3 -# - # - name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }} - # uses: clowdhaus/terraform-composite-actions/pre-commit@v1.3.0 - # with: - # terraform-version: ${{ steps.minMax.outputs.maxVersion }} - # terraform-docs-version: ${{ env.TERRAFORM_DOCS_VERSION }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 045f4e8..b6c2306 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,35 +1,33 @@ name: Release on: - workflow_dispatch: push: - branches: - - main - - master + branches: [master] paths: - - '**/*.tpl' - - '**/*.py' - - '**/*.tf' - - '.github/workflows/release.yml' + - "**/*.tf" + - ".releaserc.json" + - ".github/workflows/release.yml" + +permissions: + contents: write + issues: write + pull-requests: write jobs: release: - name: Release runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - persist-credentials: false fetch-depth: 0 + persist-credentials: false - - name: Release - uses: cycjimmy/semantic-release-action@v2 + - uses: cycjimmy/semantic-release-action@v5.0.2 with: - semantic_version: 18.0.0 + semantic_version: 25.0.8 extra_plugins: | - @semantic-release/changelog@6.0.0 - @semantic-release/git@10.0.0 - conventional-changelog-conventionalcommits@4.6.3 + @semantic-release/changelog@6.0.3 + @semantic-release/git@10.0.1 + conventional-changelog-conventionalcommits@8.0.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..5396875 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,38 @@ +name: Validate Terraform module + +on: + pull_request: + push: + branches: [master] + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: hashicorp/setup-terraform@v3 + with: + terraform_version: "0.13.1" + terraform_wrapper: false + + - uses: terraform-linters/setup-tflint@v6 + with: + tflint_version: v0.58.0 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install pre-commit + run: pipx install pre-commit + + - name: Validate root module + run: | + terraform fmt -check -recursive + terraform init -backend=false + terraform validate + pre-commit run --all-files diff --git a/.gitignore b/.gitignore index 2cb4b5c..9518e73 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ crash.log # control as they are data points which are potentially sensitive and subject # to change depending on the environment. *.tfvars +*.tfvars.json # Ignore override files as they are usually used to override resources locally and so # are not checked in diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 10db981..95acafc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,37 +1,36 @@ repos: -- repo: git://github.com/antonbabenko/pre-commit-terraform - rev: v1.68.1 - hooks: - - id: terraform_fmt - - id: terraform_validate - - id: terraform_tflint - args: - - '--args=--only=terraform_deprecated_interpolation' - - '--args=--only=terraform_deprecated_index' - - '--args=--only=terraform_unused_declarations' - - '--args=--only=terraform_comment_syntax' - - '--args=--only=terraform_documented_outputs' - - '--args=--only=terraform_documented_variables' - - '--args=--only=terraform_typed_variables' - - '--args=--only=terraform_module_pinned_source' - - '--args=--only=terraform_naming_convention' - - '--args=--only=terraform_required_version' - - '--args=--only=terraform_required_providers' - - '--args=--only=terraform_standard_module_structure' - - '--args=--only=terraform_workspace_remote' -- repo: local - hooks: - - id: terraform-docs - name: terraform-docs - language: docker_image - entry: quay.io/terraform-docs/terraform-docs:latest - args: ["markdown", "--output-file", "README.md", "--output-mode", "replace", "./"] - pass_filenames: false -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + - repo: https://github.com/antonbabenko/pre-commit-terraform + rev: v1.108.0 hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - exclude: README.md - - id: check-added-large-files - - id: detect-aws-credentials + - id: terraform_fmt + - id: terraform_validate + files: ^(main|variables|outputs|versions)\.tf$ + - id: terraform_tflint + files: ^(main|variables|outputs|versions)\.tf$ + args: + - --args=--only=terraform_deprecated_interpolation + - --args=--only=terraform_deprecated_index + - --args=--only=terraform_unused_declarations + - --args=--only=terraform_documented_outputs + - --args=--only=terraform_documented_variables + - --args=--only=terraform_typed_variables + - --args=--only=terraform_required_version + - --args=--only=terraform_required_providers + - --args=--only=terraform_standard_module_structure + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + exclude: README.md + - id: check-added-large-files + - id: detect-aws-credentials + args: [--allow-missing-credentials] + - repo: local + hooks: + - id: terraform-docs + name: Terraform docs + language: docker_image + entry: quay.io/terraform-docs/terraform-docs:0.20.0 + args: ["markdown", "table", "--output-file", "README.md", "--output-mode", "inject", "."] + pass_filenames: false diff --git a/.releaserc.json b/.releaserc.json index 66b3eef..dad592f 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,45 +1,21 @@ { - "branches": [ - "main", - "master" - ], + "branches": ["master"], "ci": false, "plugins": [ - [ - "@semantic-release/commit-analyzer", - { - "preset": "conventionalcommits" - } - ], - [ - "@semantic-release/release-notes-generator", - { - "preset": "conventionalcommits" - } - ], - [ - "@semantic-release/github", - { - "successComment": "This ${issue.pull_request ? 'PR is included' : 'issue has been resolved'} in version ${nextRelease.version} :tada:", - "labels": false, - "releasedLabels": false - } - ], - [ - "@semantic-release/changelog", - { - "changelogFile": "CHANGELOG.md", - "changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file." - } - ], - [ - "@semantic-release/git", - { - "assets": [ - "CHANGELOG.md" - ], - "message": "chore(release): version ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" - } - ] + ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }], + ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }], + ["@semantic-release/changelog", { + "changelogFile": "CHANGELOG.md", + "changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file." + }], + ["@semantic-release/github", { + "successComment": "This ${issue.pull_request ? 'PR is included' : 'issue has been resolved'} in version ${nextRelease.version} :tada:", + "labels": false, + "releasedLabels": false + }], + ["@semantic-release/git", { + "assets": ["CHANGELOG.md"], + "message": "chore(release): version ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + }] ] } diff --git a/.terraform-version b/.terraform-version new file mode 100644 index 0000000..c317a91 --- /dev/null +++ b/.terraform-version @@ -0,0 +1 @@ +0.13.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2255844 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing + +Contributions that improve this Terraform module are welcome. Please keep each +change focused, documented, and validated before opening a pull request. + +## Prerequisites + +- The Terraform version declared in `.terraform-version`. +- Docker, used by the `terraform-docs` pre-commit hook. +- Python with `pre-commit` installed. For example: `pipx install pre-commit`. + +## Local validation + +Before opening a pull request, run: + +```shell +tfswitch +pre-commit run --all-files +``` + +The command formats Terraform, validates the root module, runs TFLint, checks +for credentials, and refreshes generated Terraform documentation in +`README.md`. Do not manually edit content between Terraform Docs markers. + +## Pull requests + +- Create a branch from the repository default branch and keep the pull request + focused on one change. +- Describe the behavior being changed and include an example when the module + interface changes. +- Ensure the GitHub Actions validation workflow passes before requesting review. +- Use a Conventional Commit-compatible pull request title. Allowed types are + `feat`, `fix`, `docs`, `ci`, `chore`, `style`, and `revert`. The + subject must start with a lowercase character. + +## Releases + +Releases are automated by Semantic Release after changes are merged into the +repository default branch. It determines the next semantic version from +Conventional Commits, creates the Git tag and GitHub Release, and updates +`CHANGELOG.md`. + +- `fix:` produces a patch release. +- `feat:` produces a minor release. +- A commit with `!` in its type or scope, or a `BREAKING CHANGE:` footer, + produces a major release. + +The Terraform Registry is connected to this repository once by the module +owner. After initial registration, Registry versions are indexed from Semantic +Release Git tags. diff --git a/README.md b/README.md index 2cb4a5d..211711a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +## Compatibility + +This module requires Terraform 0.13.1 or later. Older Terraform versions are not supported. + ## Requirements @@ -39,24 +43,24 @@ | [cloudwatch\_log\_group\_kms\_key\_id](#input\_cloudwatch\_log\_group\_kms\_key\_id) | The ARN of the KMS Key to use when encrypting log data for Lambda | `string` | `null` | no | | [cloudwatch\_log\_group\_retention\_in\_days](#input\_cloudwatch\_log\_group\_retention\_in\_days) | Specifies the number of days you want to retain log events in log group for Lambda. | `number` | `90` | no | | [cloudwatch\_log\_group\_tags](#input\_cloudwatch\_log\_group\_tags) | Additional tags for the Cloudwatch log group | `map(string)` | `{}` | no | -| [create](#input\_create) | Whether to create all resources | `bool` | `true` | no | -| [create\_sns\_topic](#input\_create\_sns\_topic) | Whether to create new SNS topic | `bool` | `true` | no | +| [create](#input\_create) | (Required) Whether to create all resources | `bool` | `true` | no | +| [create\_sns\_topic](#input\_create\_sns\_topic) | (Required) Whether to create new SNS topic | `bool` | `true` | no | | [iam\_policy\_path](#input\_iam\_policy\_path) | Path of policies to that should be added to IAM role for Lambda Function | `string` | `null` | no | | [iam\_role\_boundary\_policy\_arn](#input\_iam\_role\_boundary\_policy\_arn) | The ARN of the policy that is used to set the permissions boundary for the role | `string` | `null` | no | | [iam\_role\_name\_prefix](#input\_iam\_role\_name\_prefix) | A unique role name beginning with the specified prefix | `string` | `"lambda"` | no | | [iam\_role\_path](#input\_iam\_role\_path) | Path of IAM role to use for Lambda Function | `string` | `null` | no | | [iam\_role\_tags](#input\_iam\_role\_tags) | Additional tags for the IAM role | `map(string)` | `{}` | no | | [kms\_key\_arn](#input\_kms\_key\_arn) | ARN of the KMS key used for decrypting slack webhook url | `string` | `""` | no | -| [lambda\_description](#input\_lambda\_description) | The description of the Lambda function | `string` | `null` | no | +| [lambda\_description](#input\_lambda\_description) | (Optional) The description of the Lambda function | `string` | `null` | no | | [lambda\_function\_ephemeral\_storage\_size](#input\_lambda\_function\_ephemeral\_storage\_size) | Amount of ephemeral storage (/tmp) in MB your Lambda Function can use at runtime. Valid value between 512 MB to 10,240 MB (10 GB). | `number` | `512` | no | -| [lambda\_function\_name](#input\_lambda\_function\_name) | The name of the Lambda function to create | `string` | n/a | yes | +| [lambda\_function\_name](#input\_lambda\_function\_name) | (Required) The name of the Lambda function to create | `string` | n/a | yes | | [lambda\_function\_s3\_bucket](#input\_lambda\_function\_s3\_bucket) | S3 bucket to store artifacts | `string` | `null` | no | | [lambda\_function\_store\_on\_s3](#input\_lambda\_function\_store\_on\_s3) | Whether to store produced artifacts on S3 or locally. | `bool` | `false` | no | | [lambda\_function\_tags](#input\_lambda\_function\_tags) | Additional tags for the Lambda function | `map(string)` | `{}` | no | | [lambda\_function\_vpc\_security\_group\_ids](#input\_lambda\_function\_vpc\_security\_group\_ids) | List of security group ids when Lambda Function should run in the VPC. | `list(string)` | `null` | no | | [lambda\_function\_vpc\_subnet\_ids](#input\_lambda\_function\_vpc\_subnet\_ids) | List of subnet ids when Lambda Function should run in the VPC. Usually private or intra subnets. | `list(string)` | `null` | no | | [lambda\_layers](#input\_lambda\_layers) | (Optional) List of Lambda Layer Version ARNs (maximum of 5) to attach to your Lambda Function | `list(string)` | `[]` | no | -| [lambda\_role](#input\_lambda\_role) | IAM role attached to the Lambda Function. If this is set then a role will not be created for you. | `string` | `""` | no | +| [lambda\_role](#input\_lambda\_role) | (Optional) IAM role attached to the Lambda Function. If this is set then a role will not be created for you. | `string` | `""` | no | | [messenger](#input\_messenger) | The name of the channel in Slack for notifications | `string` | n/a | yes | | [recreate\_missing\_package](#input\_recreate\_missing\_package) | Whether to recreate missing Lambda package if it is missing locally or not | `bool` | `false` | no | | [reserved\_concurrent\_executions](#input\_reserved\_concurrent\_executions) | The amount of reserved concurrent executions for this lambda function. A value of 0 disables lambda from being triggered and -1 removes any concurrency limitations | `number` | `-1` | no | diff --git a/functions/app.py b/functions/app.py index 22cc403..c893c74 100644 --- a/functions/app.py +++ b/functions/app.py @@ -120,9 +120,9 @@ def handle_event(messenger, event: dict): "type": "AdaptiveCard", "$schema":"http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.4", - "msteams": { - "width": "Full" - }, + "msteams": { + "width": "Full" + }, "body": [ { "type": "Container", @@ -157,7 +157,7 @@ def handle_event(messenger, event: dict): ] } return message - + # CodeBuild elif 'Records' in event and len(event['Records']) > 0 and 'EventSource' in event['Records'][0] and 'aws.codebuild' in event['Records'][0]['Sns']['Message']: message = json.loads(event['Records'][0]['Sns']['Message']) @@ -246,9 +246,9 @@ def handle_event(messenger, event: dict): "type": "AdaptiveCard", "$schema":"http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.4", - "msteams": { - "width": "Full" - }, + "msteams": { + "width": "Full" + }, "body": [ { "type": "Container", @@ -283,7 +283,7 @@ def handle_event(messenger, event: dict): ] } return message - + # ECS if 'Records' in event and len(event['Records']) > 0 and 'EventSource' in event['Records'][0] and 'aws.ecs' in event['Records'][0]['Sns']['Message']: def ecs_events_parser(detail_type, detail): @@ -482,7 +482,7 @@ def ecs_events_parser_title(detail_type, detail): "event_id": f'{title}' } return message - + # Microsoft Teams elif messenger == 'msteams': message = { @@ -494,9 +494,9 @@ def ecs_events_parser_title(detail_type, detail): "type": "AdaptiveCard", "$schema":"http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.4", - "msteams": { - "width": "Full" - }, + "msteams": { + "width": "Full" + }, "body": [ { "type": "Container", @@ -603,9 +603,9 @@ def ecs_events_parser_title(detail_type, detail): "type": "AdaptiveCard", "$schema":"http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.4", - "msteams": { - "width": "Full" - }, + "msteams": { + "width": "Full" + }, "body": [ { "type": "Container", @@ -640,7 +640,7 @@ def ecs_events_parser_title(detail_type, detail): ] } return message - + # Post Webhook def post(WEBHOOK_URL, message): log.debug(f'Sending message: {json.dumps(message, indent=4)}') diff --git a/functions/test/ecs-events.json b/functions/test/ecs-events.json index ad31db9..9cbb024 100644 --- a/functions/test/ecs-events.json +++ b/functions/test/ecs-events.json @@ -98,4 +98,4 @@ "updatedAt": "2020-05-23T11:11:11Z", "reason": "ECS deployment deploymentId in progress." } -} \ No newline at end of file +}