From 989a00f3300887ff6eb2368086123a5985f43c30 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Fri, 2 Apr 2021 13:43:30 +0200 Subject: [PATCH] Add a CI for docs and running examples + (generating coverage !!) (#349) * Add lint docs workflow and a testing workflow * Add scripts to run tests on examples * Add Doctum config * Adjust examples source detection Co-authored-by: Nicola Asuni --- .gitattributes | 2 + .github/workflows/lint-docs.yml | 20 +++ .github/workflows/tests.yml | 56 ++++++ .../barcodes/tcpdf_barcodes_1d_include.php | 11 +- .../barcodes/tcpdf_barcodes_2d_include.php | 11 +- scripts/doctum.php | 34 ++++ tests/.gitignore | 1 + tests/coverage.php | 66 ++++++++ tests/launch.sh | 160 ++++++++++++++++++ 9 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/lint-docs.yml create mode 100644 .github/workflows/tests.yml create mode 100644 scripts/doctum.php create mode 100644 tests/.gitignore create mode 100644 tests/coverage.php create mode 100755 tests/launch.sh diff --git a/.gitattributes b/.gitattributes index 393848b..12d7f81 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ /.github export-ignore /.gitignore export-ignore /.gitattributes export-ignore +/tests export-ignore +/scripts export-ignore diff --git a/.github/workflows/lint-docs.yml b/.github/workflows/lint-docs.yml new file mode 100644 index 0000000..7cc3850 --- /dev/null +++ b/.github/workflows/lint-docs.yml @@ -0,0 +1,20 @@ +name: lint php documentation + +on: + push: + pull_request: + types: [opened, synchronize, reopened] + branches: + - main + +jobs: + lint-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: lint php documentation + uses: sudo-bot/action-doctum@dev + with: + config-file: scripts/doctum.php + method: "parse" + cli-args: "--output-format=github --no-ansi --no-progress -v --ignore-parse-errors" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..64f2214 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,56 @@ +name: Run tests + +on: + push: + pull_request: + types: [opened, synchronize, reopened] + branches: + - main + +jobs: + test-php: + name: Test on php ${{ matrix.php-version }} and ${{ matrix.os }} + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.experimental }} + strategy: + fail-fast: false + matrix: + experimental: [false] + coverage-extension: [pcov] + php-version: ["7.1", "7.2", "7.3", "7.4", "8.0"] + os: [ubuntu-latest] + include: + - { php-version: '5.3', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } + - { php-version: '5.4', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } + - { php-version: '5.5', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } + - { php-version: '5.6', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } + - { php-version: '8.1', experimental: true, os: ubuntu-latest, coverage-extension: 'pcov' } + steps: + - uses: actions/checkout@v2 + - name: Install pdfinfo + run: sudo apt-get install -y poppler-utils + - name: Use php ${{ matrix.php-version }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: ${{ matrix.coverage-extension }} + extensions: bcmath, imagick, gd + ini-values: display_errors=on, error_reporting=-1 + - name: List php modules + run: php -m + - name: List php modules using "no php ini" mode + run: php -m -n + - name: Cache module + uses: actions/cache@v2 + with: + path: ~/.composer/cache/ + key: composer-cache + - name: Install dependencies + run: composer install --no-interaction + - name: Run php tests + run: ./tests/launch.sh + - name: Send coverage + uses: codecov/codecov-action@v1 + with: + flags: php-${{ matrix.php-version }}-${{ matrix.os }} + name: php-${{ matrix.php-version }}-${{ matrix.os }} diff --git a/examples/barcodes/tcpdf_barcodes_1d_include.php b/examples/barcodes/tcpdf_barcodes_1d_include.php index a0bde57..0add5ec 100644 --- a/examples/barcodes/tcpdf_barcodes_1d_include.php +++ b/examples/barcodes/tcpdf_barcodes_1d_include.php @@ -24,7 +24,16 @@ */ // Include the TCPDF 1D barcode class (search the class on the following directories). -$tcpdf_barcodes_1d_include_dirs = array(realpath('../../tcpdf_barcodes_1d.php'), '/usr/share/php/tcpdf/tcpdf_barcodes_1d.php', '/usr/share/tcpdf/tcpdf_barcodes_1d.php', '/usr/share/php-tcpdf/tcpdf_barcodes_1d.php', '/var/www/tcpdf/tcpdf_barcodes_1d.php', '/var/www/html/tcpdf/tcpdf_barcodes_1d.php', '/usr/local/apache2/htdocs/tcpdf/tcpdf_barcodes_1d.php'); +$tcpdf_barcodes_1d_include_dirs = array( + realpath(dirname(__FILE__) . '/../../tcpdf_barcodes_1d.php'),// True source file + realpath('../../tcpdf_barcodes_1d.php'),// Relative from $PWD + '/usr/share/php/tcpdf/tcpdf_barcodes_1d.php', + '/usr/share/tcpdf/tcpdf_barcodes_1d.php', + '/usr/share/php-tcpdf/tcpdf_barcodes_1d.php', + '/var/www/tcpdf/tcpdf_barcodes_1d.php', + '/var/www/html/tcpdf/tcpdf_barcodes_1d.php', + '/usr/local/apache2/htdocs/tcpdf/tcpdf_barcodes_1d.php' +); foreach ($tcpdf_barcodes_1d_include_dirs as $tcpdf_barcodes_1d_include_path) { if (@file_exists($tcpdf_barcodes_1d_include_path)) { require_once($tcpdf_barcodes_1d_include_path); diff --git a/examples/barcodes/tcpdf_barcodes_2d_include.php b/examples/barcodes/tcpdf_barcodes_2d_include.php index 61c4a8b..e56b8a2 100644 --- a/examples/barcodes/tcpdf_barcodes_2d_include.php +++ b/examples/barcodes/tcpdf_barcodes_2d_include.php @@ -24,7 +24,16 @@ */ // Include the TCPDF 2D barcode class (search the class on the following directories). -$tcpdf_barcodes_2d_include_dirs = array(realpath('../../tcpdf_barcodes_2d.php'), '/usr/share/php/tcpdf/tcpdf_barcodes_2d.php', '/usr/share/tcpdf/tcpdf_barcodes_2d.php', '/usr/share/php-tcpdf/tcpdf_barcodes_2d.php', '/var/www/tcpdf/tcpdf_barcodes_2d.php', '/var/www/html/tcpdf/tcpdf_barcodes_2d.php', '/usr/local/apache2/htdocs/tcpdf/tcpdf_barcodes_2d.php'); +$tcpdf_barcodes_2d_include_dirs = array( + realpath(dirname(__FILE__) . '/../../tcpdf_barcodes_2d.php'),// True source file + realpath('../../tcpdf_barcodes_2d.php'),// Relative from $PWD + '/usr/share/php/tcpdf/tcpdf_barcodes_2d.php', + '/usr/share/tcpdf/tcpdf_barcodes_2d.php', + '/usr/share/php-tcpdf/tcpdf_barcodes_2d.php', + '/var/www/tcpdf/tcpdf_barcodes_2d.php', + '/var/www/html/tcpdf/tcpdf_barcodes_2d.php', + '/usr/local/apache2/htdocs/tcpdf/tcpdf_barcodes_2d.php' +); foreach ($tcpdf_barcodes_2d_include_dirs as $tcpdf_barcodes_2d_include_path) { if (@file_exists($tcpdf_barcodes_2d_include_path)) { require_once($tcpdf_barcodes_2d_include_path); diff --git a/scripts/doctum.php b/scripts/doctum.php new file mode 100644 index 0000000..4a9c98b --- /dev/null +++ b/scripts/doctum.php @@ -0,0 +1,34 @@ +files() + ->name('*.php') + ->notPath('cache') + ->notPath('build') + ->notPath('fonts') + ->notPath('vendor') + ->notPath('tests') + ->notPath('examples') + ->in($rootDir); + +return new Doctum($iterator, [ + 'title' => 'TCPDF', + 'build_dir' => $rootDir . '/build', + 'cache_dir' => $rootDir . '/cache', + 'source_dir' => $rootDir, + 'remote_repository' => new GitHubRemoteRepository('tecnickcom/TCPDF', $rootDir), + 'footer_link' => [ + 'href' => 'https://github.com/tecnickcom/TCPDF#readme', + 'rel' => 'noreferrer noopener', + 'target' => '_blank', + 'before_text' => 'This documentation is for', + 'link_text' => 'TCPDF', + 'after_text' => 'the PHP library to build PDFs.', + ], +]); diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..56c8074 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +/coverage.lcov diff --git a/tests/coverage.php b/tests/coverage.php new file mode 100644 index 0000000..7c9beb7 --- /dev/null +++ b/tests/coverage.php @@ -0,0 +1,66 @@ + $coverageForFile) { + $coverageData .= 'SF:' . $file . "\n"; + $coverageData .= 'TN:' . str_replace($rootDir, '', $_SERVER['PHP_SELF']) . "\n"; + foreach ($coverageForFile as $line => $coverageValue) { + $coverageValue = $coverageValue === -1 ? 0 : $coverageValue; + $coverageData .= 'DA:' . $line . ',' . $coverageValue . "\n"; + } + $coverageData .= 'end_of_record' . "\n"; + } + file_put_contents($coverageFile, $coverageData, LOCK_EX | FILE_APPEND); + } + + } + + $a = new CoverageObjectPcov(); +} +if (extension_loaded('xdebug')) { + \xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); + + class CoverageObjectXdebug + { + + public function __destruct() + { + $rootDir = realpath(__DIR__ . '/../') . '/'; + $coverageFile = $rootDir . 'tests/coverage.lcov'; + $covData = xdebug_get_code_coverage(); + $coverageData = ''; + foreach ($covData as $file => $coverageForFile) { + $coverageData .= 'SF:' . $file . "\n"; + $coverageData .= 'TN:' . str_replace($rootDir, '', $_SERVER['PHP_SELF']) . "\n"; + foreach ($coverageForFile as $line => $coverageValue) { + $coverageValue = $coverageValue > 0 ? $coverageValue : 0; + $coverageData .= 'DA:' . $line . ',' . $coverageValue . "\n"; + } + $coverageData .= 'end_of_record' . "\n"; + } + file_put_contents($coverageFile, $coverageData, LOCK_EX | FILE_APPEND); + \xdebug_stop_code_coverage(true); + } + + } + + $a = new CoverageObjectXdebug(); +} diff --git a/tests/launch.sh b/tests/launch.sh new file mode 100755 index 0000000..fc7a667 --- /dev/null +++ b/tests/launch.sh @@ -0,0 +1,160 @@ +#!/bin/sh + + +command -v pdfinfo > /dev/null +if [ $? -gt 0 ]; then + echo "pdfinfo could not be found" + echo "On Debian based systems you can run: apt install -y poppler-utils" + exit 1 +fi + +# Only start here, the command checking can exit code > 0 +set -e + +EXAMPLE_FILES="$(find examples/ -type f -name 'example*.php' \ + -not -path '*/barcodes/*' \ + -not -wholename 'examples/example_006.php' \ + | sort -df)" + +EXAMPLE_BARCODE_FILES="$(find examples/barcodes -type f -name 'example*.php' \ + | sort -df)" + +TEMP_FOLDER="$(mktemp -d /tmp/TCPDF-tests.XXXXXXXXX)" +OUTPUT_FILE="${TEMP_FOLDER}/output.pdf" +OUTPUT_FILE_ERROR="${TEMP_FOLDER}/errors.txt" +ROOT_DIR="$(php -r 'echo realpath(__DIR__);')" +TESTS_DIR="${ROOT_DIR}/tests/" + +PHP_EXT_DIR="$(php -r 'echo ini_get("extension_dir");')" + +echo "php extension dir: ${PHP_EXT_DIR}" + +BCMATH_EXT="-d extension=$(find ${PHP_EXT_DIR} -type f -name 'bcmath.so')" +echo "bcmath found at: ${BCMATH_EXT}" + +COVERAGE_EXTENSION="-d extension=pcov.so" +IMAGICK_OR_GD="-dextension=gd.so" +if [ "$(php -r 'echo PHP_MAJOR_VERSION;')" = "5" ];then + X_DEBUG_EXT="$(find ${PHP_EXT_DIR} -type f -name 'xdebug.so' || '')" + echo "Xdebug found at: ${X_DEBUG_EXT}" + # pcov does not exist for PHP 5 + COVERAGE_EXTENSION="-d zend_extension=${X_DEBUG_EXT} -d xdebug.mode=coverage" + + # 5.5, 5.4, 5.3 + if [ "$(php -r 'echo (PHP_MINOR_VERSION < 6) ? "true" : "false";')" = "true" ];then + # seems like there is no bcmath extension to be found + BCMATH_EXT="" + fi + + if [ "$(php -r 'echo PHP_MINOR_VERSION;')" = "3" ];then + # pcov does not exist for PHP 5 + IMAGICK_OR_GD="-dextension=imagick.so" + fi +fi + +echo "Root folder: ${ROOT_DIR}" +echo "Temporary folder: ${TEMP_FOLDER}" + +FAILED_FLAG=0 + +cd "${ROOT_DIR}/examples" + +for file in $EXAMPLE_FILES; do + echo "File: $file" + php -l "${ROOT_DIR}/$file" > /dev/null + if [ $? -eq 0 ]; then + echo "File-lint-passed: $file" + fi + set +e + php -n \ + -d date.timezone=UTC \ + ${IMAGICK_OR_GD} ${COVERAGE_EXTENSION} \ + -d display_errors=on \ + -d error_reporting=-1 \ + -d pcov.directory="${ROOT_DIR}" \ + -d auto_prepend_file="${TESTS_DIR}/coverage.php" \ + "${ROOT_DIR}/$file" 1> "${OUTPUT_FILE}" 2> "${OUTPUT_FILE_ERROR}" + if [ $? -eq 0 ]; then + echo "File-run-passed: $file" + ERROR_LOGS="$(cat "${OUTPUT_FILE_ERROR}")" + if [ ! -z "${ERROR_LOGS}" ]; then + FAILED_FLAG=1 + set -e + echo "Logs: $file" + echo "---------------------------" + echo "${ERROR_LOGS}" + echo "---------------------------" + fi + if [ $(head -c 4 "${OUTPUT_FILE}") != "%PDF" ]; then + FAILED_FLAG=1 + echo "Generated-not-a-pdf: $file" + echo "---------------------------" + cat "${OUTPUT_FILE}" + echo "---------------------------" + continue + fi + pdfinfo "${OUTPUT_FILE}" > /dev/null + if [ $? -gt 0 ]; then + FAILED_FLAG=1 + echo "Generated-invalid-file: $file" + fi + else + echo "File-run-failed: $file" + fi + set -e +done + +for file in $EXAMPLE_BARCODE_FILES; do + echo "File: $file" + php -l "${ROOT_DIR}/$file" > /dev/null + if [ $? -eq 0 ]; then + echo "File-lint-passed: $file" + fi + set +e + php -n \ + -d date.timezone=UTC \ + ${BCMATH_EXT} ${COVERAGE_EXTENSION} \ + -d display_errors=on \ + -d error_reporting=-1 \ + -d pcov.directory="${ROOT_DIR}" \ + -d auto_prepend_file="${TESTS_DIR}/coverage.php" \ + "${ROOT_DIR}/$file" 1> "${OUTPUT_FILE}" 2> "${OUTPUT_FILE_ERROR}" + if [ $? -eq 0 ]; then + echo "File-run-passed: $file" + ERROR_LOGS="$(cat "${OUTPUT_FILE_ERROR}")" + if [ ! -z "${ERROR_LOGS}" ]; then + FAILED_FLAG=1 + set -e + echo "Logs: $file" + echo "---------------------------" + echo "${ERROR_LOGS}" + echo "---------------------------" + fi + else + FAILED_FLAG=1 + echo "File-run-failed: $file" + ERROR_LOGS="$(cat "${OUTPUT_FILE_ERROR}")" + if [ ! -z "${ERROR_LOGS}" ]; then + set -e + echo "Logs: $file" + echo "---------------------------" + echo "${ERROR_LOGS}" + echo "---------------------------" + fi + OUT_LOGS="$(cat "${OUTPUT_FILE}")" + if [ ! -z "${OUT_LOGS}" ]; then + set -e + echo "Logs: $file" + echo "---------------------------" + echo "${OUT_LOGS}" + echo "---------------------------" + fi + fi + set -e +done + +cd - > /dev/null + +rm -rf "${TEMP_FOLDER}" + +exit "${FAILED_FLAG}"