Skip to content

Commit cf78f6d

Browse files
Merge branch 'main' into feature/CCM-11067_Add_Internal_Workflows
2 parents c6f9678 + b99fd68 commit cf78f6d

File tree

6 files changed

+267
-3
lines changed

6 files changed

+267
-3
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: "Check Todo usage"
2+
description: "Check Todo usage"
3+
runs:
4+
using: "composite"
5+
steps:
6+
- name: "Check Todo usage"
7+
shell: bash
8+
run: |
9+
export BRANCH_NAME=origin/${{ github.event.repository.default_branch }}
10+
check=branch ./scripts/githooks/check-todos.sh

.github/workflows/cicd-3-deploy.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ jobs:
4848
echo "nodejs_version=$(grep "^nodejs\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
4949
echo "python_version=$(grep "^python\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
5050
echo "terraform_version=$(grep "^terraform\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
51-
# TODO: Get the version, but it may not be the .version file as this should come from the CI/CD Pull Request Workflow
5251
echo "version=$(head -n 1 .version 2> /dev/null || echo unknown)" >> $GITHUB_OUTPUT
5352
# echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
5453
- name: "List variables"

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ jobs:
101101
fetch-depth: 0 # Full history is needed to compare branches
102102
- name: "Check English usage"
103103
uses: ./.github/actions/check-english-usage
104+
check-todo-usage:
105+
name: "Check TODO usage"
106+
runs-on: ubuntu-latest
107+
timeout-minutes: 5
108+
steps:
109+
- name: "Checkout code"
110+
uses: actions/checkout@v4
111+
with:
112+
fetch-depth: 0 # Full history is needed to compare branches
113+
- name: "Check TODO usage"
114+
uses: ./.github/actions/check-todo-usage
104115
detect-terraform-changes:
105116
name: "Detect Terraform Changes"
106117
runs-on: ubuntu-latest

.github/workflows/stage-3-build.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
- name: "Upload artefact 1"
6161
run: |
6262
echo "Uploading artefact 1 ..."
63-
# TODO: Use either action/cache or action/upload-artifact
63+
# Use either action/cache or action/upload-artifact
6464
artefact-n:
6565
name: "Artefact n"
6666
runs-on: ubuntu-latest
@@ -77,4 +77,4 @@ jobs:
7777
- name: "Upload artefact n"
7878
run: |
7979
echo "Uploading artefact n ..."
80-
# TODO: Use either action/cache or action/upload-artifact
80+
# Use either action/cache or action/upload-artifact

scripts/config/pre-commit.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,10 @@ repos:
6363
entry: ./scripts/githooks/check-terraform-docs.sh
6464
language: script
6565
pass_filenames: false
66+
- repo: local
67+
hooks:
68+
- id: check-todo-usage
69+
name: Check TODO usage
70+
entry: /usr/bin/env check=branch ./scripts/githooks/check-todos.sh
71+
language: script
72+
pass_filenames: false

