provision: Use NVM to install node and npm.

NVM takes a specific node version and installs the node package and
a corresponding compatible npm package.

We use it in a somewhat hackish way to install node/npm globally with
a pinned version, since that's how we actually want to consume node in
our development environment.

Other details:
- Travis CI now is configured to use the version of node installed by
provision; the easiest way to do this was to sabotage the existing node
installation.
- jsdom is upgraded to a current version, which both requires recent
node and also is required for the tests to pass with recent node.
This fixes running the node tests on Xenial.

Fixes #1498.

[tweaked by tabbott]
This commit is contained in:
umkay 2016-09-20 23:44:01 -07:00 committed by Tim Abbott
parent 14dc5a73f5
commit 798e6faa9e
8 changed files with 43 additions and 40 deletions

View File

@ -2,6 +2,8 @@ dist: trusty
before_install: before_install:
- nvm install 0.10 - nvm install 0.10
install: install:
# Disable Travis CI's built-in NVM installation
- mv ~/.nvm ~/.travis-nvm-disabled
- pip install coveralls - pip install coveralls
- tools/travis/setup-$TEST_SUITE - tools/travis/setup-$TEST_SUITE
- tools/clean-venv-cache --travis - tools/clean-venv-cache --travis

View File

@ -293,13 +293,10 @@ if [ $(uname) = "OpenBSD" ]; then sudo cp ./puppet/zulip/files/postgresql/zulip_
./tools/setup/postgres-init-test-db ./tools/setup/postgres-init-test-db
./tools/do-destroy-rebuild-test-database ./tools/do-destroy-rebuild-test-database
./manage.py compilemessages ./manage.py compilemessages
sudo ./tools/setup/install-node
npm install npm install
``` ```
If `npm install` fails, the issue may be that you need a newer version
of `npm`. You can use `npm install -g npm` to update your version of
`npm` and try again.
To start the development server: To start the development server:
``` ```

View File

