diff --git a/runner/main/jobtypes/phpunit/phpunit.sh b/runner/main/jobtypes/phpunit/phpunit.sh index ac24bc8..8249506 100644 --- a/runner/main/jobtypes/phpunit/phpunit.sh +++ b/runner/main/jobtypes/phpunit/phpunit.sh @@ -62,6 +62,10 @@ function phpunit_to_summary() { echo "== PHPUNIT_FILTER: ${PHPUNIT_FILTER}" echo "== PHPUNIT_TESTSUITE: ${PHPUNIT_TESTSUITE}" echo "== MOODLE_CONFIG: ${MOODLE_CONFIG}" + if [[ -n "${GOOD_COMMIT}" ]] || [[ -n "${BAD_COMMIT}" ]]; then + echo "== GOOD_COMMIT: ${GOOD_COMMIT}" + echo "== BAD_COMMIT: ${BAD_COMMIT}" + fi } # This job type defines the following env variables @@ -106,7 +110,7 @@ function phpunit_check() { verify_modules $(phpunit_modules) # These env variables must be set for the job to work. - verify_env UUID ENVIROPATH WEBSERVER + verify_env UUID ENVIROPATH WEBSERVER GOOD_COMMIT BAD_COMMIT } # PHPUnit job type init. @@ -116,23 +120,62 @@ function phpunit_config() { PHPUNIT_FILTER="${PHPUNIT_FILTER:-}" PHPUNIT_TESTSUITE="${PHPUNIT_TESTSUITE:-}" EXITCODE=0 + + # If GOOD_COMMIT and BAD_COMMIT are set, it means that we are going to run a bisect + # session, so we need to enable FULLGIT (to get access to complete repository clone). + if [[ -n "${GOOD_COMMIT}" ]] && [[ -n "${BAD_COMMIT}" ]]; then + FULLGIT="yes" + # Also, we don't want to allow repetitions in the bisect session. + RUNCOUNT=1 + fi } # PHPUnit job type setup. function phpunit_setup() { + # If one of GOOD_COMMIT or BAD_COMMIT are not set, but the other is, error out. + if [[ -n "${GOOD_COMMIT}" ]] && [[ -z "${BAD_COMMIT}" ]]; then + exit_error "GOOD_COMMIT is set but BAD_COMMIT is not set." + fi + if [[ -z "${GOOD_COMMIT}" ]] && [[ -n "${BAD_COMMIT}" ]]; then + exit_error "BAD_COMMIT is set but GOOD_COMMIT is not set." + fi + # If both GOOD_COMMIT and BAD_COMMIT are set and they are the same, error out. + if [[ -n "${GOOD_COMMIT}" ]] && [[ -n "${BAD_COMMIT}" ]] && [[ "${GOOD_COMMIT}" == "${BAD_COMMIT}" ]]; then + exit_error "GOOD_COMMIT and BAD_COMMIT are set, but they are the same." + fi + + # If both GOOD_COMMIT and BAD_COMMIT are not set, we are going to run a normal session. + # (for bisect sessions we don't have to setup the environment). + if [[ -z "${GOOD_COMMIT}" ]] && [[ -z "${BAD_COMMIT}" ]]; then + phpunit_setup_normal + fi +} + +# PHPUnit job type setup for normal mode. +function phpunit_setup_normal() { # Init the PHPUnit site. echo echo ">>> startsection Initialising PHPUnit environment at $(date)<<<" echo "============================================================================" docker exec -t -u www-data "${WEBSERVER}" \ - php admin/tool/phpunit/cli/init.php \ - --force + php admin/tool/phpunit/cli/init.php echo "============================================================================" echo ">>> stopsection <<<" } # PHPUnit job type run. function phpunit_run() { + # If both GOOD_COMMIT and BAD_COMMIT are not set, we are going to run a normal session. + if [[ -z "${GOOD_COMMIT}" ]] && [[ -z "${BAD_COMMIT}" ]]; then + phpunit_run_normal + else + # If GOOD_COMMIT and BAD_COMMIT are set, we are going to run a bisect session. + phpunit_run_bisect + fi +} + +# PHPUnit job tye run for normal mode. +function phpunit_run_normal() { # Run the job type. echo if [[ RUNCOUNT -gt 1 ]]; then @@ -163,11 +206,66 @@ function phpunit_run() { while [[ ${iter} -le ${RUNCOUNT} ]]; do echo echo ">>> PHPUnit run ${iter} at $(date) <<<" - docker exec -t "${WEBSERVER}" "${cmd[@]}" + docker exec -t -u www-data "${WEBSERVER}" "${cmd[@]}" EXITCODE=$((EXITCODE + $?)) iter=$((iter+1)) done echo "============================================================================" echo ">>> stopsection <<<" -} \ No newline at end of file +} + +# PHPUnit job tye run for bisect mode. +function phpunit_run_bisect() { + # Run the job type. + echo + echo ">>> startsection Starting PHPUnit bisect session at $(date) <<<" + echo "=== Good commit: ${GOOD_COMMIT}" + echo "=== Bad commit: ${BAD_COMMIT}" + echo "============================================================================" + # Start the bisect session. + docker exec -t -u www-data "${WEBSERVER}" \ + git bisect start "${BAD_COMMIT}" "${GOOD_COMMIT}" + + # Build the int command. + local initcmd=( + php admin/tool/phpunit/cli/init.php + ) + # Build the run command. + local runcmd=( + php vendor/bin/phpunit + --disallow-test-output + --fail-on-risky + --verbose + ) + if [[ -n "${PHPUNIT_FILTER}" ]]; then + runcmd+=(--filter "${PHPUNIT_FILTER}") + fi + if [[ -n "${PHPUNIT_TESTSUITE}" ]]; then + runcmd+=(--testsuite "${PHPUNIT_TESTSUITE}") + fi + + # Generate the bisect.sh script that we are going to use to run the phpunit bisect session. + # (it runs both init and run commands together). + docker exec -i -u www-data "${WEBSERVER}" \ + bash -c "cat > bisect.sh" <<- EOF + #!/bin/bash + ${initcmd[*]} >/dev/null 2>&1; ${runcmd[*]} + exitcode=\$? + echo "============================================================================" + exit \$exitcode + EOF + + # Run the bisect session. + echo "============================================================================" + docker exec -u www-data "${WEBSERVER}" \ + git bisect run bash bisect.sh + EXITCODE=$? + + # Finish the bisect session. + docker exec -u www-data "${WEBSERVER}" \ + git bisect reset + + echo "============================================================================" + echo ">>> stopsection <<<" +} diff --git a/runner/main/modules/docker-php/docker-php.sh b/runner/main/modules/docker-php/docker-php.sh index 75e3d52..d438b79 100644 --- a/runner/main/modules/docker-php/docker-php.sh +++ b/runner/main/modules/docker-php/docker-php.sh @@ -58,6 +58,9 @@ function docker-php_setup() { -v "${SHAREDDIR}":/shared \ "${DOCKER_PHP}" + # Ensure that the whole .composer directory is writable to all (www-data needs to write there). + docker exec "${WEBSERVER}" chmod -R go+rw /var/www/.composer + echo echo "Webserver logs:" docker logs "${WEBSERVER}" diff --git a/runner/main/modules/git/git.sh b/runner/main/modules/git/git.sh index a2495eb..7ffeadf 100644 --- a/runner/main/modules/git/git.sh +++ b/runner/main/modules/git/git.sh @@ -21,6 +21,8 @@ function git_env() { env=( GIT_COMMIT + GOOD_COMMIT + BAD_COMMIT ) echo "${env[@]}" } diff --git a/runner/main/modules/moodle-core-copy/moodle-core-copy.sh b/runner/main/modules/moodle-core-copy/moodle-core-copy.sh index 1b774e3..c709637 100644 --- a/runner/main/modules/moodle-core-copy/moodle-core-copy.sh +++ b/runner/main/modules/moodle-core-copy/moodle-core-copy.sh @@ -74,7 +74,7 @@ function moodle-core-copy_setup() { fi # If the repository was cloned shallow (--depth), un-shallow it. - if (docker exec -u www-data "${WEBSERVER}" git rev-parse --is-shallow-repository); then + if (docker exec -u www-data "${WEBSERVER}" git rev-parse --is-shallow-repository | grep -q 'true'); then echo "== Unshallowing the repository." docker exec -u www-data "${WEBSERVER}" git fetch --unshallow fi @@ -91,17 +91,20 @@ function moodle-core-copy_setup() { # Copy the config.php in place echo "== Copying configuration in place." docker cp "${BASEDIR}/modules/docker-php/config.template.php" "${WEBSERVER}":/var/www/html/config.php + docker exec "${WEBSERVER}" chown -R www-data:www-data /var/www/html/config.php # Copy the plugins in place. if [[ -n "$PLUGINSTOINSTALL" ]]; then - echo "== Copying external plugins in place." - docker cp "${PLUGINSDIR}"/. "${WEBSERVER}":/var/www/html + echo "== Copying external plugins in place." + docker cp "${PLUGINSDIR}"/. "${WEBSERVER}":/var/www/html + docker exec "${WEBSERVER}" chown -R www-data:www-data /var/www/html fi # Copy composer-phar if available in caches. if [[ -f "${COMPOSERCACHE}/composer.phar" ]]; then - echo "== Copying composer.phar in place." - docker cp "${COMPOSERCACHE}/composer.phar" "${WEBSERVER}":/var/www/html/composer.phar + echo "== Copying composer.phar in place." + docker cp "${COMPOSERCACHE}/composer.phar" "${WEBSERVER}":/var/www/html/composer.phar + docker exec "${WEBSERVER}" chown -R www-data:www-data /var/www/html/composer.phar fi echo "============================================================================"