scripts/githooks/check-todos.sh

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#!/bin/bash
2+
3+
# WARNING: Please, DO NOT edit this file! It is maintained in the Repository Template (https://github.com/nhs-england-tools/repository-template). Raise a PR instead.
4+
5+
set -euo pipefail
6+
7+
# Pre-commit git hook to scan for secrets hard-coded in the codebase. This is a
8+
# gitleaks command wrapper. It will run gitleaks natively if it is installed,
9+
# otherwise it will run it in a Docker container.
10+
#
11+
# Usage:
12+
# $ [options] ./scan-secrets.sh
13+
#
14+
# Options:
15+
# check=all # check all files in the repository
16+
# check=staged-changes # check only files staged for commit.
17+
# check=working-tree-changes # check modified, unstaged files. This is the default.
18+
# check=branch # check for all changes since branching from $BRANCH_NAME
19+
# VERBOSE=true # Show all the executed commands, default is 'false'
20+
#
21+
# Exit codes:
22+
# 0 - No Todos
23+
# 1 - Todos found or error encountered
24+
# 126 - Unknown flag
25+
26+
# ==============================================================================
27+
28+
EXCLUDED_FILES=(
29+
".devcontainer/devcontainer.json"
30+
".tool-versions"
31+
"infrastructure/terraform/bin/terraform.sh"
32+
"Makefile"
33+
"project.code-workspace"
34+
"src/jekyll-devcontainer/src/.devcontainer/devcontainer.json"
35+
)
36+
37+
EXCLUDED_DIRS=(
38+
".git/"
39+
".venv/"
40+
"docs/"
41+
"node_modules/"
42+
)
43+
44+
45+
# Get files to check based on mode
46+
function get_files_to_check() {
47+
local mode="$1"
48+
case "$mode" in
49+
staged-changes)
50+
git diff --diff-filter=ACMRT --name-only --cached # ACMRT only show files added, copied, modified, renamed or that had their type changed (eg. file → symlink) in this commit. This leaves out deleted files.
51+
;;
52+
working-tree-changes)
53+
git ls-files --others --exclude-standard && git diff --diff-filter=ACMRT --name-only
54+
;;
55+
branch)
56+
git diff --diff-filter=ACMRT --name-only ${BRANCH_NAME:-origin/main}
57+
;;
58+
all)
59+
git ls-files && git ls-files --others --exclude-standard
60+
;;
61+
*)
62+
echo "Unknown check mode: $mode" >&2
63+
exit 126
64+
;;
65+
esac
66+
}
67+
68+
69+
function build_exclude_args() {
70+
local args=(
71+
--exclude=".github/actions/check-todo-usage/action.yaml"
72+
--exclude=".github/workflows/stage-1-commit.yaml"
73+
--exclude="scripts/config/pre-commit.yaml"
74+
--exclude="scripts/githooks/check-todos.sh"
75+
) # Exclude this script and its references by default, as it naturally contains TODOs. Todo todo todo <- see?
76+
77+
if [ ${#EXCLUDED_DIRS[@]} -gt 0 ]; then
78+
for dir in "${EXCLUDED_DIRS[@]}"; do
79+
args+=(--exclude-dir="$dir")
80+
done
81+
fi
82+
83+
if [ ${#EXCLUDED_FILES[@]} -gt 0 ]; then
84+
for file in "${EXCLUDED_FILES[@]}"; do
85+
args+=(--exclude="$file")
86+
done
87+
fi
88+
echo "${args[@]}"
89+
}
90+
91+
92+
function search_todos() {
93+
local mode="$1"
94+
shift # Shift positional parameters so $@ contains only exclude_args
95+
local exclude_args=("$@")
96+
local todos=""
97+
98+
local files
99+
files=$(get_files_to_check "$mode")
100+
# flatten files to unique list
101+
files=$(echo "$files" | tr ' ' '\n' | sort -u)
102+
103+
for file in $files; do
104+
skip=false
105+
106+
# Check if the file matches any exclude patterns
107+
# Exclude files based on provided arguments and predefined directories
108+
for ex in "${exclude_args[@]}"; do
109+
if [[ "$ex" == --exclude* ]]; then
110+
pattern=${ex#--exclude=}
111+
[[ "$file" == $pattern ]] && skip=true && break
112+
fi
113+
done
114+
115+
# Check if the file is in any of the excluded directories
116+
for exdir in "${EXCLUDED_DIRS[@]}"; do
117+
[[ "$file" == $exdir* ]] && skip=true && break
118+
done
119+
120+
# If the file is excluded, skip it
121+
if [ "$skip" = false ] && [ -f "$file" ]; then
122+
file_todos=$(grep -nHi TODO "$file" || true)
123+
[ -n "$file_todos" ] && todos+="$file_todos\n"
124+
fi
125+
done
126+
127+
echo -e "$todos"
128+
}
129+
130+
131+
function filter_todos_with_valid_jira_ticket() {
132+
local todos="$1"
133+
local jira_regex="[A-Z][A-Z0-9]+-[0-9]+"
134+
local todos_without_ticket=""
135+
136+
while IFS= read -r line; do
137+
# Only lines with TODO but without a valid JIRA ticket
138+
if grep -qi 'TODO' <<< "$line"; then
139+
if ! [[ "$line" =~ $jira_regex ]]; then
140+
todos_without_ticket+="$line\n"
141+
fi
142+
fi
143+
done <<< "$(echo -e "$todos")"
144+
145+
# Output only TODOs without a valid JIRA ticket
146+
echo -e "$todos_without_ticket"
147+
}
148+
149+
150+
function print_output() {
151+
local todos="$1"
152+
local exclude_args="$2"
153+
local todo_count=$(line_count "$todos")
154+
155+
echo "TODO Check Configuration:"
156+
echo "========================================="
157+
echo " Check Mode: ${check:-working-tree-changes}"
158+
echo " Total TODOs found: $todo_count"
159+
160+
if [ ${#EXCLUDED_DIRS[@]} -gt 0 ]; then
161+
echo " Excluded Directories: ${EXCLUDED_DIRS[*]}"
162+
else
163+
echo " Excluded Directories: (none)"
164+
fi
165+
166+
if [ ${#EXCLUDED_FILES[@]} -gt 0 ]; then
167+
echo " Excluded Files: ${EXCLUDED_FILES[*]}"
168+
else
169+
echo " Excluded Files: (none)"
170+
fi
171+
172+
if is-arg-true "${VERBOSE:-false}"; then
173+
echo "Grep Exclude Args: $exclude_args"
174+
fi
175+
176+
echo -e "\n========================================="
177+
echo "All TODOs found: $todo_count"
178+
echo "========================================="
179+
180+
if [ "$todo_count" -gt 0 ]; then
181+
echo "$todos"
182+
else
183+
echo "No TODOs found."
184+
fi
185+
186+
local results=$(filter_todos_with_valid_jira_ticket "$todos")
187+
local results_count=$(line_count "$results")
188+
189+
echo -e "\n========================================="
190+
echo "TODOs without a Jira ticket: $results_count"
191+
echo "========================================="
192+
193+
if [ "$results_count" -gt 0 ]; then
194+
echo "$results"
195+
exit 1
196+
else
197+
echo "No TODOs found without a Jira reference."
198+
fi
199+
}
200+
201+
202+
function main() {
203+
cd "$(git rev-parse --show-toplevel)"
204+
205+
local check_mode="${check:-working-tree-changes}"
206+
local exclude_args=$(build_exclude_args)
207+
local todos=$(search_todos "$check_mode" $exclude_args)
208+
print_output "$todos" "$exclude_args"
209+
}
210+
211+
# ==============================================================================
212+
213+
# Count non-empty lines in a string
214+
function line_count() {
215+
local input="$1"
216+
if [ -n "$input" ]; then
217+
echo -e "$input" | wc -l
218+
else
219+
echo 0
220+
fi
221+
}
222+
223+
function is-arg-true() {
224+
if [[ "$1" =~ ^(true|yes|y|on|1|TRUE|YES|Y|ON)$ ]]; then
225+
return 0
226+
else
227+
return 1
228+
fi
229+
}
230+
231+
# ==============================================================================
232+
233+
is-arg-true "${VERBOSE:-false}" && set -x
234+
235+
main "$@"
236+
237+
exit 0

0 commit comments

Comments
 (0)