Skip to content

Instantly share code, notes, and snippets.

@keesiemeijer
Last active December 8, 2023 11:02
Show Gist options
  • Star 50 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save keesiemeijer/a888f3d9609478b310c2d952644891ba to your computer and use it in GitHub Desktop.
Save keesiemeijer/a888f3d9609478b310c2d952644891ba to your computer and use it in GitHub Desktop.
Setup PHPUnit for use in the Local by Flywheel app
#!/usr/bin/env bash
# ===============================================================================
# Script to install PHPUnit in the Local by Flywheel Mac app
# These packages are installed
#
# PHPUnit, curl wget, rsync, git, subversion and composer.
#
# WordPress is installed in the `/tmp/wordpress` directory for use by PHPUnit.
# The WordPress test suite is installed in the `/tmp/wordpress-tests-lib` directory.
#
# The WordPress and WP Test Suite paths are added to the ~/.bashrc file as environment
# variables $WP_CORE_DIR and $WP_TESTS_DIR.
#
# That way plugins can make use of them for unit testing. Plugins that have their
# tests scaffolded by WP-CLI also makes use of them. VVV also adds these enviroment
# variables to the ~/.bashrc file by default.
#
# You only have to run this script once. PHPUnit (and the other packages) are
# still available next time you ssh into your site.
#
# To update WordPress and the WP Test Suite re-run this script.
# Use options to install specific versions for PHPUnit, WordPress or the WP_UnitTestCase.
#
# Note: This script doesn't install the packages globally in the Local by Flywheel app
# Packages are only installed for the site where you've run this script.
# ===============================================================================
# ===============================================================================
# Instructions
#
# 1 - Download this file (setup-phpunit.sh) inside your site's /app folder
# curl -o setup-phpunit.sh https://gist.githubusercontent.com/keesiemeijer/a888f3d9609478b310c2d952644891ba/raw/
#
# 2 - Right click your site in the Local App and click Open Site SSH
# A new terminal window will open
#
# 3 - Go to your site's /app folder:
# cd /app
#
# 4 - Run this script
# bash setup-phpunit.sh
#
# 5 - Reload the .bashrc file
# source ~/.bashrc
#
# 6 - Check if PHPUnit is installed
# phpunit --version
#
# ===============================================================================
# ===============================================================================
# Options
#
# Without options this script installs/updates PHPUnit, WordPress and the WP test suite.
#
# Install a specific PHPUnit version with the --phpunit-version option.
#
# bash setup-phpunit.sh --phpunit-version=7
#
# Install a specific WordPress version with the --wp-version option. This option
# accepts a version number, 'latest', 'trunk' or 'nightly'. Default 'latest'
#
# bash setup-phpunit.sh --wp-version=5.0
#
# Install a specific WordPress Test Suite with the --wp-ts-version option. This option
# accepts a version number, 'latest', 'trunk' or 'nightly'. Default 'latest'
#
# bash setup-phpunit.sh --wp-ts-version=trunk
#
# Update all packages (wget, curl etc) installed by this script with the --update-packages option.
#
# bash setup-phpunit.sh --update-packages
#
# Use the --help or -? option to see more information about this script.
#
# bash setup-phpunit.sh --help
#
# ===============================================================================
# ===============================================================================
# Default PHPUnit version
#
# The default installed PHPUnit version is similar to versions used in
# WordPress travis.yaml file in trunk.
#
# See https://core.trac.wordpress.org/browser/trunk/.travis.yml#L64
#
# PHPUnit version 7 is installed for PHP version 7.1 and above
# PHPUnit version 5 is installed for PHP version 7.0
# PHPUnit version 4 for all other PHP versions
#
# See ticket https://core.trac.wordpress.org/ticket/39822
# See ticket https://core.trac.wordpress.org/ticket/43218
#
# Run the command with a version if you need to test with a specific PHPUnit version
#
# bash setup-phpunit.sh --phpunit-version=7
#
# This example will install the latest PHPUnit from version 7 (e.g. 7.5.3)
#
# Available PHPUnit versions can be found here.
# https://phar.phpunit.de
#
# PHPUnit versions compatible with PHP versions can be found here.
# https://phpunit.de/supported-versions.html
#
# ===============================================================================
# Strings used in error messages.
readonly QUIT="Stopping script..."
readonly CONNECTION="Make sure you're connected to the internet."
readonly RED='\033[0;31m' # Red color.
readonly RESET='\033[0m' # No color.
# Functions
function download() {
download=false
if wget --spider "$1" >/dev/null 2>&1; then
wget -q --show-progress -O "$2" "$1" && download=true
# Check if file exists.
if [[ -f "$2" && "$download" = true ]]; then
return 0
fi
fi
printf "${RED}WARNING${RESET} Could not download %s %s\n" "$1" "$CONNECTION"
return 1
}
function download_test_suite() {
local exit=0
if wget --spider "https://develop.svn.wordpress.org/$1/tests/phpunit/includes/" >/dev/null 2>&1; then
svn export --quiet --force "https://develop.svn.wordpress.org/$1/tests/phpunit/includes/" "/tmp/tmp-wordpress-tests-lib/includes/"
svn export --quiet --force "https://develop.svn.wordpress.org/$1/tests/phpunit/data/" "/tmp/tmp-wordpress-tests-lib/data/"
svn export --quiet --force "https://develop.svn.wordpress.org/$1/wp-tests-config-sample.php" "/tmp/tmp-wordpress-tests-lib/wp-tests-config.php"
for path in includes data wp-tests-config.php; do
# Check if path exists.
[[ ! -e "/tmp/tmp-wordpress-tests-lib/$path" ]] && exit=1
done
if [[ 0 = "$exit" ]]; then
return 0
fi
fi
printf "${RED}WARNING${RESET} Could not download %s Test Suite. %s\n" "$2" "$CONNECTION"
return 1
}
function packages_installed() {
for file in /usr/bin/wget /usr/bin/curl /usr/bin/svn /usr/bin/rsync /usr/local/bin/composer /usr/bin/git; do
# Check if executable file.
if ! [[ -f "$file" && -x "$file" ]]; then
return 1
fi
done
return 0
}
function clean_up_temp_files() {
# Clean up files added by this script.
[[ -d "/tmp/tmp-wordpress/" ]] && rm -rf "/tmp/tmp-wordpress/"
[[ -d "/tmp/tmp-wordpress-tests-lib/" ]] && rm -rf "/tmp/tmp-wordpress-tests-lib/"
[[ -f "/tmp/my.cnf" ]] && rm -f "/tmp/my.cnf"
}
function exit_script() {
clean_up_temp_files
exit 1
}
# Get arguments.
for arg in "$@"
do
if [[ "$arg" =~ ^- ]]; then
# Argument start with a dash.
case "$arg" in
--phpunit-version=*) PHPUNIT_VERSION=${arg#"--phpunit-version="};;
--wp-version=*) WP_VERSION=${arg#"--wp-version="};;
--wp-ts-version=*) WP_TS_VERSION=${arg#"--wp-ts-version="};;
--update-packages*) UPDATE_PACKAGES=true;;
-?|--help)
printf "Install PHPUnit in the Local by Flywheel Mac app\n\n"
printf "Usage:\n"
printf "\tbash setup-phpunit.sh [option...]\n\n"
printf "Example:\n"
printf "\tbash setup-phpunit.sh --phpunit-version=6 --wp-version=trunk\n\n"
printf "Options:\n"
printf -- "\t--phpunit-version PHPUnit version to install\n"
printf -- "\t--wp-version WordPress version to install\n"
printf -- "\t Accepts a version number, 'latest', 'trunk' or 'nightly'. Default 'latest'\n"
printf -- "\t--wp-ts-version WordPress Test Suite version to install\n"
printf -- "\t Accepts a version number, 'latest', 'trunk' or 'nightly'. Default --wp-version option\n"
printf -- "\t--update-packages Update all packages installed by this script\n"
printf -- "\t Updates curl wget, rsync, git, subversion and composer\n"
printf -- "\t-?|--help Display information about this script\n\n"
exit 0
;;
*)
printf "Unknown option: %s.\nUse \"bash setup-phpunit.sh --help\" to see all options\n%s\n" "$arg" "$QUIT_MSG"
exit_script
;;
esac
else
# Argument doesn't start with a dash.
printf "Unknown option: %s.\nUse \"bash setup-phpunit.sh --help\" to see all options\n%s\n" "$arg" "$QUIT_MSG"
exit_script
fi
done
INSTALL_PACKAGES=false
if ! packages_installed; then INSTALL_PACKAGES=true; fi
[[ -z "$UPDATE_PACKAGES" ]] && UPDATE_PACKAGES=false
if [[ "$INSTALL_PACKAGES" = true || "$UPDATE_PACKAGES" = true ]]; then
[[ "$INSTALL_PACKAGES" = true ]] && printf "Installing packages...\n" || printf "Updating packages...\n"
# Re-synchronize the package index files from their sources.
apt-get update -y
# Install packages.
apt-get install -y wget subversion curl git rsync
# Install composer.
if [[ -f "/usr/bin/curl" && ! -f "/usr/local/bin/composer" ]]; then
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer || exit
if [[ -f "$HOME/.bashrc" ]]; then
printf "Adding .composer/vendor/bin to the PATH\n"
echo 'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> "$HOME/.bashrc"
fi
else
if [[ -f "/usr/local/bin/composer" ]]; then
printf "Updating composer...\n"
composer self-update || printf "${RED}WARNING${RESET} Could not update composer. %s\n" "$CONNECTION"
fi
fi
fi
# Re-check if all packages are installed.
if ! packages_installed; then
printf "${RED}ERROR${RESET} Missing packages. %s\n%s\n" "$CONNECTION" "$QUIT"
exit_script
fi
# Get the current PHP version.
PHP_VERSION=$(php -r "echo PHP_VERSION;")
# Get first three characters from version
readonly PHP_VERSION="${PHP_VERSION:0:3}"
# Set the PHPUnit version if needed.
if [[ -z "$PHPUNIT_VERSION" ]]; then
case "$PHP_VERSION" in
7.4|7.3|7.2|7.1)
PHPUNIT_VERSION=7
;;
7.0)
PHPUNIT_VERSION=5
;;
*)
PHPUNIT_VERSION=4
;;
esac
fi
readonly PHPUNIT_VERSION="$PHPUNIT_VERSION"
# Install PHPUnit.
printf "Installing PHPUnit %s... \n" "$PHPUNIT_VERSION"
if download "https://phar.phpunit.de/phpunit-$PHPUNIT_VERSION.phar" "phpunit-$PHPUNIT_VERSION.phar"; then
chmod +x "phpunit-$PHPUNIT_VERSION.phar"
mv "phpunit-$PHPUNIT_VERSION.phar" /usr/local/bin/phpunit
else
printf "%s\n" "$QUIT"
exit_script
fi
# Set WordPress environment variables.
if [[ -f "$HOME/.bashrc" ]]; then
# Get the variables.
source "$HOME/.bashrc"
if [[ -z "${WP_TESTS_DIR}" ]]; then
printf "Setting WP_TESTS_DIR environment variable\n"
echo 'export WP_TESTS_DIR=/tmp/wordpress-tests-lib' >> "$HOME/.bashrc"
fi
if [[ -z "${WP_CORE_DIR}" ]]; then
printf "Setting WP_CORE_DIR environment variable\n"
echo 'export WP_CORE_DIR=/tmp/wordpress' >> "$HOME/.bashrc"
fi
# Get the new variables.
source "$HOME/.bashrc"
fi
if [[ -z "$WP_CORE_DIR" || -z "$WP_TESTS_DIR" ]]; then
printf "${RED}ERROR${RESET} The WordPress directories for PHPUnit are not set\n%s\n" "$QUIT"
exit_script
fi
# Delete tmp files (if they exist).
clean_up_temp_files
# Create tmp directories.
mkdir "/tmp/tmp-wordpress/" || exit
mkdir "/tmp/tmp-wordpress-tests-lib/" || exit
# Create core and tests directories (if needed).
[[ -d "$WP_CORE_DIR" ]] || mkdir "$WP_CORE_DIR" || exit
[[ -d "$WP_TESTS_DIR" ]] || mkdir "$WP_TESTS_DIR" || exit
cd "$WP_CORE_DIR" || exit
# Set default WordPress version.
[[ -z "$WP_VERSION" ]] && WP_VERSION='latest'
# Get the latest WordPress version from API.
readonly WP_LATEST=$(wget -q -O - "http://api.wordpress.org/core/version-check/1.5/" | head -n 4 | tail -n 1);
if [[ 'latest' = "$WP_VERSION" ]]; then
WP_VERSION="$WP_LATEST"
if [[ -z "$WP_LATEST" ]]; then
printf "${RED}ERROR${RESET} Could not get latest WordPress version from api.wordpress.org. %s\n%s\n" "$CONNECTION" "$QUIT"
exit_script
fi
fi
# Set WordPress version.
readonly WP_VERSION="$WP_VERSION"
# Set default test suite version.
[[ -z "$WP_TS_VERSION" ]] && WP_TS_VERSION="$WP_VERSION"
# Install WordPress.
if [[ 'trunk' = "$WP_VERSION" ]]; then
printf "Installing WordPress trunk... \n"
svn export --quiet --force "https://develop.svn.wordpress.org/trunk/src/" "/tmp/tmp-wordpress/"
rsync -a --delete "/tmp/tmp-wordpress/" "$WP_CORE_DIR"
elif [[ 'nightly' = "$WP_VERSION" ]]; then
printf "Installing WordPress nightly... \n"
if download "https://wordpress.org/nightly-builds/wordpress-latest.zip" "/tmp/wordpress-latest.zip"; then
unzip -o -q "/tmp/wordpress-latest.zip" -d "/tmp/tmp-wordpress/"
rsync -a --delete "/tmp/tmp-wordpress/wordpress/" "$WP_CORE_DIR"
fi
else
printf "Installing WordPress %s... \n" "$WP_VERSION"
if download "https://wordpress.org/wordpress-$WP_VERSION.tar.gz" "/tmp/wordpress.tar.gz"; then
tar --strip-components=1 -zxmf "/tmp/wordpress.tar.gz" -C "/tmp/tmp-wordpress/"
rsync -a --delete "/tmp/tmp-wordpress/" "$WP_CORE_DIR"
fi
fi
if [[ 'trunk' = "$WP_TS_VERSION" || 'nightly' = "$WP_TS_VERSION" ]]; then
TS_ARCHIVE="trunk"
elif [[ $WP_TS_VERSION = 'latest' ]]; then
TS_ARCHIVE="tags/$WP_LATEST"
WP_TS_VERSION="$WP_LATEST"
else
TS_ARCHIVE="tags/$WP_TS_VERSION"
fi
# Install WP test suite.
printf "Installing WordPress %s Test Suite...\n" "$WP_TS_VERSION"
if download_test_suite "$TS_ARCHIVE" "$WP_TS_VERSION"; then
rsync -a --delete "/tmp/tmp-wordpress-tests-lib/" "$WP_TESTS_DIR"
else
if [[ 'trunk' = "$TS_ARCHIVE" ]]; then
printf "%s\n" "$QUIT"
exit_script
fi
printf "Installing Test Suite from trunk...\n"
if download_test_suite "trunk" "trunk"; then
rsync -a --delete "/tmp/tmp-wordpress-tests-lib/" "$WP_TESTS_DIR"
else
printf "%s\n" "$QUIT"
exit_script;
fi
fi
# Update credentials in the wp-tests-config.php file.
if [[ -f "$WP_TESTS_DIR/wp-tests-config.php" ]]; then
printf "Updating wp-tests-config-sample.php...\n"
if [[ $(uname -s) == 'Darwin' ]]; then
ioption='-i .bak'
else
ioption='-i'
fi
sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/youremptytestdbnamehere/wordpress_test/" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/yourusernamehere/root/" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/yourpasswordhere/root/" "$WP_TESTS_DIR/wp-tests-config.php"
fi
# Install database if it doesn't exist.
printf "Checking if database wordpress_test exists\n"
# Suppress password warnings. It silly I know :-)
printf "[client]\npassword=root\nuser=root" > "/tmp/my.cnf"
database=$(mysqlshow --defaults-file="/tmp/my.cnf" wordpress_test | grep -v Wildcard | grep -o wordpress_test)
if ! [[ "wordpress_test" = "$database" ]]; then
printf "Creating database wordpress_test\n"
mysqladmin --defaults-file="/tmp/my.cnf" create "wordpress_test" --host="localhost"
else
printf "Database wordpress_test already exists\n"
fi
if [[ -f "$WP_TESTS_DIR/wp-tests-config.php" ]]; then
# VVV has the tests config outside the $WP_TESTS_DIR dir.
cp "$WP_TESTS_DIR/wp-tests-config.php" "/tmp/wp-tests-config.php"
fi
# Cleanup files.
clean_up_temp_files
printf "\nFinished setting up packages\n\n"
@rgadon107
Copy link

