Skip to content

Commit 3636f18

Browse files
authored
Merge pull request #56 from NHSDigital/feature/CCM-8881-exclude-tool-versions-from-repo-sync
CCM-8881: Extend sync script to merge some config files rather than replacing them
2 parents bee9a5e + 74ab683 commit 3636f18

File tree

7 files changed

+141
-18
lines changed

7 files changed

+141
-18
lines changed

.github/workflows/cicd-1-pull-request.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ jobs:
4040
echo "build_datetime=$datetime" >> $GITHUB_OUTPUT
4141
echo "build_timestamp=$(date --date=$datetime -u +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
4242
echo "build_epoch=$(date --date=$datetime -u +'%s')" >> $GITHUB_OUTPUT
43-
echo "nodejs_version=$(grep "^nodejs " .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
44-
echo "python_version=$(grep "^python " .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
45-
echo "terraform_version=$(grep "^terraform " .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
43+
echo "nodejs_version=$(grep "^nodejs\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
44+
echo "python_version=$(grep "^python\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
45+
echo "terraform_version=$(grep "^terraform\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
4646
echo "version=$(echo $version)" >> $GITHUB_OUTPUT
4747
echo "is_version_prerelease=$(if [[ $version == *-* ]]; then echo "true"; else echo "false"; fi)" >> $GITHUB_OUTPUT
4848

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ jobs:
4545
echo "build_datetime=$datetime" >> $GITHUB_OUTPUT
4646
echo "build_timestamp=$(date --date=$datetime -u +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
4747
echo "build_epoch=$(date --date=$datetime -u +'%s')" >> $GITHUB_OUTPUT
48-
echo "nodejs_version=$(grep "^nodejs " .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
49-
echo "python_version=$(grep "^python " .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
50-
echo "terraform_version=$(grep "^terraform " .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
48+
echo "nodejs_version=$(grep "^nodejs\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
49+
echo "python_version=$(grep "^python\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
50+
echo "terraform_version=$(grep "^terraform\s" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT
5151
# TODO: Get the version, but it may not be the .version file as this should come from the CI/CD Pull Request Workflow
5252
echo "version=$(head -n 1 .version 2> /dev/null || echo unknown)" >> $GITHUB_OUTPUT
5353
# echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT

scripts/config/.repository-template-sync-ignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# Files and folders to ignore when syncing nhs-notify-repository-template back in to this repository
2-
scripts/config/.repository-template-sync-ignore
32
.github/workflows/
43
nhs-notify-repository-template/
54

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Files and folders to merge when syncing nhs-notify-repository-template back in to this repository
2+
scripts/config/.repository-template-sync-ignore
3+
scripts/config/.repository-template-sync-merge
4+
.tool-versions
5+
.gitignore
6+
scripts/config/vale/styles/config/vocabularies/words/accept.txt
7+
scripts/config/vale/styles/config/vocabularies/words/reject.txt

scripts/config/sonar-scanner.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ sonar.sources=.
77

88
#sonar.python.coverage.reportPaths=.coverage/coverage.xml
99
#sonar.[javascript|typescript].lcov.reportPaths=.coverage/lcov.info
10+
sonar.coverage.exclusions=scripts/**/*

scripts/githooks/sync-template-repo.sh

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@ set -euo pipefail
55
# Script to synchronise the nhs-notify-template-repository with this repository
66
#
77
# Usage:
8-
# $ [options] ./check-terraform-format.sh
8+
# $ [options] ./sync-template-repo.sh
99
#
1010
# Options:
1111
# new_only=true # Only identify new files from the template-repository
1212
# changes_only=true # Only identify files which have drifted from the template-repository
1313

1414
# ==============================================================================
1515

16-
# Command line prameters
16+
scriptdir=$(realpath "$(dirname "$0")")
17+
18+
# Command line parameters
1719
new_only=${new_only:-false}
1820
changes_only=${changes_only:-false}
1921

2022
# Set variables
2123
TEMPLATE_REPO_DIR="nhs-notify-repository-template"
2224
IGNORE_FILE="scripts/config/.repository-template-sync-ignore"
25+
MERGE_FILE="scripts/config/.repository-template-sync-merge"
2326

2427
# Check if the template directory exists
2528
if [ ! -d "${TEMPLATE_REPO_DIR}" ]; then
@@ -34,11 +37,21 @@ if [ ! -f "${IGNORE_FILE}" ]; then
3437
echo "# Files and Folders in the template repository to disregard" >> ${IGNORE_FILE}
3538
fi
3639

40+
# Check if the .template-merge file exists, create an empty one if not
41+
if [ ! -f "${MERGE_FILE}" ]; then
42+
echo "# Files and folders to merge when syncing ${TEMPLATE_REPO_DIR} back in to this repository" > ${MERGE_FILE}
43+
fi
44+
3745
# Read the .template-ignore file into an array
3846
while IFS= read -r line || [ -n "$line" ]; do
3947
IGNORED_PATHS+=("$line")
4048
done < "$IGNORE_FILE"
4149