@ -17,7 +17,7 @@
}, },
"devDependencies": { "devDependencies": {
"istanbul": "0.4.0", "istanbul": "0.4.0",
"jsdom": "0.5.7", "jsdom": "9.4.1",
"xmlhttprequest": "1.5.0", "xmlhttprequest": "1.5.0",
"nwmatcher": "1.3.6", "nwmatcher": "1.3.6",
"htmlparser2": "3.8.3", "htmlparser2": "3.8.3",

4
scripts/setup/node-wrapper Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
export NVM_DIR="/usr/local/nvm"
[ -e "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
node "$@"

4
scripts/setup/npm-wrapper Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
export NVM_DIR="/usr/local/nvm"
[ -e "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
npm "$@"

View File

@ -25,10 +25,8 @@ SUPPORTED_PLATFORMS = {
], ],
} }
NPM_VERSION = '3.9.3'
PY2_VENV_PATH = "/srv/zulip-venv" PY2_VENV_PATH = "/srv/zulip-venv"
PY3_VENV_PATH = "/srv/zulip-py3-venv" PY3_VENV_PATH = "/srv/zulip-py3-venv"
TRAVIS_NODE_PATH = os.path.join(os.environ['HOME'], 'node')
VAR_DIR_PATH = os.path.join(ZULIP_PATH, 'var') VAR_DIR_PATH = os.path.join(ZULIP_PATH, 'var')
LOG_DIR_PATH = os.path.join(VAR_DIR_PATH, 'log') LOG_DIR_PATH = os.path.join(VAR_DIR_PATH, 'log')
UPLOAD_DIR_PATH = os.path.join(VAR_DIR_PATH, 'uploads') UPLOAD_DIR_PATH = os.path.join(VAR_DIR_PATH, 'uploads')
@ -81,11 +79,9 @@ UBUNTU_COMMON_APT_DEPENDENCIES = [
"rabbitmq-server", "rabbitmq-server",
"redis-server", "redis-server",
"hunspell-en-us", "hunspell-en-us",
"nodejs",
"nodejs-legacy",
"supervisor", "supervisor",
"git", "git",
"npm", "libssl-dev",
"yui-compressor", "yui-compressor",
"wget", "wget",
"ca-certificates", # Explicit dependency in case e.g. wget is already installed "ca-certificates", # Explicit dependency in case e.g. wget is already installed
@ -120,29 +116,6 @@ REPO_STOPWORDS_PATH = os.path.join(
LOUD = dict(_out=sys.stdout, _err=sys.stderr) LOUD = dict(_out=sys.stdout, _err=sys.stderr)
def install_npm():
# type: () -> None
if not TRAVIS:
if subprocess_text_output(['npm', '--version']) != NPM_VERSION:
run(["sudo", "npm", "install", "-g", "npm@{}".format(NPM_VERSION)])
return
run(['mkdir', '-p', TRAVIS_NODE_PATH])
npm_exe = os.path.join(TRAVIS_NODE_PATH, 'bin', 'npm')
travis_npm = subprocess_text_output(['which', 'npm'])
if os.path.exists(npm_exe):
run(['sudo', 'ln', '-sf', npm_exe, travis_npm])
version = subprocess_text_output(['npm', '--version'])
if os.path.exists(npm_exe) and version == NPM_VERSION:
print("Using cached npm")
return
run(["npm", "install", "-g", "--prefix", TRAVIS_NODE_PATH, "npm@{}".format(NPM_VERSION)])
run(['sudo', 'ln', '-sf', npm_exe, travis_npm])
def main(): def main():
# type: () -> int # type: () -> int
@ -224,10 +197,12 @@ def main():
run(["tools/setup/postgres-init-test-db"]) run(["tools/setup/postgres-init-test-db"])
run(["tools/do-destroy-rebuild-test-database"]) run(["tools/do-destroy-rebuild-test-database"])
run(["python", "./manage.py", "compilemessages"]) run(["python", "./manage.py", "compilemessages"])
# Install the pinned version of npm.
install_npm() # Here we install nvm, node, and npm.
# Run npm install last because it can be flaky, and that way one run(["sudo", "tools/setup/install-node"])
# only needs to rerun `npm install` to fix the installation.
# This is a wrapper around `npm install`, which we run last since
# it can often fail due to network issues beyond our control.
try: try:
setup_node_modules() setup_node_modules()
except subprocess.CalledProcessError: except subprocess.CalledProcessError:

22
tools/setup/install-node Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e
ZULIP_PATH=$(dirname "$0")
export NVM_DIR=/usr/local/nvm
if ! [ -e "$NVM_DIR/nvm.sh" ]; then
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.32.0/install.sh | bash
fi
source "$NVM_DIR/nvm.sh"
node_version=6.6.0
nvm install "$node_version" && nvm alias default "$node_version"
# Fix messed-up uid=500 and group write bits produced by nvm
n=$(which node)
n=${n%/bin/node}
chown -R root:root "$n"
chmod -R go-w "$n"
# Install node and npm wrappers to /usr/local/bin
cp "$ZULIP_PATH/../../scripts/setup/node-wrapper" /usr/local/bin/node
cp "$ZULIP_PATH/../../scripts/setup/npm-wrapper" /usr/local/bin/npm

View File

@ -3,11 +3,10 @@ set -e
cd "$(dirname "$0")"/.. cd "$(dirname "$0")"/..
export NODE_PATH=/usr/lib/nodejs:static export NODE_PATH=static
export PATH=$PATH:node_modules/.bin export PATH=$PATH:node_modules/.bin
INDEX_JS=frontend_tests/zjsunit/index.js INDEX_JS=frontend_tests/zjsunit/index.js
NODEJS=$(which nodejs || which node)
ret=0 ret=0
if [ "$1" = "cover" ]; then if [ "$1" = "cover" ]; then
@ -26,7 +25,7 @@ elif [ "$1" = "-h" -o "$1" = "--help" ]; then
else else
# Normal testing, no coverage analysis. # Normal testing, no coverage analysis.
# Run the index.js test runner, which runs all the other tests. # Run the index.js test runner, which runs all the other tests.
"$NODEJS" --stack-trace-limit=100 "$INDEX_JS" $@ || ret=1; node --stack-trace-limit=100 "$INDEX_JS" $@ || ret=1;
fi fi
if [ $ret = '0' ]; then if [ $ret = '0' ]; then