-
Notifications
You must be signed in to change notification settings - Fork 48
225 lines (191 loc) · 9.97 KB
/
versionCheck.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# - Github Version Control Checker
# - Watches changes on version-controlled contracts and makes sure that versions are bumped in case of relevant changes:
# - Relevant changes == anything except for changes of license identifier, solidity pragma of pure comment changes
# - watched paths: src/*
# - will check all modified or new contracts in watched paths
# - will fail if a new contract was added to watched paths without contract version
# - will fail if an existing contract was modified but version was not updated
# - will update the PR title to contain all contract names and their new versions (watched paths only)
name: Version Control Checker
on:
pull_request:
types: [opened, edited, synchronize, review_requested, ready_for_review]
jobs:
check-version:
# will only run once the PR is in "Ready for Review" state
if: ${{ github.event.pull_request.draft == false }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 ##### Fetch all history for all branches
- name: Get list of modified files by this PR
id: modified_files
run: |
BASE_REF="${{ github.event.pull_request.base.ref }}"
##### get all files modified by this PR
FILES=$(git diff --name-only origin/${BASE_REF} HEAD)
##### make sure that there are modified files
if [[ -z $FILES ]]; then
echo -e "\033[31mNo files found. This should not happen. Please check the code of the Github action\033[0m"
exit 1
fi
##### Initialize empty variables
CONTRACTS=""
##### go through all file paths and identify all files in src/ folder (version control is only active in this folder)
while IFS= read -r FILE; do
if echo "$FILE" | grep -E '^src/.*\.sol$'; then
CONTRACTS="${CONTRACTS}${FILE}"$'\n'
fi
done <<< "$FILES"
##### if none found, exit here as there is nothing to do
if [[ -z "$CONTRACTS" ]]; then
echo -e "\033[32mNo version-controlled contracts found in files modified/added by this PR.\033[0m"
echo -e "\033[32mNo further checks are required.\033[0m"
# set action output to false
echo "CONTINUE=false" >> $GITHUB_ENV
exit 0
else
# set action output to true
echo "CONTINUE=true" >> $GITHUB_ENV
fi
##### Write filenames to temporary files (using variables here was causing issues due to the file names)
echo -e "$CONTRACTS" > modified_contracts.txt
- name: Verify version updates on modified contracts
id: verify_version_changes
if: env.CONTINUE == 'true'
run: |
##### Read tmp file into variable
CONTRACTS=$(cat modified_contracts.txt)
##### Initialize variables
MISSING_VERSION_TAG=()
MISSING_VERSION_UPDATE=()
UPDATED_CONTRACTS=()
echo "--------------------"
##### Process each file separately
while IFS= read -r FILE; do
echo "Now checking contract: $FILE"
VERSION_TAG=$(grep -E '^/// @custom:version' "$FILE" || true)
VERSION=$(echo "$VERSION_TAG" | sed -E 's/^\/\/\/ @custom:version ([0-9]+\.[0-9]+\.[0-9]+).*$/\1/' || true)
##### Extract the filename without extension
FILENAME=$(basename "$FILE" .sol)
##### Check if a version tag exists in the contract file
if [[ -z "$VERSION_TAG" ]]; then
echo -e "\033[31mFile does not contain a version tag\033[0m"
MISSING_VERSION_TAG+=("$FILE")
else
echo -e "\033[32mFile contains a custom:version tag\033[0m"
##### get all changes of the current file/contract
DIFF_OUTPUT=$(git diff origin/${{ github.event.pull_request.base.ref }} HEAD "$FILE")
##### Check if the version was updated in this PR
if echo "$DIFF_OUTPUT" | grep -qE '^\+/// @custom:version'; then
echo -e "\033[32mFile version was updated in this PR to version $VERSION\033[0m"
NEW_VERSION=$(echo "$VERSION_TAG" | awk '{print $NF}')
TARGET_STRING="${FILENAME} v${NEW_VERSION}"
UPDATED_CONTRACTS+=("$TARGET_STRING")
else
##### Check if changes are relevant (ignore comments, formatting, pragma, license changes)
if echo "$DIFF_OUTPUT" | grep -qE '^\+\/\/\/|^\+pragma|^\+// SPDX-License-Identifier:'; then
echo -e "\033[32mChange is non-relevant (comments/formatting/pragma/license). No version update required.\033[0m"
else
##### add to files with missing version updates
echo -e "\033[31mThe file changed but the file version was not updated\033[0m"
MISSING_VERSION_UPDATE+=("$FILE")
fi
fi
fi
echo "--------------------"
done <<< "$CONTRACTS"
##### If any contract files are missing a version tag, this must be corrected before continuing
if [[ ${#MISSING_VERSION_TAG[@]} -ne 0 ]]; then
echo "--------------------"
echo ">>>>>>"
echo -e "\033[31mThe following files are missing a custom:version tag in their code:\033[0m"
echo "${MISSING_VERSION_TAG[*]}"
echo -e "\033[31mEvery version-controlled contract needs to have a custom:version tag in its code.\033[0m"
echo -e "\033[31mThis Github action cannot complete until these issues are solved.\033[0m"
exit 1
fi
##### if the version was not updated in any of the changed contracts, store the list of affected files in a tmp file
if [[ ${#MISSING_VERSION_UPDATE[@]} -ne 0 ]]; then
echo "--------------------"
echo ">>>>>>"
echo -e "\033[31mThe following contract(s) have been modified but their version tags were not updated:\033[0m"
echo "${MISSING_VERSION_UPDATE[*]}"
echo -e "\033[31mPlease make sure to update a contract's version whenever there are changes in the file.\033[0m"
echo -e "\033[31mThis Github action cannot complete until these issues are solved.\033[0m"
echo ""
exit 1
fi
##### store any contracts that were correctly updated in a tmp file so we can check the PR title after for each of those
if [[ ${#UPDATED_CONTRACTS[@]} -ne 0 ]]; then
##### create a string from the array with all contracts
UPDATED_CONTRACTS_STR=$(IFS=,; echo "${UPDATED_CONTRACTS[*]}")
echo "UPDATED_CONTRACTS=$UPDATED_CONTRACTS_STR" >> $GITHUB_ENV
echo -e "${UPDATED_CONTRACTS_STR[*]}" > updated_contracts.txt
else
echo -e "\033[32mDid not find any contracts for which version control is activated.\033[0m"
echo -e "\033[32mNo further checks are required.\033[0m"
echo "CONTINUE=false" >> $GITHUB_ENV
exit 0
fi
- name: Compose updated PR title
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
##### Read tmp files into variables
if [ -f updated_contracts.txt ]; then
UPDATED_CONTRACTS=$(cat updated_contracts.txt)
else
UPDATED_CONTRACTS=""
fi
echo "UPDATED CONTRACTS: $UPDATED_CONTRACTS"
##### Step 1: Remove everything in and including brackets from the current title
BASE_TITLE=$(echo "$PR_TITLE" | sed 's/\s*\[.*$//')
echo "BASE_TITLE: $BASE_TITLE"
##### Step 2: Trim whitespace from the base title
BASE_TITLE="$(echo -e "${BASE_TITLE}" | sed 's/[[:space:]]*$//')"
##### Step 3: Construct the new title if there are updated contracts
if [[ -n "$UPDATED_CONTRACTS" ]]; then
# Create new title with updated contracts
PR_TITLE_UPDATED="${BASE_TITLE} [${UPDATED_CONTRACTS}]"
else
# If no updated contracts, keep the title as the base title
PR_TITLE_UPDATED="$BASE_TITLE"
fi
##### Step 4: Trim whitespace from the updated title
PR_TITLE_UPDATED="$(echo -e "${PR_TITLE_UPDATED}" | sed 's/[[:space:]]*$//')"
##### Step 5: Log current and new titles and check if an update is needed
echo "Current PR Title: '$PR_TITLE'"
echo "New PR Title: '$PR_TITLE_UPDATED'"
if [[ "$PR_TITLE" != "$PR_TITLE_UPDATED" ]]; then
echo "Updating PR title from '$PR_TITLE' to '$PR_TITLE_UPDATED'."
echo "PR_TITLE_UPDATED=$PR_TITLE_UPDATED" >> $GITHUB_ENV
echo "CONTINUE=true" >> $GITHUB_ENV
else
echo -e "\033[32mNo PR title updates are required. This Github action will end here.\033[0m"
echo "CONTINUE=false" >> $GITHUB_ENV
exit 0
fi
- name: Update the PR title on GitHub
if: env.CONTINUE == 'true'
env:
GH_PAT: ${{ secrets.GIT_ACTIONS_BOT_PAT_CLASSIC }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_TITLE_UPDATED: ${{ env.PR_TITLE_UPDATED }}
run: |
##### unset the default git token (does not have sufficient rights to perform the update)
unset GITHUB_TOKEN
##### use the Personal Access Token to log into git CLI
echo $GH_PAT | gh auth login --with-token
if ! echo $GH_PAT | gh auth login --with-token; then
echo -e "\033[31mFailed to authenticate with GitHub. Git action cannot continue\033[0m"
exit 1
fi
##### update the PR title
if ! gh pr edit ${{ github.event.pull_request.number }} --title "${{ env.PR_TITLE_UPDATED }}"; then
echo "::error::Failed to update PR title"
echo -e "\033[31mFailed to update PR title. Git action cannot continue\033[0m"
exit 1
fi