50+
# Read the .template-merge file into an array
51+
while IFS= read -r line || [ -n "$line" ]; do
52+
MERGED_PATHS+=("$line")
53+
done < "$MERGE_FILE"
54+
4255
# Check if a file is ignored.
4356
is_ignored() {
4457
local file=${1}
@@ -56,13 +69,24 @@ is_ignored() {
5669
return 1
5770
}
5871

72+
is_merge() {
73+
local file=${1}
74+
75+
for merged in "${MERGED_PATHS[@]}"; do
76+
if [[ -n "$merged" && "$file" =~ $merged ]]; then
77+
return 0
78+
fi
79+
done
80+
return 1
81+
}
82+
5983
# Navigate to the template directory
6084
cd "${TEMPLATE_REPO_DIR}" || exit
6185
FILES_ADDED=()
6286
FILES_WITH_CHANGES=()
6387

6488
# Loop through all files in the template directory
65-
while IFS= read -r -d '' file; do
89+
while IFS= read -r -d '' file || [[ -n $file ]]; do
6690
relative_path="${file#./}" # Remove leading './'
6791

6892
# Check if the file is ignored
@@ -84,27 +108,38 @@ while IFS= read -r -d '' file; do
84108
# If the file exists, check if it's different
85109
if [ "$new_only" == false ]; then
86110
if ! diff -q "$file" "$target_path" > /dev/null 2>&1; then
87-
echo "Merging changes from $relative_path"
88-
FILES_WITH_CHANGES+=("${relative_path}")
89-
cp "$file" "$target_path"
111+
if is_merge "$relative_path"; then
112+
echo "Merging changes from $relative_path"
113+
cp "$target_path" "${target_path}.bak"
114+
node "${scriptdir}/../maintenance/merge.js" "$target_path" "$file" > "${target_path}.merged"
115+
if ! cmp -s "${target_path}.merged" "${target_path}.bak"; then
116+
FILES_WITH_CHANGES+=("${relative_path}")
117+
mv "${target_path}.merged" "$target_path"
118+
fi
119+
rm -f "${target_path}.merged" "${target_path}.bak"
120+
else
121+
echo "Copying changes from $relative_path"
122+
cp "$file" "$target_path"
123+
FILES_WITH_CHANGES+=("${relative_path}")
124+
fi
90125
fi
91126
fi
92127
fi
93128
done < <(find . -type f -print0)
94129

95-
echo "${#FILES_ADDED[@]}" files added, "${#FILES_WITH_CHANGES[@]}" files with changes detected.
96-
97130
echo ------------------------------------------
131+
echo "${#FILES_ADDED[@]} files added, ${#FILES_WITH_CHANGES[@]} files with changes detected."
98132

99-
if [ "$changes_only" == false ]; then
133+
if [[ "$changes_only" == false && ${#FILES_ADDED[@]} -gt 0 ]]; then
100134
echo ------------------------------------------
101135
echo "New files added:"
102136
printf ' - %s\n' "${FILES_ADDED[@]}"
103137
fi
104138

105-
106-
if [ "$new_only" == false ]; then
139+
if [[ "$new_only" == false && ${#FILES_WITH_CHANGES[@]} -gt 0 ]]; then
107140
echo ------------------------------------------
108141
echo "Changed files:"
109142
printf ' - %s\n' "${FILES_WITH_CHANGES[@]}"
110143
fi
144+
145+
echo ------------------------------------------

scripts/maintenance/merge.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*******************************************************************************
2+
* Script to merge all added lines from source to target.
3+
* Modified lines will be left intact.
4+
*
5+
* This is intended for updating config files like .tool-versions and .gitignore
6+
* where the first token on the line remains the same
7+
*
8+
* Usage:
9+
* $ node merge.js <target> <source>
10+
*
11+
* Output:
12+
* Outputs the merged file to stdout
13+
*
14+
*******************************************************************************/
15+
16+
const fs = require("fs");
17+
18+
// Read files
19+
const [file1, file2] = process.argv.slice(2);
20+
const lines1 = fs.readFileSync(file1).toString().split('\n');
21+
const lines2 = fs.readFileSync(file2).toString().split('\n');
22+
23+
// Tokenize lines in file1 for later comparison
24+
const tokenize = line => {
25+
if (line === '') {
26+
return [];
27+
}
28+
return line.split(/\s+/).filter(x => x !== '#').slice(0, 1);
29+
};
30+
const lines1Tokens = lines1.flatMap(tokenize);
31+
32+
// Step through the files
33+
let pos1 = 0, pos2 = 0;
34+
while (pos1 < lines1.length || pos2 < lines2.length) {
35+
36+
const l1 = pos1 < lines1.length && lines1[pos1] || '';
37+
const l2 = pos2 < lines2.length && lines2[pos2] || '';
38+
39+
// If the lines match, print l1 and skip l2
40+
if (l1 !== '' && l1 === l2) {
41+
process.stdout.write(`${l1}\n`);
42+
pos1++;
43+
pos2++;
44+
continue;
45+
}
46+
47+
if (pos2 < lines2.length) {
48+
// If l2 is empty, skip l2
49+
if (l2 === '') {
50+
pos2++;
51+
continue;
52+
}
53+
54+
const [l2token] = tokenize(l2);
55+
56+
// If l2 token matches l1 token, print l1
57+
if (pos1 < lines1.length && lines1Tokens[pos1] === l2token) {
58+
process.stdout.write(`${l1}\n`);
59+
pos1++;
60+
pos2++;
61+
continue;
62+
}
63+
64+
// If l2 doesn't match any lines in file1, print l2
65+
if (l2token && !lines1Tokens.includes(l2token)) {
66+
process.stdout.write(`${l2}\n`);
67+
}
68+
pos2++
69+
continue;
70+
}
71+
72+
// If we're not at the end of file1, print l1
73+
if (pos1 < lines1.length) {
74+
if (pos1 === lines1.length - 1 && l1 === '') {
75+
// Don't print tailing newline
76+
} else {
77+
process.stdout.write(`${l1}\n`);
78+
}
79+
pos1++;
80+
}
81+
}

0 commit comments

Comments
 (0)