-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfunctions.inc.bash
More file actions
executable file
·432 lines (346 loc) · 12.2 KB
/
functions.inc.bash
File metadata and controls
executable file
·432 lines (346 loc) · 12.2 KB
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
#!/usr/bin/env bash
readonly platformGeneric="generic"
readonly platformSymfony="symfony"
function detectPlatform() {
if [[ -f $projectRoot/symfony.lock ]]; then
echo $platformSymfony
return 0
fi
echo $platformGeneric
}
################################################################
# Run a tool
# First check for a project qaConfig tool override
# Then a platform tool
# finally the Generic tool
function runTool() {
local tool="$1"
local projectOverridePath="$projectConfigPath/tools/$tool.inc.bash"
local platformPath="$DIR/../includes/$platform/$tool.inc.bash"
local genericPath="$DIR/../includes/generic/$tool.inc.bash"
if [[ -f "$projectOverridePath" ]]; then
echo "Running Project Override $tool"
source "$projectOverridePath"
return 0
elif [[ -f "$platformPath" ]]; then
echo "Running $platform $tool"
source "$platformPath"
return 0
fi
echo "Running generic $tool"
source "$genericPath"
}
# This is very much like run tool
# It will check for a project level override
# Then it will run the generic tool explicitly
function runNonPlatformTool() {
local tool="$1"
local projectOverridePath="$projectConfigPath/tools/$tool.inc.bash"
local genericPath="$DIR/../includes/generic/$tool.inc.bash"
if [[ -f "$projectOverridePath" ]]; then
echo "Running Project Override $tool"
source "$projectOverridePath"
return 0
fi
echo "Running generic $tool"
source "$genericPath"
}
################################################################
# Get the path for a config file
# Config file will be search for in:
# A qaConfig folder in the project root
# The phpqa library's configDefaults/{platform}
# The phpqa library's configDefaults/generic
#
# Usage:
#
# `configPath "relative/path/to/file/or/folder"
function configPath() {
local relativePath="$1"
local platformPath="$defaultConfigPath/$platform/$relativePath"
local genericPath="$defaultConfigPath/generic/$relativePath"
# -e FILE - True if the FILE exists and is a file, regardless of type
if [[ -e $projectConfigPath/$relativePath ]]; then
echo $projectConfigPath/$relativePath
elif [[ -e $platformPath ]]; then
echo $platformPath
else
echo $genericPath
fi
}
###############################################################
# Function to run PHP without Xdebug enabled, much faster
# Applies global memory limit (phpqaMemoryLimit) by default
# Usage:
# `phpNoXdebug path/to/php/file.php -- -arg1 -arg2`
# Note: Tool-specific memory limits can override by passing -d memory_limit=X
# (last -d wins in PHP)
function phpNoXdebug() {
if [[ ! -f ${noXdebugConfigPath} ]]; then
# Using awk to ensure that files ending without newlines do not lead to configuration error
${phpBinPath} -i | grep "\.ini" | grep -o -e '\(/[a-z0-9._-]\+\)\+\.ini' | grep -v xdebug | xargs awk 'FNR==1{print ""}1' >"$noXdebugConfigPath"
fi
set -x
# Apply global memory limit (can be overridden with explicit -d memory_limit=X after this)
${phpBinPath} -n -c "$noXdebugConfigPath" -d memory_limit=${phpqaMemoryLimit:-4G} "$@"
local exitCode=$?
set +x
echo
return $exitCode
}
###############################################################
# Function to check there are no uncommitted changes.
#
# This will also prompt you to commit these changes if you want to.
#
# Usage:
# checkForUncommitedChanges
function checkForUncommittedChanges() {
if [[ "false" != "${CI:-'false'}" ]]; then
echo "Skipping uncommited changes check in CI"
return 0
fi
if [[ "$skipUncommittedChangesCheck" == "1" ]]; then
echo "Skipping uncommitted changes check. export skipUncommittedChangesCheck=0 to reinstate"
return 0
fi
targetDir=${1:-$(pwd)}
originalDir=$(pwd)
if [[ ! -d $targetDir/.git/ ]]; then
echo "$targetDir is not a git repo"
return
fi
cd $targetDir
set +e
inGitRepo="$(git rev-parse --is-inside-work-tree 2>/dev/null)"
if [[ "" != "$inGitRepo" ]]; then
git status | grep -Eq "nothing to commit, working .*? clean"
repoDirty=$?
set -e
if (($repoDirty > 0)); then
git status
echo "
==================================================
Untracked or Uncommited changes detected
Would you like to commit (c) or abort (a)
(git commit will be 'git add -A; git commit')
Alternatively you can skip (s), but please be aware that from this point on, your code is going to be
actively changed and not having a git commit to restore to could cause you significant pain.
You have been warned.
To always skip, you can export skipUncommittedChangesCheck=1
==================================================
"
read -n 1 commitOrAbort
case "$commitOrAbort" in
s)
echo "Skipping"
return 0
;;
c)
git add -A
git commit
;;
*)
printf "\n\n\nAborting...\n\n\n"
exit 1
;;
esac
fi
fi
cd $originalDir
}
function phpunitReRunFailedOrFull() {
if [[ "false" != "${CI:-'false'}" ]]; then
return 0
fi
local rerunFailed
local reunLogFileTimeLimit=${phpunitRerunTimeoutMins:-5}
local rerunLogFile="$(find $varDir -type f -name 'phpunit.junit.xml' -mmin -$reunLogFileTimeLimit)"
if [[ "" == "$rerunLogFile" ]]; then
echo ""
return 1
fi
echo "
==================================================
PHPUnit Run detected from less than $reunLogFileTimeLimit mins ago
Would you like to just rerun failed tests?
(will timeout and run full in 10 seconds)
==================================================
"
set +e
read -t 10 -n 1 rerunFailed
set -e
if [[ "y" != "$rerunFailed" ]]; then
printf "\n\nRunning Full...\n\n"
return 1
fi
printf "\n\nRerunning Failed Only\n\n"
return 0
}
function tryAgainOrAbort() {
toolname="$1"
if [[ "false" != "${CI:-'false'}" ]]; then
echo "
==================================================
$toolname Failed...
==================================================
"
exit 1
fi
echo "
==================================================
$toolname Failed...
would you like to try again? (y/n)
(note: if you change config files, you might have to run from the top for it to take effect...)
==================================================
"
while read -n 1 tryAgainOrAbort; do
if [[ "n" == "$tryAgainOrAbort" ]]; then
printf "\n\nAborting...\n\n"
exit 1
fi
if [[ "y" == "$tryAgainOrAbort" ]]; then
break
fi
printf "\n\ninvalid choice: $tryAgainOrAbort - should be y or n \n\n would you like to try again? (y/n)"
done
printf "\n\nTrying again, good luck!\n\n"
hasBeenRestarted="true"
}
function findTestsDir() {
testsDir="$(find $projectRoot -maxdepth 1 -type d \( -name test -o -name tests \) | head -n1)"
if [[ "" == "$testsDir" ]]; then
echo "
##### ERROR ############################################
You have no 'tests' or 'test' directory.
This is not currently supported by phpqa
Please create at least an empty 'tests' directory, eg:
mkdir -p $projectRoot/tests
########################################################
" 1>&2
exit 1
fi
echo "$testsDir"
}
function findSrcDir() {
srcDir="$projectRoot/src"
if [[ "" == "$srcDir" ]]; then
echo "
##### ERROR ############################################
You have no 'src' or directory.
This is not currently supported by phpqa
Please create at least an empty 'src' directory, eg:
mkdir -p $projectRoot/src
########################################################
" 1>&2
exit 1
fi
echo "$srcDir"
}
function findBinDir() {
binDir="$(cd $projectRoot && composer config bin-dir)"
if [[ "" == "$binDir" ]]; then
echo "
##### ERROR ############################################
You have no 'bin' or directory.
This is not currently supported by phpqa
Please create at least an empty 'bin' directory, eg:
mkdir -p $projectRoot/bin
########################################################
" 1>&2
exit 1
fi
echo "$binDir"
}
###############################################################
# Archive and rotate QA tool log files with retention policy
#
# This function provides standardized log rotation for QA tools:
# - Archives current log with timestamp
# - Separates full suite runs from path-specific runs
# - Keeps last 10 logs per pattern (full suite + each unique path)
# - Warns when total logs exceed 100 files
#
# Usage:
# archiveToolLog "toolname" "$logDir" "logfile.ext" "$specifiedPath" "${pathsToCheck[@]}"
#
# Parameters:
# $1 - toolName: Name of the tool (e.g., "phpunit", "phpstan")
# $2 - logDir: Directory where logs are stored
# $3 - logFileName: Base name of the log file (e.g., "phpunit.junit.xml")
# $4 - specifiedPath: Non-empty if -p flag was used
# $5+ - pathsToCheck: Array of paths that were checked
#
# Examples:
# # Full suite run
# archiveToolLog "phpunit" "$varDir/phpunit_logs" "phpunit.junit.xml" "" "${pathsToCheck[@]}"
# # Creates: phpunit.junit.YYYYMMDD-HHMMSS.xml
#
# # Path-specific run
# archiveToolLog "phpstan" "$varDir/phpstan_logs" "phpstan.json" "1" "src/Entity tests/Unit"
# # Creates: phpstan.json.src_Entity_tests_Unit.YYYYMMDD-HHMMSS.xml
function archiveToolLog() {
local toolName="$1"
local logDir="$2"
local logFileName="$3"
local specifiedPath="$4"
shift 4
local pathsToCheck=("$@")
local logFilePath="$logDir/$logFileName"
# Only archive if log file exists
if [[ ! -f "$logFilePath" ]]; then
return 0
fi
local timestamp=$(date +"%Y%m%d-%H%M%S")
local baseFileName="${logFileName%.*}" # Remove extension
local extension="${logFileName##*.}" # Get extension
# Determine log file naming based on whether specific paths were specified
if [[ -n "$specifiedPath" ]]; then
# Path-specific run - generate suffix from paths
local pathSuffix=$(echo "${pathsToCheck[*]}" | tr -cs '[:alnum:]' '_' | sed 's/^_//; s/_$//')
local archivedLog="$logDir/${baseFileName}.${pathSuffix}.${timestamp}.${extension}"
local runType="Path-specific run: ${pathsToCheck[*]}"
# Match only logs for this specific path suffix
local archivedLogs=($(ls -1t "$logDir"/${baseFileName}.*.${extension} 2>/dev/null | grep "${baseFileName}\\.${pathSuffix}\\."))
else
# Full suite run
local archivedLog="$logDir/${baseFileName}.${timestamp}.${extension}"
local runType="Full test suite run"
# Match only full suite logs (timestamp directly after base name)
local archivedLogs=($(ls -1t "$logDir"/${baseFileName}.*.${extension} 2>/dev/null | grep -E "${baseFileName}\\.[0-9]{8}-[0-9]{6}\\.${extension}$"))
fi
# Archive with clear messaging
mv "$logFilePath" "$archivedLog"
echo "${runType}"
echo "Log: $(basename "$archivedLog")"
# Keep only last 10 logs matching this pattern
local numLogs=${#archivedLogs[@]}
if (( numLogs > 10 )); then
for ((i=10; i<numLogs; i++)); do
rm -f "${archivedLogs[$i]}"
done
echo "Cleaned up $((numLogs - 10)) old log(s)"
fi
# Check total log count across all patterns and warn if > 100
# Use a marker file to track if we've already warned for this logDir in this run
local warnMarkerFile="$logDir/.warned_high_count_$$"
local totalLogs=$(find "$logDir" -name "*.${extension}" -type f 2>/dev/null | wc -l)
if (( totalLogs > 100 )) && [[ ! -f "$warnMarkerFile" ]]; then
# Create marker to prevent duplicate warnings
touch "$warnMarkerFile"
echo ""
echo "=========================================="
echo "WARNING: HIGH LOG FILE COUNT"
echo "=========================================="
echo "Total log files in $logDir: $totalLogs"
echo ""
echo "Consider manual cleanup of old logs:"
echo " ls -lht $logDir | less"
echo ""
echo "To remove logs for specific paths:"
echo " rm $logDir/${baseFileName}.PATH_PATTERN.*.${extension}"
echo ""
echo "Retention: 10 per pattern (full suite + each -p path)"
echo "=========================================="
fi
}