Skip to content

Commit f303e6a

Browse files
Create Terraform module (nhs-england-tools#112)
## Description In this PR, we introduce a new Terraform module for scripting, refactor the Docker module and improve and extend the documentation. - Fixes nhs-england-tools#84 - Fixes nhs-england-tools#106 - Fixes nhs-england-tools#113 ## Context See `nhs-england-tools/terraform-github-aws-s3-upload` [PR #11](nhs-england-tools/terraform-github-aws-s3-upload#11) ## Type of changes - [x] Refactoring (non-breaking change) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would change existing functionality) - [ ] Bug fix (non-breaking change which fixes an issue) ## Checklist - [x] I am familiar with the [contributing guidelines](../docs/CONTRIBUTING.md) - [x] I have followed the code style of the project - [x] I have added tests to cover my changes - [x] I have updated the documentation accordingly - [ ] This PR is a result of pair or mob programming --- ## Sensitive Information Declaration To ensure the utmost confidentiality and protect your and others privacy, we kindly ask you to NOT including [PII (Personal Identifiable Information) / PID (Personal Identifiable Data)](https://digital.nhs.uk/data-and-information/keeping-data-safe-and-benefitting-the-public) or any other sensitive data in this PR (Pull Request) and the codebase changes. We will remove any PR that do contain any sensitive information. We really appreciate your cooperation in this matter. - [x] I confirm that neither PII/PID nor sensitive data are included in this PR and the codebase changes. --------- Co-authored-by: Alex Young <[email protected]>
1 parent f15e440 commit f303e6a

File tree

33 files changed

+1083
-242
lines changed

33 files changed

+1083
-242
lines changed

.gitattributes

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
scripts/docker/** linguist-vendored
22
scripts/githooks/** linguist-vendored
33
scripts/reports/** linguist-vendored
4+
scripts/terraform/** linguist-vendored
5+
scripts/tests/test.mk linguist-vendored
46
scripts/init.mk linguist-vendored
57
scripts/shellscript-linter.sh linguist-vendored
6-
scripts/test.mk linguist-vendored

.github/actions/check-terraform-format/action.yaml

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: "Lint Terraform"
2+
description: "Lint Terraform"
3+
inputs:
4+
root-modules:
5+
description: "Comma separated list of root module directories to validate, content of the 'infrastructure/environments' is checked by default"
6+
required: false
7+
runs:
8+
using: "composite"
9+
steps:
10+
- name: "Check Terraform format"
11+
shell: bash
12+
run: |
13+
check_only=true scripts/githooks/check-terraform-format.sh
14+
- name: "Validate Terraform"
15+
shell: bash
16+
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 make terraform-validate
20+
done

.github/actions/scan-secrets/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ runs:
66
- name: "Scan secrets"
77
shell: bash
88
run: |
9-
export ALL_FILES=true
9+
export ALL_FILES=true # Do not change this line, as new patterns may be added or history may be rewritten
1010
./scripts/githooks/scan-secrets.sh

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,15 @@ jobs:
6666
fetch-depth: 0 # Full history is needed to compare branches
6767
- name: "Check markdown format"
6868
uses: ./.github/actions/check-markdown-format
69-
check-terraform-format:
69+
lint-terraform:
7070
runs-on: ubuntu-latest
7171
timeout-minutes: 2
72-
name: "Check Terraform format"
72+
name: "Lint Terraform"
7373
steps:
7474
- name: "Checkout code"
75-
uses: actions/checkout@v4
76-
- name: "Check Terraform format"
77-
uses: ./.github/actions/check-terraform-format
75+
uses: actions/checkout@v3
76+
- name: "Lint Terraform"
77+
uses: ./.github/actions/lint-terraform
7878
cloc-repository:
7979
runs-on: ubuntu-latest
8080
permissions:

.tool-versions

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
1-
nodejs 18.16.0
2-
python 3.10.12
3-
terraform 1.5.0
1+
nodejs 18.17.1 # Always check AWS and Azure runtime support
2+
python 3.11.4 # Always check AWS and Azure runtime support
3+
terraform 1.5.6
44
pre-commit 3.3.3
55

6+
# ==============================================================================
67
# The section below is reserved for Docker image versions.
78

8-
# docker/koalaman/shellcheck latest@sha256:0b341f80c643aa5160815746421d22f189ed8d427fe66d639e8b79b15f8b5bf6
9-
# docker/hadolint/hadolint 2.12.0-alpine@sha256:7dba9a9f1a0350f6d021fb2f6f88900998a4fb0aaf8e4330aa8c38544f04db42
10-
9+
# alpine, SEE: https://hub.docker.com/_/alpine/tags
1110
# docker/alpine 3.18.3@sha256:c5c5fda71656f28e49ac9c5416b3643eaa6a108a8093151d6d1afc9463be8e33
12-
# docker/python 3.10.12-alpine3.18@sha256:268ba060f59c005d099661a70f53c353f2acd1401ca90f81869a04600cdae6f4
11+
12+
# nodejs, SEE: https://hub.docker.com/_/node/tags
13+
# docker/node 18.17.1-alpine3.18@sha256:982b5b6f07cd9241c9ebb163829067deac8eaefc57cfa8f31927f4b18943d971
14+
15+
# python, SEE: https://hub.docker.com/_/python/tags
16+
# docker/python 3.11.4-alpine3.18@sha256:0135ae6442d1269379860b361760ad2cf6ab7c403d21935a8015b48d5bf78a86
17+
18+
# terraform, SEE: https://hub.docker.com/r/hashicorp/terraform/tags
19+
# docker/hashicorp/terraform 1.5.6@sha256:180a7efa983386a27b43657ed610e9deed9e6c3848d54f9ea9b6cb8a5c8c25f5
20+
21+
# shellcheck, SEE: https://hub.docker.com/r/koalaman/shellcheck/tags
22+
# docker/koalaman/shellcheck latest@sha256:e40388688bae0fcffdddb7e4dea49b900c18933b452add0930654b2dea3e7d5c
23+
24+
# hadolint, SEE: https://hub.docker.com/r/hadolint/hadolint/tags
25+
# docker/hadolint/hadolint 2.12.0-alpine@sha256:7dba9a9f1a0350f6d021fb2f6f88900998a4fb0aaf8e4330aa8c38544f04db42

Makefile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# This file is for you! Edit it to implement your own hooks (make targets) into
22
# the project as automated steps to be executed on locally and in the CD pipeline.
33

4-
include ./scripts/init.mk
5-
include ./scripts/test.mk
4+
include scripts/init.mk
65

7-
# Example targets are: dependencies, build, publish, deploy, clean, etc.
6+
# ==============================================================================
7+
8+
# Example CI/CD targets are: dependencies, build, publish, deploy, clean, etc.
89

910
dependencies: # Install dependencies needed to build and test the project
1011
# TODO: Implement installation of your project dependencies
@@ -28,7 +29,9 @@ config:: # Configure development environment
2829
python-install \
2930
terraform-install
3031

31-
.SILENT: \
32+
# ==============================================================================
33+
34+
${VERBOSE}.SILENT: \
3235
build \
3336
clean \
3437
config \
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Developer Guide: Bash and Make
2+
3+
- [Developer Guide: Bash and Make](#developer-guide-bash-and-make)
4+
- [Using Make](#using-make)
5+
- [Using Bash](#using-bash)
6+
- [Make and Bash working together](#make-and-bash-working-together)
7+
- [Conventions](#conventions)
8+
- [Debugging](#debugging)
9+
- [Scripts](#scripts)
10+
- [TODO](#todo)
11+
12+
## Using Make
13+
14+
Sample make target definition:
15+
16+
```makefile
17+
some-target: # Short target description - mandatory: foo=[description]; optional: baz=[description, default is 'qux']
18+
# Recipe implementation...
19+
```
20+
21+
Run make target from a terminal:
22+
23+
```shell
24+
foo=bar make some-target # Environment variable is passed to the make target execution process
25+
make some-target foo=bar # Make argument is passed to the make target execution process
26+
```
27+
28+
By convention we use uppercase variables for global settings that you would ordinarily associate with environment variables. We use lower-case variables as arguments to call functions or make targets, in this case.
29+
30+
All make targets should be added to the `${VERBOSE}.SILENT:` section of the `make` file, which prevents `make` from printing commands before executing them. The `${VERBOSE}` prefix on the `.SILENT:` special target allows toggling it if needed. If you explicitly want output from a certain line, use `echo`.
31+
32+
It is worth noting that by default, `make` creates a new system process to execute each line of a recipe. This is not the desired behaviour for us and the entire content of a make recipe (a target) should be run in a single shell invocation. This has been configured in this repository by setting the [`.ONESHELL:`](https://www.gnu.org/software/make/manual/html_node/One-Shell.html) special target in the `scripts/init.mk` file.
33+
34+
## Using Bash
35+
36+
When working in the command-line ensure the environment variables are reset to their initial state. This can be done by reloading shell using the `env -i $SHELL` command.
37+
38+
Sample Bash function definition:
39+
40+
```shell
41+
# Short function description
42+
# Arguments (provided as environment variables):
43+
# foo=[description]
44+
# baz=[description, default is 'qux']
45+
function some-shell-function() {
46+
# Function implementation...
47+
```
48+
49+
Run Bash function from a terminal:
50+
51+
```shell
52+
source scripts/a-suite-of-shell-functions
53+
foo=bar some-shell-function # Environment variable is accessible by the function executed in the same operating system process
54+
```
55+
56+
```shell
57+
source scripts/a-suite-of-shell-functions
58+
foo=bar
59+
some-shell-function # Environment variable is still accessible by the function
60+
```
61+
62+
Run Bash script from a terminal, bear in mind that executing a script creates a child operating system process:
63+
64+
```shell
65+
# Environment variable has to be exported to be passed to a child process, DO NOT use this pattern
66+
export foo=bar
67+
scripts/a-shell-script
68+
```
69+
70+
```shell
71+
# or to be set in the same line before creating a new process, prefer this pattern over the previous one
72+
foo=bar scripts/a-shell-script
73+
74+
# or when multiple variables are required
75+
foo=bar \
76+
baz=qux \
77+
scripts/a-shell-script
78+
```
79+
80+
By convention we use uppercase variables for global settings that you would ordinarily associate with environment variables. We use lower-case variables as arguments to be passed into specific functions we call, usually on the same line, right before the function name.
81+
82+
The command `set -euo pipefail` is commonly used in the Bash scripts, to configure the behavior of the script in a way that makes it more robust and easier to debug. Here is a breakdown of each option switch:
83+
84+
- `-e`: Ensures that the script exits immediately if any command returns a non-zero exit status.
85+
- `-u`: Makes the script exit if there is an attempt to use an uninitialised variable.
86+
- `-o pipefail`: ensures that if any command in a pipeline fails (i.e., returns a non-zero exit status), then the entire pipeline will return that non-zero status. By default, a pipeline returns the exit status of the last command.
87+
88+
## Make and Bash working together
89+
90+
Sample make target calling a Bash function. Notice that `baz` is going to be accessible to the function as it is executed in the same operating system process:
91+
92+
```makefile
93+
some-target: # Run shell function - mandatory: foo=[description]
94+
source scripts/a-suite-of-shell-function
95+
baz=qux
96+
some-shell-function # 'foo' and 'baz' are accessible by the function
97+
```
98+
99+
Sample make target calling another make target. In this case a parameter `baz` has to be passed as a variable to the make target, which is executed in a child process:
100+
101+
```makefile
102+
some-target: # Call another target - mandatory: foo=[description]
103+
baz=qux \
104+
make another-target # 'foo' and 'baz' are passed to the make target
105+
```
106+
107+
Run it from a terminal:
108+
109+
```shell
110+
foo=bar make some-target
111+
```
112+
113+
## Conventions
114+
115+
### Debugging
116+
117+
To assist in investigating scripting issues, the `VERBOSE` variable is available for both Make and Bash scripts. If it is set to `true` or `1`, it prints all the commands that the script executes to the standard output. Here is how to use it:
118+
119+
for Make targets
120+
121+
```shell
122+
VERBOSE=1 make docker-example-build
123+
```
124+
125+
for Bash scripts
126+
127+
```shell
128+
VERBOSE=1 scripts/shellscript-linter.sh
129+
```
130+
131+
### Scripts
132+
133+
Most scripts provided with this repository template can utilise tools installed on your `PATH` if they are available or run them from within a Docker container. To force a script to use Docker, the `FORCE_USE_DOCKER` variable is provided. Here is an example of how to use it:
134+
135+
```shell
136+
FORCE_USE_DOCKER=1 scripts/shellscript-linter.sh
137+
```
138+
139+
You can combine it with the `VERBOSE` flag to see the details of the execution flow:
140+
141+
```shell
142+
VERBOSE=1 FORCE_USE_DOCKER=1 scripts/shellscript-linter.sh
143+
```
144+
145+
## TODO
146+
147+
- Use of CLI tools installed and available on `$PATH`
148+
- Commands run in Docker containers when a CLI tool is not installed
149+
- Explain the concept of modules in this repository
150+
- Make is used as an orchestrator and tool to integrate development processes with the CI/CD pipeline

0 commit comments

Comments
 (0)