Skip to content

Commit

Permalink
Improve the build scripts (#4465)
Browse files Browse the repository at this point in the history
There's a bunch of stuff that can be automated when setting up a local development environment. Here's some polish, etc.

Notable changes:

- Automatically check for and install NVM, update to the correct version of Node.
- Add some extra information to Docker checks.
- Add a check and fix for npm/npm#16938, which is super annoying.
- Switch to using Docker for Composer scripts.
- Defining the WordPress URL port in docker-compose.yml now defines it everywhere, including Cypress e2e tests.
- Generally clean up and hide the spammy status messages that don't benefit anyone.
- Add a welcome message at the end of the setup process.
  • Loading branch information
pento committed Jan 17, 2018
1 parent 7f7b607 commit c433d76
Show file tree
Hide file tree
Showing 15 changed files with 480 additions and 88 deletions.
8 changes: 6 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## Getting Started

Gutenberg is a Node.js-based project, built primarily in JavaScript. Be sure to have <a href="https://nodejs.org/en/">Node.js installed first</a>. You should be running a Node version matching the [current active LTS release](https://github.com/nodejs/Release#release-schedule) or newer for this plugin to work correctly. You can check your Node.js version by typing `node -v` in the Terminal prompt.
Gutenberg is a Node.js-based project, built primarily in JavaScript.

The easiest way to get started is by running the Local Environment setup script, `./bin/setup-local-env.sh`. This will check if you have everything installed and updated, and help you download any extra tools you need.

If you prefer to set things up manually, be sure to have <a href="https://nodejs.org/en/">Node.js installed first</a>. You should be running a Node version matching the [current active LTS release](https://github.com/nodejs/Release#release-schedule) or newer for this plugin to work correctly. You can check your Node.js version by typing `node -v` in the Terminal prompt.

You should also have the latest release of <a href="https://npmjs.org">npm installed</a>, npm is a separate project from Node.js and is updated frequently. If you've just installed Node.js which includes a version of npm within the installation you most likely will need to also update your npm install. To update npm, type this into your terminal: `npm install npm@latest -g`

Expand All @@ -13,7 +17,7 @@ To test the plugin, or to contribute to it, you can clone this repository and bu
First, you need a WordPress Environment to run the plugin on. The quickest way to get up and running is to use the provided docker setup. Just install [docker](https://www.docker.com/) on your machine and run `./bin/setup-local-env.sh`.

The WordPress installation should be available at `http://localhost:8888` (username: `admin`, password: `password`).
Inside the "docker" directory, you can use any docker command to interact with your containers.
Inside the "docker" directory, you can use any docker command to interact with your containers. If this port is in use, you can override it in your `docker-compose.override.yml` file. If you're running [e2e tests](https://wordpress.org/gutenberg/handbook/reference/testing-overview/#end-to-end-testing), this change will be used correctly.

Alternatively, you can use your own local WordPress environment and clone this repository right into your `wp-content/plugins` directory.

Expand Down
134 changes: 134 additions & 0 deletions bin/includes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/bin/bash

##
# Ask a Yes/No question, and way for a reply.
#
# This is a general-purpose function to ask Yes/No questions in Bash, either with or without a default
# answer. It keeps repeating the question until it gets a valid answer.
#
# @param {string} prompt The question to ask the user.
# @param {string} [default] Optional. "Y" or "N", for the default option to use if none is entered.
# @param {int} [timeout] Optional. The number of seconds to wait before using the default option.
#
# @returns {bool} true if the user replies Yes, false if the user replies No.
##
ask() {
# Source: https://djm.me/ask
local timeout endtime timediff prompt default reply

while true; do

timeout="${3:-}"

if [ "${2:-}" = "Y" ]; then
prompt="Y/n"
default=Y
elif [ "${2:-}" = "N" ]; then
prompt="y/N"
default=N
else
prompt="y/n"
default=
timeout=
fi

if [ -z "$timeout" ]; then
# Ask the question (not using "read -p" as it uses stderr not stdout)
echo -en "$1 [$prompt] "

# Read the answer (use /dev/tty in case stdin is redirected from somewhere else)
read reply </dev/tty
else
endtime=$((`date +%s` + $timeout));
while [ "$endtime" -ge `date +%s` ]; do
timediff=$(($endtime - `date +%s`))

echo -en "\r$1 [$prompt] (Default $default in ${timediff}s) "
read -t 1 reply </dev/tty

if [ -n "$reply" ]; then
break
fi
done
fi

# Default?
if [ -z "$reply" ]; then
reply=$default
fi

# Check if the reply is valid
case "$reply" in
Y*|y*) return 0 ;;
N*|n*) return 1 ;;
esac

done
}

##
# Download from a remote source.
#
# Checks for the existence of curl and wget, then downloads the remote file using the first available option.
#
# @param {string} remote The remote file to download.
# @param {string} [local] Optional. The local filename to use. If it isn't passed, STDOUT is used.
#
# @return {bool} Whether the download succeeded or not.
##
download() {
if command_exists "curl"; then
curl -s -o "${2:--}" "$1"
elif command_exists "wget"; then
wget -nv -O "${2:--}" "$1"
fi
}

##
# Add error message formatting to a string, and echo it.
#
# @param {string} message The string to add formatting to.
##
error_message() {
echo -en "\033[31mERROR\033[0m: $1"
}

##
# Add warning message formatting to a string, and echo it.
#
# @param {string} message The string to add formatting to.
##
warning_message() {
echo -en "\033[33mWARNING\033[0m: $1"
}

##
# Add status message formatting to a string, and echo it.
#
# @param {string} message The string to add formatting to.
##
status_message() {
echo -en "\033[32mSTATUS\033[0m: $1"
}

##
# Add formatting to an action string.
#
# @param {string} message The string to add formatting to.
##
action_format() {
echo -en "\033[32m$1\033[0m"
}

##
# Check if the command exists as some sort of executable.
#
# The executable form of the command could be an alias, function, builtin, executable file or shell keyword.
#
# @param {string} command The command to check.
#
# @return {bool} Whether the command exists or not.
##
command_exists() {
type -t "$1" >/dev/null 2>&1
}
63 changes: 63 additions & 0 deletions bin/install-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/bash

# Exit if any command fails
set -e

# Include useful functions
. "$(dirname "$0")/includes.sh"

# Check that Docker is installed
if ! command_exists "docker"; then
echo -e $(error_message "Docker doesn't seem to be installed. Please head on over to the Docker site to download it: $(action_format "https://www.docker.com/community-edition#/download")")
exit 1
fi

# Check that Docker is running
if ! docker info >/dev/null 2>&1; then
echo -e $(error_message "Docker isn't running. Please check that you've started your Docker app, and see it in your system tray.")
exit 1
fi

# Launch the containers
echo -e $(status_message "Updating and starting Docker containers...")
if ! docker-compose up -d; then
# Launching may fail due to the docker config file directory having changed.
# Remove the old wordpress-dev container, and try again.
docker container rm -fv wordpress-dev
docker-compose up -d
fi

HOST_PORT=$(docker inspect --format '{{(index (index .HostConfig.PortBindings "80/tcp") 0).HostPort}}' wordpress-dev)

# Wait until the docker containers are setup properely
echo -en $(status_message "Attempting to connect to wordpress...")
until $(curl -L http://localhost:$HOST_PORT -so - 2>&1 | grep -q "WordPress"); do
echo -n '.'
sleep 5
done
echo ' done!'

# Install WordPress
echo -en $(status_message "Installing WordPress...")
docker run -it --rm --volumes-from wordpress-dev --network container:wordpress-dev wordpress:cli core install --url=localhost:$HOST_PORT --title=Gutenberg --admin_user=admin --admin_password=password --admin_email=test@test.com >/dev/null

CURRENT_URL=$(docker run -it --rm --volumes-from wordpress-dev --network container:wordpress-dev wordpress:cli option get siteurl)
if [ "$CURRENT_URL" != "http://localhost:$HOST_PORT" ]; then
docker run -it --rm --volumes-from wordpress-dev --network container:wordpress-dev wordpress:cli option update home "http://localhost:$HOST_PORT"
docker run -it --rm --volumes-from wordpress-dev --network container:wordpress-dev wordpress:cli option update siteurl "http://localhost:$HOST_PORT"
fi
echo ' done!'

# Activate Gutenberg
echo -en $(status_message "Activating Gutenberg...")
docker run -it --rm --volumes-from wordpress-dev --network container:wordpress-dev wordpress:cli plugin activate gutenberg >/dev/null
echo ' done!'

# Install the PHPUnit test scaffolding
echo -en $(status_message "Installing PHPUnit test scaffolding...")
docker-compose run --rm wordpress_phpunit /app/bin/install-wp-tests.sh wordpress_test root example mysql latest false >/dev/null
echo ' done!'

# Install Composer
echo -e $(status_message "Installing and updating Composer modules...")
docker-compose run --rm composer install
89 changes: 89 additions & 0 deletions bin/install-node-nvm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/bin/bash
NVM_VERSION="v0.33.8"

# Exit if any command fails
set -e

# Include useful functions
. "$(dirname "$0")/includes.sh"

# Load NVM
if [ -n "$NVM_DIR" ]; then
# The --no-use option ensures loading NVM doesn't switch the current version.
. "$NVM_DIR/nvm.sh" --no-use
fi

# Change to the expected directory
cd "$(dirname "$0")/.."

# Check if nvm is installed
if [ "$TRAVIS" != "true" ] && ! command_exists "nvm"; then
if ask "$(error_message "NVM isn't installed, would you like to download and install it automatically?")" Y; then
# The .bash_profile file needs to exist for NVM to install
if [ ! -e ~/.bash_profile ]; then
touch ~/.bash_profile
fi

echo -en $(status_message "Installing NVM..." )
download "https://raw.githubusercontent.com/creationix/nvm/$NVM_VERSION/install.sh" | bash >/dev/null 2>&1
echo ' done!'

echo -e $(warning_message "NVM was updated, please run this command to reload it:" )
echo -e $(warning_message "$(action_format ". \$HOME/.nvm/nvm.sh")" )
echo -e $(warning_message "After that, re-run the setup script to continue." )
else
echo -e $(error_message "")
echo -e $(error_message "Please install NVM manually, then re-run the setup script to continue.")
echo -e $(error_message "NVM installation instructions can be found here: $(action_format "https://github.com/creationix/nvm")")
fi

exit 1
fi

if [ "$TRAVIS" != "true" ] && [ $NVM_VERSION != "v$(nvm --version)" ]; then
echo -en $(status_message "Updating NVM..." )
download "https://raw.githubusercontent.com/creationix/nvm/$NVM_VERSION/install.sh" | bash >/dev/null 2>&1
echo ' done!'

echo -e $(warning_message "NVM was updated, please run this command to reload it:" )
echo -e $(warning_message "$(action_format ". \$HOME/.nvm/nvm.sh")" )
echo -e $(warning_message "After that, re-run the setup script to continue." )
exit 1
fi

# Check if the current node version is up to date.
if [ "$TRAVIS" != "true" ] && [ "$(nvm current)" != "$(nvm version-remote --lts)" ]; then
echo -en $(status_message "Updating Node..." )
nvm install >/dev/null 2>&1
echo ' done!'

echo -e $(warning_message "A new node version was install, please run this command to use it:" )
echo -e $(warning_message "$(action_format "nvm use")" )
echo -e $(warning_message "After that, re-run the setup script to continue." )
exit 1
fi

# Install/update packages
echo -e $(status_message "Installing and updating NPM packages..." )
npm install

# There was a bug in NPM that caused has changes in package-lock.json. Handle that.
if [ "$TRAVIS" != "true" ] && ! git diff --exit-code package-lock.json >/dev/null; then
if ask "$(warning_message "Your package-lock.json changed, which may mean there's an issue with your NPM cache. Would you like to try and automatically clean it up?" )" N 10; then
rm -rf node_modules/
npm cache clean --force >/dev/null 2>&1
git checkout package-lock.json

echo -e $(status_message "Reinstalling NPM packages..." )
npm install

# Check that it's cleaned up now.
if git diff --exit-code package-lock.json >/dev/null; then
echo -e $(warning_message "Confirmed that the NPM cache is cleaned up." )
else
echo -e $(error_message "We were unable to clean the NPM cache, please manually review the changes to package-lock.json. Continuing with the setup process..." )
fi
else
echo -e $(warning_message "Please manually review the changes to package-lock.json. Continuing with the setup process..." )
fi
fi
Empty file modified bin/install-php-phpunit.sh
100644 → 100755
Empty file.
11 changes: 3 additions & 8 deletions bin/install-wp-tests.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/usr/bin/env bash

# Include useful functions
. "$(dirname "$0")/includes.sh"

if [ $# -lt 3 ]; then
echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
exit 1
Expand All @@ -15,14 +18,6 @@ SKIP_DB_CREATE=${6-false}
WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
WP_CORE_DIR=${WP_CORE_DIR-/tmp/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]+(\.[0-9]+)? ]]; then
WP_TESTS_TAG="tags/$WP_VERSION"
elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
Expand Down
10 changes: 6 additions & 4 deletions bin/run-wp-unit-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ if [ ${DOCKER} = "true" ]; then
else
bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
source bin/install-php-phpunit.sh

# Run the build because otherwise there will be a bunch of warnings about
# failed `stat` calls from `filemtime()`.
composer install || exit 1
npm install || exit 1
fi
# Run the build because otherwise there will be a bunch of warnings about
# failed `stat` calls from `filemtime()`.
composer install || exit 1
npm install || exit 1

npm run build || exit 1

# Make sure phpegjs parser is up to date
Expand Down
Loading

0 comments on commit c433d76

Please sign in to comment.