angular/scripts/ci/payload-size.sh
Paul Gschwendtner 1177b4e2f8 ci: make payload size tracking script work with CircleCI and Bazel limitation (#45444)
For quite some time now, since we started to use Bazel for integration tests, we
relied on some size tracking logic that did not actually fully work under Bazel.

It was thought that all the necessary CI push/PR information is available to the
Bazel test, but that was not the case. This was now fixed with the recent Rules NodeJS
v5 update where I made sure the `env.sh` variables are actually available before we
write them to the temporary file for the Bazel-access.

This now will unveil an issue because payload size goldens would start being based
on their branch name. e.g. the golden key in `13.3.x` should not be `master` but
`13.3.x`. This makes more sense than `master` as key, but makes things more
cumbersome and ideally we would not store the branch name at all (this is a larger
change though -- not worth now since we might refactor this anyway). For now we will
update the size tracking logic to always use `master` as golden key (like it worked
in the past year(s))

With the environment fix we now (again) start uploading payload size results to Firebase.
This did not work by accident either. The uploading logic is reliant on the CircleCI
commit range which is not working/reliable in upstream branches. This commit
removes this reliance on `COMMIT_RANGE` since it's not strictly necessary and
currently breaking renovate PRs. We can re-enable this when we have a solution with
CircleCI, or a workaround/resolution logic provided in e.g. `ng-dev ci determine-commit-range`.

PR Close #45444
2022-03-25 14:25:03 -07:00

157 lines
4.5 KiB
Bash

#!/usr/bin/env bash
set -eu -o pipefail
# statc makes `stat -c` work on both Linux & OSX
function statc () {
case $(uname) in
Darwin*) format='-f%z' ;;
*) format='-c%s' ;;
esac
stat ${format} $@
}
# sedr makes `sed -r` work on both Linux & OSX
function sedr () {
case $(uname) in
Darwin*) flag='-E' ;;
*) flag='-r' ;;
esac
sed ${flag} "$@"
}
readonly PROJECT_NAME="angular-payload-size"
NODE_MODULES_BIN=$PROJECT_ROOT/node_modules/.bin/
# Get the gzip size of a file with the specified compression level.
# $1: string - The file path.
# $2: number - The level of compression.
getGzipSize() {
local filePath=$1
local compLevel=$2
local compPath=$1$2.gz
local size=-1
gzip -c -$compLevel "$filePath" >> "$compPath"
size=$(statc "$compPath")
rm "$compPath"
echo $size
}
# Calculate the size of target file uncompressed size, gzip7 size, gzip9 size
# Write to global variable $payloadData, $filename
calculateSize() {
label=$(echo "$filename" | sed "s/.*\///" | sed "s/\..*//")
rawSize=$(statc $filename)
gzip7Size=$(getGzipSize "$filename" 7)
gzip9Size=$(getGzipSize "$filename" 9)
# Log the sizes (for information/debugging purposes).
printf "Size: %6d (gzip7: %6d, gzip9: %6d) %s\n" $rawSize $gzip7Size $gzip9Size $label
payloadData="$payloadData\"uncompressed/$label\": $rawSize, "
payloadData="$payloadData\"gzip7/$label\": $gzip7Size, "
payloadData="$payloadData\"gzip9/$label\": $gzip9Size, "
}
# Check whether the file size is under limit.
# Exit with an error if limit is exceeded.
# $1: string - The name in database.
# $2: string - The payload size limit file.
checkSize() {
name="$1"
limitFile="$2"
# PRs and non-PR pushes will always test against the size-limits of the current revision.
node ${PROJECT_ROOT}/scripts/ci/payload-size.js $limitFile $name ${CI_COMMIT:-}
}
# Write timestamp to global variable `$payloadData`.
addTimestamp() {
# Add Timestamp
timestamp=$(date +%s)
payloadData="$payloadData\"timestamp\": $timestamp, "
}
# Write the current CI build URL to global variable `$payloadData`.
# This allows mapping the data stored in the database to the CI build job that generated it, which
# might contain more info/context.
# $1: string - The CI build URL.
addBuildUrl() {
buildUrl="$1"
payloadData="$payloadData\"buildUrl\": \"$buildUrl\", "
}
# Write the commit message for the specified CI commit to global variable `$payloadData`.
# $1: string - The commit SHA for this build (in `<SHA-1>` format).
addMessage() {
message="${1}"
message=$(echo $message | sed 's/\r//g' | sed 's/\\/\\\\/g' | sed 's/"/\\"/g')
payloadData="$payloadData\"message\": \"$message\", "
}
# Convert the current `payloadData` value to a JSON string.
# (Basically remove trailing `,` and wrap in `{...}`.)
payloadToJson() {
echo "{$(sedr 's|, *$||' <<< $payloadData)}"
}
# Upload data to firebase database if it's commit, print out data for pull requests.
# $1: string - The name in database.
uploadData() {
name="$1"
readonly safeBranchName=$(echo $CI_BRANCH | sed -e 's/\./_/g')
readonly dbPath=/payload/$name/$safeBranchName/$CI_COMMIT
readonly jsonPayload=$(payloadToJson)
# WARNING: CI_SECRET_PAYLOAD_FIREBASE_TOKEN should NOT be printed.
set +x
$NODE_MODULES_BIN/firebase database:update --data "$jsonPayload" --project $PROJECT_NAME --confirm --token "$CI_SECRET_PAYLOAD_FIREBASE_TOKEN" $dbPath
}
# Track payload size.
# $1: string - The name in database.
# $2: string - The file path.
# $3: true | false - Whether to check the payload size and fail the test if it exceeds limit.
# $4: [string] - The payload size limit file. Only necessary if `$3` is `true`.
trackPayloadSize() {
name="$1"
path="$2"
checkSize="$3"
limitFile="${4:-}"
payloadData=""
# Calculate the file sizes.
echo "Calculating sizes for files in '$path'..."
for filename in $path; do
calculateSize
done
# Save the file sizes to be retrieved from `payload-size.js`.
echo "$(payloadToJson)" > /tmp/current.log
# If this is a non-PR build, upload the data to firebase.
if [[ "${CI_PULL_REQUEST:-}" == "false" ]]; then
echo "Uploading data for '$name'..."
addTimestamp
addBuildUrl $CI_BUILD_URL
addMessage $CI_COMMIT
uploadData $name
else
echo "Skipped uploading data for '$name', because this is a pull request."
fi
# Check the file sizes against the specified limits.
if [[ $checkSize = true ]]; then
echo "Verifying sizes against '$limitFile'..."
checkSize $name $limitFile
else
echo "Skipped verifying sizes (checkSize: false)."
fi
}