Something went wrong on our end
-
Vincent Hatakeyama authoredVincent Hatakeyama authored
odoo_scripts_common 12.25 KiB
#!/bin/zsh
# vim: set shiftwidth=2 softtabstop=2:
#
# Common functions and env var.
#
# This file is meant to be sourced.
# assume we are called from the project home
project_home=$PWD
project_name=$(basename "$project_home")
if ! type python3 > /dev/null; then
python="python2"
else
python="python3"
fi
# handy colorized variables
esc=$(printf '\033')
RESET="${esc}[0m"
DEBUG="[${esc}[36mDEBUG${RESET}]"
INFO="[${esc}[34mINFO ${RESET}]"
WARN="[${esc}[33mWARN ${RESET}]"
FATAL="[${esc}[41m${esc}[37mFATAL${RESET}]"
GREEN="${esc}[32m"
OK="[${GREEN} OK${RESET} ]"
RED="${esc}[31m"
KO="[${esc}[41m${esc}[37m KO ${RESET}]"
WHITE_BOLD="${esc}[1;37m"
function read_configuration_key () {
# Read a configuration key from any ini file
# first argument is file path
# second argument is section
# third argument is the key to use
# fourth argument is default value, if any
# fifth argument is separator, default to a space
file=$1
section=$2
configuration_key=$3
default_value=$4
separator=${5- }
echo $($python -B -c "from six.moves import configparser ; c = configparser.ConfigParser() ; c.read('${file}') ; print('$separator'.join(c.get('$section', '$configuration_key').split()) if c.has_option('$section', '$configuration_key') else '$default_value')")
}
function read_odoo_scripts_configuration_key () {
# Return configuration value from odoo_scripts configuration file
# first argument is the key to use
# second argument is default value, if any
configuration_key=${1}
default_value=$2
read_configuration_key "${project_home}/setup.cfg" odoo_scripts $configuration_key $default_value
}
function read_odoo_scripts_expandable_configuration_key () {
# return configuration value by appending any expanded values from defined super projects. glob key as appropriate, for module for example.
# first argument is the key to use
# second optional argument is the separator to use (default to comma)
configuration_key=${1}
separator=${2-,}
# read expanded configurations, only done with projects in python 3
if type python3 > /dev/null; then
configuration_value=$(python3 -B -c "from odoo_scripts.config import Configuration ; c = Configuration('$project_home') ; print('$separator'.join(c.$configuration_key))")
else
# read only local values
configuration_value=$($python -B -c "from six.moves import configparser ; import os ; c = configparser.ConfigParser() ; c.read(os.path.join('$project_home', 'setup.cfg')) ; print('$separator'.join(c.get('odoo_scripts', '$configuration_key').split() if c.has_option('odoo_scripts', '$configuration_key') else []))")
if [[ $configuration_key == modules ]]; then
configuration_value=$($python -B -c "import os;from glob import glob;print('$separator'.join([file for path in '${configuration_value}'.split('$separator') for file in glob(path) if os.path.isdir(file)]))")
fi
fi
echo $configuration_value
}
# function to be used in pipes
function colorize () {
cat | sed -E \
-e "s/(.*) (TEST) (.*) (ERROR)(.*)/${esc}[2m\1${esc}[22m ${esc}[34m${esc}[7m\2${esc}[27m \3${esc}[0m ${esc}[41m${esc}[97m${esc}[1m\4${esc}[49m${esc}[31m\5${esc}[0m/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (TEST) ([^ ]+) ([^:]+:) (OK)?(.*)/\1 ${esc}[2m\2${esc}[22m ${esc}[36m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;39m\5 ${esc}[36m${esc}[7m\6${esc}[27m${esc}[39m${esc}[36m\7$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (INFO) ([^ ]+) (odoo\.addons\.[^:]*\.tests\.[^:]*:) (Starting .*)/\1 ${esc}[2m\2${esc}[22m ${esc}[36m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;39m\5 ${esc}[36m\6$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (INFO) ([^ ]+) (odoo\.(tests\.(runner|result|stats)|modules\.module):) (.*)/\1 ${esc}[2m\2${esc}[22m ${esc}[36m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;39m\5 ${esc}[36m\8$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (INFO) ([^ ]+) (o(doo|penerp)\.(modules\.loading|tools\.translate)|openerp\.addons\.base\.ir\.ir_translation|odoo\.addons\.base\.models\.ir_module): (.*)/\1 ${esc}[2m\2${esc}[22m ${esc}[32m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;22m\5: ${esc}[38;5;64m\8$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (INFO) ([^ ]+) ([^:]*:) (=+)/\1 ${esc}[2m\2${esc}[22m ${esc}[32m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;28m\5 ${esc}[31m\6$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (INFO) ([^ ]+) ([^:]*:)( ?[^=].*)/\1 ${esc}[2m\2${esc}[22m ${esc}[32m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;28m\5${esc}[32m\6$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (DEBUG) ([^ ]+) ([^:]*:) (.*)/\1 ${esc}[2m\2${esc}[22m ${esc}[34m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;24m\5 ${esc}[34m\6$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (WARNING) ([^ ]+) ([^:]*:) (.*)/\1 ${esc}[2m\2${esc}[22m ${esc}[33m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;94m\5 ${esc}[33m\6$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (ERROR) ([^ ]+) (odoo\.(tests\.(runner|result|stats)|modules\.module):) (FAIL)?(.*)/\1 ${esc}[2m\2${esc}[22m ${esc}[35m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;88m\5 ${esc}[35m${esc}[7m\8${esc}[27m\9$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (ERROR) ([^ ]+) ([^:]*:) (FAIL)?(.*)/\1 ${esc}[2m\2${esc}[22m ${esc}[31m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[38;5;88m\5 ${esc}[31m${esc}[7m\6${esc}[27m\7$RESET/" \
-e "s/^([[:digit:]]{4,}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2},[[:digit:]]{3}) ([[:digit:]]+) (CRITICAL) ([^ ]+) ([^:]*:) (.*)/\1 ${esc}[2m\2${esc}[22m ${esc}[1;31m${esc}[7m\3${esc}[0m ${esc}[2m\4${esc}[22m ${esc}[31m\5 ${esc}[1;31m\6$RESET/" \
-e "s/ FAILED/ ${esc}[41m${esc}[97m${esc}[1mFAILED${esc}[0m/" \
}
# The analyze method does several things:
# - print a resume of failure, errors and passes
# - create a metrics file with the number of tests (when the CI environment variable equals true)
# - return an error code based on the parsing of the log file. This is meant to be used on Odoo that did not exit with
# a non-zero value when tests fail.
# The method takes the logfile as its only argument.
function analyze () {
logfile=$1
# Odoo >= 14 detection
# Odoo 17 uses odoo.tests.result rather than odoo.tests.runner
if [ $(grep -P 'odoo\.tests\.(runner|result): ([[:digit:]]+) failed, [[:digit:]]+ error\(s\) of [[:digit:]]+ tests when loading database' $logfile --count) -gt 0 ];
then
# Valid with odoo 14, 15, 16, 17
# Add junit tests results to qunit tests results
tests_ran=$(grep -P 'odoo\.tests\.(runner|result): ([[:digit:]]+) failed, [[:digit:]]+ error\(s\) of \K[[:digit:]]+' $logfile -o)
quilt_tests_ran=$(grep -P ': ([[:digit:]]+) / [[:digit:]]+ tests failed.' $logfile --only-matching | sed -n "s,: [^ ]* / \([^ ]\),\1,p" | perl -ne '$sum += $_ } { print $sum')
tests_failures=$(grep -P 'odoo\.tests\.(runner|result): \K([[:digit:]]+)' $logfile --only-matching)
quilt_tests_failures=$(grep -P ': ([[:digit:]]+) / [[:digit:]]+ tests failed.' $logfile --only-matching | sed -n "s,: \([^ ]*\) /.*,\1,p" | perl -ne '$sum += $_ } { print $sum')
tests_errors=$(grep -P 'odoo\.tests\.(runner|result): ([[:digit:]]+) failed, \K[[:digit:]]+' $logfile -o)
import_errors_number=0
else
# Valid with odoo 7, 11, 13
tests_ran=$(grep -P 'o(penerp|doo).(modules.module|[^ ]+): Ran \K([[:digit:]]+)' $logfile -o | perl -ne '$sum += $_ } { print $sum')
if [ -z "$tests_ran" ];
then
tests_ran=0
fi
tests_failures=$(grep -P 'o(penerp|doo).(modules.module|[^ ]+): Module [a-zA-Z0-9._-]+: \K([[:digit:]]+)' $logfile -o | perl -ne '$sum += $_ } { print $sum')
# that might be doable in the perl above
if [ -z "$tests_failures" ];
then
tests_failures=0
fi
tests_errors=$(grep -P 'o(penerp|doo).(modules.module|[^ ]+): Module [a-z0-9_]+: [[:digit:]]+ failures, \K([[:digit:]]+)' $logfile -o | perl -ne '$sum += $_ } { print $sum')
if [ -z "$tests_errors" ];
then
tests_errors=0
fi
import_errors=$(grep -P 'o(penerp|doo).(modules.module|[^ ]+): Can not `import [a-z0-9_]+`.' $logfile)
import_errors_number=$(grep -P 'o(penerp|doo).(modules.module|[^ ]+): Can not `import [a-z0-9_]+`.' $logfile -c)
if [[ "$import_errors_number" -ne 0 ]];
then
test_errors=$((test_errors+import_errors_number))
fi
fi
# create an OpenMetrics metrics file
if [ "$CI" = "true" ];
then
echo -e "odoo_scripts_tests_ran $tests_ran\nodoo_scripts_tests_failures $tests_failures\nodoo_scripts_tests_error $tests_error\n# EOF\n" > metrics
fi
if [ "$ODOO_TYPE" = 'odoo7' ] || [ "$ODOO_TYPE" = 'odoo8' ] || [ "$ODOO_TYPE" = 'odoo9' ] || [ "$ODOO_TYPE" = 'odoo10' ] || [ "$ODOO_TYPE" = 'odoo11' ];
then
ok=$(grep ' OK' $logfile -c)
else
ok=0
fi
# odoo 13 uses FAIL as the error message, in the form: FAIL: TestReorderingRule.test_reordering_rule
failed=$(grep ' FAIL\(ED\|:\)\| CRITICAL\| ERROR [^ ]* openerp.modules.module: Can not .import openerp\.addons\.\| TEST .* ERROR:\|Failed to initialize database\| ERROR \([[:alnum:]]\|_\)* .\+\.test_.\+ ERROR: \|invalid module names, ignored:' $logfile -c)
if [[ -n "$import_errors_number" ]];
then
failed=$((failed+$import_errors_number))
fi
warnings=$(grep ' WARNING ' $logfile -c)
# XXX Not sure this is needed anymore with the tests_failures/tests_errors detection
if [[ $failed -eq 0 ]];
then
# simple way to detect yaml failure
failed=$(grep 'o(penerp|doo).modules.loading: At least one test failed when loading the modules.' $logfile -c)
fi
echo ''
echo "${esc}[9m-----$RESET ${esc}[7m${esc}[1mTest results$RESET ${esc}[9m-----$RESET"
printf "$tests_failures failed, $tests_errors error(s) of $tests_ran tests"
if [ "$ODOO_TYPE" = 'odoo7' ] || [ "$ODOO_TYPE" = 'odoo8' ] || [ "$ODOO_TYPE" = 'odoo9' ] || [ "$ODOO_TYPE" = 'odoo10' ];
then
echo " ($ok modules passing)"
else
if [ "$ODOO_TYPE" = 'odoo11' ];
then
echo " ($ok test files passing)"
else
echo ''
fi
fi
echo ''
if [[ $failed -gt 0 ]];
then
echo -e "${RED}Failures${RESET}:"
# Highlight the failure matches in red (31).
GREP_COLORS='mt=0;31' grep "CRITICAL\|FAIL\(ED\|:\)" $logfile
GREP_COLORS='mt=0;31' grep --color=always "ERROR [^ ]* openerp\.tools\.yaml_import:" $logfile
GREP_COLORS='mt=0;31' grep --color=always "ERROR [^ ]* openerp.modules.module: Can not \`import openerp\.addons\..*\`" $logfile
# this one is for odoo 7
GREP_COLORS='mt=0;31' grep --color=always "TEST .* ERROR:" $logfile
# this one is for odoo 13 for tests that produces errors (failures are matched with FAIL: )
GREP_COLORS='mt=0;31' grep --color=always "ERROR [^ ]* .\+\.test_.\+ ERROR:" $logfile
GREP_COLORS='mt=0;31' grep --color=always "invalid module names, ignored" $logfile
if [[ -n "$import_errors" ]];
then
echo "$import_errors"
fi
fi
echo ''
if [[ $tests_failures -gt 0 ]] || [[ $tests_errors -gt 0 ]];
then
echo "$FATAL Tests failed (found failure and errors in Ran N failed/failures, M errors)"
return 42
fi
if [[ $failed -gt 0 ]];
then
echo "$FATAL Tests failed (found failure with grep)"
return 20
fi
if [[ "${FAIL_ON_WARNING:-False}" != "False" ]];
then
if [[ $warnings -gt 0 ]];
then
echo "$FATAL Tests failed ($warnings WARNING found)"
return 2
fi
fi
return 0
}
# Make ODOO_TYPE available to files that sources this file.
ODOO_TYPE=${ODOO_TYPE:-$(read_odoo_scripts_configuration_key odoo_type odoo8)}