mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
ci: use new size tracking in integration tests (#62650)
Use the new size tracking within integration tests PR Close #62650
This commit is contained in:
committed by
Kirill Cherkashin
parent
8caaf5ed22
commit
b0effa1cc3
+1
-1
@@ -9,7 +9,7 @@ export const format: FormatConfig = {
|
||||
'**/*.{yaml,yml}',
|
||||
'**/*.{js,ts,mjs,mts,cjs,cts,tsx}',
|
||||
'devtools/**/*.{js,ts,mjs,mts,cjs,cts,html,scss}',
|
||||
|
||||
'integration/**/size.json',
|
||||
// Do not format d.ts files as they are generated
|
||||
'!**/*.d.ts',
|
||||
// Both third_party and .yarn are directories containing copied code which should
|
||||
|
||||
+1
-1
@@ -415,7 +415,7 @@ groups:
|
||||
- *no-groups-above-this-rejected
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'goldens/size-tracking/**/{*,.*}'
|
||||
'integration/**/size.json'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
|
||||
@@ -11,9 +11,6 @@ exports_files([
|
||||
"karma-js.conf.js",
|
||||
"browser-providers.conf.js",
|
||||
YARN_PATH,
|
||||
"scripts/ci/bazel-payload-size.sh",
|
||||
"scripts/ci/payload-size.sh",
|
||||
"scripts/ci/payload-size.js",
|
||||
"package.json",
|
||||
"angular.json",
|
||||
])
|
||||
|
||||
@@ -271,7 +271,7 @@ yarn_install(
|
||||
|
||||
git_repository(
|
||||
name = "devinfra",
|
||||
commit = "6f54d143077baef582d70873722166fdc040066c",
|
||||
commit = "ae6afbc8c8cd972146d1ac062ccd93b9e6587986",
|
||||
remote = "https://github.com/angular/dev-infra.git",
|
||||
)
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
exports_files([
|
||||
"size-tracking/integration-payloads.json",
|
||||
])
|
||||
|
||||
filegroup(
|
||||
name = "public-api",
|
||||
srcs = glob([
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"cli-hello-world": {
|
||||
"uncompressed": {
|
||||
"main": 137461,
|
||||
"polyfills": 34579
|
||||
}
|
||||
},
|
||||
"cli-hello-world-ivy-i18n": {
|
||||
"uncompressed": {
|
||||
"main": 135813,
|
||||
"polyfills": 35883
|
||||
}
|
||||
},
|
||||
"cli-hello-world-lazy": {
|
||||
"uncompressed": {
|
||||
"main": 108611,
|
||||
"polyfills": 34169,
|
||||
"lazy.routes": 361
|
||||
}
|
||||
},
|
||||
"forms": {
|
||||
"uncompressed": {
|
||||
"main": 181773,
|
||||
"polyfills": 33772
|
||||
}
|
||||
},
|
||||
"animations": {
|
||||
"uncompressed": {
|
||||
"main": 143167,
|
||||
"polyfills": 34023,
|
||||
"open-close.component": 1190
|
||||
}
|
||||
},
|
||||
"animations-async": {
|
||||
"uncompressed": {
|
||||
"main": 86540,
|
||||
"polyfills": 33782,
|
||||
"browser": 63949,
|
||||
"open-close.component": 1218
|
||||
}
|
||||
},
|
||||
"standalone-bootstrap": {
|
||||
"uncompressed": {
|
||||
"main": 94769,
|
||||
"polyfills": 33802
|
||||
}
|
||||
},
|
||||
"defer": {
|
||||
"uncompressed": {
|
||||
"main": 12709,
|
||||
"polyfills": 33807,
|
||||
"defer.component": 345
|
||||
}
|
||||
},
|
||||
"platform-server-hydration/browser": {
|
||||
"uncompressed": {
|
||||
"main": 221976,
|
||||
"polyfills": 34544,
|
||||
"event-dispatch-contract.min": 476
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,4 @@ load("//integration:index.bzl", "ng_integration_test")
|
||||
ng_integration_test(
|
||||
name = "test",
|
||||
setup_chromium = True,
|
||||
track_payload_size = "cli-hello-world-ivy-i18n",
|
||||
)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"dist/main.js": 135813,
|
||||
"dist/polyfills.js": 35883
|
||||
}
|
||||
@@ -2,5 +2,4 @@ load("//integration:index.bzl", "ng_integration_test")
|
||||
|
||||
ng_integration_test(
|
||||
name = "test",
|
||||
track_payload_size = "cli-hello-world-lazy",
|
||||
)
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
This test checks bundle sizes when there is a lazy module. It also checks if the `ngDevMode` global variable and string references in `packages/core/src/util/ng_dev_mode.ts` are correctly removed.
|
||||
|
||||
This test contains a lazy route to ensure `ngDevMode` removal happens even across chunks, and a payload size check in `/goldens/size-tracking/integration-payloads.json` to ensure extra code is not retained accidentally.
|
||||
This test contains a lazy route to ensure `ngDevMode` removal happens even across chunks, and a payload size check to ensure extra code is not retained accidentally.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dist/main.js": 108611,
|
||||
"dist/polyfills.js": 34169,
|
||||
"dist/lazy.routes-[hash].js": 361
|
||||
}
|
||||
@@ -2,5 +2,4 @@ load("//integration:index.bzl", "ng_integration_test")
|
||||
|
||||
ng_integration_test(
|
||||
name = "test",
|
||||
track_payload_size = "cli-hello-world",
|
||||
)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"dist/main.js": 137461,
|
||||
"dist/polyfills.js": 34579
|
||||
}
|
||||
@@ -2,5 +2,4 @@ load("//integration:index.bzl", "ng_integration_test")
|
||||
|
||||
ng_integration_test(
|
||||
name = "test",
|
||||
track_payload_size = "defer",
|
||||
)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dist/main.js": 12709,
|
||||
"dist/polyfills.js": 33807,
|
||||
"dist/defer.component-[hash].js": 345
|
||||
}
|
||||
@@ -14,8 +14,6 @@ def _ng_integration_test(name, setup_chromium = False, **kwargs):
|
||||
pinned_npm_packages = kwargs.pop("pinned_npm_packages", [])
|
||||
toolchains = kwargs.pop("toolchains", [])
|
||||
environment = kwargs.pop("environment", {})
|
||||
track_payload_size = kwargs.pop("track_payload_size", None)
|
||||
track_payload_paths = kwargs.pop("track_payload_paths", [""])
|
||||
data = kwargs.pop("data", [])
|
||||
|
||||
if setup_chromium:
|
||||
@@ -33,23 +31,6 @@ def _ng_integration_test(name, setup_chromium = False, **kwargs):
|
||||
"yarn test",
|
||||
])
|
||||
|
||||
if track_payload_size:
|
||||
commands += [
|
||||
"yarn build",
|
||||
]
|
||||
for path in track_payload_paths:
|
||||
commands += [
|
||||
# TODO: Replace the track payload-size script with a RBE and Windows-compatible script.
|
||||
"$(rootpath //:scripts/ci/bazel-payload-size.sh) {bundle}{path} 'dist{path}/*.js' true ${runfiles}/angular/$(rootpath //goldens:size-tracking/integration-payloads.json)".format(bundle = track_payload_size, path = path, runfiles = "${RUNFILES}"),
|
||||
]
|
||||
|
||||
data += [
|
||||
"//goldens:size-tracking/integration-payloads.json",
|
||||
"//:scripts/ci/bazel-payload-size.sh",
|
||||
"//:scripts/ci/payload-size.sh",
|
||||
"//:scripts/ci/payload-size.js",
|
||||
]
|
||||
|
||||
# Complete list of npm packages to override in the test's package.json file mapped to
|
||||
# tgz archive to use for the replacement. This is the full list for all integration
|
||||
# tests. Any given integration does not need to use all of these packages.
|
||||
|
||||
@@ -2,5 +2,4 @@ load("//integration:index.bzl", "ng_integration_test")
|
||||
|
||||
ng_integration_test(
|
||||
name = "test",
|
||||
track_payload_size = "animations-async",
|
||||
)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"dist/main.js": 86540,
|
||||
"dist/polyfills.js": 33782,
|
||||
"dist/browser-[hash].js": 63949,
|
||||
"dist/open-close.component-[hash].js": 1218
|
||||
}
|
||||
@@ -2,5 +2,4 @@ load("//integration:index.bzl", "ng_integration_test")
|
||||
|
||||
ng_integration_test(
|
||||
name = "test",
|
||||
track_payload_size = "animations",
|
||||
)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dist/main.js": 143167,
|
||||
"dist/polyfills.js": 34023,
|
||||
"dist/open-close.component-[hash].js": 1190
|
||||
}
|
||||
@@ -3,8 +3,4 @@ load("//integration:index.bzl", "ng_integration_test")
|
||||
ng_integration_test(
|
||||
name = "test",
|
||||
setup_chromium = True,
|
||||
track_payload_paths = [
|
||||
"/browser",
|
||||
],
|
||||
track_payload_size = "platform-server-hydration",
|
||||
)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dist/browser/main-[hash].js": 221976,
|
||||
"dist/browser/polyfills-[hash].js": 34544,
|
||||
"dist/browser/event-dispatch-contract.min.js": 476
|
||||
}
|
||||
@@ -2,5 +2,4 @@ load("//integration:index.bzl", "ng_integration_test")
|
||||
|
||||
ng_integration_test(
|
||||
name = "test",
|
||||
track_payload_size = "standalone-bootstrap",
|
||||
)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"dist/main.js": 94769,
|
||||
"dist/polyfills.js": 33802
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
# Source optional CI environment variables which are sandboxed out
|
||||
# of the environment when running integration tests under Bazel
|
||||
readonly bazelVarEnv="/tmp/bazel-ci-env.sh"
|
||||
if [[ -f "$bazelVarEnv" ]]; then
|
||||
source $bazelVarEnv
|
||||
fi
|
||||
|
||||
# If running locally, at a minimum set PROJECT_ROOT
|
||||
if [[ -z "${PROJECT_ROOT:-}" ]]; then
|
||||
PROJECT_ROOT=$(cd $(dirname $0)/../..; pwd)
|
||||
fi
|
||||
|
||||
# Bazel payload size tracking should always be treated as if this runs as part of
|
||||
# a pull request. i.e. the results are not uploaded. This is necessary as Bazel test
|
||||
# targets do not necessarily run for every commit, and cached results might originate
|
||||
# from RBE-built pull requests. We will overhaut size-tracking anyway..
|
||||
export CI_PULL_REQUEST="true"
|
||||
|
||||
source ${PROJECT_ROOT}/scripts/ci/payload-size.sh
|
||||
trackPayloadSize "$@"
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Imports
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Get limit file, project name and commit SHA from command line arguments.
|
||||
const [, , limitFile, project, commit] = process.argv;
|
||||
|
||||
const THRESHOLD_BYTES = 5000;
|
||||
const THRESHOLD_PERCENT = 5;
|
||||
|
||||
// Load sizes.
|
||||
const currentSizes = JSON.parse(fs.readFileSync('/tmp/current.log', 'utf8'));
|
||||
const allLimitSizes = JSON.parse(fs.readFileSync(limitFile, 'utf8'));
|
||||
const limitSizes = allLimitSizes[project];
|
||||
if (!limitSizes) {
|
||||
throw new Error(`ERROR: Project '${project}' is missing from limit file ${limitFile}.`);
|
||||
}
|
||||
|
||||
// Check current sizes against limits.
|
||||
let failed = false;
|
||||
const successMessages = [];
|
||||
const failureMessages = [];
|
||||
for (const compressionType in limitSizes) {
|
||||
if (typeof limitSizes[compressionType] === 'object') {
|
||||
const limitPerFile = limitSizes[compressionType];
|
||||
|
||||
for (const filename in limitPerFile) {
|
||||
const expectedSize = limitPerFile[filename];
|
||||
const actualSize = currentSizes[`${compressionType}/${filename}`];
|
||||
|
||||
if (actualSize === undefined) {
|
||||
failed = true;
|
||||
// An expected compression type/file combination is missing. Maybe the file was renamed or
|
||||
// removed. Report it as an error, so the user updates the corresponding limit file.
|
||||
console.error(
|
||||
`ERROR: Commit ${commit} ${compressionType} ${filename} measurement is missing. ` +
|
||||
'Maybe the file was renamed or removed.',
|
||||
);
|
||||
} else {
|
||||
const absoluteSizeDiff = Math.abs(actualSize - expectedSize);
|
||||
// If size diff is larger than THRESHOLD_BYTES or THRESHOLD_PERCENT...
|
||||
if (
|
||||
absoluteSizeDiff > THRESHOLD_BYTES ||
|
||||
absoluteSizeDiff > (expectedSize * THRESHOLD_PERCENT) / 100
|
||||
) {
|
||||
failed = true;
|
||||
// We must also catch when the size is significantly lower than the payload limit, so
|
||||
// we are forced to update the expected payload number when the payload size reduces.
|
||||
// Otherwise, we won't be able to catch future regressions that happen to be below
|
||||
// the artificially inflated limit.
|
||||
const operator = actualSize > expectedSize ? 'exceeded' : 'fell below';
|
||||
|
||||
failureMessages.push(
|
||||
`FAIL: Commit ${commit} ${compressionType} ${filename} ${operator} expected size by ${THRESHOLD_BYTES} bytes or >${THRESHOLD_PERCENT}% ` +
|
||||
`(expected: ${expectedSize}, actual: ${actualSize}).`,
|
||||
);
|
||||
} else {
|
||||
successMessages.push(
|
||||
`SUCCESS: Commit ${commit} ${compressionType} ${filename} did NOT cross size threshold of ${THRESHOLD_BYTES} bytes or >${THRESHOLD_PERCENT} ` +
|
||||
`(expected: ${expectedSize}, actual: ${actualSize}).`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Group failure messages separately from success messages so they are easier to find.
|
||||
successMessages.concat(failureMessages).forEach((message) => console.error(message));
|
||||
|
||||
if (failed) {
|
||||
const projectRoot = path.resolve(__dirname, '../..');
|
||||
const limitFileRelPath = path.relative(projectRoot, limitFile);
|
||||
console.info(
|
||||
`If this is a desired change, please update the size limits in file '${limitFileRelPath}'.`,
|
||||
);
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.info(
|
||||
`Payload size check passed. All diffs are less than ${THRESHOLD_PERCENT}% or ${THRESHOLD_BYTES} bytes.`,
|
||||
);
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
#!/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="$(mktemp).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() {
|
||||
# Remove .js and -T74CPV26.js from the filename
|
||||
label=$(echo "$filename" | sed "s/\(-[A-Z0-9]\{8\}\)\?\.js//" | 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 --force --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
|
||||
}
|
||||
Reference in New Issue
Block a user