diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..94554c3 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,74 @@ +workflows: + version: 2 + main: + jobs: + - php73-build + - php74-build + - php80-build + +version: 2 + +job-references: + mysql_image: &mysql_image + cimg/mysql:5.7 + + setup_environment: &setup_environment + name: "Setup Environment Variables" + command: | + echo "export PATH=$HOME/.composer/vendor/bin:$PATH" >> $BASH_ENV + source /home/circleci/.bashrc + + install_dependencies: &install_dependencies + name: "Install Dependencies" + command: | + sudo apt-get update && sudo apt-get install mysql-client subversion + + php_job: &php_job + environment: + - WP_TESTS_DIR: "/tmp/wordpress-tests-lib" + - WP_CORE_DIR: "/tmp/wordpress/" + steps: + - checkout + - run: php --version + - run: composer --version + - run: *setup_environment + - run: *install_dependencies + - run: + name: "Run Tests" + command: | + rm -rf $WP_TESTS_DIR $WP_CORE_DIR + bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest + make test-unit + WP_MULTISITE=1 make test-unit + make test-style + +jobs: + php73-build: + <<: *php_job + docker: + - image: cimg/php:7.3 + - image: *mysql_image + + php74-build: + <<: *php_job + docker: + - image: cimg/php:7.4 + - image: *mysql_image + + php80-build: + <<: *php_job + docker: + - image: cimg/php:8.0 + - image: *mysql_image + + php81-build: + <<: *php_job + docker: + - image: cimg/php:8.1 + - image: *mysql_image + + php82-build: + <<: *php_job + docker: + - image: cimg/php:8.2 + - image: *mysql_image \ No newline at end of file diff --git a/.gitignore b/.gitignore index 486d806..9a91ca9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /vendor composer.lock coverage.clover -/.idea \ No newline at end of file +/.idea +/.phpunit.result.cache \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0ef483b --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +.PHONY: test +test: test-unit test-style + +.PHONY: test-unit +test-unit: vendor + vendor/bin/phpunit + +.PHONY: test-style +test-style: vendor + vendor/bin/phpcs + +vendor: composer.json + composer install --ignore-platform-reqs + +.PHONY: update-deps +update-deps: + composer update --with-all-dependencies + +.PHONY: clean +clean: + rm -rf vendor + rm -f tests/.phpunit.result.cache \ No newline at end of file diff --git a/README.md b/README.md index 2825211..f9d37f0 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,16 @@ Job queues for WordPress. +## Install + +The recommended way to install this library in your project is by loading it through Composer: + +```shell +composer require deliciousbrains/wp-queue +``` + +It is highly recommended to prefix wrap the library class files using [PHP-Scoper](https://packagist.org/packages/humbug/php-scoper), to prevent collisions with other projects using this same library. + ## Prerequisites WP_Queue requires PHP __7.3+__. @@ -111,6 +121,86 @@ add_filter( 'wp_queue_default_connection', function() { } ); ``` +## Contributing + +Contributions are welcome via Pull Requests, but please do raise an issue before +working on anything to discuss the change if there isn't already an issue. If there +is an approved issue you'd like to tackle, please post a comment on it to let people know +you're going to have a go at it so that effort isn't wasted through duplicated work. + +### Unit & Style Tests + +When working on the library, please add unit tests to the appropriate file in the +`tests` directory that cover your changes. + +#### Setting Up + +We use the standard WordPress test libraries for running unit tests. + +Please run the following command to set up the libraries: + +```shell +bin/install-wp-tests.sh db_name db_user db_pass +``` + +Substitute `db_name`, `db_user` and `db_pass` as appropriate. + +Please be aware that running the unit tests is a **destructive operation**, *database +tables will be cleared*, so please use a database name dedicated to running unit tests. +The standard database name usually used by the WordPress community is `wordpress_test`, e.g. + +```shell +bin/install-wp-tests.sh wordpress_test root root +``` + +Please refer to the [Initialize the testing environment locally](https://make.wordpress.org/cli/handbook/misc/plugin-unit-tests/#3-initialize-the-testing-environment-locally) +section of the WordPress Handbook's [Plugin Integration Tests](https://make.wordpress.org/cli/handbook/misc/plugin-unit-tests/) +entry should you run into any issues. + +#### Running Unit Tests + +To run the unit tests, simply run: + +```shell +make test-unit +``` + +If the `composer` dependencies aren't in place, they'll be automatically installed first. + +#### Running Style Tests + +It's important that the code in the library use a consistent style to aid in quickly +understanding it, and to avoid some common issues. `PHP_Code_Sniffer` is used with +mostly standard WordPress rules to help check for consistency. + +To run the style tests, simply run: + +```shell +make test-style +``` + +If the `composer` dependencies aren't in place, they'll be automatically installed first. + +#### Running All Tests + +To make things super simple, just run the following to run all tests: + +```shell +make +``` + +If the `composer` dependencies aren't in place, they'll be automatically installed first. + +### Creating a PR + +When creating a PR, please make sure to mention which GitHub issue is being resolved +at the top of the description, e.g.: + +`Resolves #123` + +The unit and style tests will be run automatically, the PR will not be eligible for +merge unless they pass, and the branch is up-to-date with `master`. + ## License -WP Queue is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). +WP Queue is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). \ No newline at end of file diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh new file mode 100755 index 0000000..ee05775 --- /dev/null +++ b/bin/install-wp-tests.sh @@ -0,0 +1,181 @@ +#!/usr/bin/env bash + +if [ $# -lt 3 ]; then + echo "usage: $0 [db-host] [wp-version] [skip-database-creation]" + exit 1 +fi + +DB_NAME=$1 +DB_USER=$2 +DB_PASS=$3 +DB_HOST=${4-localhost} +WP_VERSION=${5-latest} +SKIP_DB_CREATE=${6-false} + +TMPDIR=${TMPDIR-/tmp} +TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//") +WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib} +WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress} + +download() { + if [ `which curl` ]; then + curl -s "$1" > "$2"; + elif [ `which wget` ]; then + wget -nv -O "$2" "$1" + fi +} + +if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then + WP_BRANCH=${WP_VERSION%\-*} + WP_TESTS_TAG="branches/$WP_BRANCH" + +elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then + WP_TESTS_TAG="branches/$WP_VERSION" +elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then + if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then + # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x + WP_TESTS_TAG="tags/${WP_VERSION%??}" + else + WP_TESTS_TAG="tags/$WP_VERSION" + fi +elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + WP_TESTS_TAG="trunk" +else + # http serves a single offer, whereas https serves multiple. we only want one + download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json + grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json + LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') + if [[ -z "$LATEST_VERSION" ]]; then + echo "Latest WordPress version could not be found" + exit 1 + fi + WP_TESTS_TAG="tags/$LATEST_VERSION" +fi +set -ex + +install_wp() { + + if [ -d $WP_CORE_DIR ]; then + return; + fi + + mkdir -p $WP_CORE_DIR + + if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + mkdir -p $TMPDIR/wordpress-trunk + rm -rf $TMPDIR/wordpress-trunk/* + svn export --quiet https://core.svn.wordpress.org/trunk $TMPDIR/wordpress-trunk/wordpress + mv $TMPDIR/wordpress-trunk/wordpress/* $WP_CORE_DIR + else + if [ $WP_VERSION == 'latest' ]; then + local ARCHIVE_NAME='latest' + elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then + # https serves multiple offers, whereas http serves single. + download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json + if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then + # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x + LATEST_VERSION=${WP_VERSION%??} + else + # otherwise, scan the releases and get the most up to date minor version of the major release + local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'` + LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1) + fi + if [[ -z "$LATEST_VERSION" ]]; then + local ARCHIVE_NAME="wordpress-$WP_VERSION" + else + local ARCHIVE_NAME="wordpress-$LATEST_VERSION" + fi + else + local ARCHIVE_NAME="wordpress-$WP_VERSION" + fi + download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz + tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR + fi + + download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php +} + +install_test_suite() { + # portable in-place argument for both GNU sed and Mac OSX sed + if [[ $(uname -s) == 'Darwin' ]]; then + local ioption='-i.bak' + else + local ioption='-i' + fi + + # set up testing suite if it doesn't yet exist + if [ ! -d $WP_TESTS_DIR ]; then + # set up testing suite + mkdir -p $WP_TESTS_DIR + rm -rf $WP_TESTS_DIR/{includes,data} + svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data + fi + + if [ ! -f wp-tests-config.php ]; then + download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php + # remove all forward slashes in the end + WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::") + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s:__DIR__ . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php + fi + +} + +recreate_db() { + shopt -s nocasematch + if [[ $1 =~ ^(y|yes)$ ]] + then + mysqladmin drop $DB_NAME -f --user="$DB_USER" --password="$DB_PASS"$EXTRA + create_db + echo "Recreated the database ($DB_NAME)." + else + echo "Leaving the existing database ($DB_NAME) in place." + fi + shopt -u nocasematch +} + +create_db() { + mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA +} + +install_db() { + + if [ ${SKIP_DB_CREATE} = "true" ]; then + return 0 + fi + + # parse DB_HOST for port or socket references + local PARTS=(${DB_HOST//\:/ }) + local DB_HOSTNAME=${PARTS[0]}; + local DB_SOCK_OR_PORT=${PARTS[1]}; + local EXTRA="" + + if ! [ -z $DB_HOSTNAME ] ; then + if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then + EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" + elif ! [ -z $DB_SOCK_OR_PORT ] ; then + EXTRA=" --socket=$DB_SOCK_OR_PORT" + elif ! [ -z $DB_HOSTNAME ] ; then + EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" + fi + fi + + # create database + if [ $(mysql --user="$DB_USER" --password="$DB_PASS"$EXTRA --execute='show databases;' | grep ^$DB_NAME$) ] + then + echo "Reinstalling will delete the existing test database ($DB_NAME)" + read -p 'Are you sure you want to proceed? [y/N]: ' DELETE_EXISTING_DB + recreate_db $DELETE_EXISTING_DB + else + create_db + fi +} + +install_wp +install_test_suite +install_db diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..eb38ddb --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,78 @@ + + + + . + /vendor/ + /node_modules/ + /tests/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /tests/* + + \ No newline at end of file diff --git a/phpcs.xml.dist b/phpcs.xml.dist deleted file mode 100644 index 27b7f68..0000000 --- a/phpcs.xml.dist +++ /dev/null @@ -1,29 +0,0 @@ - - - - . - - - - - - - - - - - - - - - - - - - - - - - /tests/* - - diff --git a/src/WP_Queue/Exceptions/WorkerAttemptsExceededException.php b/src/WP_Queue/Exceptions/WorkerAttemptsExceededException.php index 6a96ff6..53c49f6 100644 --- a/src/WP_Queue/Exceptions/WorkerAttemptsExceededException.php +++ b/src/WP_Queue/Exceptions/WorkerAttemptsExceededException.php @@ -4,5 +4,8 @@ use Exception; +/** + * Exception for when maximum number of attempts to process a job exceeded. + */ class WorkerAttemptsExceededException extends Exception { } diff --git a/src/WP_Queue/Job.php b/src/WP_Queue/Job.php index 8dd57ec..b4522f4 100644 --- a/src/WP_Queue/Job.php +++ b/src/WP_Queue/Job.php @@ -3,7 +3,6 @@ namespace WP_Queue; use Carbon\Carbon; -use Exception; abstract class Job { diff --git a/src/WP_Queue/Worker.php b/src/WP_Queue/Worker.php index cafa0af..cf19509 100644 --- a/src/WP_Queue/Worker.php +++ b/src/WP_Queue/Worker.php @@ -3,7 +3,6 @@ namespace WP_Queue; use Exception; -use WP_Queue\Connections\ConnectionInterface; use WP_Queue\Exceptions\WorkerAttemptsExceededException; class Worker {