diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48b8bf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor/ diff --git a/.travis.yml b/.travis.yml index 2aac67a..584735a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -146,6 +146,9 @@ env: - DRUPAL_TI_CACHE_DIRS_HOME=".composer|.drush|.dist" - DRUPAL_TI_CACHE_DIRS_TRAVIS_BUILD_DIR="tests/vendor|tests/behat/vendor" + # Enable code coverage on simpletest. + - DRUPAL_TI_SIMPLETEST_COVERAGE="1" + matrix: # Ensure that runners work isolated. #- DRUPAL_TI_RUNNERS="phpunit" DRUPAL_TI_ENVIRONMENT="drupal-7" diff --git a/.travis.yml.dist b/.travis.yml.dist index b5367d3..4a620ea 100644 --- a/.travis.yml.dist +++ b/.travis.yml.dist @@ -87,6 +87,32 @@ env: # etc. to only output those channels. #- DRUPAL_TI_DEBUG_FILE_OUTPUT="selenium xvfb webserver" + # Simpletest Coverage options + # Currently coveralls does not support the coverage report of simpletest. + # We developed a mechanism that will automatically analyze the coverage of + # your modules via the build-in coverage tool of simpletest. If you want to + # make use of this tool, make sure that you added simpletest in the list of + # runners. If you are planning to generate simpletest coverage reports, make + # sure that you read the GitHub section as well. + - DRUPAL_TI_SIMPLETEST_COVERAGE="1" + # Set to "1" if you want to enable the coverage report. + - DRUPAL_TI_SIMPLETEST_COVERAGE_GENERATE_BADGES="1" + # We have a script that will automatically generate a code coverage badge. + # If you set this value to "1" we will create a badge while generating the + # simpletest coverage report. + + # GitHub settings + # If you are planning to generate simpletest coverage reports, you will need + # to add some secured data to your .travis.yml file. This can be done by + # executing three commands. Make sure that you have a working GitHub + # token. (See https://help.github.com/articles/creating-an-access-token-for-command-line-use/) + # travis encrypt "DRUPAL_TI_GITHUB_EMAIL=[[ YOUR GITHUB E-MAIL ADDRESS ]]" + # --repo [[YOUR GITHUB USERNAME]]/[[YOUR REPOSITORY]] --add + # travis encrypt "DRUPAL_TI_GITHUB_NAME=[[ YOUR FULL NAME ]]" --repo + # [[YOUR GITHUB USERNAME]]/[[YOUR REPOSITORY]] --add + # travis encrypt "DRUPAL_TI_GITHUB_TOKEN=[[ YOUR GITHUB API TOKEN ]]" --repo + # [[YOUR GITHUB USERNAME]]/[[YOUR REPOSITORY]] --add + matrix: # [[[ SELECT ANY OR MORE OPTIONS ]]] #- DRUPAL_TI_RUNNERS="phpunit" diff --git a/functions/coverage.sh b/functions/coverage.sh new file mode 100644 index 0000000..97f9964 --- /dev/null +++ b/functions/coverage.sh @@ -0,0 +1,117 @@ +#!/bin/bash +# @file +# Common functionality for setting up simpletest code coverage + +# +# Ensure that phpcov is installed. +# +function drupal_ti_ensure_phpcov() { + if [ "$DRUPAL_TI_SIMPLETEST_COVERAGE" != "1" ] ; then return ; fi + + # This function is re-entrant. + if [ -r "$TRAVIS_BUILD_DIR/../drupal_ti-phpcov-installed" ] + then + return + fi + + ln -sf $HOME/drupal_ti/vendor/phpunit/phpcov/phpcov "$HOME/.composer/vendor/bin" + ln -sf $HOME/drupal_ti/vendor $DRUPAL_TI_DRUPAL_DIR/ + + cd "$DRUPAL_TI_DRUPAL_DIR" + wget https://www.drupal.org/files/issues/2189345-39.patch + wget https://gist.githubusercontent.com/legovaer/753c489c1f16dc162dc8d3a9a662c05a/raw/922c7ac2fde36079895c803c04d40bd132551fc8/add-phpcov-coverage.patch + git apply -v 2189345-39.patch + git apply -v add-phpcov-coverage.patch + + touch "$TRAVIS_BUILD_DIR/../drupal_ti-phpcov-installed" +} + +# +# We need to copy the module to the module folder. +# +function drupal_ti_simpletest_coverage_install_module() { + if [ "$DRUPAL_TI_SIMPLETEST_COVERAGE" != "1" ] ; then return ; fi + + # Load environment variables + drupal_ti_simpletest_coverage_vars + + drush pm-uninstall $DRUPAL_TI_MODULE_NAME -y + rm -rf "$DRUPAL_TI_DRUPAL_DIR/$DRUPAL_TI_MODULES_PATH/$DRUPAL_TI_MODULE_NAME" + cp -R "$DRUPAL_TI_TMP_MODULE_PATH" "$DRUPAL_TI_DRUPAL_DIR/$DRUPAL_TI_MODULES_PATH/$DRUPAL_TI_MODULE_NAME" + drush en $DRUPAL_TI_MODULE_NAME -y +} + +function drupal_ti_coverage_prepare() { + if [ "$DRUPAL_TI_SIMPLETEST_COVERAGE" != "1" ] ; then return ; fi + + # Load environment variables + drupal_ti_simpletest_coverage_vars + cp -R $TRAVIS_BUILD_DIR $DRUPAL_TI_TMP_MODULE_PATH + + drupal_ti_ensure_apt_get + ( + cd $DRUPAL_TI_DIST_DIR + wget http://ftp.us.debian.org/debian/pool/main/x/xdebug/php5-xdebug_2.2.5-1_amd64.deb + dpkg -x php5-xdebug_2.2.5-1_amd64.deb . + ) +} + +function drupal_ti_simpletest_coverage_start() { + if [ "$DRUPAL_TI_SIMPLETEST_COVERAGE" != "1" ] ; then return ; fi + + phpcov start +} + +function drupal_ti_simpletest_coverage_report() { + if [ "$DRUPAL_TI_SIMPLETEST_COVERAGE" != "1" ] ; then return ; fi + + # Load environment variables + drupal_ti_simpletest_coverage_vars + + phpcov stop --html $DRUPAL_TI_DRUPAL_DIR/coverage-report \ + --configuration $DRUPAL_TI_DRUPAL_DIR/$DRUPAL_TI_MODULES_PATH/$DRUPAL_TI_MODULE_NAME/phpcov.xml.dist + + # DRUPAL_TI_SIMPLETEST_COVERAGE_GENERATE_BADGES + cd "$DRUPAL_TI_DRUPAL_DIR" + + # Ensure that the reports branch exists. + if [ ! -d "coverage-report/" ]; then + return + fi + cp /tmp/coverage.sqlite coverage-report/ + cd coverage-report/ + git init + git remote add origin https://github.com/$TRAVIS_REPO_SLUG.git + drupal_ci_git_add_credentials + drupal_ci_git_ensure_reports_branch $TRAVIS_BRANCH-reports + + # Clone the reports branch and delete all the old data. + ls -ls + + # Generate the code coverage badge if required. + if [ "$DRUPAL_TI_SIMPLETEST_COVERAGE_GENERATE_BADGES" = "1" ] + then + php "$DRUPAL_TI_SCRIPT_DIR/utility/generate_simpletest_coverage_badge.php" + fi + + # Add, commit and push all report files. + git add * + git commit -m "Added report for $TRAVIS_JOB_NUMBER" + git push --set-upstream origin $BRANCH + git tag $TRAVIS_JOB_NUMBER + git push --tags + + echo "SIMPLETEST CODE COVERAGE COMPLETED!" + echo "The simpletest coverage report can be found at https://rawgit.com/$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH-reports/index.html" + + if [ "$DRUPAL_TI_SIMPLETEST_COVERAGE_GENERATE_BADGES" = "1" ] + then + echo "A code coverage badge has been generated:" + echo "GitHub markup: [![Coverage](https://rawgit.com/$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH-reports/badge.svg)](https://rawgit.com/$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH-reports/index.html)" + echo "Image URL: https://rawgit.com/$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH-reports/badge.svg" + fi +} + +function drupal_ti_simpletest_coverage_vars() { + export DRUPAL_TI_TMP_MODULE_PATH="$HOME/$DRUPAL_TI_MODULE_NAME" +} \ No newline at end of file diff --git a/functions/git.sh b/functions/git.sh new file mode 100644 index 0000000..38a27fe --- /dev/null +++ b/functions/git.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# @file +# Functionalities for GIT usage. + +# Ensures that the git settings are set. +function drupal_ti_ensure_git() { + # This function is re-entrant. + if [ -r "$TRAVIS_BUILD_DIR/../drupal_ti-git-settings-added" ] + then + return + fi + cd $HOME + + # Check if the e-mail address and the name are specified. + : ${DRUPAL_TI_GITHUB_EMAIL?"Need to set DRUPAL_TI_GITHUB_EMAIL"} + : ${DRUPAL_TI_GITHUB_NAME?"Need to set DRUPAL_TI_GITHUB_NAME"} + + git config --global user.email "${DRUPAL_TI_GITHUB_EMAIL}" + git config --global user.name "${DRUPAL_TI_GITHUB_NAME}" + git config --global push.default simple + + touch "$TRAVIS_BUILD_DIR/../drupal_ti-git-settings-added" +} + +# +# Ensures that the reports branch exists. +# +function drupal_ci_git_ensure_reports_branch() { + BRANCH=$1 + git fetch + if [[ $(git ls-remote --heads https://github.com/$TRAVIS_REPO_SLUG.git $BRANCH | wc -l) == *"1"* ]]; then + echo "$BRANCH exists, deleting the remote branch and re-creating." + git push origin --delete $BRANCH + git branch -D $BRANCH + fi + git checkout -b $BRANCH +} + +# +# Adds the credentials to the current repository. +# +function drupal_ci_git_add_credentials() { + # Check if the current directory has a git repository. + if [ -d ".git" ]; then + : ${DRUPAL_TI_GITHUB_TOKEN?"Need to set DRUPAL_TI_GITHUB_TOKEN"} + git config credential.helper "store --file=.git/credentials" + echo "https://${DRUPAL_TI_GITHUB_TOKEN}:x-oauth-basic@github.com" > .git/credentials + else + echo "Error in drupal_ci_git_add_credentials(): directory is not a git repository"; + fi +} diff --git a/runners/simpletest/after_script.sh b/runners/simpletest/after_script.sh new file mode 100755 index 0000000..25befc0 --- /dev/null +++ b/runners/simpletest/after_script.sh @@ -0,0 +1,3 @@ +#!/bin/bash +# Stop the coverage analyzer and generate the report. +drupal_ti_simpletest_coverage_report; diff --git a/runners/simpletest/before_install.sh b/runners/simpletest/before_install.sh new file mode 100755 index 0000000..8193d58 --- /dev/null +++ b/runners/simpletest/before_install.sh @@ -0,0 +1,3 @@ +#!/bin/bash +# +drupal_ti_coverage_prepare diff --git a/runners/simpletest/before_script.sh b/runners/simpletest/before_script.sh index 5a526b6..a926155 100755 --- a/runners/simpletest/before_script.sh +++ b/runners/simpletest/before_script.sh @@ -3,9 +3,25 @@ set -e $DRUPAL_TI_DEBUG +# Ensure that the GIT configurations have been set. +drupal_ti_ensure_git + # Ensure the right Drupal version is installed. +# The first time this is run, it will install Drupal. +# Note: This function is re-entrant. drupal_ti_ensure_drupal +# Ensure that phpcov is installed. +drupal_ti_ensure_phpcov + +# Change to the Drupal directory +cd "$DRUPAL_TI_DRUPAL_DIR" + +# Create the the module directory (only necessary for D7) +# For D7, this is sites/default/modules +mkdir -p "$DRUPAL_TI_DRUPAL_DIR/$DRUPAL_TI_MODULES_PATH" +cd "$DRUPAL_TI_DRUPAL_DIR/$DRUPAL_TI_MODULES_PATH" + # Enable simpletest module. cd "$DRUPAL_TI_DRUPAL_DIR" drush --yes en simpletest @@ -16,3 +32,6 @@ drupal_ti_ensure_module # Clear caches and run a web server. drupal_ti_clear_caches drupal_ti_run_server + +# Make sure that we aren't using a symbolic link of the module. +drupal_ti_simpletest_coverage_install_module \ No newline at end of file diff --git a/runners/simpletest/script.sh b/runners/simpletest/script.sh index a9f0bf9..7035b62 100755 --- a/runners/simpletest/script.sh +++ b/runners/simpletest/script.sh @@ -11,6 +11,7 @@ then ARGS=( "${ARGS[@]}" "$DRUPAL_TI_SIMPLETEST_GROUP" ) fi +drupal_ti_simpletest_coverage_start cd "$DRUPAL_TI_DRUPAL_DIR" { php "$DRUPAL_TI_SIMPLETEST_FILE" --php $(which php) "${ARGS[@]}" || echo "1 fails"; } | tee /tmp/simpletest-result.txt diff --git a/utility/generate_simpletest_coverage_badge.php b/utility/generate_simpletest_coverage_badge.php new file mode 100644 index 0000000..f845c4d --- /dev/null +++ b/utility/generate_simpletest_coverage_badge.php @@ -0,0 +1,42 @@ +loadHTMLFile($file); + +$xpath = new DOMXpath($doc); + +$elements = $xpath->query("//table//tr[1]//td[3]"); + +$percent = NULL; +if (!is_null($elements)) { + foreach ($elements as $element) { + $nodes = $element->childNodes; + foreach ($nodes as $node) { + $percent = str_replace('%', '', $node->nodeValue); + } + } +} + + +if ($percent == NULL) { + $url = "https://img.shields.io/badge/coverage-fail-lightgrey.svg"; +} +else { + if ($percent <= 17) $color = "red"; + elseif ($percent <= 34) $color = "orange"; + elseif ($percent <= 41) $color = "yellow"; + elseif ($percent <= 58) $color = "yellowgreen"; + elseif ($percent <= 75) $color = "green"; + else $color = "brightgreen"; + + $percent = $percent . '%'; + $url = "https://img.shields.io/badge/coverage-$percent-$color.svg"; +} + +# Download and rename the badge. +exec("curl -O https://img.shields.io/badge/coverage-$percent-$color.svg"); +exec("mv coverage-$percent-$color.svg badge.svg");