aboutsummaryrefslogtreecommitdiff
path: root/.ci
diff options
context:
space:
mode:
authorFlorian Walch <florian@fwalch.com>2015-07-05 10:52:36 +0300
committerThiago de Arruda <tpadilha84@gmail.com>2015-07-08 07:42:16 -0300
commitd2eb4a934683b5da63000d8b79a0d4c9a314d1c0 (patch)
tree36e2a564d18bea57f7f427c8a8acc1952190fa78 /.ci
parentbac2700e2f2aaa8842f8bd48ae54cc52703d7d6f (diff)
downloadrneovim-d2eb4a934683b5da63000d8b79a0d4c9a314d1c0.tar.gz
rneovim-d2eb4a934683b5da63000d8b79a0d4c9a314d1c0.tar.bz2
rneovim-d2eb4a934683b5da63000d8b79a0d4c9a314d1c0.zip
Travis: Refactor CI files, use container infrastructure.
* Split build steps to utilize the Travis build lifecycle. * Move shell code from `.travis.yml` into Bash files in `.ci/`, one file for each step of the Travis build lifecycle. * Use configuration variables in `.travis.yml` to change build behavior (e.g. build 32-bit with `BUILD_32BIT=ON`). * Keep all configuration in environment variables in `.travis.yml`. In scripts, concatenate environment variables according to configuration to change to different behavior. * Add GCC 5 builds for Linux. * Use Travis's caching feature [1] for third-party dependencies and pip packages. * Allow failures MSan, as the errors it reports have to be fixed first. Valgrind is still disabled, but can be enabled by setting `env: VALGRIND=ON` for a job in `.travis.yml`. [1] http://docs.travis-ci.com/user/caching
Diffstat (limited to '.ci')
-rwxr-xr-x.ci/after_success.sh10
-rwxr-xr-x.ci/before_cache.sh24
-rwxr-xr-x.ci/before_install.sh13
-rwxr-xr-x.ci/before_script.sh24
-rw-r--r--.ci/clang.sh73
-rwxr-xr-x.ci/clint.sh3
-rw-r--r--.ci/common.sh74
-rw-r--r--.ci/common/build.sh79
-rw-r--r--.ci/common/test.sh85
-rw-r--r--.ci/gcc-32.sh37
-rw-r--r--.ci/gcc.sh42
-rwxr-xr-x.ci/install.sh20
-rw-r--r--.ci/mingw.sh18
-rwxr-xr-x.ci/run_tests.sh26
-rwxr-xr-x.ci/script.sh21
15 files changed, 302 insertions, 247 deletions
diff --git a/.ci/after_success.sh b/.ci/after_success.sh
new file mode 100755
index 0000000000..bc75e06b85
--- /dev/null
+++ b/.ci/after_success.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ -n "${CI_TARGET}" ]]; then
+ exit
+fi
+
+coveralls --encoding iso-8859-1 || echo 'coveralls upload failed.'
diff --git a/.ci/before_cache.sh b/.ci/before_cache.sh
new file mode 100755
index 0000000000..8925da92f3
--- /dev/null
+++ b/.ci/before_cache.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ "${TRAVIS_OS_NAME}" != linux ]]; then
+ # Caches are only enabled for Travis's Linux container infrastructure,
+ # but this script is still executed on OS X.
+ exit
+fi
+
+# Don't cache pip's log and selfcheck.
+rm -rf "${HOME}/.cache/pip/log"
+rm -f "${HOME}/.cache/pip/selfcheck.json"
+
+# Update the third-party dependency cache only if the build was successful.
+if [[ -f "${SUCCESS_MARKER}" ]]; then
+ if [[ ! -f "${CACHE_MARKER}" ]] || [[ "${BUILD_NVIM_DEPS}" == true ]]; then
+ echo "Updating third-party dependency cache."
+ rm -rf "${HOME}/.cache/nvim-deps"
+ mv -T "${DEPS_INSTALL_PREFIX}" "${HOME}/.cache/nvim-deps"
+ touch "${CACHE_MARKER}"
+ fi
+fi
diff --git a/.ci/before_install.sh b/.ci/before_install.sh
new file mode 100755
index 0000000000..e70654c9be
--- /dev/null
+++ b/.ci/before_install.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ -n "${CI_TARGET}" ]]; then
+ exit
+fi
+
+if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
+ brew update
+fi
+pip install --user --upgrade pip
diff --git a/.ci/before_script.sh b/.ci/before_script.sh
new file mode 100755
index 0000000000..c1c2659562
--- /dev/null
+++ b/.ci/before_script.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ -n "${CI_TARGET}" ]]; then
+ exit
+fi
+
+CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "${CI_DIR}/common/build.sh"
+
+if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
+ # Adds user to a dummy group.
+ # That allows to test changing the group of the file by `os_fchown`.
+ sudo dscl . -create /Groups/chown_test
+ sudo dscl . -append /Groups/chown_test GroupMembership "${USER}"
+else
+ # Compile dependencies.
+ build_deps
+fi
+
+rm -rf "${LOG_DIR}"
+mkdir -p "${LOG_DIR}"
diff --git a/.ci/clang.sh b/.ci/clang.sh
deleted file mode 100644
index 70ed7d4764..0000000000
--- a/.ci/clang.sh
+++ /dev/null
@@ -1,73 +0,0 @@
-. "$CI_SCRIPTS/common.sh"
-
-sudo pip install cpp-coveralls
-
-# Use custom Clang and enable sanitizers on Linux.
-if [ "$TRAVIS_OS_NAME" = "linux" ]; then
- if [ -z "$CLANG_SANITIZER" ]; then
- echo "CLANG_SANITIZER not set."
- exit 1
- fi
-
- clang_version=3.6
- echo "Installing Clang $clang_version..."
-
- sudo add-apt-repository "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu precise main"
- sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA9EF27F
-
- sudo add-apt-repository "deb http://llvm.org/apt/precise/ llvm-toolchain-precise-$clang_version main"
- wget -q -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
-
- sudo apt-get update -qq
- sudo apt-get install -y -q clang-$clang_version
-
- export CC=/usr/bin/clang-$clang_version
- symbolizer=/usr/bin/llvm-symbolizer-$clang_version
- export ASAN_SYMBOLIZER_PATH=$symbolizer
- export MSAN_SYMBOLIZER_PATH=$symbolizer
- export ASAN_OPTIONS="detect_leaks=1:log_path=$tmpdir/asan"
- export TSAN_OPTIONS="external_symbolizer_path=$symbolizer log_path=$tmpdir/tsan"
- export UBSAN_OPTIONS="log_path=$tmpdir/ubsan" # not sure if this works
- CMAKE_EXTRA_FLAGS="-DTRAVIS_CI_BUILD=ON \
- -DUSE_GCOV=ON \
- -DBUSTED_OUTPUT_TYPE=plainTerminal \
- -DCLANG_${CLANG_SANITIZER}=ON"
-else
- CMAKE_EXTRA_FLAGS="-DTRAVIS_CI_BUILD=ON \
- -DUSE_GCOV=ON \
- -DBUSTED_OUTPUT_TYPE=plainTerminal"
-fi
-
-setup_deps x64
-
-# Build and output version info.
-$MAKE_CMD CMAKE_EXTRA_FLAGS="$CMAKE_EXTRA_FLAGS" nvim
-build/bin/nvim --version
-
-# Run unittests.
-make unittest
-
-# Run functional tests.
-# FIXME (fwalch): Disabled for MSAN because of SIGPIPE error.
-if [ "$TRAVIS_OS_NAME" = linux ] && ! [ "$CLANG_SANITIZER" = MSAN ]; then
- if ! $MAKE_CMD test; then
- asan_check "$tmpdir"
- exit 1
- fi
- asan_check "$tmpdir"
-fi
-
-# Run legacy tests.
-if ! $MAKE_CMD oldtest; then
- reset
- asan_check "$tmpdir"
- exit 1
-fi
-asan_check "$tmpdir"
-
-coveralls --encoding iso-8859-1 || echo 'coveralls upload failed.'
-
-# Test if correctly installed.
-sudo -E $MAKE_CMD install
-/usr/local/bin/nvim --version
-/usr/local/bin/nvim -e -c "quit"
diff --git a/.ci/clint.sh b/.ci/clint.sh
deleted file mode 100755
index 53769a2552..0000000000
--- a/.ci/clint.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-make lint
diff --git a/.ci/common.sh b/.ci/common.sh
deleted file mode 100644
index 4894c0d5ad..0000000000
--- a/.ci/common.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-set -eu
-
-valgrind_check() {
- check_logs "$1" "valgrind-*"
-}
-
-asan_check() {
- check_logs "$1" "*san.*"
-}
-
-check_logs() {
- local err=""
- check_core_dumps
- # Iterate through each log to remove an useless warning
- for log in $(find "$1" -type f -name "$2"); do
- sed -i "$log" \
- -e '/Warning: noted but unhandled ioctl/d' \
- -e '/could cause spurious value errors to appear/d' \
- -e '/See README_MISSING_SYSCALL_OR_IOCTL for guidance/d'
- done
- # Now do it again, but only consider files with size > 0
- for log in $(find "$1" -type f -name "$2" -size +0); do
- cat "$log"
- err=1
- done
- if [ -n "$err" ]; then
- echo "Runtime errors detected"
- exit 1
- fi
-}
-
-check_core_dumps() {
- sleep 2
-
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
- cores="$(find /cores/ -type f -print)"
- dbg="lldb -Q -o bt -f build/bin/nvim -c"
- else
- # TODO(fwalch): Will trigger if a file named core.* exists outside of .deps.
- cores="$(find ./ -type f -not -path '*.deps*' -name 'core.*' -print)"
- dbg="gdb -n -batch -ex bt build/bin/nvim"
- fi
-
- if [ -z "$cores" ]; then
- return
- fi
- for c in $cores; do
- $dbg $c
- done
- exit 1
-}
-
-setup_deps() {
- sudo pip install --upgrade pip
- sudo pip install neovim
-
- # For pip3
- # https://github.com/travis-ci/travis-ci/issues/1528
- # sudo apt-get install -q python3.3-dev
- # curl -Ss http://python-distribute.org/distribute_setup.py | sudo python3
- # curl -Ss https://raw.github.com/pypa/pip/master/contrib/get-pip.py | sudo python3
- # sudo pip3.3 install neovim
-
- if [ "$BUILD_NVIM_DEPS" != "true" ]; then
- eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) deps-${1}"
- elif [ "$TRAVIS_OS_NAME" = "linux" ]; then
- sudo apt-get install libtool
- fi
-}
-
-tmpdir="$(pwd)/tmp"
-rm -rf "$tmpdir"
-mkdir -p "$tmpdir"
-suppressions="$(pwd)/.valgrind.supp"
diff --git a/.ci/common/build.sh b/.ci/common/build.sh
new file mode 100644
index 0000000000..0140be3637
--- /dev/null
+++ b/.ci/common/build.sh
@@ -0,0 +1,79 @@
+build_deps() {
+ if [[ "${BUILD_32BIT}" == ON ]]; then
+ if [[ "${BUILD_MINGW}" == ON ]]; then
+ >&2 echo "32-bit MinGW builds not supported."
+ exit 1
+ fi
+
+ DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}"
+ fi
+ if [[ "${BUILD_MINGW}" == ON ]]; then
+ DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} ${CMAKE_FLAGS_MINGW}"
+ fi
+
+ rm -rf "${DEPS_INSTALL_PREFIX}"
+
+ # If there is a valid cache and we're not forced to recompile,
+ # use cached third-party dependencies.
+ if [[ -f "${CACHE_MARKER}" ]] && [[ "${BUILD_NVIM_DEPS}" != true ]]; then
+ echo "Using third-party dependencies from Travis's cache (last updated: $(stat -c '%y' "${CACHE_MARKER}"))."
+
+ mkdir -p "$(dirname "${DEPS_INSTALL_PREFIX}")"
+ ln -Ts "${HOME}/.cache/nvim-deps" "${DEPS_INSTALL_PREFIX}"
+ return
+ fi
+
+ mkdir -p "${DEPS_BUILD_DIR}"
+ cd "${DEPS_BUILD_DIR}"
+ echo "Configuring with '${DEPS_CMAKE_FLAGS}'."
+ cmake ${DEPS_CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}/third-party/"
+
+ if ! ${MAKE_CMD}; then
+ exit 1
+ fi
+
+ cd "${TRAVIS_BUILD_DIR}"
+}
+
+build_nvim() {
+ if [[ -n "${CLANG_SANITIZER}" ]]; then
+ CMAKE_FLAGS="${CMAKE_FLAGS} -DCLANG_${CLANG_SANITIZER}=ON"
+ fi
+ if [[ "${BUILD_32BIT}" == ON ]]; then
+ if [[ "${BUILD_MINGW}" == ON ]]; then
+ >&2 echo "32-bit MinGW builds not supported."
+ exit 1
+ fi
+
+ CMAKE_FLAGS="${CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}"
+ fi
+ if [[ "${BUILD_MINGW}" == ON ]]; then
+ CMAKE_FLAGS="${CMAKE_FLAGS} ${CMAKE_FLAGS_MINGW}"
+ fi
+
+ mkdir -p "${BUILD_DIR}"
+ cd "${BUILD_DIR}"
+ echo "Configuring with '${CMAKE_FLAGS}'."
+ cmake ${CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}"
+
+ echo "Building nvim."
+ if ! ${MAKE_CMD} nvim; then
+ exit 1
+ fi
+
+ echo "Building libnvim."
+ if ! ${MAKE_CMD} libnvim; then
+ exit 1
+ fi
+
+ echo "Building nvim-test."
+ if ! ${MAKE_CMD} nvim-test; then
+ exit 1
+ fi
+
+ # Invoke nvim to trigger *San early.
+ bin/nvim --version
+ bin/nvim -u NONE -e -c ':qall'
+
+ cd "${TRAVIS_BUILD_DIR}"
+}
diff --git a/.ci/common/test.sh b/.ci/common/test.sh
new file mode 100644
index 0000000000..2eaaf0b2b1
--- /dev/null
+++ b/.ci/common/test.sh
@@ -0,0 +1,85 @@
+check_core_dumps() {
+ sleep 2
+
+ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
+ local cores="$(find /cores/ -type f -print)"
+ local dbg_cmd="lldb -Q -o bt -f ${BUILD_DIR}/bin/nvim -c"
+ else
+ # FIXME (fwalch): Will trigger if a file named core.* exists outside of $DEPS_BUILD_DIR.
+ local cores="$(find ./ -type f -not -path "*${DEPS_BUILD_DIR}*" -name 'core.*' -print)"
+ local dbg_cmd="gdb -n -batch -ex bt ${BUILD_DIR}/bin/nvim"
+ fi
+
+ if [ -z "${cores}" ]; then
+ return
+ fi
+ for core in $cores; do
+ ${dbg_cmd} "${core}"
+ done
+ exit 1
+}
+
+check_logs() {
+ # Iterate through each log to remove an useless warning.
+ for log in $(find "${1}" -type f -name "${2}"); do
+ sed -i "${log}" \
+ -e '/Warning: noted but unhandled ioctl/d' \
+ -e '/could cause spurious value errors to appear/d' \
+ -e '/See README_MISSING_SYSCALL_OR_IOCTL for guidance/d'
+ done
+
+ # Now do it again, but only consider files with size > 0.
+ local err=""
+ for log in $(find "${1}" -type f -name "${2}" -size +0); do
+ cat "${log}"
+ err=1
+ done
+ if [[ -n "${err}" ]]; then
+ echo "Runtime errors detected."
+ exit 1
+ fi
+}
+
+valgrind_check() {
+ check_logs "${1}" "valgrind-*"
+}
+
+asan_check() {
+ check_logs "${1}" "*san.*"
+}
+
+run_unittests() {
+ ${MAKE_CMD} -C "${BUILD_DIR}" unittest
+}
+
+run_functionaltests() {
+ if ! ${MAKE_CMD} -C "${BUILD_DIR}" functionaltest; then
+ asan_check "${LOG_DIR}"
+ valgrind_check "${LOG_DIR}"
+ exit 1
+ fi
+ asan_check "${LOG_DIR}"
+ valgrind_check "${LOG_DIR}"
+}
+
+run_oldtests() {
+ if ! make -C "${TRAVIS_BUILD_DIR}/src/nvim/testdir"; then
+ reset
+ asan_check "${LOG_DIR}"
+ valgrind_check "${LOG_DIR}"
+ exit 1
+ fi
+ asan_check "${LOG_DIR}"
+ valgrind_check "${LOG_DIR}"
+}
+
+install_nvim() {
+ ${MAKE_CMD} -C "${BUILD_DIR}" install
+
+ "${INSTALL_PREFIX}/bin/nvim" --version
+ "${INSTALL_PREFIX}/bin/nvim" -u NONE -e -c ':help' -c ':qall' || {
+ echo "Running ':help' in the installed nvim failed."
+ echo "Maybe the helptags have not been generated properly."
+ exit 1
+ }
+}
diff --git a/.ci/gcc-32.sh b/.ci/gcc-32.sh
deleted file mode 100644
index f1b2627fee..0000000000
--- a/.ci/gcc-32.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-. "$CI_SCRIPTS/common.sh"
-
-sudo apt-get install gcc-multilib g++-multilib
-
-setup_deps x86
-
-CMAKE_EXTRA_FLAGS="-DTRAVIS_CI_BUILD=ON \
- -DCMAKE_SYSTEM_PROCESSOR=i386 \
- -DCMAKE_SYSTEM_LIBRARY_PATH=/lib32:/usr/lib32:/usr/local/lib32 \
- -DFIND_LIBRARY_USE_LIB64_PATHS=OFF \
- -DCMAKE_IGNORE_PATH=/lib:/usr/lib:/usr/local/lib \
- -DCMAKE_TOOLCHAIN_FILE=$TRAVIS_BUILD_DIR/cmake/i386-linux-gnu.toolchain.cmake \
- -DBUSTED_OUTPUT_TYPE=plainTerminal"
-
-# Build and output version info.
-$MAKE_CMD DEPS_CMAKE_FLAGS="$CMAKE_EXTRA_FLAGS" \
- CMAKE_EXTRA_FLAGS="$CMAKE_EXTRA_FLAGS" nvim
-build/bin/nvim --version
-
-# Build library.
-$MAKE_CMD CMAKE_EXTRA_FLAGS="$CMAKE_EXTRA_FLAGS" libnvim
-
-# Run unittests.
-$MAKE_CMD unittest
-
-# Run functional tests.
-$MAKE_CMD test
-check_core_dumps
-
-# Run legacy tests.
-$MAKE_CMD oldtest
-check_core_dumps
-
-# Test if correctly installed.
-sudo -E $MAKE_CMD install
-/usr/local/bin/nvim --version
-/usr/local/bin/nvim -e -c "quit"
diff --git a/.ci/gcc.sh b/.ci/gcc.sh
deleted file mode 100644
index 2e760c7b68..0000000000
--- a/.ci/gcc.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-. "$CI_SCRIPTS/common.sh"
-
-sudo pip install cpp-coveralls
-
-# FIXME: Valgrind temporarily disabled (Timeouts on Travis).
-# if [ "$TRAVIS_OS_NAME" = "linux" ]; then
-# sudo apt-get install valgrind
-# export VALGRIND=1
-# export VALGRIND_LOG="$tmpdir/valgrind-%p.log"
-# fi
-
-setup_deps x64
-
-CMAKE_EXTRA_FLAGS="-DTRAVIS_CI_BUILD=ON \
- -DUSE_GCOV=ON \
- -DBUSTED_OUTPUT_TYPE=plainTerminal"
-
-# Build and output version info.
-$MAKE_CMD CMAKE_EXTRA_FLAGS="$CMAKE_EXTRA_FLAGS" nvim
-build/bin/nvim --version
-
-# Build library.
-$MAKE_CMD CMAKE_EXTRA_FLAGS="$CMAKE_EXTRA_FLAGS" libnvim
-
-# Run unittests.
-make unittest
-
-# Run functional tests.
-if ! $MAKE_CMD test; then
- valgrind_check "$tmpdir"
- exit 1
-fi
-valgrind_check "$tmpdir"
-
-# Run legacy tests.
-if ! $MAKE_CMD oldtest; then
- valgrind_check "$tmpdir"
- exit 1
-fi
-valgrind_check "$tmpdir"
-
-coveralls --encoding iso-8859-1 || echo 'coveralls upload failed.'
diff --git a/.ci/install.sh b/.ci/install.sh
new file mode 100755
index 0000000000..42c8026396
--- /dev/null
+++ b/.ci/install.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ -n "${CI_TARGET}" ]]; then
+ exit
+fi
+
+if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
+ brew install gettext
+elif [[ "${BUILD_MINGW}" == ON ]]; then
+ # TODO: When Travis gets a recent version of Mingw-w64 use packages:
+ # binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64-dev mingw-w64-tools
+
+ echo "Downloading MinGW..."
+ wget -q -O - "http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win32/Personal%20Builds/rubenvb/gcc-4.8-release/i686-w64-mingw32-gcc-4.8.0-linux64_rubenvb.tar.xz" | tar xJf - -C "${HOME}/.local"
+fi
+
+pip install --user --upgrade cpp-coveralls neovim
diff --git a/.ci/mingw.sh b/.ci/mingw.sh
deleted file mode 100644
index e1372cecc9..0000000000
--- a/.ci/mingw.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-. "$CI_SCRIPTS/common.sh"
-
-# FIXME: When Travis gets a recent version of Mingw-w64 use this
-#sudo apt-get install binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64-dev mingw-w64-tools
-#sudo apt-get install wine
-sudo apt-get install libc6-dev-i386
-
-# mingw-w64 build from http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/rubenvb/gcc-4.8-release/
-wget "http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win32/Personal%20Builds/rubenvb/gcc-4.8-release/i686-w64-mingw32-gcc-4.8.0-linux64_rubenvb.tar.xz" -O mingw.tar.xz
-sudo tar -axf mingw.tar.xz -C /opt
-export PATH=$PATH:/opt/mingw32/bin
-
-# Build third-party
-mkdir .deps
-cd .deps
-cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/mingw32-w64-cross-travis.toolchain.cmake ../third-party/
-cmake --build .
-cd ..
diff --git a/.ci/run_tests.sh b/.ci/run_tests.sh
new file mode 100755
index 0000000000..f3a6466c5e
--- /dev/null
+++ b/.ci/run_tests.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+# TODO: Stop here for MinGW builds,
+# building Neovim doesn't work yet.
+if [[ "${BUILD_MINGW}" == ON ]]; then
+ echo "Neovim doesn't build on MinGW yet; stopping build."
+ touch "${SUCCESS_MARKER}"
+ exit
+fi
+
+CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "${CI_DIR}/common/build.sh"
+source "${CI_DIR}/common/test.sh"
+
+build_nvim
+
+run_unittests
+run_functionaltests
+run_oldtests
+
+install_nvim
+
+touch "${SUCCESS_MARKER}"
diff --git a/.ci/script.sh b/.ci/script.sh
new file mode 100755
index 0000000000..4d0666ec0e
--- /dev/null
+++ b/.ci/script.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ -n "${CI_TARGET}" ]]; then
+ make lint
+ exit 0
+fi
+
+# This will pass the environment variables down to a bash process which runs
+# as $USER, while retaining the environment variables defined and belonging
+# to secondary groups given above in usermod.
+if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
+ # Set up precompiled third-party dependencies.
+ eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) deps-x64"
+
+ sudo -E su "${USER}" -c ".ci/run_tests.sh"
+else
+ .ci/run_tests.sh
+fi