diff --git a/.travis.yml b/.travis.yml index 51f92c8..aa058c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,23 @@ services: - docker script: + # Shellcheck - shellcheck *.sh - - shellcheck ci-deploy/*.sh - - cd .. && - git clone https://github.com/whatwg/html.git --depth 2 && - IS_TEST_OF_HTML_BUILD_ITSELF=true bash ./html-build/ci-deploy/outside-container.sh + - shellcheck ci-build/*.sh + + # Build the Docker container, tagged as whatwg/html-build + - bash ci-build/docker-build.sh + + # Test the Docker container + - git clone https://github.com/whatwg/html.git --depth 2 + - mkdir output + - bash ci-build/docker-run.sh html output + + # Tag and publish the Docker container + - docker tag whatwg/html-build "whatwg/html-build:$(git rev-list --count HEAD)" + - docker tag whatwg/html-build whatwg/html-build:latest + - if [[ "$TRAVIS_PULL_REQUEST" = "false" ]]; then docker login --username "$DOCKER_USERNAME" --password "$DOCKER_PASSWORD"; fi + - if [[ "$TRAVIS_PULL_REQUEST" = "false" ]]; then docker push whatwg/html-build; fi branches: only: diff --git a/ci-deploy/Dockerfile b/ci-build/Dockerfile similarity index 78% rename from ci-deploy/Dockerfile rename to ci-build/Dockerfile index a68ef15..0506dfd 100644 --- a/ci-deploy/Dockerfile +++ b/ci-build/Dockerfile @@ -37,18 +37,6 @@ RUN apt-get install --yes --no-install-recommends ./prince_13.5-1_debian10_amd64 rm prince_13.5-1_debian10_amd64.deb && \ echo '@font-face { font-family: serif; src: local("Symbola") }' >> /usr/lib/prince/style/fonts.css -ARG html_build_dir ADD . /whatwg/html-build -# Note: we do not ADD /whatwg/html, but instead mount it in outside-container.html, since it -# contains the deploy_key, and thus should not be part of the image. The image is cached, publicly, -# on Docker Hub. -ENV HTML_SOURCE /whatwg/html - -ARG travis_pull_request -ARG is_test_of_html_build_itself -ENV TRAVIS_PULL_REQUEST=${travis_pull_request} -ENV IS_TEST_OF_HTML_BUILD_ITSELF=${is_test_of_html_build_itself} - -ENV SKIP_BUILD_UPDATE_CHECK=true -ENTRYPOINT ["bash", "/whatwg/html-build/ci-deploy/inside-container.sh"] +ENTRYPOINT ["bash", "/whatwg/html-build/ci-build/inside-container.sh"] diff --git a/ci-build/README.md b/ci-build/README.md new file mode 100644 index 0000000..f2e471d --- /dev/null +++ b/ci-build/README.md @@ -0,0 +1,10 @@ +# HTML Standard CI Build + +This directory contains the infrastructure for building and running a Docker container, [whatwg/html-build](https://hub.docker.com/r/whatwg/html-build), which performs a "full" build of the HTML Standard, producing artifacts ready for deployment. + +The relevant entrypoints are: + +- `docker-build.sh` will build the Docker container +- `docker-run.sh $INPUT $OUTPUT` will run the Docker container to do such a full build. + - `$INPUT` should contain a checkout of the [whatwg/html](https://github.com/whatwg/html) repository + - `$OUTPUT` should be an empty directory diff --git a/ci-build/docker-build.sh b/ci-build/docker-build.sh new file mode 100644 index 0000000..d36ce54 --- /dev/null +++ b/ci-build/docker-build.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -o errexit +set -o nounset +set -o pipefail +shopt -s extglob + +TMP_DIR=$(mktemp -d) + +function main { + local here + here=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd ) + + # We want the image to contain: + # * All of the important stuff from the top-level (html-build) directory + # * But, the Dockerfile from this (ci-build) directory + # And in particular it should *not* contain the top-level Dockerfile, non-.pl dotfiles, .git/, and + # any html/ and output/ directories that might be hanging around from local testing. + cp "$here/Dockerfile" "$TMP_DIR" + cd "$here/.." + cp -r !(.*|html|output|Dockerfile) "$TMP_DIR" + cp .*.pl "$TMP_DIR" + cd "$TMP_DIR" + trap cleanTemp EXIT + + local docker_hub_repo="whatwg/html-build" + + # Build the Docker image, using Docker Hub as a cache. (This will be fast if nothing has changed + # in html-build or its dependencies). + docker pull whatwg/wattsi + docker pull ptspts/pdfsizeopt + docker pull "$docker_hub_repo" || true + docker build --cache-from "$docker_hub_repo" --tag "$docker_hub_repo" . +} + +function cleanTemp { + rm -rf "$TMP_DIR" +} + +main "$@" diff --git a/ci-build/docker-run.sh b/ci-build/docker-run.sh new file mode 100644 index 0000000..3cacb53 --- /dev/null +++ b/ci-build/docker-run.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -o errexit +set -o nounset +set -o pipefail +shopt -s extglob + +HTML_SOURCE=$(realpath "$1") +HTML_OUTPUT=$(realpath "$2") + +docker run --rm --mount "type=bind,source=$HTML_SOURCE,destination=/whatwg/html,readonly=1" \ + --env "HTML_SOURCE=/whatwg/html" \ + --mount "type=bind,source=$HTML_OUTPUT,destination=/whatwg/output" \ + --env "HTML_OUTPUT=/whatwg/output" \ + whatwg/html-build diff --git a/ci-build/inside-container.sh b/ci-build/inside-container.sh new file mode 100644 index 0000000..c02ebd0 --- /dev/null +++ b/ci-build/inside-container.sh @@ -0,0 +1,32 @@ +#!/bin/bash +set -o errexit +set -o nounset +set -o pipefail +cd "$(dirname "$0")/../.." + +PDF_SERVE_PORT=8080 + +SKIP_BUILD_UPDATE_CHECK=true ./html-build/build.sh + +echo "" +echo "Running conformance checker..." +# the -Xmx1g argument sets the size of the Java heap space to 1 gigabyte +java -Xmx1g -jar ./vnu.jar --skip-non-html "$HTML_OUTPUT" +echo "" + +# Serve the built output so that Prince can snapshot it +# The nohup/sleep incantations are necessary because normal & does not work inside Docker: +# https://stackoverflow.com/q/50211207/3191 +( + cd "$HTML_OUTPUT" + nohup bash -c "python3 -m http.server $PDF_SERVE_PORT &" && sleep 4 +) + +echo "" +echo "Building PDF..." +PDF_TMP="$(mktemp --suffix=.pdf)" +prince --verbose --output "$PDF_TMP" "http://0.0.0.0:$PDF_SERVE_PORT/" + +echo "" +echo "Optimizing PDF..." +PATH=/bin/pdfsizeopt:$PATH pdfsizeopt --v=30 "$PDF_TMP" "$HTML_OUTPUT/print.pdf" diff --git a/ci-deploy/.dockerignore b/ci-deploy/.dockerignore deleted file mode 100644 index eb41cad..0000000 --- a/ci-deploy/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -# Git checkout metadata changes every time you check out. If we left these directories there, Docker's caches (based on -# comparing the contents of the files ADDed) would be invalidated. -**/.git diff --git a/ci-deploy/README.md b/ci-deploy/README.md deleted file mode 100644 index d223f12..0000000 --- a/ci-deploy/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# HTML Standard CI Deploy - -This directory contains files used specifically for deploying the HTML Standard on Travis CI. They are not generally relevant to local builds. - -The setup is assumed to be a directory containing: - -- A subdirectory `html-build` containing the contents of this entire [whatwg/html-build](https://github.com/whatwg/html-build) repository -- A subdirectory `html` containing the contents of the [whatwg/html](https://github.com/whatwg/html) repository - -Then, run the `html-build/ci-deploy/outside-container.sh` script. What it does is documented via inline comments; check it out to learn more. In particular, note that several environment variables are assumed to be set, via the CI system. diff --git a/ci-deploy/deploy-key.enc b/ci-deploy/deploy-key.enc deleted file mode 100644 index 06f68a8..0000000 Binary files a/ci-deploy/deploy-key.enc and /dev/null differ diff --git a/ci-deploy/inside-container.sh b/ci-deploy/inside-container.sh deleted file mode 100644 index 4bf2845..0000000 --- a/ci-deploy/inside-container.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash -set -o errexit -set -o nounset -set -o pipefail -cd "$(dirname "$0")/../.." - -PDF_SERVE_PORT=8080 -WEB_ROOT="html.spec.whatwg.org" -COMMITS_DIR="commit-snapshots" -REVIEW_DIR="review-drafts" - -SERVER="165.227.248.76" -SERVER_PUBLIC_KEY="ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDt6Igtp73aTOYXuFb8qLtgs80wWF6cNi3/AItpWAMpX3PymUw7stU7Pi+IoBJz21nfgmxaKp3gfSe2DPNt06l8=" - -# `export`ed because build.sh reads it -HTML_OUTPUT="$(pwd)/output" -export HTML_OUTPUT - -# Note: $TRAVIS_PULL_REQUEST is either a number or false, not true or false. -# https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables -TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST:-false} -IS_TEST_OF_HTML_BUILD_ITSELF=${IS_TEST_OF_HTML_BUILD_ITSELF:-false} - -# Build the spec into the output directory -./html-build/build.sh - -# Conformance-check the result -echo "" -echo "Running conformance checker..." -# the -Xmx1g argument sets the size of the Java heap space to 1 gigabyte -java -Xmx1g -jar ./vnu.jar --skip-non-html "$HTML_OUTPUT" -echo "" - -# Serve the built output so that Prince can snapshot it -# The nohup/sleep incantations are necessary because normal & does not work inside Docker: -# https://stackoverflow.com/q/50211207/3191 -( - cd "$HTML_OUTPUT" - nohup bash -c "python3 -m http.server $PDF_SERVE_PORT &" && sleep 4 -) - -echo "" -echo "Building PDF..." -PDF_TMP="$(mktemp --suffix=.pdf)" -prince --verbose --output "$PDF_TMP" "http://0.0.0.0:$PDF_SERVE_PORT/" - -echo "" -echo "Optimizing PDF..." -PATH=/bin/pdfsizeopt:$PATH pdfsizeopt --v=30 "$PDF_TMP" "$HTML_OUTPUT/print.pdf" - -if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then - echo "Skipping deploy for non-master" - exit 0 -fi -if [[ "$IS_TEST_OF_HTML_BUILD_ITSELF" == "true" ]]; then - echo "Skipping deploy for html-build testing purposes" - exit 0 -fi - -# Add the (decoded) deploy key to the SSH agent, so scp works -chmod 600 html/deploy-key -eval "$(ssh-agent -s)" -ssh-add html/deploy-key -echo "$SERVER $SERVER_PUBLIC_KEY" > known_hosts - -# Sync, including deletes, but ignoring the stuff we'll deploy below, so that we don't delete them. -echo "Deploying build output..." -# --chmod=D755,F644 means read-write for user, read-only for others. -rsync --rsh="ssh -o UserKnownHostsFile=known_hosts" \ - --archive --chmod=D755,F644 --compress --verbose \ - --delete --exclude="$COMMITS_DIR" --exclude="$REVIEW_DIR" \ - "$HTML_OUTPUT/" "deploy@$SERVER:/var/www/$WEB_ROOT" - -# Now sync a commit snapshot and a review draft, if any -# (See https://github.com/whatwg/html-build/issues/97 potential improvements to commit snapshots.) -echo "" -echo "Deploying Commit Snapshot and Review Drafts, if any..." -# --chmod=D755,F644 means read-write for user, read-only for others. -rsync --rsh="ssh -o UserKnownHostsFile=known_hosts" \ - --archive --chmod=D755,F644 --compress --verbose \ - "$HTML_OUTPUT/$COMMITS_DIR" "$HTML_OUTPUT/$REVIEW_DIR" "deploy@$SERVER:/var/www/$WEB_ROOT" - -echo "" -echo "All done!" diff --git a/ci-deploy/outside-container.sh b/ci-deploy/outside-container.sh deleted file mode 100644 index 0fe1776..0000000 --- a/ci-deploy/outside-container.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash -set -o errexit -set -o nounset -set -o pipefail -shopt -s extglob - -HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -TMP_DIR=$(mktemp -d) - -function main { - cp "$HERE/Dockerfile" "$TMP_DIR" - cd "$HERE/.." - cp -r !(.*|html|Dockerfile) "$TMP_DIR" - cp .*.pl "$TMP_DIR" - cd "$TMP_DIR" - trap cleanTemp EXIT - - DOCKER_USERNAME="domenicdenicola" - DOCKER_HUB_REPO="whatwg/html-deploy" - - # Set from the outside: - TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST:-false} - IS_TEST_OF_HTML_BUILD_ITSELF=${IS_TEST_OF_HTML_BUILD_ITSELF:-false} - - # When not running pull request builds: - # - DOCKER_PASSWORD is set from the outside - # - ENCRYPTION_LABEL is set from the outside - - # Build the Docker image, using Docker Hub as a cache. (This will be fast if nothing has changed - # in wattsi or html-build). - docker build --cache-from "$DOCKER_HUB_REPO:latest" \ - --tag "$DOCKER_HUB_REPO:latest" \ - --build-arg "html_build_dir=$TMP_DIR" \ - --build-arg "travis_pull_request=$TRAVIS_PULL_REQUEST" \ - --build-arg "is_test_of_html_build_itself=$IS_TEST_OF_HTML_BUILD_ITSELF" \ - . - if [[ "$TRAVIS_PULL_REQUEST" == "false" && "$IS_TEST_OF_HTML_BUILD_ITSELF" == "false" ]]; then - # Decrypt the deploy key from this script's location into the html/ directory, since that's the - # directory that will be shared with the container (but not built into the image). - ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key" - ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv" - ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR} - ENCRYPTED_IV=${!ENCRYPTED_IV_VAR} - openssl aes-256-cbc -K "$ENCRYPTED_KEY" -iv "$ENCRYPTED_IV" \ - -in "$HERE/deploy-key.enc" -out html/deploy-key -d - fi - - # Run the inside-container.sh script, with the html/ directory mounted inside the container. - echo "" - cd "$HERE/../.." - docker run --mount "type=bind,source=$(pwd)/html,destination=/whatwg/html,readonly=1" "$DOCKER_HUB_REPO:latest" - - if [[ "$TRAVIS_PULL_REQUEST" == "false" && "$IS_TEST_OF_HTML_BUILD_ITSELF" == "false" ]]; then - # If the build succeeded and we got here, upload the Docker image to Docker Hub, so that future runs - # can use it as a cache. - echo "" - docker tag "$DOCKER_HUB_REPO:latest" "$DOCKER_HUB_REPO:$TRAVIS_BUILD_NUMBER" && - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD" - docker push "$DOCKER_HUB_REPO" - fi -} - -function cleanTemp { - rm -rf "$TMP_DIR" -} - -main "$@"