diff --git a/.travis.yml b/.travis.yml index 22ec51b2..8983221b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,11 @@ before_install: # https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Travis-CI-supports-yarn - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.12.3 - export PATH="$HOME/.yarn/bin:$PATH" + # Install Docker 19.03.8 for BuildKit support, see https://docs.travis-ci.com/user/docker/ + - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - + - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" + - sudo apt-get update + - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce=5:19.03.8~3-0~ubuntu-xenial stages: - name: tag @@ -60,7 +65,7 @@ jobs: # https://docs.travis-ci.com/user/docker/ - | sudo rm -f /usr/local/bin/docker-compose - curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-$(uname -s)-$(uname -m) > docker-compose + curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m) > docker-compose chmod +x docker-compose sudo mv docker-compose /usr/local/bin - yarn do shadowbox/integration_test/run diff --git a/src/shadowbox/docker/Dockerfile b/src/shadowbox/docker/Dockerfile index fc8ad9b4..88a0ad4a 100644 --- a/src/shadowbox/docker/Dockerfile +++ b/src/shadowbox/docker/Dockerfile @@ -15,7 +15,21 @@ # Newer node images have no valid content trust data. # Pin the image node:12.16.3-alpine (linux/amd64) by hash. # See versions at https://hub.docker.com/_/node?tab=tags&name=alpine -FROM node@sha256:12b2154fb459fa5f42c54771524609db041e7ef3465935d0ca82940d2d72669d +ARG NODE_IMAGE="node@sha256:12b2154fb459fa5f42c54771524609db041e7ef3465935d0ca82940d2d72669d" + +# Multi-stage build: use a build image to prevent bloating the shadowbox image with dependencies. +# Run `yarn` and build inside the container to package the right dependencies for the image. +FROM ${NODE_IMAGE} AS build + +RUN apk add --no-cache --upgrade bash +WORKDIR / + +COPY . . +RUN yarn install +RUN ROOT_DIR=/ yarn do shadowbox/server/build + +# shadowbox image +FROM ${NODE_IMAGE} # Versions can be found at https://github.com/Jigsaw-Code/outline-ss-server/releases ARG SS_VERSION=1.1.1 @@ -38,15 +52,11 @@ RUN /etc/periodic/weekly/update_mmdb WORKDIR /root/shadowbox +# Install shadowbox and third party dependencies. +COPY --from=build /build/shadowbox/app app RUN mkdir bin && curl -SsL https://github.com/Jigsaw-Code/outline-ss-server/releases/download/v${SS_VERSION}/outline-ss-server_${SS_VERSION}_linux_x86_64.tar.gz | tar xz -C bin outline-ss-server COPY third_party/prometheus/prometheus ./bin/ COPY src/shadowbox/package.json . -COPY yarn.lock . - -RUN yarn install --prod - -# Install management service -COPY build/shadowbox/app app/ # Create default state directory. RUN mkdir -p /root/shadowbox/persisted-state diff --git a/src/shadowbox/docker/build_action.sh b/src/shadowbox/docker/build_action.sh index 5a7797b9..560ff1b5 100755 --- a/src/shadowbox/docker/build_action.sh +++ b/src/shadowbox/docker/build_action.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -do_action shadowbox/server/build - export DOCKER_CONTENT_TRUST=${DOCKER_CONTENT_TRUST:-1} +# Enable Docker BuildKit (https://docs.docker.com/develop/develop-images/build_enhancements) +export DOCKER_BUILDKIT=1 docker build --force-rm --build-arg GITHUB_RELEASE="${TRAVIS_TAG:-none}" -t ${SB_IMAGE:-outline/shadowbox} $ROOT_DIR -f src/shadowbox/docker/Dockerfile diff --git a/src/shadowbox/docker/cmd.sh b/src/shadowbox/docker/cmd.sh index bb80854b..2570d06e 100755 --- a/src/shadowbox/docker/cmd.sh +++ b/src/shadowbox/docker/cmd.sh @@ -41,4 +41,4 @@ ulimit -n 32768 # Start cron, which is used to check for updates to the IP-to-country database crond -node app/server/main.js +node app/main.js diff --git a/src/shadowbox/docker/run_action.sh b/src/shadowbox/docker/run_action.sh index 347314b4..4f8b718c 100755 --- a/src/shadowbox/docker/run_action.sh +++ b/src/shadowbox/docker/run_action.sh @@ -38,7 +38,7 @@ declare -a docker_bindings=( -e SB_API_PREFIX=TestApiPrefix -e SB_CERTIFICATE_FILE=${SB_CERTIFICATE_FILE} -e SB_PRIVATE_KEY_FILE=${SB_PRIVATE_KEY_FILE} - -e SB_METRICS_URL=${SB_METRICS_URL:-} + -e SB_METRICS_URL="${SB_METRICS_URL:-https://dev.metrics.getoutline.org}" ) readonly IMAGE="${SB_IMAGE:-outline/shadowbox}" diff --git a/src/shadowbox/infrastructure/logging.ts b/src/shadowbox/infrastructure/logging.ts index b6f4a71a..97d70950 100644 --- a/src/shadowbox/infrastructure/logging.ts +++ b/src/shadowbox/infrastructure/logging.ts @@ -44,8 +44,10 @@ function makeLogMessage(level: LevelPrefix, callsite: Callsite, message: string) // See // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString const timeStr = new Date().toISOString(); - return `${level}${timeStr} ${process.pid} ${path.basename(callsite.getFileName())}:${ - callsite.getLineNumber()}] ${message}`; + // TODO(alalama): preserve the source file structure in the webpack build so we can use + // `callsite.getFileName()`. + return `${level}${timeStr} ${process.pid} ${ + path.basename(callsite.getFileName() || __filename)}:${callsite.getLineNumber()}] ${message}`; } export function error(message: string) { diff --git a/src/shadowbox/server/build_action.sh b/src/shadowbox/server/build_action.sh index df675fe6..9195f306 100755 --- a/src/shadowbox/server/build_action.sh +++ b/src/shadowbox/server/build_action.sh @@ -16,16 +16,6 @@ readonly OUT_DIR=$BUILD_DIR/shadowbox rm -rf $OUT_DIR +mkdir -p $OUT_DIR -mkdir -p $OUT_DIR/js - -# Compile Typescript -tsc -p src/shadowbox --outDir $OUT_DIR/js - -# Assemble the node app -readonly APP_DIR=$OUT_DIR/app -mkdir -p $APP_DIR -# Copy built code, without test files. -rsync --exclude='**/*.spec.js' --exclude='mocks' -r $OUT_DIR/js/* $APP_DIR/ -# Copy static resources -cp -r $ROOT_DIR/src/shadowbox/package.json $APP_DIR +webpack --config=src/shadowbox/webpack.config.js ${BUILD_ENV:+--mode=${BUILD_ENV}} diff --git a/src/shadowbox/tsconfig.json b/src/shadowbox/tsconfig.json index e8f1b596..6cf26dd2 100644 --- a/src/shadowbox/tsconfig.json +++ b/src/shadowbox/tsconfig.json @@ -1,12 +1,13 @@ { "compilerOptions": { - "target": "es6", + "target": "es2015", "removeComments": false, "noImplicitAny": false, "noImplicitThis": true, "module": "commonjs", "rootDir": ".", - "resolveJsonModule": true + "resolveJsonModule": true, + "sourceMap": true }, "include": [ "server/main.ts", diff --git a/src/shadowbox/webpack.config.js b/src/shadowbox/webpack.config.js new file mode 100644 index 00000000..3a69b7e5 --- /dev/null +++ b/src/shadowbox/webpack.config.js @@ -0,0 +1,35 @@ +// Copyright 2020 The Outline Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const path = require('path'); +const webpack = require('webpack'); + +const config = { + mode: 'production', + entry: path.resolve(__dirname, './server/main.ts'), + target: 'node', + output: { + filename: 'main.js', + path: path.resolve(__dirname, '../../build/shadowbox/app'), + }, + module: {rules: [{test: /\.ts(x)?$/, use: 'ts-loader'}]}, + plugins: [ + // WORKAROUND: some of our (transitive) dependencies use node-gently, which hijacks `require`. + // Setting global.GENTLY to false makes these dependencies use standard require. + new webpack.DefinePlugin({'global.GENTLY': false}) + ], + resolve: {extensions: ['.tsx', '.ts', '.js']}, +}; + +module.exports = config;