#!/usr/bin/env bash set -u -e -o pipefail # Prints out usage information for the script. function printUsage { echo -e "\e[1mrun-bazel-via-tunnel.sh\e[0m - Runs a bazel command using a saucelabs tunnel \e[1mUsage:\e[0m $0 --tunnel-id= \\ --username= --key= \e[1mExample:\e[0m ./run-bazel-via-tunnel.sh --tunnel-id= \\ --username= --key= \\ yarn bazel test //src:everything Flags: --username: The saucelabs username --key: The saucelabs access key --tunnel-id: An identifier for the saucelabs tunnel"; } # Ensures a file is created, creating directories for the full path as needed. function touch-safe { for f in "$@"; do [ -d $f:h ] || mkdir -p $f:h && command touch $f done } # The root directory of the git project the script is running in. readonly GIT_ROOT_DIR=$(git rev-parse --show-toplevel 2> /dev/null) # Location for the saucelabs log file. readonly SAUCE_LOG_FILE=/tmp/angular/sauce-connect.log # Location for the saucelabs ready to connect lock file. readonly SAUCE_READY_FILE=/tmp/angular/sauce-connect-ready-file.lock # Location for the saucelabs ready to connection process id lock file. readonly SAUCE_PID_FILE=/tmp/angular/sauce-connect-pid-file.lock # Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not # acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout. readonly SAUCE_READY_FILE_TIMEOUT=120 # Create saucelabs log file if it doesn't already exist. touch-safe $SAUCE_LOG_FILE; # Handle configuration of script from command line flags and arguments OPTIONS=$(getopt -u -l tunnel-id:,username:,key:,help --options "" -- "$@") # Exit if flag parsing fails. if [ $? != 0 ] ; then echo "Failed to parse flags, exiting" && printUsage >&2 ; exit 1 ; fi set -- $OPTIONS while true; do case "$1" in --tunnel-id) shift SAUCE_TUNNEL_IDENTIFIER=$1 ;; --username) shift SAUCE_USERNAME=$1 ;; --key) shift SAUCE_ACCESS_KEY=$1 ;; --help) printUsage exit 2 ;; --) shift USER_COMMAND=$@ break ;; *) shift ;; esac done # Check each required flag and parameter if [[ -z ${SAUCE_TUNNEL_IDENTIFIER+x} ]]; then echo "Missing required flag: --tunnel-id" badCommandSyntax=1 fi if [[ -z ${SAUCE_USERNAME+x} ]]; then echo "Missing required flag: --username" badCommandSyntax=1 fi if [[ -z ${SAUCE_ACCESS_KEY+x} ]]; then echo "Missing required flag: --key" badCommandSyntax=1 fi if [[ "${USER_COMMAND}" == "" ]]; then echo "Missing required bazel command: Bazel command for running in saucelabs tunnel" badCommandSyntax=1 elif [[ ! $USER_COMMAND =~ ^(yarn bazel) ]]; then echo "The command provided must be a bazel command run via yarn, beginning with \"yarn bazel\"" badCommandSyntax=1 fi # If any required flag or parameter were found to be missing or incorrect, exit the script. if [[ ${badCommandSyntax+x} ]]; then echo printUsage exit 1 fi # Command arguments that will be passed to sauce-connect. # By default we disable SSL bumping for all requests. This is because SSL bumping is # not needed for our test setup and in order to perform the SSL bumping, Saucelabs # intercepts all HTTP requests in the tunnel VM and modifies them. This can cause # flakiness as it makes all requests dependent on the SSL bumping middleware. # See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping sauceArgs="--no-ssl-bump-domains all" sauceArgs="${sauceArgs} --logfile ${SAUCE_LOG_FILE}" sauceArgs="${sauceArgs} --readyfile ${SAUCE_READY_FILE}" sauceArgs="${sauceArgs} --pidfile ${SAUCE_PID_FILE}" sauceArgs="${sauceArgs} --tunnel-identifier ${SAUCE_TUNNEL_IDENTIFIER}" sauceArgs="${sauceArgs} -u ${SAUCE_USERNAME}" ######################### # Open saucelabs tunnel # ######################### ${GIT_ROOT_DIR}/node_modules/sauce-connect/bin/sc -k $SAUCE_ACCESS_KEY ${sauceArgs} & ######################################## # Wait for saucelabs tunnel to connect # ######################################## counter=0 while [[ ! -f ${SAUCE_READY_FILE} ]]; do counter=$((counter + 1)) # Counter needs to be multiplied by two because the while loop only sleeps a half second. # This has been made in favor of better progress logging (printing dots every half second) if [ $counter -gt $[${SAUCE_READY_FILE_TIMEOUT} * 2] ]; then echo "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file." echo "Printing logfile output:" echo "" cat ${SAUCE_LOG_FILE} exit 5 fi printf "." sleep 0.5 done ######################### # Execute Bazel command # ######################### # Prevent immediate exit for Bazel test failures set +e ( cd $GIT_ROOT_DIR && \ # Run bazel command with saucelabs specific environment variables passed to the action # The KARMA_WEB_TEST_MODE and SAUCE_TUNNEL_IDENTIFIER environment variables provide # envirnment variables to be read in the karma configuration file to set correct # configurations for karma saucelabs and browser configs. # Usage of these envirnment variables can be seen in this repo in # /karma-js.conf.js and /browser-providers.conf.js eval "$USER_COMMAND --define=KARMA_WEB_TEST_MODE=SL_REQUIRED \ --action_env=SAUCE_USERNAME=$SAUCE_USERNAME \ --action_env=SAUCE_ACCESS_KEY=$SAUCE_ACCESS_KEY \ --action_env=SAUCE_READY_FILE=$SAUCE_READY_FILE \ --action_env=SAUCE_PID_FILE=$SAUCE_PID_FILE \ --action_env=SAUCE_TUNNEL_IDENTIFIER=$SAUCE_TUNNEL_IDENTIFIER" ) BAZEL_EXIT_CODE=$? echo "Exit code for bazel command was: $BAZEL_EXIT_CODE" # Reenable immediate exit for failure exit code set -e ############################## # Close the saucelabs tunnel # ############################## if [[ ! -f ${SAUCE_PID_FILE} ]]; then echo "Could not find Saucelabs tunnel PID file. Cannot stop tunnel.." exit 1 fi echo "Shutting down Sauce Connect tunnel" # The process id for the sauce-connect instance is stored inside of the pidfile. tunnelProcessId=$(cat ${SAUCE_PID_FILE}) # Kill the process by using the PID that has been read from the pidfile. Note that # we cannot use killall because CircleCI base container images don't have it installed. kill ${tunnelProcessId} while (ps -p ${tunnelProcessId} &> /dev/null); do printf "." sleep .5 done echo "" echo "Sauce Connect tunnel has been shut down" exit $BAZEL_EXIT_CODE