Skip to content

Commit aa3b6fb

Browse files
Merge pull request #133 from NHSDigital/CCM-14510_FixTestAndTerraformMakTargets
CCM-14510 Fix Test and TF Make Targets
2 parents 3e35778 + 1d81d2f commit aa3b6fb

10 files changed

Lines changed: 175 additions & 106 deletions

File tree

.github/actions/lint-terraform/action.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ inputs:
77
runs:
88
using: "composite"
99
steps:
10+
- name: "Install Terraform binary"
11+
shell: bash
12+
run: |
13+
asdf plugin add terraform || true
14+
asdf install terraform || true
1015
- name: "Check Terraform format"
1116
shell: bash
1217
run: |
1318
check_only=true scripts/githooks/check-terraform-format.sh
1419
- name: "Validate Terraform"
1520
shell: bash
1621
run: |
17-
stacks=${{ inputs.root-modules }}
18-
for dir in $(find infrastructure/environments -maxdepth 1 -mindepth 1 -type d; echo ${stacks//,/$'\n'}); do
19-
dir=$dir opts='-backend=false' make terraform-init
20-
dir=$dir make terraform-validate
21-
done
22+
make terraform-validate-all

.github/workflows/stage-1-commit.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ jobs:
148148
steps:
149149
- name: "Checkout code"
150150
uses: actions/checkout@v4
151+
- name: "Setup ASDF"
152+
uses: asdf-vm/actions/setup@1902764435ca0dd2f3388eea723a4f92a4eb8302
151153
- name: "Lint Terraform"
152154
uses: ./.github/actions/lint-terraform
153155
trivy-iac:

infrastructure/terraform/components/dnsroot/sns_topic_costs.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
resource "aws_sns_topic" "costs" {
2-
name = "${local.csi}-costs"
2+
name = "${local.csi}-costs"
33
}
44

55
resource "aws_sns_topic_policy" "costs" {

scripts/config/pre-commit.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ repos:
1313
- id: mixed-line-ending
1414
- id: pretty-format-json
1515
args: ['--autofix']
16+
exclude: '(^|/)package(-lock)?\.json$'
1617
# - id: ...
1718
- repo: local
1819
hooks:

scripts/docker/examples/python/assets/hello_world/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ MarkupSafe==2.1.3
88
pip==23.3
99
setuptools==78.1.1
1010
Werkzeug==3.0.6
11-
wheel==0.41.1
11+
wheel==0.46.2
1212
WTForms==3.0.1

scripts/githooks/check-terraform-format.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ function main() {
2929
# check_only=[do not format, run check only]
3030
function terraform-fmt() {
3131

32-
local opts=
3332
if is-arg-true "$check_only"; then
34-
opts="-check"
33+
make terraform-fmt-check
34+
else
35+
make terraform-fmt
3536
fi
36-
opts=$opts make terraform-fmt
3737
}
3838

3939
# ==============================================================================

scripts/githooks/check-todos.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ function search_todos() {
120120

121121
# If the file is excluded, skip it
122122
if [ "$skip" = false ] && [ -f "$file" ]; then
123-
file_todos=$(grep -nHiE '\bTODO\b' "$file" || true)
123+
file_todos=$(grep -nHiE '\bTODO(:| )' "$file" || true)
124124
[ -n "$file_todos" ] && todos+="$file_todos\n"
125125
fi
126126
done
@@ -136,7 +136,7 @@ function filter_todos_with_valid_jira_ticket() {
136136

137137
while IFS= read -r line; do
138138
# Only lines with TODO but without a valid JIRA ticket
139-
if grep -qnHiE '\bTODO\b' <<< "$line"; then
139+
if grep -qnHiE '\bTODO(:| )' <<< "$line"; then
140140
if ! [[ "$line" =~ $jira_regex ]]; then
141141
todos_without_ticket+="$line\n"
142142
fi

scripts/init.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ _install-dependency: # Install asdf dependency - mandatory: name=[listed in the
4646
asdf install ${name} $(or ${version},)
4747

4848
_install-dependencies: # Install all the dependencies listed in .tool-versions
49-
for plugin in $$(grep ^[a-z] .tool-versions | sed 's/[[:space:]].*//'); do
50-
make _install-dependency name="$${plugin}"
49+
for plugin in $$(grep '^[a-z]' .tool-versions | cut -f1 -d' '); do \
50+
$(MAKE) _install-dependency name=$${plugin}; \
5151
done
5252

5353
clean:: # Remove all generated and temporary files (common) @Operations

scripts/terraform/terraform.mk

Lines changed: 149 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,173 @@
1-
# This file is for you! Edit it to implement your own Terraform make targets.
1+
# Terraform Make Targets for TFScaffold
2+
# NHS Notify standard for production infrastructure
3+
# Requires infrastructure/terraform/bin/terraform.sh
24

35
# ==============================================================================
4-
# Custom implementation - implementation of a make target should not exceed 5 lines of effective code.
5-
# In most cases there should be no need to modify the existing make targets.
6-
7-
terraform-init: # Initialise Terraform - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform init command, default is none/empty] @Development
8-
make _terraform cmd="init" \
9-
dir=$(or ${terraform_dir}, ${dir}) \
10-
opts=$(or ${terraform_opts}, ${opts})
11-
12-
terraform-plan: # Plan Terraform changes - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform plan command, default is none/empty] @Development
13-
make _terraform cmd="plan" \
14-
dir=$(or ${terraform_dir}, ${dir}) \
15-
opts=$(or ${terraform_opts}, ${opts})
16-
17-
terraform-apply: # Apply Terraform changes - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform apply command, default is none/empty] @Development
18-
make _terraform cmd="apply" \
19-
dir=$(or ${terraform_dir}, ${dir}) \
20-
opts=$(or ${terraform_opts}, ${opts})
21-
22-
terraform-destroy: # Destroy Terraform resources - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform destroy command, default is none/empty] @Development
23-
make _terraform \
24-
cmd="destroy" \
25-
dir=$(or ${terraform_dir}, ${dir}) \
26-
opts=$(or ${terraform_opts}, ${opts})
27-
28-
terraform-fmt: # Format Terraform files - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform fmt command, default is '-recursive'] @Quality
29-
make _terraform cmd="fmt" \
30-
dir=$(or ${terraform_dir}, ${dir}) \
31-
opts=$(or ${terraform_opts}, ${opts})
32-
33-
terraform-validate: # Validate Terraform configuration - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform validate command, default is none/empty] @Quality
34-
make _terraform cmd="validate" \
35-
dir=$(or ${terraform_dir}, ${dir}) \
36-
opts=$(or ${terraform_opts}, ${opts})
37-
38-
clean:: # Remove Terraform files (terraform) - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set] @Operations
39-
make _terraform cmd="clean" \
40-
dir=$(or ${terraform_dir}, ${dir}) \
41-
opts=$(or ${terraform_opts}, ${opts})
42-
43-
_terraform: # Terraform command wrapper - mandatory: cmd=[command to execute]; optional: dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], opts=[options to pass to the Terraform command, default is none/empty]
44-
# 'TERRAFORM_STACK' is passed to the functions as environment variable
45-
TERRAFORM_STACK=$(or ${TERRAFORM_STACK}, $(or ${terraform_stack}, $(or ${STACK}, ${stack})))
46-
dir=$(or ${dir}, ${TERRAFORM_STACK})
47-
. "scripts/terraform/terraform.lib.sh"; \
48-
terraform-${cmd} # 'dir' and 'opts' are accessible by the function as environment variables, if set
6+
# TFScaffold Terraform Operations
7+
8+
terraform-plan: # Plan Terraform changes - mandatory: component=[component_name], environment=[environment]; optional: project=[default: nhs], region=[default: eu-west-2], group=[default: dev], opts=[additional options] @Development
9+
# Example: make terraform-plan component=mycomp environment=myenv group=mygroup
10+
# Args: --project nhs --region eu-west-2 --component mycomp --environment myenv --group mygroup --action plan
11+
make _terraform-scaffold action=plan \
12+
component=$(component) \
13+
environment=$(environment) \
14+
project=$(or ${project}, nhs) \
15+
region=$(or ${region}, eu-west-2) \
16+
group=$(or ${group}, dev) \
17+
opts=$(or ${opts}, )
18+
19+
terraform-plan-destroy: # Plan Terraform destroy - mandatory: component=[component_name], environment=[environment]; optional: project, region, group, opts @Development
20+
# Example: make terraform-plan-destroy component=mycomp environment=myenv group=mygroup
21+
# Args: --project nhs --region eu-west-2 --component mycomp --environment myenv --group mygroup --action plan-destroy
22+
make _terraform-scaffold action=plan-destroy \
23+
component=$(component) \
24+
environment=$(environment) \
25+
project=$(or ${project}, nhs) \
26+
region=$(or ${region}, eu-west-2) \
27+
group=$(or ${group}, dev) \
28+
opts=$(or ${opts}, )
29+
30+
terraform-apply: # Apply Terraform changes - mandatory: component=[component_name], environment=[environment]; optional: project, region, group, build_id, opts @Development
31+
# Example: make terraform-apply component=mycomp environment=myenv group=mygroup
32+
# Args: --project nhs --region eu-west-2 --component mycomp --environment myenv --group mygroup --action apply
33+
make _terraform-scaffold action=apply \
34+
component=$(component) \
35+
environment=$(environment) \
36+
project=$(or ${project}, nhs) \
37+
region=$(or ${region}, eu-west-2) \
38+
group=$(or ${group}, dev) \
39+
build_id=$(or ${build_id}, ) \
40+
opts=$(or ${opts}, )
41+
42+
terraform-destroy: # Destroy Terraform resources - mandatory: component=[component_name], environment=[environment]; optional: project, region, group, opts @Development
43+
# Example: make terraform-destroy component=mycomp environment=myenv group=mygroup
44+
# Args: --project nhs --region eu-west-2 --component mycomp --environment myenv --group mygroup --action destroy
45+
make _terraform-scaffold action=destroy \
46+
component=$(component) \
47+
environment=$(environment) \
48+
project=$(or ${project}, nhs) \
49+
region=$(or ${region}, eu-west-2) \
50+
group=$(or ${group}, dev) \
51+
opts=$(or ${opts}, )
52+
53+
terraform-output: # Get Terraform outputs - mandatory: component=[component_name], environment=[environment]; optional: project, region, group @Development
54+
# Example: make terraform-output component=mycomp environment=myenv group=mygroup
55+
# Args: --project nhs --region eu-west-2 --component mycomp --environment myenv --group mygroup --action output
56+
make _terraform-scaffold action=output \
57+
component=$(component) \
58+
environment=$(environment) \
59+
project=$(or ${project}, nhs) \
60+
region=$(or ${region}, eu-west-2) \
61+
group=$(or ${group}, dev)
62+
63+
_terraform-scaffold: # Internal wrapper for terraform.sh - mandatory: action=[terraform action]; optional: component, environment, project, region, group, bootstrap, build_id, opts
64+
cd infrastructure/terraform && \
65+
if [ "$(bootstrap)" = "true" ]; then \
66+
./bin/terraform.sh \
67+
--bootstrap \
68+
--project $(project) \
69+
--region $(region) \
70+
--group $(group) \
71+
--action $(action) \
72+
$(if $(opts),-- $(opts),); \
73+
else \
74+
./bin/terraform.sh \
75+
--project $(project) \
76+
--region $(region) \
77+
--component $(component) \
78+
--environment $(environment) \
79+
--group $(group) \
80+
$(if $(build_id),--build-id $(build_id),) \
81+
--action $(action) \
82+
$(if $(opts),-- $(opts),); \
83+
fi
4984

5085
# ==============================================================================
51-
# Quality checks - please DO NOT edit this section!
52-
53-
terraform-shellscript-lint: # Lint all Terraform module shell scripts @Quality
54-
for file in $$(find scripts/terraform -type f -name "*.sh"); do
55-
file=$${file} scripts/shellscript-linter.sh
56-
done
57-
58-
terraform-sec: # TFSEC check against Terraform files - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform fmt command, default is '-recursive'] @Quality
59-
tfsec infrastructure/terraform \
60-
--force-all-dirs \
61-
--exclude-downloaded-modules \
62-
--config-file scripts/config/tfsec.yaml
63-
64-
terraform-docs: # Terraform-docs check against Terraform files - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform fmt command, default is '-recursive'] @Quality
65-
for dir in ./infrastructure/terraform/components/* ./infrastructure/terraform/modules/*; do \
86+
# Formatting and Validation
87+
88+
terraform-fmt: # Format Terraform files in components/ and modules/ (excludes etc/) @Quality
89+
# Example: make terraform-fmt
90+
@cd infrastructure/terraform && \
91+
for dir in components modules; do \
92+
[ -d "$$dir" ] && terraform fmt -recursive "$$dir"; \
93+
done
94+
95+
terraform-fmt-check: # Check Terraform formatting in components/ and modules/ (excludes etc/) @Quality
96+
# Example: make terraform-fmt-check
97+
@cd infrastructure/terraform && \
98+
for dir in components modules; do \
99+
[ -d "$$dir" ] && terraform fmt -check -recursive "$$dir"; \
100+
done
101+
102+
terraform-validate: # Validate Terraform configuration - mandatory: component=[component_name] @Quality
103+
# Example: make terraform-validate component=mycomp
104+
# Note: Validation does not require environment/group as it checks syntax only
105+
cd infrastructure/terraform/components/$(component) && \
106+
terraform init -backend=false && \
107+
terraform validate
108+
109+
terraform-validate-all: # Validate all Terraform components @Quality
110+
# Example: make terraform-validate-all
111+
for dir in infrastructure/terraform/components/*; do \
66112
if [ -d "$$dir" ]; then \
67-
./scripts/terraform/terraform-docs.sh $$dir; \
68-
fi \
113+
echo "Validating $$(basename $$dir)..."; \
114+
cd $$dir && \
115+
terraform init -backend=false && \
116+
terraform validate && \
117+
cd - > /dev/null; \
118+
fi; \
69119
done
70120

71-
# ==============================================================================
72-
# Module tests and examples - please DO NOT edit this section!
121+
terraform-sec: # Run Trivy IaC security scanning on Terraform code @Quality
122+
# Example: make terraform-sec
123+
./scripts/terraform/trivy-scan.sh --mode iac infrastructure/terraform
124+
125+
terraform-docs: # Generate Terraform documentation - optional: component=[specific component, or all if omitted] @Quality
126+
# Example: make terraform-docs component=mycomp
127+
# Example: make terraform-docs (generates for all components)
128+
@if [ -n "$(component)" ]; then \
129+
./scripts/terraform/terraform-docs.sh infrastructure/terraform/components/$(component); \
130+
else \
131+
for dir in infrastructure/terraform/components/* infrastructure/terraform/modules/*; do \
132+
if [ -d "$$dir" ]; then \
133+
./scripts/terraform/terraform-docs.sh $$dir; \
134+
fi; \
135+
done; \
136+
fi
73137

74-
terraform-example-provision-aws-infrastructure: # Provision example of AWS infrastructure @ExamplesAndTests
75-
make terraform-init
76-
make terraform-plan opts="-out=terraform.tfplan"
77-
make terraform-apply opts="-auto-approve terraform.tfplan"
78-
79-
terraform-example-destroy-aws-infrastructure: # Destroy example of AWS infrastructure @ExamplesAndTests
80-
make terraform-destroy opts="-auto-approve"
138+
# ==============================================================================
139+
# Cleanup
81140

82-
terraform-example-clean: # Remove Terraform example files @ExamplesAndTests
83-
dir=$(or ${dir}, ${TERRAFORM_STACK})
84-
. "scripts/terraform/terraform.lib.sh"; \
85-
terraform-clean
86-
rm -f ${TERRAFORM_STACK}/.terraform.lock.hcl
141+
clean:: # Remove Terraform build artifacts and cache @Operations
142+
# Example: make clean
143+
rm -rf infrastructure/terraform/components/*/build
144+
rm -rf infrastructure/terraform/components/*/.terraform
145+
rm -rf infrastructure/terraform/components/*/.terraform.lock.hcl
146+
rm -rf infrastructure/terraform/bootstrap/.terraform
147+
rm -rf infrastructure/terraform/bootstrap/.terraform.lock.hcl
148+
rm -rf infrastructure/terraform/plugin-cache/*
87149

88150
# ==============================================================================
89-
# Configuration - please DO NOT edit this section!
151+
# Installation
90152

91-
terraform-install: # Install Terraform @Installation
153+
terraform-install: # Install Terraform using asdf @Installation
154+
# Example: make terraform-install
92155
make _install-dependency name="terraform"
93156

94157
# ==============================================================================
95158

96159
${VERBOSE}.SILENT: \
97-
_terraform \
160+
_terraform-scaffold \
98161
clean \
99162
terraform-apply \
100163
terraform-destroy \
101-
terraform-example-clean \
102-
terraform-example-destroy-aws-infrastructure \
103-
terraform-example-provision-aws-infrastructure \
104-
terraform-fmt \
105164
terraform-docs \
106-
terraform-init \
165+
terraform-fmt \
166+
terraform-fmt-check \
107167
terraform-install \
168+
terraform-output \
108169
terraform-plan \
109-
terraform-shellscript-lint \
170+
terraform-plan-destroy \
171+
terraform-sec \
110172
terraform-validate \
173+
terraform-validate-all \

scripts/tests/test.mk

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,14 @@ test: # Run all the test tasks @Testing
6969
test-load
7070

7171
_test:
72-
set -e
73-
script="./scripts/tests/${name}.sh"
74-
if [ -e "$${script}" ]; then
75-
exec $${script}
76-
else
77-
echo "make test-${name} not implemented: $${script} not found" >&2
72+
set -e; \
73+
script="./scripts/tests/${name}.sh"; \
74+
if [ -e "$${script}" ]; then \
75+
exec $${script}; \
76+
else \
77+
echo "test-${name}: Not currently implemented"; \
78+
echo "Create $${script} to implement this test target"; \
79+
exit 0; \
7880
fi
7981

8082
${VERBOSE}.SILENT: \

0 commit comments

Comments
 (0)