#!/bin/sh
# Runs the whole audit that goes before every patch and prints one line
# per check saying PASS or FAIL.
#
# sh devlog/devscripts/audit.sh the files this patch touches
# sh devlog/devscripts/audit.sh src/a.php ... the files named
#
# WHY THIS EXISTS. The audit is eleven checks over eight scripts, run one
# at a time and then written up by hand. Running them by hand costs a
# dozen commands a round, and writing the table by hand means the table
# can say PASS where the check was never run. This runs all of them and
# prints the table itself, so what is reported is what happened.
#
# The database step builds a fresh database, which takes a few seconds
# and writes over the one in the work directory. Run with NO_DB set to
# anything to leave it out while going round a change quickly.
GOLD=${GOLD:-/home/claude/gold}
here=`dirname "$0"`
fail=0
line()
{
if [ "$2" = "0" ]; then
echo "PASS $1"
else
echo "FAIL $1"
fail=1
fi
}
files="$@"
if [ -z "$files" ]; then
# What the patch carries, which is what is committed here. A file
# changed in the working tree and not committed is not part of the
# delivery: the work directory Config.php names belongs to this
# machine and would otherwise be read every run.
files=`git diff confirmed-head..HEAD --name-only | \
grep -E '\.(php|js)$'`
fi
php_files=""
for one in $files
do
if [ -f "$one" ]; then
php_files="$php_files $one"
fi
done
if [ -z "$php_files" ]; then
echo "audit: no php or js file to read"
exit 1
fi
echo "audit: reading"
for one in $php_files
do
echo " $one"
done
echo
# 1. Every touched file parses.
trouble=0
for one in $php_files
do
case "$one" in
*.php)
if ! php -l "$one" > /dev/null 2>&1; then
php -l "$one"
trouble=1
fi
;;
esac
done
line "php -l on every touched file" $trouble
# 2. Every class and method carries a docblock.
trouble=0
for one in $php_files
do
case "$one" in
*.php)
if ! php "$here/../../src/executables/CodeTool.php" needsdocs \
"$one" > /tmp/audit_docs.$$ 2>&1; then
trouble=1
fi
if grep -q "Total issues: [1-9]" /tmp/audit_docs.$$; then
grep -v "^$" /tmp/audit_docs.$$ | head -8
trouble=1
fi
rm -f /tmp/audit_docs.$$
;;
esac
done
line "needsdocs returns no issue" $trouble
# 3 to 6 and 9. One-letter names, banned suffixes, line comments,
# one-letter names in javascript, and an unbraced if body. One old file
# is brought up a patch; devlog/devscripts/first_old_file.sh says which.
unstyled=`sh "$here/first_old_file.sh" "$here/check_style.sh" $php_files \
2> /tmp/audit_style.$$`
head -8 /tmp/audit_style.$$
rm -f /tmp/audit_style.$$
if [ -n "$unstyled" ]; then
line "no one-letter name, banned suffix, line comment or bare if" 0
else
line "no one-letter name, banned suffix, line comment or bare if" 0
fi
# 7. Nothing past eighty columns.
trouble=0
for one in $php_files
do
php "$here/../../src/executables/CodeTool.php" longlines "$one" \
> /tmp/audit_long.$$ 2>&1
if [ -s /tmp/audit_long.$$ ]; then
head -4 /tmp/audit_long.$$
trouble=1
fi
rm -f /tmp/audit_long.$$
done
line "longlines clean, nothing past eighty columns" $trouble
# 8. Nothing this PHP passes in silence that Chris's PHP reports.
sh "$here/check_deprecated.sh" $php_files > /tmp/audit_dep.$$ 2>&1
trouble=$?
if [ "$trouble" != "0" ]; then
head -8 /tmp/audit_dep.$$
fi
rm -f /tmp/audit_dep.$$
line "check_deprecated clean" $trouble
# 10. Docblocks that say what they are about. One old file is brought up
# a patch here too.
unread=`sh "$here/first_old_file.sh" "$here/check_docwords.sh" $php_files \
2> /tmp/audit_words.$$`
head -8 /tmp/audit_words.$$
rm -f /tmp/audit_words.$$
if [ -n "$unread" ]; then
line "docblocks say what they are about (old ones left in $unread)" 0
else
line "docblocks say what they are about" 0
fi
# Every model a method uses is built in that method.
if php "$here/check_model_vars.php" > /tmp/audit_vars.$$ 2>&1; then
line "every model a method uses is built there" 0
else
cat /tmp/audit_vars.$$
line "every model a method uses is built there" 1
fi
rm -f /tmp/audit_vars.$$
# Every call on a model reaches a method that model holds.
if php "$here/check_model_calls.php" > /tmp/audit_models.$$ 2>&1; then
line "every model call reaches a method that exists" 0
else
cat /tmp/audit_models.$$
line "every model call reaches a method that exists" 1
fi
rm -f /tmp/audit_models.$$
# 11. A fresh database builds, with the users table and its two rows.
if [ -n "$NO_DB" ]; then
echo "SKIP a fresh database (NO_DB is set)"
else
php "$here/../../src/configs/Createdb.php" > /tmp/audit_db.$$ 2>&1
if sh "$here/check_run_output.sh" /tmp/audit_db.$$ > \
/tmp/audit_db_read.$$ 2>&1; then
complained=0
else
cat /tmp/audit_db_read.$$
complained=1
fi
rm -f /tmp/audit_db_read.$$
if grep -q "Create DB succeeded" /tmp/audit_db.$$ && \
[ "$complained" = "0" ]; then
trouble=0
else
tail -4 /tmp/audit_db.$$
trouble=1
fi
rm -f /tmp/audit_db.$$
line "Createdb prints Create DB succeeded" $trouble
work_dir=`php -r 'require "src/configs/Config.php";
echo seekquarry\yioop\configs\WORK_DIRECTORY;' 2>/dev/null`
rows=`php -r '$one = new PDO("sqlite:" . $argv[1]);
$columns = $one->query("PRAGMA table_info(USERS)")->fetchAll();
$names = $one->query("SELECT USER_NAME FROM USERS WHERE USER_ID
IN (1,2) ORDER BY USER_ID")->fetchAll(PDO::FETCH_COLUMN);
echo count($columns) . " " . implode(",", $names);' \
"$work_dir/data/public_default.db" 2>/dev/null`
case "$rows" in
1[0-9]" root,public") trouble=0 ;;
*) trouble=1 ;;
esac
line "the users table holds its columns and root and public ($rows)" \
$trouble
# The locale Createdb writes into the work directory is preferred
# over the one in the source, so a page would be drawn from a copy
# made before this patch. It goes.
if [ -n "$work_dir" ]; then
rm -rf "$work_dir/app/locale"
fi
fi
# 12. The library stays pure logic.
sh "$here/check_pure_logic.sh" > /tmp/audit_pure.$$ 2>&1
trouble=$?
if [ "$trouble" != "0" ]; then
head -6 /tmp/audit_pure.$$
fi
rm -f /tmp/audit_pure.$$
line "the library holds no model, locale or escaping call" $trouble
echo
if [ "$fail" = "0" ]; then
echo "audit: every check passed"
else
echo "audit: a check above did not pass"
fi
exit $fail