From d4e42a4697a52eca7b053e7c7454d6446d0c8b1e Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sun, 1 May 2022 14:50:44 +1000 Subject: [PATCH] chore(web): report on file size --- resources/build/github.inc.sh | 71 +++++++++++++++ web/tools/check-build-size.sh | 164 ++++++++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 resources/build/github.inc.sh create mode 100644 web/tools/check-build-size.sh diff --git a/resources/build/github.inc.sh b/resources/build/github.inc.sh new file mode 100644 index 0000000000..c68fbb5979 --- /dev/null +++ b/resources/build/github.inc.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +## +## Writes a status check message to GitHub against the reported SHA +## Requires the variable GITHUB_TOKEN to be set to a valid token +## +write_github_status_check() { + local CONTEXT=$1 + local STATE=$2 + local MESSAGE=$3 + local TARGETURL=$4 + local SHA=$5 + + if [ -z $TARGETURL ]; then + local JSON='{"state": $state, "description": $description, "context": $context}' + else + local JSON='{"state": $state, "target_url": $targeturl, "description": $description, "context": $context}' + fi + + JSON=$($JQ --null-input -c \ + --arg state "$STATE" \ + --arg targeturl "$TARGETURL" \ + --arg description "$MESSAGE" \ + --arg context "$CONTEXT" \ + "$JSON") + + # On Windows, charset encoding is a pain. Simplest + # solution is to sidestep it with a temp file. + + JSON_TEMPFILE=`mktemp` + echo "$JSON" > "$JSON_TEMPFILE" + + curl \ + -s -w "%{stderr}%{http_code}%{stdout}" \ + -X POST \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/keymanapp/keyman/statuses/$SHA \ + --data-binary @"$JSON_TEMPFILE" > "$JSON_TEMPFILE.out" 2>"$JSON_TEMPFILE.err" + + # Check that the HTTP result code is 2xx + + if ! grep \^2 "$JSON_TEMPFILE.err" > /dev/null; then + echo "GitHub transaction failed." + cat "$JSON_TEMPFILE.out" + EXITCODE=1 + else + EXITCODE=0 + fi + + rm -f "$JSON_TEMPFILE" + rm -f "$JSON_TEMPFILE.out" + rm -f "$JSON_TEMPFILE.err" + + return $EXITCODE +} + +## +## Writes a status check message to GitHub against the SHA that the current +## TeamCity build is running on. BUILD_VCS_NUMBER must be set to a valid git SHA. +## Requires the variable GITHUB_TOKEN to be set to a valid token. +## +write_github_status_check_from_teamcity() { + local CONTEXT=$1 + local STATE=$2 + local MESSAGE=$3 + local TARGETURL=$4 + local SHA=$BUILD_VCS_NUMBER + report_github_status "$CONTEXT" "$RESULT_STATE" "$RESULT_MESSAGE" "" "$SHA" +} diff --git a/web/tools/check-build-size.sh b/web/tools/check-build-size.sh new file mode 100644 index 0000000000..f8aa1bb929 --- /dev/null +++ b/web/tools/check-build-size.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +# +# This script checks the built, minified file size for keymanweb.js against +# the latest published version and optionally issues a status check against +# the relevant commit on GitHub reporting on the file size and its suitability. +# + +set -eu + +# If keymanweb.js is more than SIZE_THRESHOLD bytes larger, we emit a failure status +SIZE_THRESHOLD=1024 + +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || readlink -f "${BASH_SOURCE[0]}")" +. "$(dirname "$THIS_SCRIPT")/../../resources/build/build-utils.sh" +. "$KEYMAN_ROOT/resources/build/jq.inc.sh" +. "$KEYMAN_ROOT/resources/build/github.inc.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +display_usage() { + echo "check-build-size.sh [--write-status|-w] [--report|-r] [--sha sha] [--github-token token]" + echo + echo "Checks the built file size for KeymanWeb against the most recent" + echo "successful build." + echo + echo "Reports the file size to console, and optionally adds a status check" + echo "to the repository on GitHub, if --write-status|-w is set. The env vars" + echo "GITHUB_TOKEN and BUILD_VCS_NUMBER are used if present." + echo + echo "If --report is not set, the script will exit with code 0 if there are no" + echo "errors, even if the file size is larger." + echo + echo "Parameters:" + echo " --write-status, -w Writes a status check to TeamCity" + echo " --report, -r Set exit code to:" + echo " 0, success, file size <= current version" + echo " 1, warning, file size slightly larger" + echo " 2, failure, file size significantly larger" + echo " 3, error, script failed" + echo " --github-token token Use token to report to GitHub, defaults to \$GITHUB_TOKEN" + echo " --sha sha Use sha for status check, defaults to \$BUILD_VCS_NUMBER" + exit 1 +} + +parse_params() { + while [[ $# -gt 0 ]] ; do + key="$1" + case $key in + --write-status|-w) + WRITE_STATUS=true + ;; + --report|-r) + REPORT=true + ;; + --sha) + TARGET_SHA="$2" + shift + ;; + --github-token) + GITHUB_TOKEN="$2" + shift + ;; + --help|-h|-\?) + display_usage + exit 0 + ;; + *) + echo "$0: invalid option: $key" + display_usage + exit 64 + esac + shift # past argument + done +} + +WRITE_STATUS=false +REPORT=false + +parse_params "$@" + +# +# Get file size of the latest local minified build +# + +LOCAL_FILE=web/release/web/keymanweb.js +LOCAL_FILE_SIZE=`stat --printf="%s" $KEYMAN_ROOT/$LOCAL_FILE` + +# +# Get the most recent build for $TIER from downloads.keyman.com +# + +DOWNLOADS_VERSION_API=https://downloads.keyman.com/api/version/web +REMOTE_KEYMANWEB_VERSIONS=`curl -s $DOWNLOADS_VERSION_API` +REMOTE_VERSION=`echo $REMOTE_KEYMANWEB_VERSIONS | $JQ -r ".web.$TIER"` + +REMOTE_FILE=https://downloads.keyman.com/web/$TIER/$REMOTE_VERSION/static/release/web/keymanweb.js +REMOTE_FILE_SIZE=`curl "$REMOTE_FILE" --location --silent --write-out '%{size_download}' --output /dev/null` + +# +# Report statistics +# + +echo "This build of keymanweb.js: $(printf "%'d" $LOCAL_FILE_SIZE) bytes" +echo "Last release build of keymanweb.js, version $REMOTE_VERSION: $(printf "%'d" $REMOTE_FILE_SIZE) bytes" + +# +# Verify that we are within expected bounds +# + +DIFF=$(($REMOTE_FILE_SIZE - $LOCAL_FILE_SIZE)) +if (( $DIFF < 0 )); then + DIFF=$((-$DIFF)) +fi + +PERCENT_DIFF=$((DIFF * 100 / $REMOTE_FILE_SIZE)) + +if (( $LOCAL_FILE_SIZE <= $REMOTE_FILE_SIZE )); then + # We are good -- the new build is smaller than the old one + RESULT_STATE=success + REPORT_CODE=0 + RESULT_MESSAGE="✅ Excellent! This build of keymanweb.js is $(printf "%'d" $LOCAL_FILE_SIZE) bytes, $(printf "%'d" $DIFF) bytes ($PERCENT_DIFF%) smaller than build $REMOTE_VERSION." +elif (( $DIFF < $SIZE_THRESHOLD )); then + # Warning, larger, but less than 1kb larger + RESULT_STATE=success + REPORT_CODE=1 + RESULT_MESSAGE="⚠️ Warning: This build of keymanweb.js is $(printf "%'d" $LOCAL_FILE_SIZE) bytes, $(printf "%'d" $DIFF) bytes ($PERCENT_DIFF%) larger than build $REMOTE_VERSION." +else + # Failure - new build is significantly larger + DIFF=$(($LOCAL_FILE_SIZE - $REMOTE_FILE_SIZE)) + RESULT_STATE=failure + REPORT_CODE=2 + RESULT_MESSAGE="❌ Oh dear! This build of keymanweb.js is $(printf "%'d" $LOCAL_FILE_SIZE) bytes, $(printf "%'d" $DIFF) bytes ($PERCENT_DIFF%) larger than build $REMOTE_VERSION." +fi + +echo "$RESULT_MESSAGE" + +if $WRITE_STATUS; then + if [ -z ${GITHUB_TOKEN+x} ]; then + # If we have a GITHUB_TOKEN env var set, either via environment in TeamCity, + # or via command line parameter, then we can attempt to report a GitHub status + # check + die "Error: GITHUB_TOKEN variable is not set." + fi + + if [ ! -z ${BUILD_VCS_NUMBER+x} ]; then + # If we are running on TeamCity, we should have the BUILD_VCS_NUMBER env var + # referencing the git commit sha against which we should report the status + write_github_status_check_from_teamcity "check/web/file-size" "$RESULT_STATE" "$RESULT_MESSAGE" "" + elif [ ! -z ${TARGET_SHA+x} ]; then + # When running locally, we can report to GitHub if the sha is passed on the + # command line + write_github_status_check "check/web/file-size" "$RESULT_STATE" "$RESULT_MESSAGE" "" $TARGET_SHA + else + die "Error: could not find SHA to report against." + fi +fi + +if $REPORT; then + exit $REPORT_CODE +fi + +exit 0