CI: Consolidate CircleCI commands for readability
This way there are only 3 "commands" (really, entire scripts) that
CircleCI runs, each which begins with a descriptive comment.
This commit also reduces the number of backgrounded commands, and most
backgrounded commands start with a word in the comment that describes it
well, so the 'stdout_*.txt' and 'stderr_*.txt' log outputs auto-captured
by CircleCI will have more readable names and we don't need those *.log
files.
Recommend -w to view diff.
diff --git a/circle.yml b/circle.yml
index 89c56a4..e38fd7e 100644
--- a/circle.yml
+++ b/circle.yml
@@ -39,69 +39,74 @@
cache_directories:
- ~/sauce-connect
pre:
- - "test $SAUCE_USERNAME && test $SAUCE_ACCESS_KEY
- # Sauce Labs credentials required. Sign up here: https://saucelabs.com/opensauce/"
- ? |-
- {
- mkdir -p ~/sauce-connect
- cd ~/sauce-connect
- if [ -x sc-*-linux/bin/sc ]; then
- echo Using cached sc-*-linux/bin/sc
- else
- time wget https://saucelabs.com/downloads/sc-latest-linux.tar.gz
- time tar -xzf sc-latest-linux.tar.gz
- fi
- # Sauce Connect randomly fails so try twice https://git.io/vPN8v
- time sc-*-linux/bin/sc --user $SAUCE_USERNAME --api-key $SAUCE_ACCESS_KEY \
- --readyfile ~/sauce_is_ready
- test -e ~/sauce_was_ready && exit
- time sc-*-linux/bin/sc --user $SAUCE_USERNAME --api-key $SAUCE_ACCESS_KEY \
- --readyfile ~/sauce_is_ready
- test -e ~/sauce_was_ready && exit
- echo 'ERROR: Exited twice without creating readyfile' \
- | tee /dev/stderr > ~/sauce_is_ready
+ # SauceConnect: download if not cached, and launch with retry
+ test $SAUCE_USERNAME && test $SAUCE_ACCESS_KEY || {
+ echo 'Sauce Labs credentials required. Sign up here: https://saucelabs.com/opensauce/'
exit 1
- } >$CIRCLE_ARTIFACTS/sauce-connect.log 2>&1
+ }
+
+ mkdir -p ~/sauce-connect
+ cd ~/sauce-connect
+ if [ -x sc-*-linux/bin/sc ]; then
+ echo Using cached sc-*-linux/bin/sc
+ else
+ time wget https://saucelabs.com/downloads/sc-latest-linux.tar.gz
+ time tar -xzf sc-latest-linux.tar.gz
+ fi
+ # Sauce Connect randomly fails so try twice https://git.io/vPN8v
+ time sc-*-linux/bin/sc --user $SAUCE_USERNAME --api-key $SAUCE_ACCESS_KEY \
+ --readyfile ~/sauce_is_ready
+ test -e ~/sauce_was_ready && exit
+ time sc-*-linux/bin/sc --user $SAUCE_USERNAME --api-key $SAUCE_ACCESS_KEY \
+ --readyfile ~/sauce_is_ready
+ test -e ~/sauce_was_ready && exit
+ echo 'ERROR: Exited twice without creating readyfile' \
+ | tee /dev/stderr > ~/sauce_is_ready
+ exit 1
:
background: true
- test -x $json || npm install json
test:
- override:
+ pre:
# Safari on Sauce can only connect to port 3000, 4000, 7000, or 8000. Edge needs port 7000 or 8000.
# https://david263a.wordpress.com/2015/04/18/fixing-safari-cant-connect-to-localhost-issue-when-using-sauce-labs-connect-tunnel/
# https://support.saucelabs.com/customer/portal/questions/14368823-requests-to-localhost-on-microsoft-edge-are-failing-over-sauce-connect
- - PORT=8000 make server >$CIRCLE_ARTIFACTS/make_server.log 2>&1:
+ - PORT=8000 make server:
background: true
- # CircleCI expects test results to be reported in an JUnit/xUnit-style XML file:
- # https://circleci.com/docs/test-metadata/
- # Our unit tests are in a browser, so they can't write to a file, and Sauce
- # apparently truncates custom data in their test result reports, so instead we
- # POST to this trivial Node server on localhost:9000 that writes the body of
- # any POST request to $CIRCLE_TEST_REPORTS/mocha/xunit.xml
- - mkdir -p $CIRCLE_TEST_REPORTS/mocha
- - ? |-
- node << 'EOF' >$CIRCLE_TEST_REPORTS/mocha/xunit.xml \
- 2>$CIRCLE_ARTIFACTS/mocha-test-report.log
- require('http').createServer(function(req, res) {
- res.setHeader('Access-Control-Allow-Origin', '*');
- req.pipe(process.stdout);
- req.on('end', res.end.bind(res));
- })
- .listen(9000);
- console.error('listening on http://0.0.0.0:9000/');
- EOF
- :
- background: true
-
- # Wait for tunnel to be ready (`make server` and the trivial Node server
- # are much faster, no need to wait for them)
+ # Wait for tunnel to be ready (`make server` is much faster, no need to wait for it)
- while [ ! -e ~/sauce_is_ready ]; do sleep 1; done; touch ~/sauce_was_ready; test -z "$(<~/sauce_is_ready)"
- # Start taking screenshots in the background while the unit tests are running
+ override:
- ? |-
- {
+ # Screenshots: capture in the background while running unit tests
+ mkdir -p $CIRCLE_TEST_REPORTS/mocha
+
+ # CircleCI expects test results to be reported in an JUnit/xUnit-style XML file:
+ # https://circleci.com/docs/test-metadata/
+ # Our unit tests are in a browser, so they can't write to a file, and Sauce
+ # apparently truncates custom data in their test result reports, so instead we
+ # POST to this trivial Node server on localhost:9000 that writes the body of
+ # any POST request to $CIRCLE_TEST_REPORTS/mocha/xunit.xml
+ node -e '
+ require("http").createServer(function(req, res) {
+ res.setHeader("Access-Control-Allow-Origin", "*");
+ req.pipe(process.stdout);
+ req.on("end", res.end.bind(res));
+ })
+ .listen(9000);
+ console.error("listening on http://0.0.0.0:9000/");
+ ' 2>&1 >$CIRCLE_TEST_REPORTS/mocha/xunit.xml | {
+ # ^ note: `2>&1` must precede `>$CIRCLE_TEST_REPORTS/...` because
+ # shell redirect is like assignment; if it came after, then both
+ # stdout and stderr would be written to `xunit.xml` and nothing
+ # would be piped into here
+
+ head -1 # wait for "listening on ..." to be logged
+
+ # https://circleci.com/docs/environment-variables/
build_name="CircleCI build #$CIRCLE_BUILD_NUM"
if [ $CIRCLE_PR_NUMBER ]; then
build_name="$build_name: PR #$CIRCLE_PR_NUMBER"
@@ -115,17 +120,17 @@
time { test -d node_modules/wd || npm install wd; }
time node script/screenshots.js http://localhost:8000/test/visual.html \
&& touch ~/screenshots_are_ready || echo EXIT STATUS $? | tee /dev/stderr > ~/screenshots_are_ready:
- } >$CIRCLE_ARTIFACTS/screenshots.log 2>&1
+ }
:
background: true
- # Run in-browser unit tests, based on:
- # https://wiki.saucelabs.com/display/DOCS/JavaScript+Unit+Testing+Methods
- # "build" and "customData" parameters from:
- # https://wiki.saucelabs.com/display/DOCS/Test+Configuration+Options#TestConfigurationOptions-TestAnnotation
- # CircleCI environment variables from:
- # https://circleci.com/docs/environment-variables/
- |-
+ # Unit tests in the browser
+
+ echo '1. Launch tests'
+ echo
+
+ # https://circleci.com/docs/environment-variables/
build_name="CircleCI build #$CIRCLE_BUILD_NUM"
if [ $CIRCLE_PR_NUMBER ]; then
build_name="$build_name: PR #$CIRCLE_PR_NUMBER"
@@ -135,6 +140,8 @@
fi
build_name="$build_name @ ${CIRCLE_SHA1:0:7}"
+ # "build" and "customData" parameters from:
+ # https://wiki.saucelabs.com/display/DOCS/Test+Configuration+Options#TestConfigurationOptions-TestAnnotation
set -o pipefail
curl -i -X POST https://saucelabs.com/rest/v1/$SAUCE_USERNAME/js-tests \
-u $SAUCE_USERNAME:$SAUCE_ACCESS_KEY \
@@ -148,13 +155,11 @@
"platforms": [["", "Chrome", ""]]
}' | tee /dev/stderr | tail -1 > js-tests.json
- # Wait for tests to finish:
- #
- # > Make the request multiple times as the tests run until the response
- # > contains `completed: true` to the get the final results.
- #
- # https://wiki.saucelabs.com/display/DOCS/JavaScript+Unit+Testing+Methods
- - |-
+ echo '2. Wait for tests to finish:'
+ echo
+ # > Make the request multiple times as the tests run until the response
+ # > contains `completed: true` to the get the final results.
+ # https://wiki.saucelabs.com/display/DOCS/JavaScript+Unit+Testing+Methods
while true # Bash has no do...while >:(
do
sleep 5
@@ -169,21 +174,26 @@
[ "$($json completed <status.json)" != false ] && break
done
- # Complain to Circle CI if any unit tests failed
- - test "$($json 'js tests'.0.result.failures <status.json)" = 0
+ echo '3. Exit with non-zero status code if any unit tests failed'
+ exit "$($json 'js tests'.0.result.failures <status.json)"
- # Wait for screenshots to be ready
- - while [ ! -e ~/screenshots_are_ready ]; do sleep 1; done; test -z "$(<~/screenshots_are_ready)":
- timeout: 300
-
- # Stitch together images
- |-
+ # Stitch together screenshots and diff against master
+
+ echo '0. Wait for screenshots to be ready'
+ echo
+ while [ ! -e ~/screenshots_are_ready ]; do sleep 1; done
+ test -z "$(<~/screenshots_are_ready)" || exit 1
+
+ echo '1. Stitch together pieces'
+ echo
for img in $(ls $CIRCLE_ARTIFACTS/imgs/pieces/); do
convert $(ls -1 $CIRCLE_ARTIFACTS/imgs/pieces/$img/*.png | sort -n) -append $CIRCLE_ARTIFACTS/imgs/$img.png
done
- # Download the latest screenshots from master.
- - |-
+ echo '2. Download the latest screenshots from master'
+ echo
+
artifacts_json="$(curl https://circleci.com/api/v1/project/mathquill/mathquill/latest/artifacts?branch=ci.cleanup)"
#when done testing, restore: artifacts_json="$(curl https://circleci.com/api/v1/project/mathquill/mathquill/latest/artifacts?branch=master)"
echo
@@ -205,10 +215,11 @@
echo "$baseline_imgs"
echo
- test -z "$baseline_imgs" || curl $baseline_imgs
+ test -z "$baseline_imgs" && { echo 'No baseline images to download'; exit; }
+ curl $baseline_imgs
- # Generate image diffs.
- - |-
+ echo '3. Generate image diffs'
+ echo
cd $CIRCLE_ARTIFACTS/imgs/
for file in $(ls *.png); do
# if evergreen browser, browser version of previous screenshot may not match,
@@ -218,5 +229,6 @@
compare -metric AE $baseline $file ${file/%.png/_DIFF.png}
done
true # ignore errors like "image widths or heights differ"
+
post:
- killall --wait sc; true # wait for Sauce Connect to close the tunnel; ignore errors since it's just cleanup