@hazephase In the Terminal, make sure that the shell script ( setup-phpunit.sh) is located in the /app directory. If it's it in a different directory (for example /app/a888f3d9609478b310c2d952644891ba/setup-phpunit.sh, you will not be able to open and execute the target script. It's just a matter of relocating the shell script (once it's been installed to your project) to the root of the /app directory. Then call the script. It should install easily and quickly.

@keesiemeijer
Copy link
Author

@hazephase I've updated the script (revision 15) to look if packages are installed instead of checking the internet connection. It should work with the Local app version 2.4.2

@iCaspar
Copy link

iCaspar commented Sep 28, 2018

Thanks for this @keesiemeijer, 👍 for the fix!

@JJJ
Copy link

JJJ commented Oct 16, 2018

Continues to work with Local Environment 1.3.1. 🤗

@keesiemeijer
Copy link
Author

keesiemeijer commented Feb 2, 2019

revision 17 — The default PHPUnit version is updated to 6 for PHP versions 7+

See ticket https://core.trac.wordpress.org/ticket/43218

@keesiemeijer
Copy link
Author

keesiemeijer commented Feb 4, 2019

Since revision 19 you can use specific options for PHPUnit, WordPress and the WordPress test suite. Use the options
--phpunit-version, --wp-version, --wp-ts-version and --update-packages.

use bash setup-phpunit.sh --help for more information

@DevinWalker
Copy link

So easy and simple! Thanks @keesiemeijer

@mintplugins
Copy link

When I try and test with phpunit -version, I am getting this response:

Fatal error: Cannot use PHPUnit\Framework\MockObject\Stub as Stub because the name is already in use in phar:///usr/local/bin/phpunit/phpunit-mock-objects/Builder/InvocationMocker.php on line 16

Does anybody know what might be going on here?

@mintplugins
Copy link

mintplugins commented Mar 7, 2019

It must have been an old version of phpUnit already installed. I spun up a new site in LocalByFlywheel and started over, and all is working 👍 Thanks!

On my old LocalByFlywheel site, I uninstalled PHPunit by running this before any of the steps here, and it fixed my issue:

sudo rm -r /usr/local/bin/phpunit

Update: Today I just ran into this again on a separate LocalByFlyWheel, and had to upgrade PHP to 7.2 to fix this.

@kurudrive
Copy link

Thanks!!!!!!!!!!
I am so happpppppyyyyyyyyyyyy!!!!!!!
Yeahhhhhhhhhhhhhhhhhhhhhhh!!!!!!!!

@DrewAPicture
Copy link

@keesiemeijer This is dope. Thank you!

@iamlasse
Copy link

This is amazing! Thanks for putting in the work!!!

@alexstandiford
Copy link

I've used this several times, and it has worked like a charm, however when working with it today I ran into an error when I run phpunit --version:

Fatal error: Cannot use PHPUnit\Framework\MockObject\Stub as Stub because the name is already in use in phar:///usr/local/bin/phpunit/phpunit-mock-objects/Builder/InvocationMocker.php on line 16

I was able to fix this by updating my PHP version to at least 7.1.4, and that fixed it.

@keesiemeijer
Copy link
Author

@alexstandiford I think it depends what PHPUnit version you were using. See here what versions are compatible with what PHP versions. https://phpunit.de/supported-versions.html

You could've also have downgraded the PHPUnit version to make it compatible (I think).

bash setup-phpunit.sh --phpunit-version=4

Maybe I could automate that in the script itself?

@alexstandiford
Copy link

@keesiemeijer You probably could automate that, actually. Since you're already fetching the php version in your script, you could probably associate which version of phpunit should be used to the php-version if the ---phpunit-version isn't set?

@keesiemeijer
Copy link
Author

keesiemeijer commented Jun 4, 2019

@alexstandiford I found out why you've gotten this error. PHPUnit 6 is not compatible with PHP 7.0.3 (shipped with the Local app). It is however compatible with PHP 7.0.13 and up.

In the latest revision (22) it installs PHPUnit 7 for PHP 7.1 and up, PHPUnit 5 for PHP 7.0, and PHPUnit 4 for all other versions.

@alexstandiford
Copy link

alexstandiford commented Jul 24, 2019

If you happen to be using this workflow to set up PHPUnit with PHPStorm:
https://localbyflywheel.com/community/t/local-phpunit-phpstorm/6203/16

You can set it up pretty fast using this script along with a really basic script I tossed together from the instructions provided by Clay.

  1. Set up ports as detailed in step 1 in the link above
  2. open site SSH and run this script.
    https://gist.github.com/alexstandiford/0728ba7b21caa323a5ecf67c6e98abd2
  3. Restart local
  4. Open site SSH and run this script.
  5. Start on step 4 in the link above.

@afragen
Copy link

afragen commented Jul 25, 2019

@keesiemeijer With MacOS Terminal moving to a default of zsh in Catalina MacOS 10.15, is there any need to adapt this script?

@alexstandiford
Copy link

@afragen I don't think so. I've been running zsh instead of bash with this script for a little while now and it's been working as-expected.

@afragen
Copy link

afragen commented Jul 25, 2019

Thanks for the confirmation @alexstandiford

@afragen
Copy link

afragen commented Jul 28, 2019

FYI, I had to make a number of changes to @keesiemeijer's excellent script to make it work with Local Lightning. You can find my modifications at https://github.com/afragen/setup-phpunit/blob/master/setup-phpunit.sh

I put a blog post on using WordPress Core Development with Local Lightning.

@alexstandiford
Copy link

FYI, I had to make a number of changes to @keesiemeijer's excellent script to make it work with Local Lightning. You can find my modifications at https://github.com/afragen/setup-phpunit/blob/lightning/setup-phpunit.sh

I put a blog post on using WordPress Core Development with Local Lightning.

I was just thinking about this the other day. Thanks for sharing!

@rgadon107
Copy link

rgadon107 commented Mar 30, 2020

@keesiemeijer I'm running Local (Local Lightening) version 5.2.8+2771 and attempting to install setup-phpunit.sh via SSH with iTerm2 (Terminal). The site is a bare WP install (v5.3.2) using the TwentyTwenty theme and no plugins.

The script fails to install, and bails out. Attached is a screenshot of my Terminal. Perhaps it will provide some insight into the point of failure and how to correct.

setup-phpunit_sh_script_failed_to_install_in_local_lightening

BTW, I don't put a lot of stock in the error message. I am connected to the internet, so that's not the source of the problem. The point about 'missing packages' is too vague to be of any use to me. Which packages (other than apt-get)? It's not clear.

Until I can get your script running on Local, I may need to go back to LocalByFlywheel (version 3.3.0) and run PHPUnit using that app instead. It's not the end of the world. LBF is a little slower than Local, but it may work.

@rgadon107
Copy link

rgadon107 commented Mar 31, 2020

@afragen Your modified script worked for me (^^^)! As you discovered and fixed, the .bashrc file was missing from the root directory in Mac OS X. [Aside: I have a .bash_profile file, but no .bashrc config file.] Your updated script fixes the problem.

I initially didn't fork your script because your related blog post described a specific use case of testing the leading edge of WP. I'm looking to install setup-phpunit.sh to run unit and integration tests on a WP plugin I built while running Local (Lightening).

Your updated script gets me one step closer to writing tests.

Thank you for solving this problem and responding in a timely manner.

@rgadon107
Copy link

@afragen While your script works in Local Lightening, I find that it does not persist in memory. Every time I restart my container on Local, I have to reinstall the shell script. Is there a particular option, setting, or flag I can invoke in the script to allow it to persist between sessions?

@afragen
Copy link

afragen commented Apr 4, 2020

@rgadon107 we should probably move this discussion to an issue on that repo.

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