Skip to content

Instantly share code, notes, and snippets.

@EvanHerman
Last active December 3, 2021 02:56
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EvanHerman/d63810511f3ff12aa98b7a10cb5528ed to your computer and use it in GitHub Desktop.
Save EvanHerman/d63810511f3ff12aa98b7a10cb5528ed to your computer and use it in GitHub Desktop.
WordPress Plugin CircleCI 2.0 Config - PHPCS, PHPUnit and rsync Deployment
workflows:
version: 2
main:
jobs:
- php56-build
- php70-build
- php71-build
- php72-build
- deploy:
requires:
- php56-build
- php70-build
- php71-build
- php72-build
version: 2
jobs:
php56-build:
docker:
- image: circleci/php:5.6
- image: circleci/mysql:5.7
environment:
- WP_TESTS_DIR: "/tmp/wordpress-tests-lib"
- WP_CORE_DIR: "/tmp/wordpress/"
steps:
- checkout
- run:
name: "Setup Environment Variables"
command: |
echo "export PATH=$HOME/.composer/vendor/bin:$PATH" >> $BASH_ENV
source /home/circleci/.bashrc
- run:
name: "Install Dependencies"
command: |
sudo apt-get update && sudo apt-get install subversion
sudo docker-php-ext-install mysqli
sudo sh -c "printf '\ndeb http://ftp.us.debian.org/debian sid main\n' >> /etc/apt/sources.list"
sudo apt-get update && sudo apt-get install mysql-client-5.7
git submodule update --init
composer global require "phpunit/phpunit=5.7.*"
composer global require wp-coding-standards/wpcs
phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
- run:
name: "Run PHPCS"
command: |
phpcs --standard=phpcs.ruleset.xml --extensions=php --colors -s -p -v .
- run:
name: "Run PHPUnit - Single Site"
command: |
SKIP_DB_CREATE=false
rm -rf $WP_TESTS_DIR $WP_CORE_DIR
bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest $SKIP_DB_CREATE
phpunit
- run:
name: "Run PHPUnit - Multi Site"
command: |
WP_MULTISITE=1 phpunit
php70-build:
docker:
- image: circleci/php:7.0
- image: circleci/mysql:5.7
environment:
- WP_TESTS_DIR: "/tmp/wordpress-tests-lib"
- WP_CORE_DIR: "/tmp/wordpress/"
steps:
- checkout
- run:
name: "Setup Environment Variables"
command: |
echo "export PATH=$HOME/.composer/vendor/bin:$PATH" >> $BASH_ENV
source /home/circleci/.bashrc
- run:
name: "Install Dependencies"
command: |
sudo apt-get update && sudo apt-get install subversion
sudo docker-php-ext-install mysqli
sudo sh -c "printf '\ndeb http://ftp.us.debian.org/debian sid main\n' >> /etc/apt/sources.list"
sudo apt-get update && sudo apt-get install mysql-client-5.7
git submodule update --init
composer global require "phpunit/phpunit=5.7.*"
composer global require wp-coding-standards/wpcs
phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
- run:
name: "Run PHPCS"
command: |
phpcs --standard=phpcs.ruleset.xml --extensions=php --colors -s -p -v .
- run:
name: "Run PHPUnit - Single Site"
command: |
rm -rf $WP_TESTS_DIR $WP_CORE_DIR
bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest
phpunit
- run:
name: "Run PHPUnit - Multi Site"
command: |
WP_MULTISITE=1 phpunit
php71-build:
docker:
- image: circleci/php:7.1
- image: circleci/mysql:5.7
environment:
- WP_TESTS_DIR: "/tmp/wordpress-tests-lib"
- WP_CORE_DIR: "/tmp/wordpress/"
steps:
- checkout
- run:
name: "Setup Environment Variables"
command: |
echo "export PATH=$HOME/.composer/vendor/bin:$PATH" >> $BASH_ENV
source /home/circleci/.bashrc
- run:
name: "Install Dependencies"
command: |
sudo apt-get update && sudo apt-get install subversion
sudo docker-php-ext-install mysqli
sudo sh -c "printf '\ndeb http://ftp.us.debian.org/debian sid main\n' >> /etc/apt/sources.list"
sudo apt-get update && sudo apt-get install mysql-client-5.7
git submodule update --init
composer global require "phpunit/phpunit=5.7.*"
composer global require wp-coding-standards/wpcs
phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
- run:
name: "Run PHPCS"
command: |
phpcs --standard=phpcs.ruleset.xml --extensions=php --colors -s -p -v .
- run:
name: "Run PHPUnit - Single Site"
command: |
rm -rf $WP_TESTS_DIR $WP_CORE_DIR
bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest
phpunit
- run:
name: "Run PHPUnit - Multi Site"
command: |
WP_MULTISITE=1 phpunit
php72-build:
docker:
- image: circleci/php:7.2
- image: circleci/mysql:5.7
environment:
- WP_TESTS_DIR: "/tmp/wordpress-tests-lib"
- WP_CORE_DIR: "/tmp/wordpress/"
steps:
- checkout
- run:
name: "Setup Environment Variables"
command: |
echo "export PATH=$HOME/.composer/vendor/bin:$PATH" >> $BASH_ENV
source /home/circleci/.bashrc
- run:
name: "Install Dependencies"
command: |
sudo apt-get update && sudo apt-get install subversion
sudo docker-php-ext-install mysqli
sudo sh -c "printf '\ndeb http://ftp.us.debian.org/debian sid main\n' >> /etc/apt/sources.list"
sudo apt-get update && sudo apt-get install mysql-client-5.7
git submodule update --init
composer global require "phpunit/phpunit=5.7.*"
composer global require wp-coding-standards/wpcs
phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
- run:
name: "Run PHPCS"
command: |
phpcs --standard=phpcs.ruleset.xml --extensions=php --colors -s -p -v .
- run:
name: "Run PHPUnit - Single Site - Generate Coverage Report"
command: |
rm -rf $WP_TESTS_DIR $WP_CORE_DIR
bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest
phpunit --log-junit /tmp/test-results/phpunit/junit-coverage-report.xml
- store_test_results:
path: /tmp/test-results
- run:
name: "Run PHPUnit - Multisite"
command: |
WP_MULTISITE=1 phpunit
deploy:
docker:
- image: circleci/php:latest-node-browsers-legacy
steps:
- add_ssh_keys:
fingerprints:
- "SSH Fingerprint from CircleCI Project Settings > SSH Permissions"
- checkout
- run:
name: Update npm
command: sudo npm install -g npm@latest
- run:
name: Install Grunt.js
command: sudo npm install -g grunt-cli
- run:
name: Update submodules
command: git submodule update --init
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- run:
name: Install node packages
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- node_modules
- run:
name: Build the plugin
command: |
grunt build
mkdir -p /tmp/artifacts
cp -a build/*.zip /tmp/artifacts
- deploy:
name: Deploy the plugin
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
./bin/deploy.sh live
else
./bin/deploy.sh --dry-run
fi
- store_artifacts:
path: /tmp/artifacts
#!/bin/bash
INVALID_PARAMETERS="\033[1;31mError:\033[0m Please make sure you've indicated correct parameters."
# Path to plugin directory on the remote server
PLUGIN_DIR="/path/on/remote/server/to/wp-content/plugins/${CIRCLE_PROJECT_REPONAME}"
# Set Remote server SSH credentials (If this is a public Repo, you will want to set these as CircleCI environment variables)
SSH_CREDS="user@host"
# Add the server IP to the known_hosts file
# Required for CircleCI to allow SSH connections to remote server
# example: ssh-keyscan 123.456.789.123 >> ~/.ssh/known_hosts
ssh-keyscan REMOTE.SERVER.IP >> ~/.ssh/known_hosts
cd ${HOME}/project/build/${CIRCLE_PROJECT_REPONAME}
if [ $# -eq 0 ]
then
echo -e ${INVALID_PARAMETERS}
elif [ $1 == "--dry-run" ]
then
echo "Running dry-run deployment."
rsync --stats --dry-run --delete --progress -avz -e "ssh -p22" ./ ${SSH_CREDS}:${PLUGIN_DIR}
elif [ $1 == "live" ]
then
echo "Running actual deploy"
rsync --stats --delete -avz -e "ssh -p22" ./ ${SSH_CREDS}:${PLUGIN_DIR}
else
echo -e ${INVALID_PARAMETERS};
fi
#!/usr/bin/env bash
if [ $# -lt 3 ]; then
echo "usage: $0 <db-name> <db-user> <db-pass> [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]+$ ]]; 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-nightly
download https://wordpress.org/nightly-builds/wordpress-latest.zip $TMPDIR/wordpress-nightly/wordpress-nightly.zip
unzip -q $TMPDIR/wordpress-nightly/wordpress-nightly.zip -d $TMPDIR/wordpress-nightly/
mv $TMPDIR/wordpress-nightly/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
svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
svn co --quiet 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/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
}
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
mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
}
install_wp
install_test_suite
install_db
@EvanHerman
Copy link
Author

Note: The Circle CI config file should be placed in the plugins root directory, inside of a .circleci/ directory.

Example: wp-content/plugins/plugin-name/.circleci/config.yml

@EvanHerman
Copy link
Author

Note: deploy.sh and install-wp-tests.sh files should be placed in the plugins root directory, inside of a bin/ directory.

Example: wp-content/plugins/plugin-name/bin/deploy.sh and wp-content/plugins/plugin-name/bin/install-wp-tests.sh

@EvanHerman
Copy link
Author

In the example below we're using a Digital Ocean droplet setup through Server Pilot, so the SSH user is serverpilot. Your SSH user may differ.

It's also advised that you generate a SSH key pair specifically for deployments, so you're not reusing an existing SSH key.

Install Private Key on CircleCI:

  • To install the private SSH key into Circle CI, first head to the project
  • From the project head into Project Settings > SSH Permissions
  • Copy the contents of the private key (cat ~/.ssh/sshkey | pbcopy)
  • In CircleCI, click the 'Add SSH Key' button and paste the contents of the private key into the field, leaving the hostname empty

Install Public Key on Digital Ocean:
You'll need to install the public key on your Digital Ocean droplet. To do so, you can use the following command
to SSH into your server and paste the contents of the public key on your local machine into the ~/.ssh/authorized_keys
file on the Digital Ocean droplet.

cat ~/.ssh/sshkey.pub | ssh serverpilot@123.456.789.123 "cat >> ~/.ssh/authorized_keys"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment