Compare commits

..

50 Commits

Author SHA1 Message Date
Alex Eagle af4eb00c91 docs: add changelog for 5.2.1 2018-01-17 09:39:46 -08:00
Alex Eagle d3e7ebb3b4 release: cut the 5.2.1 release 2018-01-17 09:37:50 -08:00
Alex Eagle 420f5c4275 build(bazel): remove spurious file (#21455)
PR Close #21455
2018-01-17 08:24:34 -08:00
Alan Agius b773a4ab98 docs(aio): change df-question to app-question (#21438)
closes: #21404
PR Close #21438
2018-01-17 07:20:52 -08:00
Jason Aden 55f15c54d9 docs(aio): add description and docs links for code samples (#21561)
PR Close #21561
2018-01-17 07:19:37 -08:00
Xander Garbett 4556532c26 feat(core): add binding name to content changed error (#20352)
Adding the binding name to the error message recieved by the user gives
extra context on what exactly changed. The tests are also updated to
reflect the new error message.

PR Close #20352
2018-01-17 07:17:00 -08:00
Benjamin Ingberg 54e75766ad fix(core): fix chained http call (#20924)
Fixes an issue where chained http calls would prematurely call
testability whenStable callbacks after the first http call.

Fixes #20921

PR Close #20924
2018-01-17 07:14:55 -08:00
Victor Berchet d3333f04ba refactor(core): refactor WrappedValue (#20997)
- Improve `WrappedValue` by adding `unwrap` symetrical to `wrap`.
- remove dead code - `ValueUnwrapper`

The property `wrapped` is an implementation details and should never be accessed
directly - use `unwrap(wrappedValue)`. Will change to protected in Angular 7.

PR Close #20997
2018-01-16 07:13:24 -08:00
ghetolay 75f8522b8d feat(forms): handle string with and without line boundary on pattern validator (#19256)
PR Close #19256
2018-01-16 07:12:14 -08:00
Pete Bacon Darwin a771ee5d90 build(aio): move file cleaning to later in the doc gen (#21540)
Previously the generated files were cleaned out before
doc-gen began (via a yarn pre-script). This can cause a
race condition in the CLI server, which prevents the new
generated files from being picked up.

Now we delay the cleaning until the last minute to ensure
that they ar still picked up by the webpack server.

PR Close #21540
2018-01-16 07:11:01 -08:00
Alex Eagle a4cbe3542a ci: disable integration/cli-hello-world test (#21492)
it is non-hermetic and breaks often due to unpinned dependencies.

PR Close #21492
2018-01-12 14:57:45 -08:00
Keen Yee Liau cc9419d1ca fix(language-service): Clear caches when program changes (#21337)
This commit fixes a bug whereby the caches are not cleared when the
program changes. This subsequently produces the incorrect error of
'Component ... is not included in a module ...'.

PR Close #19405

PR Close #21337
2018-01-12 14:43:34 -08:00
Chuck Jazdzewski d5393c7f91 docs(compiler): document the $any type cast function (#20968)
Closes #20966

PR Close #20968
2018-01-12 14:38:42 -08:00
Pete Bacon Darwin 71dd92bbb8 style(aio): enforce strict TypeScript checks (#21342)
Closes #20646

PR Close #21342
2018-01-12 14:37:02 -08:00
Olivier Combe 977978edb5 test(common): make date pipe tests work in more timezones (#21379)
Fixes #21112
PR Close #21379
2018-01-12 13:50:06 -08:00
George Kalpakas eb70966065 fix(aio): correctly handle redirects (#21416)
- Fixes handling of some redirects by the ServiceWorker.
- Fixes redirect for old `NgFor` to new `NgForOf` URL.

Fixes #21318

PR Close #21416
2018-01-12 13:49:10 -08:00
George Kalpakas cf4bea587d ci(aio): run e2e tests in production mode (#21470)
This will enable catching errors introduced by build optimizations that
do not appear in `development` mode.

Fixes #21446

PR Close #21470
2018-01-12 13:46:00 -08:00
Olivier Combe 8e9cd57951 fix(common): set correct timezone for ISO8601 dates in Safari (#21506)
Fixes #21491
PR Close #21506
2018-01-12 13:21:11 -08:00
Olivier Combe f23896f519 docs: fix release schedule date (#21474)
PR Close #21474
2018-01-12 12:10:26 -08:00
Olivier Combe 0e59d18fc2 ci: add angular robot config file (#21489)
PR Close #21489
2018-01-12 10:12:28 -08:00
Igor Minar 54c8a321a9 ci: update pullapprove rules now that we allow selfapprovals (#21494)
PR Close #21494
2018-01-12 10:11:37 -08:00
Pete Bacon Darwin 9005a6f3cd feat(aio): implement survey notification link (#21371)
Closes #21094

PR Close #21371
2018-01-12 10:06:08 -08:00
Marc Laval 3c6a5063f7 fix(benchpress): should still support selenium_webdriver < 3.6.0 (#21477)
PR Close #21477
2018-01-11 10:54:11 -08:00
Kapunahele Wong b49d54e606 docs(forms): clarify note in reactive forms doc (#21134)
PR Close #21134
2018-01-11 07:04:15 -08:00
Olivier Combe 55fd82e587 docs: fix release schedule date (#21469)
PR Close #21469
2018-01-11 06:45:49 -08:00
Kara Erickson 7f3d0bbf97 build: update polyfill size (#21461)
PR Close #21461
2018-01-10 17:07:32 -08:00
Kapunahele Wong 3db02d244a docs: fix lazy-loading example (#20306)
PR Close #20306
2018-01-10 16:26:28 -08:00
Kapunahele Wong 50b605686e docs: fix yarn.lock (#20306)
PR Close #20306
2018-01-10 16:26:28 -08:00
Kapunahele Wong 64d4aafbc7 docs(aio): add NgModule docs (#20306)
PR Close #20306
2018-01-10 16:26:28 -08:00
Chuck Jazdzewski a931a419fa fix(compiler): make .ngsummary.json files idempotent (#21448)
Fixes: #21432

PR Close #21448
2018-01-10 16:21:32 -08:00
Miško Hevery 6a97b5b722 docs(ivy): add Ivy as a recognized label (#21428)
PR Close #21428
2018-01-10 15:32:59 -08:00
Igor Minar aad1126446 docs: update the release schedule with v6 info (#21435)
Fixes #20649

PR Close #21435
2018-01-10 15:20:27 -08:00
George Kalpakas 7b463df52b fix(aio): preserve static Observable methods (#21351)
PR Close #21351
2018-01-10 14:30:42 -08:00
Igor Minar a2432c9f10 build(aio): turn on namedChunks option to make debugging, profiling and tracking easier (#21351)
PR Close #21351
2018-01-10 14:30:42 -08:00
Igor Minar e500484ccc build(aio): upgrade to angular@5.2.0 (#21351)
-rw-r--r--  1 iminar  eng   72498 Jan  9 22:20 dist/0.0d2802b63e9f4f4615cd.chunk.js
-rw-r--r--  1 iminar  eng   14872 Jan  9 22:20 dist/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1558 Jan  9 22:20 dist/inline.cb4b7a639193fc489d3b.bundle.js
-rw-r--r--  1 iminar  eng  454654 Jan  9 22:20 dist/main.b65f32ffc92e075e64e0.bundle.js
-rw-r--r--  1 iminar  eng   40264 Jan  9 22:20 dist/polyfills.87edf5d695f14a29bf91.bundle.js
-rw-r--r--  1 iminar  eng   54001 Jan  9 22:20 dist/worker-basic.min.js

PR Close #21351
2018-01-10 14:30:42 -08:00
Igor Minar a0dcb0b828 ci(aio): track sizes of all js files (#21351)
PR Close #21351
2018-01-10 14:30:42 -08:00
Igor Minar c4b71920d1 build(aio): upgrade to angular@5.2.0-rc.0 (#21351)
Because of c2b3792 one of the test assertions had to be adjusted (more info: https://github.com/angular/angular/pull/21351#issuecomment-356083940).

PR Close #21351
2018-01-10 14:30:42 -08:00
Alex Eagle 650f5fb5c7 build(bazel): fix merge conflict between c4f02e2 and ef956a2 (#21453)
PR Close #21453
2018-01-10 12:57:38 -08:00
Chuck Jazdzewski c32e83334b fix(compiler): cache external reference resolution (#21359)
Cache reference resolution for external references as finding
the declaration of a symbol is expensive and does not change
for a program once created.

This resolves a signficant performance regression in the langauge
service.

PR Close #21359
2018-01-10 12:34:07 -08:00
Olivier Combe 7bdd9aecbd build: upgrade yarn to 1.3.2 (#21406)
Fixes #20566
PR Close #21406
2018-01-10 12:32:47 -08:00
Alex Eagle 5ede67c345 build: move repeated tsconfig attributes to a macro (#20964)
This helps ensure we use the same tsconfig.json file for all compilations.
Next steps are to make it the same tsconfig.json file used by the editor

PR Close #20964
2018-01-10 12:30:44 -08:00
Suguru Inatomi 31b671ab54 fix(aio): support multibyte character in heading (#21414)
PR Close #21414
2018-01-10 12:25:45 -08:00
Alex Eagle 3804d20b6d docs(bazel): document an installation issue (#21401)
observed by Igor on a Mac

PR Close #21401
2018-01-10 12:24:03 -08:00
Igor Minar 0a5a87887e build(aio): upgrade to uglify-es@3.3.5 (#21350)
This should fix the size regression spotted via the previous commit.

-rw-r--r--  1 iminar  eng   72498 Jan  8 00:03 dist/0.86a7a08f7866e6cdc36f.chunk.js
-rw-r--r--  1 iminar  eng   14872 Jan  8 00:03 dist/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1558 Jan  8 00:03 dist/inline.7722895d8c844f710bcd.bundle.js
-rw-r--r--  1 iminar  eng  453905 Jan  8 00:03 dist/main.faff0e2da95443f759f5.bundle.js
-rw-r--r--  1 iminar  eng   40264 Jan  8 00:03 dist/polyfills.87edf5d695f14a29bf91.bundle.js
-rw-r--r--  1 iminar  eng   54001 Jan  8 00:03 dist/worker-basic.min.js

PR Close #21350
2018-01-10 12:22:12 -08:00
Igor Minar c46afce0f5 build(aio): upgrade to @angular/cli@1.6.3 (#21350)
This change introduces a size regression of 9kb for main.js :-(

I filed an issue for this: https://github.com/angular/angular-cli/issues/9108

-rw-r--r--  1 iminar  eng   72546 Jan  5 19:27 dist.cli-1.6.3/0.86a7a08f7866e6cdc36f.chunk.js
-rw-r--r--  1 iminar  eng   14893 Jan  5 19:27 dist.cli-1.6.3/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1558 Jan  5 19:27 dist.cli-1.6.3/inline.7722895d8c844f710bcd.bundle.js
-rw-r--r--  1 iminar  eng  466484 Jan  5 19:27 dist.cli-1.6.3/main.faff0e2da95443f759f5.bundle.js
-rw-r--r--  1 iminar  eng   40363 Jan  5 19:27 dist.cli-1.6.3/polyfills.87edf5d695f14a29bf91.bundle.js
-rw-r--r--  1 iminar  eng   54001 Jan  5 19:27 dist.cli-1.6.3/worker-basic.min.js

PR Close #21350
2018-01-10 12:22:12 -08:00
courtneypattison 76c781fd37 docs(router): remove extra brackets (#21294)
PR Close #21294
2018-01-10 12:20:48 -08:00
Alex Rickabaugh 51eb3d418e fix(service-worker): properly handle invalid hashes in all scenarios (#21288)
When the SW fetches URLs listed in a manifest with hashes, it checks
the content hash against the manifest to make sure it has the correct
version of the URL. In the event of a mismatch, the SW is supposed to
consider the manifest invalid, and avoid using it. There are 3 cases
to consider by which this can happen.

Case 1: during the initial SW installation, a manifest is activated
without waiting for every URL to be fully loaded. In the background,
every prefetch URL listed by the manifest is requested and cached.
One such prefetch request could fail the hash test, and cause the
manifest to be treated as invalid. In such a case, the SW should
enter a state of EXISTING_CLIENTS_ONLY, as the latest manifest is
invalid.

This case works today.

Case 2: during the initial SW installation, as in Case 1, a manifest
is activated without waiting for each URL to fully load. However,
it's possible that the application could request a URL with a bad
hash before background initialization tries to load that URL. This
happens if, for example, the application has a broken index.html.

In this case, the SW should enter a state of EXISTING_CLIENTS_ONLY,
and serve the request from the network instead.

What happens today is that the internal error escapes the SW and
is returned as a rejected Promise to respondWith(), causing a
browser-level error that the site cannot be loaded, breaking the
site.

This change allows the SW to detect the error and enter the correct
state, falling back on the network if needed.

Case 3: during checkForUpdate(), the SW will try to fully cache the
new update before making it the latest version. Failure here is
complicated - if the page fails to load due to transient network
conditions (timeouts, 500s, etc), then it makes sense to continue
serving the existing cached version, and attempt to activate the
update on the next cycle.

If the page fails due to non-transient conditions though (400 error,
hash mismatch, etc), then the SW should consider the updated
manifest invalid, and enter a state of EXISTING_CLIENTS_ONLY.

Currently, all errors are treated as transient.

This change causes the SW to treat all errors during updates as
non-transient, which can cause the SW to unnecessarily enter a
safe mode. A future change can allow the SW to remain in normal mode
if the error is provably transient.

PR Close #21288
2018-01-10 12:18:55 -08:00
cexbrayat 48c18985cc fix(animations): fix increment/decrement aliases example (#18323)
PR Close #18323
2018-01-10 12:07:24 -08:00
Misko Hevery 167cbed266 build: add bazel rulse for benchmarks (#21436)
PR Close #21436
2018-01-10 12:01:17 -08:00
Matias Niemelä 70e8802540 docs(core): provide note for unit test changes with the ng-star-inserted className (#21450)
PR Close #21450
2018-01-10 11:14:28 -08:00
11368 changed files with 327236 additions and 1146226 deletions
-71
View File
@@ -1,71 +0,0 @@
# Bazel does not yet support wildcards or other .gitignore semantics for
# .bazelignore. Two issues for this feature request are outstanding:
# https://github.com/bazelbuild/bazel/issues/7093
# https://github.com/bazelbuild/bazel/issues/8106
.git
node_modules
dist
aio/content
aio/node_modules
aio/tools/examples/shared/node_modules
packages/bazel/node_modules
# All integration test node_modules folders
integration/bazel_workspace_tests/bazel_ngtsc_plugin/node_modules
integration/cli-elements-universal/node_modules
integration/cli-hello-world/node_modules
integration/cli-hello-world-ivy-compat/node_modules
integration/cli-hello-world-ivy-i18n/node_modules
integration/cli-hello-world-ivy-minimal/node_modules
integration/cli-hello-world-lazy/node_modules
integration/cli-hello-world-ts-47/node_modules
integration/dynamic-compiler/node_modules
integration/hello_world__closure/node_modules
integration/hello_world__systemjs_umd/node_modules
integration/i18n/node_modules
integration/injectable-def/node_modules
integration/ivy-i18n/node_modules
integration/ng-add-localize/node_modules
integration/trusted-types/node_modules
integration/forms/node_modules
integration/ng_elements/node_modules
integration/ng_elements_schematics/node_modules
integration/ng_update/node_modules
integration/ng_update_migrations/node_modules
integration/ngcc/node_modules
integration/platform-server/node_modules
integration/service-worker-schema/node_modules
integration/side-effects/node_modules
integration/terser/node_modules
integration/typings_test_ts36/node_modules
integration/typings_test_ts37/node_modules
# All integration test .yarn_local_cache folders
integration/bazel_workspace_tests/bazel_ngtsc_plugin/.yarn_local_cache
integration/cli-elements-universal/.yarn_local_cache
integration/cli-hello-world/.yarn_local_cache
integration/cli-hello-world-ivy-compat/.yarn_local_cache
integration/cli-hello-world-ivy-i18n/.yarn_local_cache
integration/cli-hello-world-ivy-minimal/.yarn_local_cache
integration/cli-hello-world-lazy/.yarn_local_cache
integration/cli-hello-world-ts-47/.yarn_local_cache
integration/dynamic-compiler/.yarn_local_cache
integration/hello_world__closure/.yarn_local_cache
integration/hello_world__systemjs_umd/.yarn_local_cache
integration/i18n/.yarn_local_cache
integration/injectable-def/.yarn_local_cache
integration/ivy-i18n/.yarn_local_cache
integration/ng-add-localize/.yarn_local_cache
integration/trusted-types/.yarn_local_cache
integration/forms/.yarn_local_cache
integration/ng_elements/.yarn_local_cache
integration/ng_elements_schematics/.yarn_local_cache
integration/ng_update/.yarn_local_cache
integration/ng_update_migrations/.yarn_local_cache
integration/ngcc/.yarn_local_cache
integration/platform-server/.yarn_local_cache
integration/service-worker-schema/.yarn_local_cache
integration/side-effects/.yarn_local_cache
integration/terser/.yarn_local_cache
integration/typings_test_ts36/.yarn_local_cache
integration/typings_test_ts37/.yarn_local_cache
-145
View File
@@ -1,145 +0,0 @@
# Enable debugging tests with --config=debug
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
###############################
# Filesystem interactions #
###############################
# Create symlinks in the project:
# - dist/bin for outputs
# - dist/testlogs, dist/genfiles
# - bazel-out
# NB: bazel-out should be excluded from the editor configuration.
# The checked-in /.vscode/settings.json does this for VSCode.
# Other editors may require manual config to ignore this directory.
# In the past, we say a problem where VSCode traversed a massive tree, opening file handles and
# eventually a surprising failure with auto-discovery of the C++ toolchain in
# MacOS High Sierra.
# See https://github.com/bazelbuild/bazel/issues/4603
build --symlink_prefix=dist/
# Turn off legacy external runfiles
build --nolegacy_external_runfiles
run --nolegacy_external_runfiles
test --nolegacy_external_runfiles
# Turn on --incompatible_strict_action_env which was on by default
# in Bazel 0.21.0 but turned off again in 0.22.0. Follow
# https://github.com/bazelbuild/bazel/issues/7026 for more details.
# This flag is needed to so that the bazel cache is not invalidated
# when running bazel via `yarn bazel`.
# See https://github.com/angular/angular/issues/27514.
build --incompatible_strict_action_env
run --incompatible_strict_action_env
test --incompatible_strict_action_env
# Do not build runfile trees by default. If an execution strategy relies on runfile
# symlink teee, the tree is created on-demand. See: https://github.com/bazelbuild/bazel/issues/6627
# and https://github.com/bazelbuild/bazel/commit/03246077f948f2790a83520e7dccc2625650e6df
build --nobuild_runfile_links
build --enable_runfiles
###############################
# Release support #
# Turn on these settings with #
# --config=release #
###############################
# Releases should always be stamped with version control info
# This command assumes node on the path and is a workaround for
# https://github.com/bazelbuild/bazel/issues/4802
build:release --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=release"
build:release --stamp
# Snapshots should also be stamped with version control information.
build:snapshot-build --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=snapshot"
build:snapshot-build --stamp
###############################
# Output #
###############################
# A more useful default output mode for bazel query
# Prints eg. "ng_module rule //foo:bar" rather than just "//foo:bar"
query --output=label_kind
# By default, failing tests don't print any output, it goes to the log file
test --test_output=errors
################################
# Settings for CircleCI #
################################
# Bazel flags for CircleCI are in /.circleci/bazel.linux.rc and /.circleci/bazel.windows.rc
##################################
# Remote Build Execution support #
# Turn on these settings with #
# --config=remote #
##################################
# The following --define=EXECUTOR=remote will be able to be removed
# once https://github.com/bazelbuild/bazel/issues/7254 is fixed
build:remote --define=EXECUTOR=remote
# Set a higher timeout value, just in case.
build:remote --remote_timeout=600
# Increase the default number of jobs by 50% because our build has lots of
# parallelism
build:remote --jobs=150
build:remote --google_default_credentials
# Force remote exeuctions to consider the entire run as linux
build:remote --cpu=k8
build:remote --host_cpu=k8
# Toolchain and platform related flags
build:remote --crosstool_top=@npm//@angular/build-tooling/bazel/remote-execution/cpp:cc_toolchain_suite
build:remote --extra_toolchains=@npm//@angular/build-tooling/bazel/remote-execution/cpp:cc_toolchain
build:remote --extra_execution_platforms=@npm//@angular/build-tooling/bazel/remote-execution:platform
build:remote --host_platform=@npm//@angular/build-tooling/bazel/remote-execution:platform
build:remote --platforms=@npm//@angular/build-tooling/bazel/remote-execution:platform
# Remote instance and caching
build:remote --remote_instance_name=projects/internal-200822/instances/primary_instance
build:remote --project_id=internal-200822
build:remote --remote_cache=remotebuildexecution.googleapis.com
build:remote --remote_executor=remotebuildexecution.googleapis.com
##################################
# Saucelabs tests settings #
# Turn on these settings with #
# --config=saucelabs #
##################################
# For saucelabs tests we don't want to enable flaky test attempts. Karma has its own integrated
# retry mechanism and we do not want to retry unnecessarily if Karma already tried multiple times.
test:saucelabs --flaky_test_attempts=1
################
# Flag Aliases #
################
# --ng_perf will ask the Ivy compiler to produce performance results for each build.
build --flag_alias=ng_perf=//packages/compiler-cli:ng_perf
#####################################################################
# Folders to ignore for integration tests (nested Bazel workspaces) #
#####################################################################
# The nested Bazel integration test workspace should not be analysed as part of
# Skyframe, but should also not be ignored in order to be able to glob for its files.
# TODO: Simplify this once https://github.com/bazelbuild/bazel/issues/12034 is fixed
build --deleted_packages=integration/bazel_workspace_tests/bazel_ngtsc_plugin,integration/bazel_workspace_tests/bazel_ngtsc_plugin/src,integration/bazel_workspace_tests/bazel_ngtsc_plugin/src/hello-world,integration/bazel_workspace_tests/bazel_ngtsc_plugin/test,integration/bazel_workspace_tests/bazel_ngtsc_plugin/test/e2e,integration/bazel_workspace_tests/bazel_ngtsc_plugin/tools,integration/bazel_workspace_tests/bazel_ngtsc_plugin/tools/angular
query --deleted_packages=integration/bazel_workspace_tests/bazel_ngtsc_plugin,integration/bazel_workspace_tests/bazel_ngtsc_plugin/src,integration/bazel_workspace_tests/bazel_ngtsc_plugin/src/hello-world,integration/bazel_workspace_tests/bazel_ngtsc_plugin/test,integration/bazel_workspace_tests/bazel_ngtsc_plugin/test/e2e,integration/bazel_workspace_tests/bazel_ngtsc_plugin/tools,integration/bazel_workspace_tests/bazel_ngtsc_plugin/tools/angular
####################################################
# User bazel configuration
# NOTE: This needs to be the *last* entry in the config.
####################################################
# Load any settings which are specific to the current user. Needs to be *last* statement
# in this config, as the user configuration should be able to overwrite flags from this file.
try-import .bazelrc.user
-1
View File
@@ -1 +0,0 @@
5.0.0
+3
View File
@@ -0,0 +1,3 @@
{
"directory" : "bower_components"
}
-19
View File
@@ -1,19 +0,0 @@
# Encryption
Based on https://github.com/circleci/encrypted-files
In the CircleCI web UI, we have a secret variable called `KEY`
https://circleci.com/gh/angular/angular/edit#env-vars
which is only exposed to non-fork builds
(see "Pass secrets to builds from forked pull requests" under
https://circleci.com/gh/angular/angular/edit#advanced-settings)
We use this as a symmetric AES encryption key to encrypt tokens like
a GitHub token that enables publishing snapshots.
To create the github_token file, we take this approach:
- Find the angular-builds:token in the internal pw database
- Go inside the CircleCI default docker image so you use the same version of openssl as we will at runtime: `docker run --rm -it circleci/node:10.12`
- echo "https://[token]:@github.com" > credentials
- openssl aes-256-cbc -e -in credentials -out .circleci/github_token -k $KEY
- If needed, base64-encode the result so you can copy-paste it out of docker: `base64 github_token`
-15
View File
@@ -1,15 +0,0 @@
# Settings in this file should be OS agnostic. Use the bazel.<OS>.rc files for OS specific settings.
# Don't be spammy in the logs
build --noshow_progress
# Print all the options that apply to the build.
# This helps us diagnose which options override others
# (e.g. /etc/bazel.bazelrc vs. tools/bazel.rc)
build --announce_rc
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
test --flaky_test_attempts=2
# More details on failures
build --verbose_failures=true
-23
View File
@@ -1,23 +0,0 @@
# These options are enabled when running on CI
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
# See documentation in /docs/BAZEL.md
# Import config items common to both Linux and Windows setups.
# https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics
try-import %workspace%/.circleci/bazel.common.rc
# Save downloaded repositories in a location that can be cached by CircleCI. This helps us
# speeding up the analysis time significantly with Bazel managed node dependencies on the CI.
build --repository_cache=/home/circleci/bazel_repository_cache
# Workaround https://github.com/bazelbuild/bazel/issues/3645
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
# Limit Bazel to consuming resources that fit in CircleCI "xlarge" class
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
build --local_cpu_resources=20
build --local_ram_resources=32768
# All build executed remotely should be done using our RBE configuration.
build:remote --google_default_credentials
build --config=remote
-17
View File
@@ -1,17 +0,0 @@
# These options are enabled when running on CI
# We do this by copying this file to $env:ProgramData\bazel.bazelrc at the start of the build.
# See documentation in /docs/BAZEL.md
# Import config items common to both Linux and Windows setups.
# https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics
try-import %workspace%/.circleci/bazel.common.rc
# Manually set the local resources used in windows CI runs
build --local_ram_resources=120000
build --local_cpu_resources=32
# All windows jobs run on master and should use http caching
build --remote_http_cache=https://storage.googleapis.com/angular-team-cache
build --remote_accept_cached=true
build --remote_upload_local_results=true
build --google_default_credentials
+50 -814
View File
@@ -3,839 +3,75 @@
# Note: YAML anchors allow an object to be re-used, reducing duplication.
# The ampersand declares an alias for an object, then later the `<<: *name`
# syntax dereferences it.
# See https://blog.daemonl.com/2016/02/yaml.html
# See http://blog.daemonl.com/2016/02/yaml.html
# To validate changes, use an online parser, eg.
# https://yaml-online-parser.appspot.com/
# http://yaml-online-parser.appspot.com/
# CircleCI configuration version
# Version 2.1 allows for extra config reuse features
# https://circleci.com/docs/2.0/reusing-config/#getting-started-with-config-reuse
version: 2.1
# Variables
# We don't want to include the current branch name in the cache key because that would prevent
# PRs from being able to restore the cache since the branch names are always different for PRs.
# The cache key should only consist of dynamic values that change whenever something in the
# cache changes. For example:
# 1) yarn lock file changes --> cached "node_modules" are different.
# 2) bazel repository definitions change --> cached bazel repositories are different.
# Windows needs its own cache key because binaries in node_modules are different.
# **NOTE 1 **: In order to avoid the cache from growing indefinitely and causing slow-downs, we invalidate the cache monthly.
# (See https://support.circleci.com/hc/en-us/articles/360012618473-Creating-a-daily-cache.)
# **NOTE 2 **: If you change the cache key prefix, also sync the cache_key_fallback to match.
# **NOTE 3 **: Keep the static part of the cache key as prefix to enable correct fallbacks.
# See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI.
var_3: &cache_key v8-angular-node-16-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "aio/yarn.lock" }}
# We invalidate the cache if the Bazel version changes because otherwise the `bazelisk` cache
# folder will contain all previously used versions and ultimately cause the cache restoring to
# be slower due to its growing size.
var_4: &cache_key_fallback v8-angular-node-16-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
## IMPORTANT
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
var_1: &docker_image angular/ngcontainer:0.1.0
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.1.0
# Windows needs its own cache key because binaries in node_modules are different.
var_3_win: &cache_key_win v10-angular-win-node-16-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}
var_4_win: &cache_key_win_fallback v10-angular-win-node-16-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
# Settings common to each job
anchor_1: &job_defaults
working_directory: ~/ng
docker:
- image: *docker_image
# Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the
# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable.
var_5: &components_repo_unit_tests_cache_key v2-angular-components-{{ checksum "month.txt" }}-7a24e95bafbdeb697f74a48e275c2442bcbefc74
var_6: &components_repo_unit_tests_cache_key_fallback v2-angular-components-{{ checksum "month.txt" }}
# After checkout, rebase on top of master.
# Similar to travis behavior, but not quite the same.
# See https://discuss.circleci.com/t/1662
anchor_2: &post_checkout
post: git pull --ff-only origin "refs/pull/${CIRCLE_PULL_REQUEST//*pull\//}/merge"
# Workspace initially persisted by the `setup` job, and then enhanced by `build-npm-packages`.
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
# https://circleci.com/blog/deep-diving-into-circleci-workspaces/
var_7: &workspace_location ~/
# Filter to run a job on builds for pull requests only.
var_8: &only_on_pull_requests
filters:
branches:
only:
- /pull\/\d+/
# Filter to skip a job on builds for pull requests.
var_9: &skip_on_pull_requests
filters:
branches:
ignore:
- /pull\/\d+/
# Filter to run a job on builds for the main branch only.
var_10: &only_on_main_branch
filters:
branches:
only:
- main
# Filter to run a job on all releasable branches.
var_11: &only_release_branches
filters:
branches:
only:
- main
- /\d+\.\d+\.x/
# CircleCI orbs
# https://circleci.com/developer/orbs.
orbs:
node: circleci/node@5.0.1
devinfra: angular/dev-infra@1.0.6
# Executor Definitions
# https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-executors
# **NOTE 1**: Pin to exact images using an ID (SHA). See https://circleci.com/docs/2.0/circleci-images/#using-a-docker-image-id-to-pin-an-image-to-a-fixed-version.
# (Using the tag in not necessary when pinning by ID, but include it anyway for documentation purposes.)
# **NOTE 2**: If you change the version of the docker images, also change the `cache_key` suffix.
# **NOTE 3**: If you change the version of Node.js provided by the docker images, also update `.devcontainer/recommended-Dockerfile` to match the new version.
executors:
default-executor:
parameters:
resource_class:
type: string
default: medium
docker:
- image: cimg/node:16.10.0
resource_class: << parameters.resource_class >>
working_directory: ~/ng
test-browser-executor:
parameters:
resource_class:
type: string
default: medium
docker:
- image: cimg/node:16.10.0-browsers
resource_class: << parameters.resource_class >>
working_directory: ~/ng
windows-executor:
working_directory: ~/ng
resource_class: windows.2xlarge
shell: bash
machine:
image: windows-server-2019-vs2019:201908-02
# Command Definitions
# https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-commands
commands:
custom_attach_workspace:
description: Attach workspace at a predefined location
steps:
- attach_workspace:
at: *workspace_location
# Install java runtime which is required by some integration tests such as
# //integration:hello_world__closure_test, //integration:i18n_test and
# //integration:ng_elements_test to run the closure compiler
install_java:
description: Install java
steps:
- run:
name: Install java
command: |
sudo apt-get update
# Install java runtime
sudo apt-get install default-jre
# Initializes the CI environment by setting up common environment variables.
init_environment:
description: Initializing environment (setting up variables)
steps:
- run:
name: Set up environment
environment:
CIRCLE_GIT_BASE_REVISION: << pipeline.git.base_revision >>
CIRCLE_GIT_REVISION: << pipeline.git.revision >>
command: ./.circleci/env.sh
- devinfra/setup-bazel-remote-exec
- run:
# Configure git as the CircleCI `checkout` command does.
# This is needed because we only checkout on the setup job.
# Add GitHub to known hosts
name: Configure git
command: |
mkdir -p ~/.ssh
echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' >> ~/.ssh/known_hosts
git config --global url."ssh://git@github.com".insteadOf "https://github.com" || true
git config --global gc.auto 0 || true
init_saucelabs_environment:
description: Sets up a domain that resolves to the local host.
steps:
- run:
name: Preparing environment for running tests on Sauce Labs.
command: |
# For SauceLabs jobs, we set up a domain which resolves to the machine which launched
# the tunnel. We do this because devices are sometimes not able to properly resolve
# `localhost` or `127.0.0.1` through the SauceLabs tunnel. Using a domain that does not
# resolve to anything on SauceLabs VMs ensures that such requests are always resolved
# through the tunnel, and resolve to the actual tunnel host machine (i.e. the CircleCI VM).
# More context can be found in: https://github.com/angular/angular/pull/35171.
setPublicVar SAUCE_LOCALHOST_ALIAS_DOMAIN "angular-ci.local"
setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev)
- run:
# Sets up a local domain in the machine's host file that resolves to the local
# host. This domain is helpful in Sauce Labs tests where devices are not able to
# properly resolve `localhost` or `127.0.0.1` through the sauce-connect tunnel.
name: Setting up alias domain for local host.
command: echo "127.0.0.1 $SAUCE_LOCALHOST_ALIAS_DOMAIN" | sudo tee -a /etc/hosts
save_month_to_file:
description: Store the current year and month in a file, so that it can be used for computing the cache key.
steps:
- run:
name: Save month to file
# Note: Make sure this file is excluded in the `.gitignore` as otherwise the
# snapshot stamping would have the `-with-local-changes` suffix.
command: date +%Y-%m > month.txt
yarn_install:
description: Install dependencies
steps:
- run:
name: Running Yarn install
command: yarn install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
# Yarn's requests sometimes take more than 10mins to complete (especially on Windows).
no_output_timeout: 45m
notify_webhook_on_fail:
description: Notify a webhook about failure
parameters:
# `webhook_url_env_var` are secret env vars defined in CircleCI project settings.
# The URLs come from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
webhook_url_env_var:
type: env_var_name
steps:
- run:
when: on_fail
command: |
notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job for $CIRCLE_BRANCH branch failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}"
curl --request POST --header "Content-Type: application/json" --data "$notificationJson" ${<< parameters.webhook_url_env_var >>}
# Job definitions
# Jobs can include parameters that are passed in the workflow job invocation.
# https://circleci.com/docs/2.0/reusing-config/#authoring-parameterized-jobs
version: 2
jobs:
setup:
executor: default-executor
steps:
- checkout
- save_month_to_file
- init_environment
- devinfra/rebase-pr-on-target-branch:
base_revision: << pipeline.git.base_revision >>
head_revision: << pipeline.git.revision >>
# This cache is saved in the build-npm-packages so that Bazel cache is also included.
- restore_cache:
keys:
- *cache_key
- *cache_key_fallback
- yarn_install
- run: yarn --cwd aio install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
# Make the bazel directories and add a file to them if they don't exist already so that
# persist_to_workspace does not fail.
- run: |
if [ ! -d ~/bazel_repository_cache ]; then
mkdir ~/bazel_repository_cache
touch ~/bazel_repository_cache/MARKER
fi
# Persist any changes at this point to be reused by further jobs.
# **NOTE**: To add new content to the workspace, always persist on the same root.
- persist_to_workspace:
root: *workspace_location
paths:
- ./ng
- ./bazel_repository_cache
lint:
executor: default-executor
<<: *job_defaults
steps:
- custom_attach_workspace
- init_environment
- checkout:
<<: *post_checkout
# Check BUILD.bazel formatting before we have a node_modules directory
# Then we don't need any exclude pattern to avoid checking those files
- run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) ||
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
# Run the skylark linter to check our Bazel rules
- run: 'find . -type f -name "*.bzl" |
xargs java -jar /usr/local/bin/Skylint_deploy.jar ||
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
- restore_cache:
key: *cache_key
- run: yarn -s tslint
- run: yarn -s ng-dev format changed $CI_GIT_BASE_REVISION --check
- run: yarn -s ts-circular-deps:check
- run: yarn -s ng-dev pullapprove verify
- run: yarn -s ng-dev ngbot verify
- run: yarn -s ng-dev commit-message validate-range $CI_GIT_BASE_REVISION $CI_GIT_REVISION
- run: yarn -s check-tooling-setup
- run: yarn install --frozen-lockfile --non-interactive
- run: ./node_modules/.bin/gulp lint
test:
executor:
name: test-browser-executor
# Now that large integration tests are running locally in parallel (they can't run on RBE yet
# as they require network access for yarn install), this test is running out of memory
# consistently with the xlarge machine.
# TODO: switch back to xlarge once integration tests are running on remote-exec
resource_class: 2xlarge+
build:
<<: *job_defaults
resource_class: large
steps:
- custom_attach_workspace
- init_environment
- install_java
- run:
# We need to explicitly specify the --symlink_prefix option because otherwise we would
# not be able to easily find the output bin directory when uploading artifacts for size
# measurements.
command: yarn test:ci
no_output_timeout: 20m
# Publish bundle artifacts which will be used to calculate the size change. **Note**: Make
# sure that the size plugin from the Angular robot fetches the artifacts from this CircleCI
# job (see .github/angular-robot.yml). Additionally any artifacts need to be stored with the
# following path format: "{projectName}/{context}/{fileName}". This format is necessary
# because otherwise the bot is not able to pick up the artifacts from CircleCI. See:
# https://github.com/angular/github-robot/blob/master/functions/src/plugins/size.ts#L392-L394
- store_artifacts:
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js
destination: core/hello_world/bundle
- store_artifacts:
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js
destination: core/todo/bundle
- store_artifacts:
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js.br
destination: core/hello_world/bundle.br
- store_artifacts:
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br
destination: core/todo/bundle.br
- checkout:
<<: *post_checkout
- restore_cache:
key: *cache_key
# NOTE: This is currently limited to main builds only. See the `monitoring` configuration.
saucelabs:
executor:
name: default-executor
# In order to avoid the bottleneck of having a slow host machine, we acquire a better
# container for this job. This is necessary because we launch a lot of browsers concurrently
# and therefore the tunnel and Karma need to process a lot of file requests and tests.
resource_class: xlarge
steps:
- custom_attach_workspace
- init_environment
- init_saucelabs_environment
- run:
name: Run Bazel tests on Saucelabs
# See /tools/saucelabs/README.md for more info
command: |
yarn bazel run //tools/saucelabs:sauce_service_setup
TESTS=$(./node_modules/.bin/bazelisk query --output label '(kind(karma_web_test, ...) intersect attr("tags", "saucelabs", ...)) except attr("tags", "fixme-saucelabs", ...)')
yarn bazel test --config=saucelabs ${TESTS}
yarn bazel run //tools/saucelabs:sauce_service_stop
no_output_timeout: 40m
- notify_webhook_on_fail:
webhook_url_env_var: SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
- run: bazel info release
- run: bazel run @yarn//:yarn
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
# This avoids waiting for a build command to finish before running the first test
# See https://github.com/bazelbuild/bazel/issues/4257
- run: bazel query --output=label '//modules/... union //packages/... union //tools/... union @angular//...' | xargs bazel test --config=ci
test_aio:
executor: test-browser-executor
steps:
- custom_attach_workspace
- init_environment
# Build aio
- run: yarn --cwd aio build --progress=false
# Lint the code
- run: yarn --cwd aio lint
# Run unit tests
- run: yarn --cwd aio test --progress=false --watch=false
# Run e2e tests
- run: yarn --cwd aio e2e --configuration=ci
# Run PWA-score tests
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
# Run accessibility tests
- run: yarn --cwd aio test-a11y-score-localhost
# Check the bundle sizes.
- run: yarn --cwd aio payload-size
# Run unit tests for Firebase redirects
- run: yarn --cwd aio redirects-test
deploy_aio:
executor: test-browser-executor
steps:
- custom_attach_workspace
- init_environment
# Deploy angular.io to production (if necessary)
- run: setPublicVar_CI_STABLE_BRANCH
- run: yarn --cwd aio deploy-production
test_aio_local:
executor: test-browser-executor
steps:
- custom_attach_workspace
- init_environment
# Build aio (with local Angular packages)
- run: yarn --cwd aio build-local-ci
# Run unit tests
- run: yarn --cwd aio test --progress=false --watch=false
# Run e2e tests
- run: yarn --cwd aio e2e --configuration=ci
# Run PWA-score tests
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
# Check the bundle sizes.
- run: yarn --cwd aio payload-size aio-local
test_aio_tools:
executor: default-executor
steps:
- custom_attach_workspace
- init_environment
# Install
- run: yarn --cwd aio install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
- run: yarn --cwd aio extract-cli-command-docs
# Run tools tests
- run: yarn --cwd aio tools-test
- run: ./aio/aio-builds-setup/scripts/test.sh
test_docs_examples:
executor:
name: test-browser-executor
resource_class: xlarge
parallelism: 5
steps:
- custom_attach_workspace
- init_environment
# Install aio
- run: yarn --cwd aio install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
# Run examples tests. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
# Since the parallelism is set to "5", there will be five parallel CircleCI containers.
# with either "0", "1", etc as node index. This can be passed to the "--shard" argument.
- run: yarn --cwd aio example-e2e --setup --local --cliSpecsConcurrency=5 --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
aio_preview:
executor: default-executor
environment:
AIO_SNAPSHOT_ARTIFACT_PATH: &aio_preview_artifact_path 'aio/tmp/snapshot.tgz'
steps:
- custom_attach_workspace
- init_environment
- run: ./aio/scripts/build-artifacts.sh $AIO_SNAPSHOT_ARTIFACT_PATH $CI_PULL_REQUEST $CI_COMMIT
- store_artifacts:
path: *aio_preview_artifact_path
# The `destination` needs to be kept in sync with the value of
# `AIO_ARTIFACT_PATH` in `aio/aio-builds-setup/Dockerfile`
destination: aio/dist/aio-snapshot.tgz
- run: node ./aio/scripts/create-preview $CIRCLE_BUILD_NUM
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
test_aio_preview:
executor: test-browser-executor
steps:
- custom_attach_workspace
- init_environment
- run: yarn --cwd aio install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
- run:
name: Wait for preview and run tests
command: node aio/scripts/test-preview.js $CI_PULL_REQUEST $CI_COMMIT $CI_AIO_MIN_PWA_SCORE
# The `build-npm-packages` tasks exist for backwards-compatibility with old scripts and
# tests that rely on the pre-Bazel `dist/packages-dist` output structure (build.sh).
# Having multiple jobs that independently build in this manner duplicates some work; we build
# the bazel packages more than once. Even though we have a remote cache, these jobs will
# typically run in parallel so up-to-date outputs will not be available at the time the build
# starts.
build-npm-packages:
executor:
name: default-executor
resource_class: xlarge
steps:
- custom_attach_workspace
- init_environment
- run: yarn build
# Save the npm packages from //packages/... for other workflow jobs to read
- persist_to_workspace:
root: *workspace_location
paths:
- ng/dist/packages-dist
- ng/dist/angular-in-memory-web-api-dist
- ng/dist/zone.js-dist
# Save dependencies and bazel repository cache to use on subsequent runs.
- save_cache:
key: *cache_key
paths:
- ~/.cache/yarn
- ~/bazel_repository_cache
- ~/.cache/bazelisk
# This job creates compressed tarballs (`.tgz` files) for all Angular packages and stores them as
# build artifacts. This makes it easy to try out changes from a PR build for testing purposes.
# More info CircleCI build artifacts: https://circleci.com/docs/2.0/artifacts
#
# NOTE: Currently, this job only runs for PR builds. See `publish_snapshot` for non-PR builds.
publish_packages_as_artifacts:
executor: default-executor
environment:
AIMWA_PACKAGES_DIR: &aimwa_packages_dir 'dist/angular-in-memory-web-api-dist'
AIMWA_PACKAGES_ARCHIVES_DIR: &aimwa_packages_archives_dir 'dist/angular-in-memory-web-api-dist-archives'
NG_PACKAGES_DIR: &ng_packages_dir 'dist/packages-dist'
NG_PACKAGES_ARCHIVES_DIR: &ng_packages_archives_dir 'dist/packages-dist-archives'
ZONEJS_PACKAGES_DIR: &zonejs_packages_dir 'dist/zone.js-dist'
ZONEJS_PACKAGES_ARCHIVES_DIR: &zonejs_packages_archives_dir 'dist/zone.js-dist-archives'
steps:
- custom_attach_workspace
- init_environment
# Publish `@angular/*` packages.
- run:
name: Create artifacts for @angular/* packages
command: ./scripts/ci/create-package-archives.sh $CI_BRANCH $CI_COMMIT $NG_PACKAGES_DIR $NG_PACKAGES_ARCHIVES_DIR
- store_artifacts:
path: *ng_packages_archives_dir
destination: angular
# Publish the `angular-in-memory-web-api` package.
- run:
name: Create artifacts for the `angular-in-memory-web-api` package
# Need to remove the zone.js.tgz before archive
command: ./scripts/ci/create-package-archives.sh $CI_BRANCH $CI_COMMIT $AIMWA_PACKAGES_DIR $AIMWA_PACKAGES_ARCHIVES_DIR
- store_artifacts:
path: *aimwa_packages_archives_dir
destination: angular-in-memory-web-api
# Publish the `zone.js` package.
- run:
name: Create artifacts for the `zone.js` package
# Need to remove the zone.js.tgz before archive
command: rm -rf $ZONEJS_PACKAGES_DIR/archive && ./scripts/ci/create-package-archives.sh $CI_BRANCH $CI_COMMIT $ZONEJS_PACKAGES_DIR $ZONEJS_PACKAGES_ARCHIVES_DIR
- store_artifacts:
path: *zonejs_packages_archives_dir
destination: zone.js
# This job updates the content of repos like github.com/angular/core-builds
# for every green build on angular/angular.
publish_snapshot:
executor: default-executor
steps:
- custom_attach_workspace
- init_environment
# CircleCI has a config setting to force SSH for all github connections
# This is not compatible with our mechanism of using a Personal Access Token
# Clear the global setting
- run: git config --global --unset "url.ssh://git@github.com.insteadof"
- run:
name: Decrypt github credentials
# We need ensure that the same default digest is used for encoding and decoding with
# OpenSSL. OpenSSL versions might have different default digests which can cause
# decryption failures based on the installed OpenSSL version. https://stackoverflow.com/a/39641378/4317734
command: 'openssl aes-256-cbc -d -in .circleci/github_token -md md5 -k "${KEY}" -out ~/.git_credentials'
- run: ./scripts/ci/publish-build-artifacts.sh
aio_misc:
executor: default-executor
steps:
- custom_attach_workspace
- run:
name: Check website provided in contributors.json file
command: yarn node aio/scripts/test-external-urls.js
aio_monitoring_stable:
executor: test-browser-executor
steps:
- custom_attach_workspace
- init_environment
- run: setPublicVar_CI_STABLE_BRANCH
- run:
name: Check out `aio/` and yarn from the stable branch
command: |
git fetch origin $CI_STABLE_BRANCH
git checkout --force origin/$CI_STABLE_BRANCH -- aio/ .yarn/ .yarnrc
# Ignore yarn's engines check, because we checked out `aio/package.json` from the stable
# branch and there could be a node version skew, which is acceptable in this monitoring job.
- run: yarn config set ignore-engines true
- run:
name: Run tests against https://angular.io/
command: ./aio/scripts/test-production.sh https://angular.io/ $CI_AIO_MIN_PWA_SCORE
- notify_webhook_on_fail:
webhook_url_env_var: SLACK_CARETAKER_WEBHOOK_URL
- notify_webhook_on_fail:
webhook_url_env_var: SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
aio_monitoring_next:
executor: test-browser-executor
steps:
- custom_attach_workspace
- init_environment
- run:
name: Run tests against https://next.angular.io/
command: ./aio/scripts/test-production.sh https://next.angular.io/ $CI_AIO_MIN_PWA_SCORE
- notify_webhook_on_fail:
webhook_url_env_var: SLACK_CARETAKER_WEBHOOK_URL
- notify_webhook_on_fail:
webhook_url_env_var: SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
legacy-unit-tests-saucelabs:
executor:
name: default-executor
# In order to avoid the bottleneck of having a slow host machine, we acquire a better
# container for this job. This is necessary because we launch a lot of browsers concurrently
# and therefore the tunnel and Karma need to process a lot of file requests and tests.
resource_class: xlarge
steps:
- custom_attach_workspace
- init_environment
- init_saucelabs_environment
- run:
name: Starting Saucelabs tunnel service
command: ./tools/saucelabs/sauce-service.sh run
background: true
# Build test fixtures for a test that rely on Bazel-generated fixtures. Note that disabling
# specific tests which are reliant on such generated fixtures is not an option as SystemJS
# in the Saucelabs legacy job always fetches referenced files, even if the imports would be
# guarded by an check to skip in the Saucelabs legacy job. We should be good running such
# test in all supported browsers on Saucelabs anyway until this job can be removed.
- run:
name: Preparing Bazel-generated fixtures required in legacy tests
command: |
yarn bazel build \
//packages/core/test:downleveled_es5_fixture \
//packages/common/locales
# Needed for the ES5 downlevel reflector test in `packages/core/test/reflection`.
mkdir -p dist/legacy-test-out/core/test/reflection/
cp dist/bin/packages/core/test/reflection/es5_downleveled_inheritance_fixture.js \
dist/legacy-test-out/core/test/reflection/es5_downleveled_inheritance_fixture.js
# Locale files are needed for i18n tests running within Saucelabs. These are added
# directly as sources so that the TypeScript compilation of `/packages/tsconfig.json`
# can succeed. Note that the base locale and currencies files are checked-in, so
# we do not need to re-generate those through Bazel.
mkdir -p packages/common/locales/extra
cp dist/bin/packages/common/locales/*.ts packages/common/locales
cp dist/bin/packages/common/locales/extra/*.ts packages/common/locales/extra
# Build ZoneJS so that it can be loaded globally in the Karma tests.
- run: yarn bazel build //packages/zone.js:npm_package
# Build the bundle for all tests to run within Saucelabs
- run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
- run:
# Waiting on ready ensures that we don't run tests too early without Saucelabs not being ready.
name: Waiting for Saucelabs tunnel to connect
command: ./tools/saucelabs/sauce-service.sh ready-wait
- run:
name: Running tests on Saucelabs.
command: |
KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
- run:
name: Stop Saucelabs tunnel service
command: ./tools/saucelabs/sauce-service.sh stop
# Job that runs all unit tests of the `angular/components` repository.
components-repo-unit-tests:
executor:
name: default-executor
resource_class: xlarge
steps:
- custom_attach_workspace
- init_environment
# Restore the cache before cloning the repository because the clone script re-uses
# the restored repository if present. This reduces the amount of times the components
# repository needs to be cloned (this is slow and increases based on commits in the repo).
- restore_cache:
keys:
- *components_repo_unit_tests_cache_key
# Whenever the `angular/components` SHA is updated, the cache key will no longer
# match. The fallback cache will still match, and CircleCI will restore the most
# recently cached repository folder. Without the fallback cache, we'd need to download
# the repository from scratch and it would slow down the job. This is because we can't
# clone the repository with reduced `--depth`, but rather need to clone the whole
# repository to be able to support arbitrary SHAs.
- *components_repo_unit_tests_cache_key_fallback
- run:
name: 'Fetching angular/components repository'
command: ./scripts/ci/clone_angular_components_repo.sh
- run:
# Run yarn install to fetch the Bazel binaries as used in the components repo.
name: Installing dependencies.
command: yarn --cwd ${COMPONENTS_REPO_TMP_DIR} install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
- save_cache:
key: *components_repo_unit_tests_cache_key
paths:
# Temporary directory must be kept in sync with the `$COMPONENTS_REPO_TMP_DIR` env
# variable. It needs to be hardcoded here, because env variables interpolation is
# not supported.
- '/tmp/angular-components-repo'
- run:
# Copy zone.js package to dist/packages-dist, so `angular/components` can also use the local zone.js build.
name: Setting up zone.js release packages.
command: cp -r dist/zone.js-dist/zone.js dist/packages-dist/
- run:
# Updates the `angular/components` `package.json` file to refer to the release output
# inside the `packages-dist` directory.
name: Setting up framework release packages.
command: node scripts/ci/update-framework-deps-to-dist-packages.js ${COMPONENTS_REPO_TMP_DIR}/package.json dist/packages-dist/
- run:
# Run `yarn install` again to install the Angular packages from `packages-dist/` and update the lockfile.
# NOTE: We cannot rely on Bazel to run `yarn install`, because it uses the `--frozen-lockfile` flag and fails.
name: Installing local Angular packages.
command: yarn --cwd ${COMPONENTS_REPO_TMP_DIR} install --non-interactive --cache-folder ~/.cache/yarn
- run:
name: 'Running `angular/components` unit tests'
command: ./scripts/ci/run_angular_components_unit_tests.sh
test_zonejs:
executor:
name: default-executor
resource_class: xlarge
steps:
- custom_attach_workspace
- init_environment
- install_java
# Install
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
# Run zone.js tools tests
- run: yarn --cwd packages/zone.js promisetest
- run: yarn --cwd packages/zone.js promisefinallytest
- run: yarn bazel build //packages/zone.js:npm_package &&
cp dist/bin/packages/zone.js/npm_package/bundles/zone-mix.umd.js ./packages/zone.js/test/extra/ &&
cp dist/bin/packages/zone.js/npm_package/bundles/zone-patch-electron.umd.js ./packages/zone.js/test/extra/ &&
cp dist/bin/packages/zone.js/npm_package/bundles/zone.umd.js ./packages/zone.js/build/test/closure/zone.js
- run: yarn --cwd packages/zone.js jest:test
- run: yarn --cwd packages/zone.js jest:nodetest
- run: yarn --cwd packages/zone.js electrontest
- run: yarn --cwd packages/zone.js closuretest
- run: yarn --cwd packages/zone.js/test/typings install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
- run: yarn --cwd packages/zone.js/test/typings test
# Windows jobs
# Docs: https://circleci.com/docs/2.0/hello-world-windows/
test_win:
executor: windows-executor
steps:
- checkout
- save_month_to_file
- init_environment
# Setup the proper NodeJS version. The image comes pre-installed with `nvm-windows`.
- run:
name: Install NodeJS version from `.nvmrc`.
command: |
nvm install $(cat .nvmrc)
nvm use $(cat .nvmrc)
- restore_cache:
keys:
- *cache_key_win
- *cache_key_win_fallback
# Install project dependencies, and install Bazelisk globally. This is necessary as
# Windows might error when `bazel` is invoked from the project node modules. The Bazel
# invocation might modify the symlinked project `node_modules` again, causing failures.
- yarn_install
- run: yarn global add @bazel/bazelisk@${BAZELISK_VERSION}
- run:
name: Build all windows CI targets
command: |
$(yarn global bin)/bazelisk build //packages/compiler-cli/...
no_output_timeout: 15m
- run:
name: Test all windows CI targets
command: |
$(yarn global bin)/bazelisk test --test_tag_filters="-browser:chromium-local" //packages/compiler-cli/...
no_output_timeout: 15m
- save_cache:
key: *cache_key_win
paths:
- node_modules
- ~/AppData/Local/bazelisk
test_angular_devtools:
executor: test-browser-executor
steps:
- custom_attach_workspace
- init_environment
- run:
name: Run unit tests
command: yarn devtools:test
- run:
name: Test production build
command: yarn devtools:build:chrome
- "node_modules"
workflows:
version: 2
default_workflow:
jobs:
- setup:
filters:
branches:
ignore: g3
- lint:
requires:
- setup
- test:
requires:
- setup
- build-npm-packages:
requires:
- setup
- legacy-unit-tests-saucelabs:
requires:
- setup
- test_aio:
requires:
- setup
- deploy_aio:
requires:
- test_aio
- test_aio_local:
requires:
- build-npm-packages
- test_aio_tools:
requires:
- build-npm-packages
- test_docs_examples:
requires:
- build-npm-packages
- aio_preview:
# Only run on PR builds. (There can be no previews for non-PR builds.)
<<: *only_on_pull_requests
requires:
- setup
- test_aio_preview:
requires:
- aio_preview
- publish_packages_as_artifacts:
requires:
- build-npm-packages
- publish_snapshot:
<<: *only_release_branches
requires:
# Only publish if tests and integration tests pass
- test
# Only publish if `aio`/`docs` tests using the locally built Angular packages pass
- test_aio_local
- test_docs_examples
# Get the artifacts to publish from the build-packages-dist job
# since the publishing script expects the legacy outputs layout.
- build-npm-packages
- legacy-unit-tests-saucelabs
- components-repo-unit-tests:
requires:
- build-npm-packages
- test_zonejs:
requires:
- setup
- test_win:
requires:
- setup
- test_angular_devtools:
requires:
- setup
monitoring:
jobs:
- setup
- aio_misc:
requires:
- setup
- aio_monitoring_stable:
requires:
- setup
- aio_monitoring_next:
requires:
- setup
- saucelabs:
# Testing saucelabs via Bazel currently taking longer than the legacy saucelabs job as it
# each karma_web_test target is provisioning and tearing down browsers which is adding
# a lot of overhead. Running once daily in the main branch to avoid wasting resources and
# slowing down CI for PRs.
# TODO: Run this job on all branches (including PRs) once karma_web_test targets can
# share provisioned browsers and we can remove the legacy saucelabs job.
requires:
- setup
triggers:
- schedule:
<<: *only_on_main_branch
# Runs monitoring jobs at 10:00AM every day.
cron: '0 10 * * *'
- lint
- build
-76
View File
@@ -1,76 +0,0 @@
####################################################################################################
# Helpers for defining environment variables for CircleCI.
#
# In CircleCI, each step runs in a new shell. The way to share ENV variables across steps is to
# export them from `$BASH_ENV`, which is automatically sourced at the beginning of every step (for
# the default `bash` shell).
#
# See also https://circleci.com/docs/2.0/env-vars/#using-bash_env-to-set-environment-variables.
####################################################################################################
# Set and print an environment variable.
#
# Use this function for setting environment variables that are public, i.e. it is OK for them to be
# visible to anyone through the CI logs.
#
# Usage: `setPublicVar <name> <value>`
function setPublicVar() {
setSecretVar $1 "$2";
echo "$1=$2";
}
# Set (without printing) an environment variable.
#
# Use this function for setting environment variables that are secret, i.e. should not be visible to
# everyone through the CI logs.
#
# Usage: `setSecretVar <name> <value>`
function setSecretVar() {
# WARNING: Secrets (e.g. passwords, access tokens) should NOT be printed.
# (Keep original shell options to restore at the end.)
local -r originalShellOptions=$(set +o);
set +x -eu -o pipefail;
local assignmentStatement="export $1=\"${2:-}\";"
echo "${assignmentStatement}" >> $BASH_ENV;
eval "${assignmentStatement}"
# Restore original shell options.
eval "$originalShellOptions";
}
# Create a function to set an environment variable, when called.
#
# Use this function for creating setter for public environment variables that require expensive or
# time-consuming computaions and may not be needed. When needed, you can call this function to set
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
#
# Arguments:
# - `<name>`: The name of the environment variable. The generated setter function will be
# `setPublicVar_<name>`.
# - `<code>`: The code to run to compute the value for the variable. Since this code should be
# executed lazily, it must be properly escaped. For example:
# ```sh
# # DO NOT do this:
# createPublicVarSetter MY_VAR "$(whoami)"; # `whoami` will be evaluated eagerly
#
# # DO this isntead:
# createPublicVarSetter MY_VAR "\$(whoami)"; # `whoami` will NOT be evaluated eagerly
# ```
#
# Usage: `createPublicVarSetter <name> <code>`
#
# Example:
# ```sh
# createPublicVarSetter MY_VAR 'echo "FOO"';
# echo $MY_VAR; # Not defined
#
# setPublicVar_MY_VAR;
# source $BASH_ENV;
# echo $MY_VAR; # FOO
# ```
function createPublicVarSetter() {
echo "setPublicVar_$1() { setPublicVar $1 \"$2\"; }" >> $BASH_ENV;
}
-4
View File
@@ -1,4 +0,0 @@
####################################################################################################
# Set bazel configuration for CircleCI runs.
####################################################################################################
cp "${PROJECT_ROOT}/.circleci/bazel.linux.rc" ".bazelrc.user";
-103
View File
@@ -1,103 +0,0 @@
#!/usr/bin/env bash
# Variables
readonly projectDir=$(realpath "$(dirname ${BASH_SOURCE[0]})/..")
readonly envHelpersPath="$projectDir/.circleci/env-helpers.inc.sh";
# Load helpers and make them available everywhere (through `$BASH_ENV`).
source $envHelpersPath;
echo "source $envHelpersPath;" >> $BASH_ENV;
####################################################################################################
# Define PUBLIC environment variables for CircleCI.
####################################################################################################
# See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info.
####################################################################################################
setPublicVar CI "$CI"
setPublicVar PROJECT_ROOT "$projectDir";
setPublicVar CI_AIO_MIN_PWA_SCORE "95";
# This is the branch being built; e.g. `pull/12345` for PR builds.
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL";
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
# `CI_COMMIT_RANGE` is only used on push builds (a.k.a. non-PR, non-scheduled builds and rerun
# workflows of such builds).
setPublicVar CI_GIT_BASE_REVISION "${CIRCLE_GIT_BASE_REVISION}";
setPublicVar CI_GIT_REVISION "${CIRCLE_GIT_REVISION}";
setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION";
setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}";
setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
setPublicVar CI_PR_REPONAME "$CIRCLE_PR_REPONAME";
setPublicVar CI_PR_USERNAME "$CIRCLE_PR_USERNAME";
####################################################################################################
# Define "lazy" PUBLIC environment variables for CircleCI.
# (I.e. functions to set an environment variable when called.)
####################################################################################################
createPublicVarSetter CI_STABLE_BRANCH "\$(npm info @angular/core dist-tags.latest | sed -r 's/^\\s*([0-9]+\\.[0-9]+)\\.[0-9]+.*$/\\1.x/')";
####################################################################################################
# Define SECRET environment variables for CircleCI.
####################################################################################################
setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN";
setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN";
####################################################################################################
# Define SauceLabs environment variables for CircleCI.
####################################################################################################
setPublicVar SAUCE_USERNAME "angular-framework";
setSecretVar SAUCE_ACCESS_KEY "f4bf7c639c5a-c6bb-d6a4-a4b5-800aa111";
# TODO(josephperrott): Remove environment variables once all saucelabs tests are via bazel method.
setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log
setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock
setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock
setPublicVar SAUCE_TUNNEL_IDENTIFIER "angular-framework-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX}"
# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not
# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout.
setPublicVar SAUCE_READY_FILE_TIMEOUT 120
####################################################################################################
# Define environment variables for the `angular/components` repo unit tests job.
####################################################################################################
# We specifically use a directory within "/tmp" here because we want the cloned repo to be
# completely isolated from angular/angular in order to avoid any bad interactions between
# their separate build setups. **NOTE**: When updating the temporary directory, also update
# the `save_cache` path configuration in `config.yml`
setPublicVar COMPONENTS_REPO_TMP_DIR "/tmp/angular-components-repo"
setPublicVar COMPONENTS_REPO_URL "https://github.com/angular/components.git"
setPublicVar COMPONENTS_REPO_BRANCH "main"
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`.
setPublicVar COMPONENTS_REPO_COMMIT "7a24e95bafbdeb697f74a48e275c2442bcbefc74"
####################################################################################################
# Create shell script in /tmp for Bazel actions to access CI envs without
# busting the cache. Used by payload-size.sh script in integration tests.
####################################################################################################
readonly bazelVarEnv="/tmp/bazel-ci-env.sh"
echo "# Setup by /.circle/env.sh" > $bazelVarEnv
echo "export PROJECT_ROOT=\"${PROJECT_ROOT}\";" >> $bazelVarEnv
echo "export CI_BRANCH=\"${CI_BRANCH}\";" >> $bazelVarEnv
echo "export CI_BUILD_URL=\"${CI_BUILD_URL}\";" >> $bazelVarEnv
echo "export CI_COMMIT=\"${CI_COMMIT}\";" >> $bazelVarEnv
echo "export CI_PULL_REQUEST=\"${CI_PULL_REQUEST}\";" >> $bazelVarEnv
echo "export CI_REPO_NAME=\"${CI_REPO_NAME}\";" >> $bazelVarEnv
echo "export CI_REPO_OWNER=\"${CI_REPO_OWNER}\";" >> $bazelVarEnv
echo "export CI_SECRET_PAYLOAD_FIREBASE_TOKEN=\"${CI_SECRET_PAYLOAD_FIREBASE_TOKEN}\";" >> $bazelVarEnv
####################################################################################################
# Platform-specific environment setup (which can leverage the base variables from here)
####################################################################################################
# Conditionally, load additional environment settings based on the current VM
# operating system running. We detect Windows by checking for `%AppData%`.
if [[ -n "${APPDATA}" ]]; then
source ${projectDir}/.circleci/env.windows.sh
else
source ${projectDir}/.circleci/env.linux.sh
fi
-10
View File
@@ -1,10 +0,0 @@
####################################################################################################
# Set bazel configuration for CircleCI runs.
####################################################################################################
cp "${PROJECT_ROOT}/.circleci/bazel.windows.rc" ".bazelrc.user";
# Expose the Bazelisk version. We need to run Bazelisk globally since Windows has problems launching
# Bazel from a node modules directoy that might be modified by the Bazel Yarn install then.
setPublicVar BAZELISK_VERSION \
"$(cd ${PROJECT_ROOT}; node -p 'require("./package.json").devDependencies["@bazel/bazelisk"]')"
Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
#!/bin/sh
# Install bazel remote cache proxy
# This is temporary until the feature is no longer experimental on CircleCI.
# See remote cache documentation in /docs/BAZEL.md
set -u -e
readonly DOWNLOAD_URL="https://5-116431813-gh.circle-artifacts.com/0/pkg/bazel-remote-proxy-$(uname -s)_$(uname -m)"
curl --fail -o ~/bazel-remote-proxy "$DOWNLOAD_URL"
chmod +x ~/bazel-remote-proxy
-105
View File
@@ -1,105 +0,0 @@
#!/usr/bin/env node
/**
* Usage (cli):
* ```
* node create-preview <build-number> <job-name> <webhook-url>
* ```
*
* Usage (JS):
* ```js
* require('./trigger-webhook').
* triggerWebhook(buildNumber, jobName, webhookUrl).
* then(...);
* ```
*
* Triggers a notification webhook with CircleCI specific info.
*
* It can be used for notifying external servers and trigger operations based on CircleCI job status
* (e.g. triggering the creation of a preview based on previously stored build atrifacts).
*
* The body of the sent payload is of the form:
* ```json
* {
* "payload": {
* "build_num": ${buildNumber}
* "build_parameters": {
* "CIRCLE_JOB": "${jobName}"
* }
* }
* }
* ```
*
* When used from JS, it returns a promise which resolves to an object of the form:
* ```json
* {
* "statucCode": ${statusCode},
* "responseText": "${responseText}"
* }
* ```
*
* NOTE:
* - When used from the cli, the command will exit with an error code if the response's status code
* is outside the [200, 400) range.
* - When used from JS, the returned promise will be resolved, even if the response's status code is
* outside the [200, 400) range. It is up to the caller to decide how this should be handled.
*/
// Imports
const {request} = require('https');
// Exports
module.exports = {
triggerWebhook,
};
// Run
if (require.resolve === module) {
_main(process.argv.slice(2));
}
// Helpers
function _main(args) {
triggerWebhook(...args)
.then(
({statusCode, responseText}) => (200 <= statusCode && statusCode < 400) ?
console.log(`Status: ${statusCode}\n${responseText}`) :
Promise.reject(new Error(`Request failed (status: ${statusCode}): ${responseText}`)))
.catch(err => {
console.error(err);
process.exit(1);
});
}
function postJson(url, data) {
return new Promise((resolve, reject) => {
const opts = {method: 'post', headers: {'Content-Type': 'application/json'}};
const onResponse = res => {
const statusCode = res.statusCode || -1;
let responseText = '';
res.on('error', reject)
.on('data', d => responseText += d)
.on('end', () => resolve({statusCode, responseText}));
};
request(url, opts, onResponse).on('error', reject).end(JSON.stringify(data));
});
}
async function triggerWebhook(buildNumber, jobName, webhookUrl) {
if (!buildNumber || !jobName || !webhookUrl || isNaN(buildNumber)) {
throw new Error(
'Missing or invalid arguments.\n' +
'Expected: buildNumber (number), jobName (string), webhookUrl (string)');
}
const data = {
payload: {
build_num: +buildNumber,
build_parameters: {CIRCLE_JOB: jobName},
},
};
return postJson(webhookUrl, data);
}
-31
View File
@@ -1,31 +0,0 @@
# VSCode Remote Development - Developing inside a Container
This folder contains configuration files that can be used to opt into working on this repository in a [Docker container](https://www.docker.com/resources/what-container) via [VSCode](https://code.visualstudio.com/)'s Remote Development feature (see below).
Info on remote development and developing inside a container with VSCode:
- [VSCode: Remote Development](https://code.visualstudio.com/docs/remote/remote-overview)
- [VSCode: Developing inside a Container](https://code.visualstudio.com/docs/remote/containers)
- [VSCode: Remote Development FAQ](https://code.visualstudio.com/docs/remote/faq)
## Usage
_Prerequisite: [Install Docker](https://docs.docker.com/install) on your local environment._
To get started, read and follow the instructions in [Developing inside a Container](https://code.visualstudio.com/docs/remote/containers). The [.devcontainer/](.) directory contains pre-configured `devcontainer.json` and `Dockerfile` files, which you can use to set up remote development with a docker container.
In a nutshell, you need to:
- Install the [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension.
- Copy [recommended-Dockerfile](./recommended-Dockerfile) to `Dockerfile` (and optionally tweak to suit your needs).
- Copy [recommended-devcontainer.json](./recommended-devcontainer.json) to `devcontainer.json` (and optionally tweak to suit your needs).
- Open VSCode and bring up the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette).
- Type `Remote-Containers: Open Folder in Container` and choose your local clone of [angular/angular](https://github.com/angular/angular).
The `.devcontainer/devcontainer.json` and `.devcontainer/Dockerfile` files are ignored by git, so you can have your own local versions. We may occasionally update the template files ([recommended-devcontainer.json](./recommended-devcontainer.json), [recommended-Dockerfile](./recommended-Dockerfile)), in which case you will need to manually update your local copies (if desired).
## Updating `recommended-devcontainer.json` and `recommended-Dockerfile`
You can update and commit the recommended config files (which people use as basis for their local configs), if you find that something is broken, out-of-date or can be improved.
Please, keep in mind that any changes you make will potentially be used by many people on different environments. Try to keep these config files cross-platform compatible and free of personal preferences.
-24
View File
@@ -1,24 +0,0 @@
# Image metadata and config.
# Ideally, the Node.js version should match what we use on CI.
# See `executors > default-executor` in `.circleci/config.yml`.
FROM cimg/node:14-browsers
LABEL name="Angular dev environment" \
description="This image can be used to create a dev environment for building Angular." \
vendor="angular" \
version="1.0"
EXPOSE 4000 4200 4433 5000 8080 9876
# Switch to `root` (CircleCI images use `circleci` as the user).
USER root
# Configure `Node.js`/`npm`.
RUN npm config --global set user root
# Go! (And keep going.)
CMD ["tail", "--follow", "/dev/null"]
@@ -1,16 +0,0 @@
// Reference: https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference
{
"name": "Angular dev container",
"dockerFile": "Dockerfile",
"appPort": [4000, 4200, 4433, 5000, 8080, 9876],
"postCreateCommand": "yarn install",
"extensions": [
"devondcarew.bazel-code",
"gkalpak.aio-docs-utils",
"ms-vscode.vscode-typescript-tslint-plugin",
"xaver.clang-format",
// The following extensions are useful when working on angular.io (i.e. inside the `aio/` directory).
//"angular.ng-template",
//"dbaeumer.vscode-eslint",
],
}
+1 -1
View File
@@ -1,4 +1,4 @@
# https://editorconfig.org
# http://editorconfig.org
root = true
+3
View File
@@ -4,3 +4,6 @@
# JS and TS files must always use LF for tools to work
*.js eol=lf
*.ts eol=lf
# Must keep Windows line ending to be parsed correctly
scripts/windows/packages.txt eol=crlf
+55 -4
View File
@@ -1,6 +1,57 @@
Please help us process issues more efficiently by filing an
issue using one of the following templates:
<!--
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
https://github.com/angular/angular/issues/new/choose
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
-->
Thank you!
## I'm submitting a...
<!-- Check one of the following options with "x" -->
<pre><code>
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report <!-- Please search GitHub for a similar issue or PR before submitting -->
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
</code></pre>
## Current behavior
<!-- Describe how the issue manifests. -->
## Expected behavior
<!-- Describe what the desired behavior would be. -->
## Minimal reproduction of the problem with instructions
<!--
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).
-->
## What is the motivation / use case for changing the behavior?
<!-- Describe the motivation or the concrete use case. -->
## Environment
<pre><code>
Angular version: X.Y.Z
<!-- Check whether this is still an issue in the most recent Angular version -->
Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: XX <!-- run `node --version` -->
- Platform: <!-- Mac, Linux, Windows -->
Others:
<!-- Anything else relevant? Operating system version, IDE, package manager, HTTP server, ... -->
</code></pre>
-85
View File
@@ -1,85 +0,0 @@
name: Bug Report
description: Report a bug in the Angular Framework
body:
- type: dropdown
id: affected-packages
attributes:
label: Which @angular/* package(s) are the source of the bug?
options:
- animations
- bazel
- common
- compiler-cli
- compiler
- core
- elements
- forms
- language-service
- localize
- platform-browser-dynamic
- platform-browser
- platform-server
- router
- service-worker
- upgrade
- Don't known / other
multiple: true
validations:
required: true
- type: dropdown
id: is-regression
attributes:
label: Is this a regression?
options:
- 'Yes'
- 'No'
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
validations:
required: true
- type: input
id: reproduction
attributes:
label: Please provide a link to a minimal reproduction of the bug
- type: textarea
id: exception-or-error
attributes:
label: Please provide the exception or error you saw
render: true
- type: textarea
id: environment
attributes:
label: Please provide the environment you discovered this bug in (run `ng version`)
render: true
placeholder: |
Angular CLI: 12.0.5
Node: 14.17.0
Package Manager: yarn 1.22.10
OS: linux x64
Angular: 12.0.5
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1200.5
@angular-devkit/build-angular 12.0.5
@angular-devkit/core 12.0.5
rxjs 6.6.7
typescript 4.2.4
- type: textarea
id: other
attributes:
label: Anything else?
@@ -1,47 +0,0 @@
name: 'Feature Request'
description: Suggest a feature for Angular Framework
body:
- type: dropdown
id: affected-packages
attributes:
label: Which @angular/* package(s) are relevant/related to the feature request?
options:
- animations
- bazel
- common
- compiler-cli
- compiler
- core
- elements
- forms
- language-service
- localize
- platform-browser-dynamic
- platform-browser
- platform-server
- router
- service-worker
- upgrade
multiple: true
- type: textarea
id: description
attributes:
label: Description
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Proposed solution
validations:
required: true
- type: textarea
id: alternatives-considered
attributes:
label: Alternatives considered
validations:
required: true
-58
View File
@@ -1,58 +0,0 @@
name: 'Docs or angular.io Bug Report'
description: Report an issue in Angular's documentation or angular.io application
body:
- type: textarea
id: description
attributes:
label: Describe the problem that you experienced
validations:
required: true
- type: input
id: affected-url
attributes:
label: Enter the URL of the topic with the problem
- type: textarea
id: documentation-goal
attributes:
label: Describe what you were looking for in the documentation
- type: textarea
id: reproduction-steps
attributes:
label: Describe the actions that led you to experience the problem
- type: textarea
id: expected-vs-actual-behavior
attributes:
label: Describe what you want to experience that would fix the problem
- type: textarea
id: screenshot
attributes:
label: Add a screenshot if that helps illustrate the problem
- type: textarea
id: exception-or-error
attributes:
label: If this problem caused an exception or error, please paste it here
render: true
placeholder: |
```
Paste the exception or error here inside a markdown code block,
which is annotated by three grave \(&grave;\) characters before and after the text block.
```
- type: textarea
id: browser-info
attributes:
label: If the problem is browser-specific, please specify the device, OS, browser, and version
render: true
- type: textarea
id: additional-info
attributes:
label: Provide any additional information here in as much as detail as you can
render: true
-54
View File
@@ -1,54 +0,0 @@
name: 'Angular DevTools'
description: Report an issue or suggest a feature for Angular DevTools
body:
- type: checkboxes
id: bug-report-or-feature-request
attributes:
label: Is this a bug report or a feature request?
description: Select one.
options:
- label: Bug Report
- label: Feature Request
- type: textarea
id: reproduction-steps
attributes:
label: Please provide the steps to reproduce the issue [Bug Report only]
- type: textarea
id: expected-vs-actual-behavior
attributes:
label: Please provide the expected behavior vs the actual behavior you encountered [Bug Report only]
- type: textarea
id: screenshot
attributes:
label: Please provide a screenshot if possible [Bug Report only]
- type: textarea
id: exception-or-error
attributes:
label: Please provide the exception or error you saw [Bug Report only]
render: true
- type: textarea
id: browser-info
attributes:
label: Is this a browser-specific issue? If so, please specify the device, browser, and version. [Bug Report only]
render: true
- type: textarea
id: description
attributes:
label: Description [Feature Request only]
- type: textarea
id: proposed-solution
attributes:
label: Proposed solution [Feature Request only]
- type: textarea
id: alternatives-considered
attributes:
label: Alternatives considered [Feature Request only]
-14
View File
@@ -1,14 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Security issue disclosure
url: https://angular.io/guide/security#report-issues
about: Report a security issue in Angular Framework, CDK, Material, or CLI
- name: Angular CLI
url: https://github.com/angular/angular-cli/issues/new/choose
about: Issues and feature requests for Angular CLI
- name: Angular Material and Components Development Kit (CDK)
url: https://github.com/angular/components/issues/new/choose
about: Issues and feature requests for Angular Material
- name: Support Request
url: https://github.com/angular/angular/blob/main/CONTRIBUTING.md#question
about: Questions and requests for support
+16 -16
View File
@@ -1,7 +1,7 @@
## PR Checklist
Please check if your PR fulfills the following requirements:
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
@@ -10,17 +10,17 @@ Please check if your PR fulfills the following requirements:
What kind of change does this PR introduce?
<!-- Please check the one that applies to this PR using "x". -->
- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] CI related changes
- [ ] Documentation content changes
- [ ] angular.io application / infrastructure changes
- [ ] Other... Please describe:
```
[ ] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] angular.io application / infrastructure changes
[ ] Other... Please describe:
```
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
@@ -32,10 +32,10 @@ Issue Number: N/A
## Does this PR introduce a breaking change?
- [ ] Yes
- [ ] No
```
[ ] Yes
[ ] No
```
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->
+24 -162
View File
@@ -1,11 +1,5 @@
# Configuration for angular-robot
#options for the size plugin
size:
disabled: false
maxSizeIncrease: 2000
circleCiStatusName: 'ci/circleci: test'
# options for the merge plugin
merge:
# the status will be added to your pull requests
@@ -13,178 +7,46 @@ merge:
# set to true to disable
disabled: false
# the name of the status
context: 'ci/angular: merge status'
context: "ci/angular: merge status"
# text to show when all checks pass
successText: 'All checks passed!'
successText: "All checks passed!"
# text to show when some checks are failing
failureText: 'The following checks are failing:'
# the g3 status will be added to your pull requests if they include files that match the patterns
g3Status:
# set to true to disable
disabled: false
# the name of the status
context: 'google3'
# text to show when the status is pending, {{PRNumber}} will be replaced by the PR number
pendingDesc: 'Googler: run g3sync presubmit {{PRNumber}}'
# text to show when the status is success
successDesc: 'Does not affect google3'
# link to use for the details
url: 'http://go/angular/g3sync'
# list of patterns to check for the files changed by the PR
# this list must be manually kept in sync with google3/third_party/javascript/angular2/copy.bara.sky
include:
- 'LICENSE'
- 'modules/benchmarks/**'
- 'modules/system.d.ts'
- 'packages/**'
# list of patterns to ignore for the files changed by the PR
exclude:
- 'packages/*'
- 'packages/bazel/*'
- 'packages/bazel/src/*'
- 'packages/bazel/src/api-extractor/**'
- 'packages/bazel/src/builders/**'
- 'packages/bazel/src/ng_module/**'
- 'packages/bazel/src/ng_package/**'
- 'packages/bazel/src/protractor/**'
- 'packages/bazel/src/schematics/**'
- 'packages/bazel/src/types_bundle/**'
- 'packages/compiler-cli/src/ngcc/**'
- 'packages/compiler-cli/linker/**'
- 'packages/compiler-cli/ngcc/**'
- 'packages/compiler-cli/src/ngtsc/sourcemaps/**'
# 'private' mostly contains entrypoints for 3P Angular.
# Note that 'private/migrations' _is_ used.
- 'packages/compiler-cli/private/bazel.ts'
- 'packages/compiler-cli/private/localize.ts'
- 'packages/compiler-cli/private/tooling.ts'
- 'packages/compiler-cli/private/babel.d.ts'
# google3 defines its own binary entrypoints.
- 'packages/compiler-cli/src/bin/**'
- 'packages/docs/**'
- 'packages/elements/schematics/**'
- 'packages/examples/**'
- 'packages/language-service/**'
- 'packages/localize/**'
- 'packages/private/**'
- 'packages/service-worker/**'
- 'packages/common/locales/generate-locales-tool/**'
- 'packages/common/locales/index.bzl'
- 'packages/http/**'
- '**/.gitignore'
- '**/.gitkeep'
- '**/yarn.lock'
- '**/package.json'
- '**/third_party/**'
- '**/tsconfig-build.json'
- '**/tsconfig-tsec.json'
- '**/tsconfig.json'
- '**/rollup.config.js'
- '**/BUILD.bazel'
- '**/*.md'
- 'packages/**/integrationtest/**'
- 'packages/**/test/**'
- 'packages/zone.js/*'
- 'packages/zone.js/dist/**'
- 'packages/zone.js/doc/**'
- 'packages/zone.js/example/**'
- 'packages/zone.js/scripts/**'
failureText: "The following checks are failing:"
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.\nPlease help to unblock it by resolving these conflicts. Thanks!"
mergeConflictComment: "Hello? Don't want to hassle you. Sure you're busy. But this PR has some merge conflicts that you probably ought to resolve.
\nThat is... if you want it to be merged someday..."
# label to monitor
mergeLabel: 'action: merge'
# adding any of these labels will also add the merge label
mergeLinkedLabels:
- 'action: merge-assistance'
mergeLabel: "PR action: merge"
# list of checks that will determine if the merge label can be added
checks:
# require that the PR has reviews from all requested reviewers
#
# This enables us to request reviews from both eng and tech writers, or multiple eng folks, and prevents accidental merges.
# Rather than merging PRs with pending reviews, if all approvals are obtained and additional reviews are not needed, any pending reviewers should be removed via GitHub UI (this also leaves an audit trail behind these decisions).
requireReviews: true,
# whether the PR shouldn't have a conflict with the base branch
noConflict: true
# list of labels that a PR needs to have, checked with a regexp.
# list of labels that a PR needs to have, checked with a regexp (e.g. "PR target:" will work for the label "PR target: master")
requiredLabels:
- 'target: *'
- "PR target:"
- "cla: yes"
# list of labels that a PR shouldn't have, checked after the required labels with a regexp
forbiddenLabels:
- 'target: TBD'
- 'action: cleanup'
- 'action: review'
- 'state: blocked'
- "PR target: TBD"
- "cla: no"
# list of PR statuses that need to be successful
requiredStatuses:
- 'ci/circleci: build'
- 'ci/circleci: lint'
- 'ci/angular: size'
- 'google3'
- 'pullapprove'
- "continuous-integration/travis-ci/pr"
- "code-review/pullapprove"
- "ci/circleci: build"
- "ci/circleci: lint"
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
# {{PLACEHOLDER}} will be replaced by the list of failing checks
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:\n{{PLACEHOLDER}}\n\n**If you want your PR to be merged, it has to pass all the CI checks.**\n\nIf you can't get the PR to a green state due to flakes or broken `main`, please try rebasing to `main` and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
# options for the triage plugin
triage:
# number of the milestone to apply when the issue has not been triaged yet
needsTriageMilestone: 83,
# number of the milestone to apply when the issue is triaged
defaultMilestone: 82,
# arrays of labels that determine if an issue has been triaged by the caretaker
l1TriageLabels:
- - 'area: *'
# arrays of labels that determine if an issue has been fully triaged
l2TriageLabels:
- - 'P0'
- 'area: *'
- - 'P1'
- 'area: *'
- - 'P2'
- 'area: *'
- - 'P3'
- 'area: *'
- - 'P4'
- 'area: *'
- - 'P5'
- 'area: *'
- - 'feature'
- 'area: *'
- - 'discussion'
- 'area: *'
- - 'needs clarification'
- 'area: *'
- - 'needs reproduction'
- 'area: *'
# options for the triage PR plugin
triagePR:
# set to true to disable
disabled: false
# number of the milestone to apply when the PR has not been triaged yet
needsTriageMilestone: 83,
# number of the milestone to apply when the PR is triaged
defaultMilestone: 82,
# arrays of labels that determine if a PR has been triaged by the caretaker
l1TriageLabels:
- - 'area: *'
# arrays of labels that determine if a PR has been fully triaged
l2TriageLabels:
- - 'area: *'
# options for rerunning CI
rerunCircleCI:
# set to true to disable
disabled: false
# the label which when added triggers a rerun of the default CircleCI workflow
triggerRerunLabel: 'action: rerun CI at HEAD'
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
# {{PLACEHOLDER}} will be replaced by the list of failing checks
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label. It won't do anything good though, because the following checks are still failing:
\n{{PLACEHOLDER}}
\n
\n**If you want your PR to be merged, it has to pass all the CI checks.**
\n
\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
-25
View File
@@ -1,25 +0,0 @@
name: DevInfra
on:
pull_request_target:
types: [opened, synchronize, reopened]
# Declare default permissions as read only.
permissions:
contents: read
jobs:
labels:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2
- uses: angular/dev-infra/github-actions/commit-message-based-labels@22d3067021130271afcfd02d063828c5bdd9c2d7
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
post_approval_changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2
- uses: angular/dev-infra/github-actions/post-approval-changes@22d3067021130271afcfd02d063828c5bdd9c2d7
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
-19
View File
@@ -1,19 +0,0 @@
name: Feature request triage bot
on:
schedule:
# Run at 14:00 every day
- cron: '0 14 * * *'
# Declare default permissions as read only.
permissions:
contents: read
jobs:
feature_triage:
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/feature-request@22d3067021130271afcfd02d063828c5bdd9c2d7
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
-19
View File
@@ -1,19 +0,0 @@
name: Lock closed inactive issues
on:
schedule:
# Run at 16:00 every day
- cron: '0 16 * * *'
# Declare default permissions as read only.
permissions:
contents: read
jobs:
lock_closed:
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/lock-closed@22d3067021130271afcfd02d063828c5bdd9c2d7
with:
lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }}
-52
View File
@@ -1,52 +0,0 @@
name: OpenSSF Scorecard
on:
branch_protection_rule:
schedule:
- cron: '0 0 * * 0'
push:
branches: [main]
workflow_dispatch:
# Declare default permissions as read only.
permissions:
contents: read
jobs:
analysis:
name: Scorecards analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results
id-token: write
actions: read
contents: read
steps:
- name: 'Checkout code'
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3.1.0
with:
persist-credentials: false
- name: 'Run analysis'
uses: ossf/scorecard-action@e363bfca00e752f91de7b7d2a77340e2e523cb18 # tag=v2.0.4
with:
results_file: results.sarif
results_format: sarif
repo_token: ${{ secrets.GITHUB_TOKEN }}
publish_results: true
# Upload the results as artifacts.
- name: 'Upload artifact'
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # tag=v3.1.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
uses: github/codeql-action/upload-sarif@807578363a7869ca324a79039e6db9c843e0e100 # tag=v2.1.27
with:
sarif_file: results.sarif
-48
View File
@@ -1,48 +0,0 @@
# Update the `events.json` file that powers the [AIO events page](https://angular.io/events) (if
# necessary) and create a pull request.
#
# For more details on the overall process, see
# [aio/scripts/generate-events/README.md](../../aio/scripts/generate-events/README.md).
name: Update AIO events
on:
workflow_dispatch:
inputs: {}
schedule:
# Run every day at 15:00.
- cron: '0 15 * * *'
# Declare default permissions as read only.
permissions:
contents: read
jobs:
update_events:
name: Update `events.json` (if necessary)
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2
with:
# Setting `persist-credentials: false` prevents the github-action account from being the
# account that is attempted to be used for authentication, instead the remote is set to
# an authenticated URL.
persist-credentials: false
- name: Install AIO dependencies
run: yarn --cwd=aio install
- name: Generate `events.json`
run: node aio/scripts/generate-events/index.mjs --ignore-invalid-dates
- name: Create a PR (if necessary)
uses: angular/dev-infra/github-actions/create-pr-for-changes@3c526cbb36b8517829dbbf02a7833fa3081479bb
with:
branch-prefix: docs-update-events
pr-title: 'docs: update events'
pr-description: |
Generated `events.json` with the latest events retrieved from the Firebase DB.
pr-labels: |
action: review
area: docs
target: patch
angular-robot-token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
+5 -32
View File
@@ -1,33 +1,21 @@
.DS_STORE
/dist/
/bazel-out
/integration/bazel/bazel-*
*.log
bazel-*
e2e_test.*
node_modules
# CircleCI temporary file for cache key computation.
# See `save_month_to_file` in `.circleci/config.yml`.
month.txt
bower_components
tools/gulp-tasks/cldr/cldr-data/
# Include when developing application packages.
pubspec.lock
.c9
.idea/
.devcontainer/*
!.devcontainer/README.md
!.devcontainer/recommended-devcontainer.json
!.devcontainer/recommended-Dockerfile
.settings/
.vscode/launch.json
.vscode/settings.json
.vscode/tasks.json
*.swo
*.swp
modules/.settings
.vscode
modules/.vscode
.vimrc
.nvimrc
# Don't check in secret files
*secret.js
@@ -41,18 +29,3 @@ yarn-error.log
# rollup-test output
/modules/rollup-test/dist/
# User specific bazel settings
.bazelrc.user
# User specific ng-dev settings
.ng-dev.user*
.notes.md
baseline.json
# Ignore .history for the xyz.local-history VSCode extension
.history
# Husky
.husky/_
-145
View File
@@ -1,145 +0,0 @@
<type>(<scope>): <summary>
<Describe the motivation behind this change - explain WHY you are making this change. Wrap all lines
at 100 characters.>
Fixes #<issue number>
# ────────────────────────────────────────── 100 chars ────────────────────────────────────────────┤
# Example Commit Messages
# =======================
# ─── Example: Simple refactor ────────────────────────────────────────────────────────────────────┤
# refactor(core): rename refreshDynamicEmbeddedViews to refreshEmbeddedViews
#
# Improve code readability. The original name no longer matches how the function is used.
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
# ─── Example: Simple docs change ─────────────────────────────────────────────────────────────────┤
# docs: clarify the service limitation in providers.md guide
#
# Fixes #36332
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
# ─── Example: A bug fix ──────────────────────────────────────────────────────────────────────────┤
# fix(ngcc): ensure lockfile is removed when `analyzeFn` fails
#
# Previously an error thrown in the `analyzeFn` would cause the ngcc process to exit immediately
# without removing the lockfile, and potentially before the unlocker process had been successfully
# spawned resulting in the lockfile being orphaned and left behind.
#
# Now we catch these errors and remove the lockfile as needed.
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
# ─── Example: Breaking change ────────────────────────────────────────────────────────────────────┤
# feat(bazel): simplify ng_package by dropping esm5 and fesm5
#
# esm5 and fesm5 distributions are no longer needed and have been deprecated in the past.
#
# https://v9.angular.io/guide/deprecations#esm5-and-fesm5-code-formats-in-angular-npm-packages
#
# This commit modifies ng_package to no longer distribute these two formats in npm packages built by
# ng_package (e.g. @angular/core).
#
# This commit intentionally doesn't fully clean up the ng_package rule to remove all traces of esm5
# and fems5 build artifacts as that is a bigger cleanup and currently we are narrowing down the
# scope of this change to the MVP needed for v10, which in this case is 'do not put esm5 and fesm5'
# into the npm packages.
#
# More cleanup to follow: https://angular-team.atlassian.net/browse/FW-2143
#
# BREAKING CHANGE: esm5 and fesm5 format is no longer distributed in Angular's npm packages e.g.
# @angular/core
#
# Angular CLI will automatically downlevel the code to es5 if differential loading is enabled in the
# Angular project, so no action is required from Angular CLI users.
#
# If you are not using Angular CLI to build your application or library, and you need to be able to
# build es5 artifacts, then you will need to downlevel the distributed Angular code to es5 on your
# own.
#
#
# Fixes #1234
# ─────────────────────────────────────────────────────────────────────────────────────────────────┤
# Angular Commit Message Format
# =============================
#
# The full specification of the Angular Commit Message Format can be found at
# https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit
#
# The following is an excerpt of the specification with the most commonly needed info.
#
# Each commit message consists of a *header*, a *body*, and a *footer*.
#
# <header>
# <BLANK LINE>
# <body>
# <BLANK LINE>
# <footer>
#
# The header is mandatory.
#
# The body is mandatory for all commits except for those of scope "docs". When the body is required
# it must be at least 20 characters long.
#
# The footer is optional.
#
# Any line of the commit message cannot be longer than 100 characters.
#
#
# Commit Message Header
# ---------------------
#
# <type>(<scope>): <short summary>
# │ │ │
# │ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
# │ │
# │ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
# │ elements|forms|http|language-service|localize|platform-browser|
# │ platform-browser-dynamic|platform-server|router|service-worker|
# │ upgrade|zone.js|packaging|changelog|docs-infra|migrations|ngcc|ve|
# │ devtools
# │ https://github.com/angular/angular/blob/main/CONTRIBUTING.md#scope
# │
# └─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|style|test
# https://github.com/angular/angular/blob/main/CONTRIBUTING.md#type
#
#
# Commit Message Body
# ---------------------
#
# Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
#
# Explain the motivation for the change in the commit message body. This commit message should
# explain WHY you are making the change. You can include a comparison of the previous behavior with
# the new behavior in order to illustrate the impact of the change.
#
#
# Commit Message Footer
# ---------------------
#
# The footer can contain information about breaking changes and is also the place to reference
# GitHub issues, Jira tickets, and other PRs that this commit closes or is related to.
#
# ```
# BREAKING CHANGE: <breaking change summary>
# <BLANK LINE>
# <breaking change description + migration instructions>
# <BLANK LINE>
# <BLANK LINE>
# Fixes #<issue number>
# ```
#
# Breaking Change section should start with the phrase "BREAKING CHANGE: " followed by a summary of
# the breaking change, a blank line, and a detailed description of the breaking change that also
# includes migration instructions.
#
-11
View File
@@ -1,11 +0,0 @@
#!/bin/sh
. "$(dirname $0)/_/husky.sh"
set +e
yarn -s ng-dev commit-message pre-commit-validate --file $1 2>/dev/null
if [ $? -ne 0 ]; then
echo "WARNING: failed to run commit message validation (ng-dev commit-mesage pre-commit-validate)"
fi
exit 0;
-11
View File
@@ -1,11 +0,0 @@
#!/bin/sh
. "$(dirname $0)/_/husky.sh"
set +e
yarn -s ng-dev format staged 2>/dev/null
if [ $? -ne 0 ]; then
echo "WARNING: failed to run file formatting (ng-dev format staged)"
fi
exit 0;
-11
View File
@@ -1,11 +0,0 @@
#!/bin/sh
. "$(dirname $0)/_/husky.sh"
set +e
yarn -s ng-dev commit-message restore-commit-message-draft $1 $2 2>/dev/null
if [ $? -ne 0 ]; then
echo "WARNING: failed to attempt to restore commit message draft (ng-dev commit-message restore-commit-message-draft)"
fi
exit 0;
-20
View File
@@ -1,20 +0,0 @@
import {CaretakerConfig} from '@angular/ng-dev';
/** The configuration for `ng-dev caretaker` commands. */
export const caretaker: CaretakerConfig = {
githubQueries: [
{
name: 'Merge Queue',
query: `is:pr is:open status:success label:"action: merge"`,
},
{
name: 'Merge Assistance Queue',
query: `is:pr is:open label:"action: merge-assistance"`,
},
{
name: 'Initial Triage Queue',
query: `is:open no:milestone`,
},
],
caretakerGroup: 'angular-caretaker',
};
-41
View File
@@ -1,41 +0,0 @@
import {CommitMessageConfig} from '@angular/ng-dev';
/**
* The configuration for `ng-dev commit-message` commands.
*/
export const commitMessage: CommitMessageConfig = {
maxLineLength: Infinity,
minBodyLength: 20,
minBodyLengthTypeExcludes: ['docs'],
scopes: [
'animations',
'bazel',
'benchpress',
'changelog',
'common',
'compiler',
'compiler-cli',
'core',
'dev-infra',
'devtools',
'docs-infra',
'elements',
'forms',
'http',
'language-service',
'localize',
'migrations',
'ngcc',
'packaging',
'platform-browser',
'platform-browser-dynamic',
'platform-server',
'platform-webworker',
'platform-webworker-dynamic',
'router',
'service-worker',
'upgrade',
've',
'zone.js',
],
};
-15
View File
@@ -1,15 +0,0 @@
import {caretaker} from './caretaker.mjs';
import {commitMessage} from './commit-message.mjs';
import {format} from './format.mjs';
import {github} from './github.mjs';
import {pullRequest} from './pull-request.mjs';
import {release} from './release.mjs';
export {
commitMessage,
format,
github,
pullRequest,
caretaker,
release,
};
-35
View File
@@ -1,35 +0,0 @@
import {FormatConfig} from '@angular/ng-dev';
/**
* Configuration for the `ng-dev format` command.
*/
export const format: FormatConfig = {
'prettier': {
'matchers': ['**/*.{yaml,yml}'],
},
'clang-format': {
'matchers': [
'**/*.{js,ts}',
// TODO: burn down format failures and remove aio and integration exceptions.
'!aio/**',
'!integration/**',
// Both third_party and .yarn are directories containing copied code which should
// not be modified.
'!third_party/**',
'!.yarn/**',
// Do not format d.ts files as they are generated
'!**/*.d.ts',
// Do not format generated ng-dev script
'!dev-infra/ng-dev.js',
'!dev-infra/build-worker.js',
// Do not format compliance test-cases since they must match generated code
'!packages/compiler-cli/test/compliance/test_cases/**/*.js',
// Do not format the locale files which are checked-in for Google3, but generated using
// the `generate-locales-tool` from `packages/common/locales`.
'!packages/core/src/i18n/locale_en.ts',
'!packages/common/locales/closure-locale.ts',
'!packages/common/src/i18n/currencies.ts',
],
},
'buildifier': true,
};
-15
View File
@@ -1,15 +0,0 @@
# The file is inert unless it's explicitly included into the local git config via:
#
# ```
# git config --add include.path '../.ng-dev/gitconfig'
# ```
#
# Calling that command will append the following into `.git/config` of the current git workspace
# (i.e. $GIT_DIR, typically `angular/.git/config`):
#
# ```
# [include]
# path = ../.ng-dev/gitconfig
# ```
[commit]
template = .gitmessage
-11
View File
@@ -1,11 +0,0 @@
import {GithubConfig} from '@angular/ng-dev';
/**
* Github configuration for the `ng-dev` command. This repository is used as
* remote for the merge script and other utilities like `ng-dev pr rebase`.
*/
export const github: GithubConfig = {
owner: 'angular',
name: 'angular',
mainBranchName: 'main',
};
-23
View File
@@ -1,23 +0,0 @@
import {PullRequestConfig} from '@angular/ng-dev';
/**
* Configuration for the merge tool in `ng-dev`. This sets up the labels which
* are respected by the merge script (e.g. the target labels).
*/
export const pullRequest: PullRequestConfig = {
githubApiMerge: false,
mergeReadyLabel: 'action: merge',
caretakerNoteLabel: 'action: caretaker note',
commitMessageFixupLabel: 'merge: fix commit message',
requiredBaseCommits: {
// PRs that target either `main` or the patch branch, need to be rebased
// on top of the latest commit message validation fix.
// These SHAs are the commits that update the required license text in the header.
'main': '5aeb9a4124922d8ac08eb73b8f322905a32b0b3a',
'10.0.x': '27b95ba64a5d99757f4042073fd1860e20e3ed24',
},
// `dev-infra` and `docs-infra` are not affecting the public NPM packages. Similarly,
// the `bazel` package is not considered part of the public API so that features
// can land in patch branches.
targetLabelExemptScopes: ['dev-infra', 'docs-infra', 'bazel'],
};
-35
View File
@@ -1,35 +0,0 @@
import {ReleaseConfig} from '@angular/ng-dev';
/** Configuration for the `ng-dev release` command. */
export const release: ReleaseConfig = {
publishRegistry: 'https://wombat-dressing-room.appspot.com',
representativeNpmPackage: '@angular/core',
npmPackages: [
{name: '@angular/animations'},
{name: '@angular/bazel'},
{name: '@angular/common'},
{name: '@angular/compiler'},
{name: '@angular/compiler-cli'},
{name: '@angular/core'},
{name: '@angular/elements'},
{name: '@angular/forms'},
{name: '@angular/language-service'},
{name: '@angular/localize'},
{name: '@angular/platform-browser'},
{name: '@angular/platform-browser-dynamic'},
{name: '@angular/platform-server'},
{name: '@angular/router'},
{name: '@angular/service-worker'},
{name: '@angular/upgrade'},
],
buildPackages: async () => {
// The buildTargetPackages function is loaded at runtime as the loading the script
// causes an invocation of Bazel.
const {performNpmReleaseBuild} = await import('../scripts/build/package-builder.mjs');
return performNpmReleaseBuild();
},
releaseNotes: {
hiddenScopes: ['aio', 'bazel', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
},
releasePrLabels: ['area: build & ci', 'action: merge', 'PullApprove: disable'],
};
-10
View File
@@ -1,10 +0,0 @@
{
"compilerOptions": {
"strict": true,
"target": "es2020",
"module": "Node16",
"noEmit": true,
"skipLibCheck": true,
"types": []
}
}
-1
View File
@@ -1 +0,0 @@
engine-strict = true
+1 -1
View File
@@ -1 +1 @@
16.10.0
8.9
-9
View File
@@ -1,9 +0,0 @@
{
"printWidth": 100,
"tabWidth": 2,
"tabs": false,
"singleQuote": true,
"semicolon": true,
"quoteProps": "preserve",
"bracketSpacing": false
}
+324 -1361
View File
File diff suppressed because it is too large Load Diff
+84
View File
@@ -0,0 +1,84 @@
language: node_js
# Work-around for https://github.com/travis-ci/travis-ci/issues/8836#issuecomment-356362524.
# (Restore `sudo: false` once that is resolved.)
sudo: required
dist: trusty
node_js:
- '8.9.1'
addons:
# firefox: "38.0"
apt:
sources:
# needed to install g++ that is used by npms's native modules
- ubuntu-toolchain-r-test
packages:
# needed to install g++ that is used by npms's native modules
- g++-4.8
# https://docs.travis-ci.com/user/jwt
jwt:
# SAUCE_ACCESS_KEY<=secret for NGBUILDS_IO_KEY to work around travis-ci/travis-ci#7223, unencrypted value in valentine as NGBUILDS_IO_KEY>
# we alias NGBUILDS_IO_KEY to $SAUCE_ACCESS_KEY in env.sh and set the SAUCE_ACCESS_KEY there
- secure: "L7nrZwkAtFtYrP2DykPXgZvEKjkv0J/TwQ/r2QGxFTaBq4VZn+2Dw0YS7uCxoMqYzDwH0aAOqxoutibVpk8Z/16nE3tNmU5RzltMd6Xmt3qU2f/JDQLMo6PSlBodnjOUsDHJgmtrcbjhqrx/znA237BkNUu6UZRT7mxhXIZpn0U="
branches:
except:
- g3
cache:
yarn: true
directories:
- ./node_modules
- ./.chrome/chromium
- ./aio/node_modules
env:
global:
# GITHUB_TOKEN_ANGULAR=<github token, a personal access token of the angular-builds account, account access in valentine>
# This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery.
- secure: "aCdHveZuY8AT4Jr1JoJB4LxZsnGWRe/KseZh1YXYe5UtufFCtTVHvUcLn0j2aLBF0KpdyS+hWf0i4np9jthKu2xPKriefoPgCMpisYeC0MFkwbmv+XlgkUbgkgVZMGiVyX7DCYXVahxIoOUjVMEDCbNiHTIrfEuyq24U3ok2tHc="
# FIREBASE_TOKEN
# This is needed for publishing builds to the "aio-staging" and "angular-io" firebase projects.
# This token was generated using the aio-deploy@angular.io account using `firebase login:ci` and password from valentine
- secure: "L5CyQmpwWtoR4Qi4xlWQh/cL1M6ZeJL4W4QAr4HdKFMgYt9h+Whqkymyh2NxwmCbPvWa7yUd+OiLQUDCY7L2VIg16hTwoe2CgYDyQA0BEwLzxtRrJXl93TfwMlrUx5JSIzAccD6D4sjtz8kSFMomK2Nls33xOXOukwyhVMjd0Cg="
# ANGULAR_PAYLOAD_FIREBASE_TOKEN
# This is for payload size data to "angular-payload-size" firebase project
# This token was generated using the payload@angular.io account using `firebase login:ci` and password from valentine
- secure: "SxotP/ymNy6uWAVbfwM9BlwETPEBpkRvU/F7fCtQDDic99WfQHzzUSQqHTk8eKk3GrGAOSL09vT0WfStQYEIGEoS5UHWNgOnelxhw+d5EnaoB8vQ0dKQBTK092hQg4feFprr+B/tCasyMV6mVwpUzZMbIJNn/Rx7H5g1bp+Gkfg="
matrix:
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
- CI_MODE=e2e
- CI_MODE=e2e_2
- CI_MODE=js
- CI_MODE=saucelabs_required
# deactivated, see #19768
# - CI_MODE=browserstack_required
- CI_MODE=saucelabs_optional
- CI_MODE=browserstack_optional
- CI_MODE=aio_tools_test
- CI_MODE=aio
- CI_MODE=aio_e2e AIO_SHARD=0
- CI_MODE=aio_e2e AIO_SHARD=1
- CI_MODE=bazel
matrix:
fast_finish: true
allow_failures:
- env: "CI_MODE=saucelabs_optional"
- env: "CI_MODE=browserstack_optional"
before_install:
# source the env.sh script so that the exported variables are available to other scripts later on
- source ./scripts/ci/env.sh print
install:
- ./scripts/ci/install.sh
script:
- ./scripts/ci/build.sh
- ./scripts/ci/test.sh
# deploy is part of 'script' and not 'after_success' so that we fail the build if the deployment fails
- ./scripts/ci/deploy.sh
- ./scripts/ci/angular.sh
# all the scripts under this line will not quickly abort in case ${TRAVIS_TEST_RESULT} is 1 (job failure)
- ./scripts/ci/cleanup.sh
- ./scripts/ci/print-logs.sh
-25
View File
@@ -1,25 +0,0 @@
# VSCode Configuration
This folder contains opt-in [Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings), [Tasks](https://code.visualstudio.com/docs/editor/tasks), [Launch Configurations](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations) and [Extension Recommendations](https://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions) that the Angular team recommends using when working on this repository.
## Usage
To use the recommended configurations follow the steps below:
- install the recommended extensions in `.vscode/extensions.json`
- copy (or link) `.vscode/recommended-settings.json` to `.vscode/settings.json`
- copy (or link) `.vscode/recommended-launch.json` to `.vscode/launch.json`
- copy (or link) `.vscode/recommended-tasks.json` to `.vscode/tasks.json`
- restart the editor
If you already have your custom workspace settings, you should instead manually merge the file contents.
This isn't an automatic process, so you will need to repeat it when settings are updated.
To see the recommended extensions select "Extensions: Show Recommended Extensions" in the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette).
## Editing `.vscode/recommended-*.json` files
If you wish to add extra configuration items please keep in mind any modifications you make here will be used by many users.
Try to keep these settings/configurations to things that help facilitate the development process and avoid altering the user workflow whenever possible.
-16
View File
@@ -1,16 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"devondcarew.bazel-code",
"gkalpak.aio-docs-utils",
"ms-vscode.vscode-typescript-tslint-plugin",
"xaver.clang-format",
// The following extensions are useful when working on angular.io (i.e. inside the `aio/` directory).
//"angular.ng-template",
//"dbaeumer.vscode-eslint",
//"errata-ai.vale-server",
],
}
-75
View File
@@ -1,75 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Attach to bazel test ... --config=debug",
"type": "node",
"request": "attach",
"port": 9229,
"address": "localhost",
"restart": false,
"sourceMaps": true,
"localRoot": "${workspaceRoot}",
"remoteRoot": "${workspaceRoot}",
"stopOnEntry": false,
"timeout": 600000,
"outFiles": ["${workspaceFolder}/dist/out/**/packages/**/*.js"]
},
{
"name": "Attach to bazel test ... --config=debug (no source maps)",
"type": "node",
"request": "attach",
"port": 9229,
"address": "localhost",
"restart": false,
"sourceMaps": false,
"localRoot": "${workspaceRoot}",
"remoteRoot": "${workspaceRoot}",
"stopOnEntry": false,
"timeout": 600000,
"outFiles": ["${workspaceFolder}/dist/out/**/packages/**/*.js"]
},
{
"name": "IVY:packages/core/test/acceptance",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": ["test", "packages/core/test/acceptance", "--config=debug"],
"port": 9229,
"address": "localhost",
"restart": true,
"sourceMaps": true,
"timeout": 600000,
"outFiles": ["${workspaceFolder}/dist/out/**/packages/**/*.js"]
},
{
"name": "IVY:packages/core/test/render3",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": ["test", "packages/core/test/render3", "--config=debug"],
"port": 9229,
"address": "localhost",
"restart": true,
"sourceMaps": true,
"timeout": 600000,
"outFiles": ["${workspaceFolder}/dist/out/**/packages/**/*.js"]
},
{
"name": "IVY:packages/core/test",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": ["test", "packages/core/test", "--config=debug"],
"port": 9229,
"address": "localhost",
"restart": true,
"sourceMaps": true,
"timeout": 600000,
"outFiles": ["${workspaceFolder}/dist/out/**/packages/**/*.js"]
}
]
}
-32
View File
@@ -1,32 +0,0 @@
{
// Format js and ts files on save with `clang-format.executable`
// If `clang-format.executable` is not being used, these two settings should be removed otherwise it will break existing formatting.
// You can instead run `yarn gulp format` to manually format your code.
"[javascript]": {
"editor.formatOnSave": true,
},
"[typescript]": {
"editor.formatOnSave": true,
},
// Please install https://marketplace.visualstudio.com/items?itemName=xaver.clang-format to take advantage of `clang-format` in VSCode.
// (See https://clang.llvm.org/docs/ClangFormat.html for more info `clang-format`.)
"clang-format.executable": "${workspaceRoot}/node_modules/.bin/clang-format",
// Exclude third party modules and build artifacts from the editor watchers/searches.
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/**": true,
"**/bazel-out/**": true,
"**/dist/**": true,
"**/aio/src/generated/**": true,
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/bazel-out": true,
"**/dist": true,
"**/aio/src/generated": true,
".history": true,
},
"git.ignoreLimitWarning": true,
}
-109
View File
@@ -1,109 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "IVY:packages/core/test/...",
"type": "shell",
"command": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": [
"test",
"packages/core/test",
"packages/core/test/acceptance",
"packages/core/test/render3",
],
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
},
},
{
"label": "VE:packages/core/test/...",
"type": "shell",
"command": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": [
"test",
"packages/core/test",
"packages/core/test/acceptance",
"packages/core/test/render3",
],
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
},
},
{
"label": "IVY:packages/core/test/acceptance",
"type": "shell",
"command": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": [
"test",
"packages/core/test/acceptance",
],
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
},
},
{
"label": "VE:packages/core/test/acceptance",
"type": "shell",
"command": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": [
"test",
"packages/core/test/acceptance",
],
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
},
},
{
"label": "IVY:packages/core/test",
"type": "shell",
"command": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": [
"test",
"packages/core/test",
],
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
},
},
{
"label": "VE:packages/core/test",
"type": "shell",
"command": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": [
"test",
"packages/core/test",
],
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
},
},
{
"label": "IVY:packages/core/test/render3",
"type": "shell",
"command": "${workspaceFolder}/node_modules/.bin/bazelisk",
"args": [
"test",
"packages/core/test/render3",
],
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
},
},
],
}
-13
View File
@@ -1,13 +0,0 @@
# Yarn Vendoring
We utilize Yarn's `yarn-path` configuration in a shared `.yarnrc` file to enforce
everyone using the same version of Yarn. Yarn checks the `.yarnrc` file to
determine if yarn should delegate the command to a vendored version at the
provided path.
## How to update
To update to the latest version of Yarn as our vendored version:
- Run this command
```sh
yarn policies set-version latest
```
- Remove the previous version
-147520
View File
File diff suppressed because one or more lines are too long
-5
View File
@@ -1,5 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
yarn-path ".yarn/releases/yarn-1.22.17.cjs"
+47 -47
View File
@@ -1,65 +1,65 @@
load("//tools:defaults.bzl", "nodejs_binary")
package(default_visibility = ["//visibility:public"])
exports_files([
"LICENSE",
"karma-js.conf.js",
"browser-providers.conf.js",
"scripts/ci/bazel-payload-size.sh",
"scripts/ci/payload-size.sh",
"scripts/ci/payload-size.js",
"package.json",
"tsconfig.json",
])
alias(
name = "tsconfig.json",
actual = "//packages:tsconfig-build.json",
# This rule belongs in node_modules/BUILD
# It's here as a workaround for
# https://github.com/bazelbuild/bazel/issues/374#issuecomment-296217940
filegroup(
name = "node_modules",
# Performance workaround: list individual files
# Reduces the number of files as inputs to nodejs_binary:
# bazel query "deps(:node_modules)" | wc -l
# This won't scale in the general case.
# TODO(alexeagle): figure out what to do
srcs = glob(["/".join([
"node_modules",
pkg,
"**",
ext,
]) for pkg in [
"jasmine",
"typescript",
"zone.js",
"tsutils",
"@types/jasmine",
"@types/node",
"@types/source-map",
"tsickle",
"hammerjs",
"protobufjs",
"bytebuffer",
"reflect-metadata",
"source-map-support",
"minimist",
] for ext in [
"*.js",
"*.json",
"*.d.ts",
]]),
)
filegroup(
name = "web_test_bootstrap_scripts",
# do not sort
srcs = [
"@npm//:node_modules/core-js-bundle/index.js",
"//packages/zone.js/bundles:zone.umd.js",
"//packages/zone.js/bundles:zone-testing.umd.js",
"//packages/zone.js/bundles:task-tracking.umd.js",
# Including systemjs because it defines `__eval`, which produces correct stack traces.
"@npm//:node_modules/systemjs/dist/system.src.js",
"@npm//:node_modules/reflect-metadata/Reflect.js",
"//:node_modules/reflect-metadata/Reflect.js",
"//:node_modules/zone.js/dist/zone.js",
"//:node_modules/zone.js/dist/async-test.js",
"//:node_modules/zone.js/dist/sync-test.js",
"//:node_modules/zone.js/dist/fake-async-test.js",
"//:node_modules/zone.js/dist/proxy.js",
"//:node_modules/zone.js/dist/jasmine-patch.js",
],
)
filegroup(
name = "angularjs_scripts",
name = "angularjs",
# do not sort
srcs = [
# We also declare the unminified AngularJS files since these can be used for
# local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts)
"@npm//:node_modules/angular-1.5/angular.js",
"@npm//:node_modules/angular-1.5/angular.min.js",
"@npm//:node_modules/angular-1.6/angular.js",
"@npm//:node_modules/angular-1.6/angular.min.js",
"@npm//:node_modules/angular-1.7/angular.js",
"@npm//:node_modules/angular-1.7/angular.min.js",
"@npm//:node_modules/angular-mocks-1.5/angular-mocks.js",
"@npm//:node_modules/angular-mocks-1.6/angular-mocks.js",
"@npm//:node_modules/angular-mocks-1.7/angular-mocks.js",
"@npm//:node_modules/angular-mocks-1.8/angular-mocks.js",
"@npm//:node_modules/angular-1.8/angular.js",
"@npm//:node_modules/angular-1.8/angular.min.js",
"//:node_modules/angular/angular.js",
"//:node_modules/angular-mocks/angular-mocks.js",
],
)
# Detect if the build is running under --stamp
config_setting(
name = "stamp",
values = {"stamp": "true"},
)
nodejs_binary(
name = "yarn_vendored",
data = [".yarn/releases/yarn-1.22.17.cjs"],
entry_point = ".yarn/releases/yarn-1.22.17.cjs",
visibility = ["//integration:__subpackages__"],
)
+2590 -3272
View File
File diff suppressed because it is too large Load Diff
-6557
View File
File diff suppressed because it is too large Load Diff
-71
View File
@@ -1,71 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering a safe and welcoming environment, we as
the Angular team pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity, gender expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Use welcoming and inclusive language
* Respect each other
* Provide and gracefully accept constructive criticism
* Show empathy towards other community members
Examples of unacceptable behavior by participants include:
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* The use of sexualized language or imagery
* Unwelcome sexual attention or advances
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Angular team are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Angular team have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, and to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies to all Angular communication channels - online or in person,
and it also applies when an individual is representing the project or its community in
public spaces. Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the Angular team at conduct@angular.io. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The Angular team
will maintain confidentiality with regard to the reporter of an incident.
Enforcement may result in an indefinite ban from all official Angular communication
channels, or other actions as deemed appropriate by the Angular team.
Angular maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+127 -260
View File
@@ -1,7 +1,7 @@
# Contributing to Angular
We would love for you to contribute to Angular and help make it even better than it is today!
As a contributor, here are the guidelines we would like you to follow:
We would love for you to contribute to Angular and help make it even better than it is
today! As a contributor, here are the guidelines we would like you to follow:
- [Code of Conduct](#coc)
- [Question or Problem?](#question)
@@ -12,168 +12,110 @@ As a contributor, here are the guidelines we would like you to follow:
- [Commit Message Guidelines](#commit)
- [Signing the CLA](#cla)
## <a name="coc"></a> Code of Conduct
Help us keep Angular open and inclusive.
Please read and follow our [Code of Conduct][coc].
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][coc].
## <a name="question"></a> Got a Question or Problem?
Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests.
Instead, we recommend using [Stack Overflow](https://stackoverflow.com/questions/tagged/angular) to ask support-related questions. When creating a new question on Stack Overflow, make sure to add the `angular` tag.
Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [Stack Overflow](https://stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
Stack Overflow is a much better place to ask questions since:
- there are thousands of people willing to help on Stack Overflow
- questions and answers stay available for public viewing so your question/answer might help someone else
- questions and answers stay available for public viewing so your question / answer might help someone else
- Stack Overflow's voting system assures that the best answers are prominently visible.
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
If you would like to chat about the question in real-time, you can reach out via [our Discord server][discord].
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
## <a name="issue"></a> Found a Bug?
If you find a bug in the source code, you can help us by [submitting an issue](#submit-issue) to our [GitHub Repository][github].
Even better, you can [submit a Pull Request](#submit-pr) with a fix.
If you find a bug in the source code, you can help us by
[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can
[submit a Pull Request](#submit-pr) with a fix.
## <a name="feature"></a> Missing a Feature?
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub Repository.
If you would like to *implement* a new feature, please consider the size of the change in order to determine the right steps to proceed:
* For a **Major Feature**, first open an issue and outline your proposal so that it can be discussed.
This process allows us to better coordinate our efforts, prevent duplication of work, and help you to craft the change so that it is successfully accepted into the project.
**Note**: Adding a new topic to the documentation, or significantly re-writing a topic, counts as a major feature.
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub
Repository. If you would like to *implement* a new feature, please submit an issue with
a proposal for your work first, to be sure that we can use it.
Please consider what kind of change it is:
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,
and help you to craft the change so that it is successfully accepted into the project.
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
## <a name="submit"></a> Submission Guidelines
### <a name="submit-issue"></a> Submitting an Issue
Before you submit an issue, please search the issue tracker. An issue for your problem might already exist and the discussion might inform you of workarounds readily available.
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
We want to fix all the issues as soon as possible, but before fixing a bug, we need to reproduce and confirm it.
In order to reproduce bugs, we require that you provide a minimal reproduction.
Having a minimal reproducible scenario gives us a wealth of important information without going back and forth to you with additional questions.
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:
A minimal reproduction allows us to quickly confirm a bug (or point out a coding problem) as well as confirm that we are fixing the right problem.
- version of Angular used
- 3rd-party libraries and their versions
- and most importantly - a use-case that fails
We require a minimal reproduction to save maintainers' time and ultimately be able to fix more bugs.
Often, developers find coding problems themselves while preparing a minimal reproduction.
We understand that sometimes it might be hard to extract essential bits of code from a larger codebase, but we really need to isolate the problem before we can fix it.
A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If plunker is not a suitable way to demonstrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demonstrating the problem.
Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you, we are going to close an issue that doesn't have enough info to be reproduced.
We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
You can file new issues by selecting from our [new issue templates](https://github.com/angular/angular/issues/new/choose) and filling out the issue template.
Unfortunately we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
You can file new issues by filling out our [new issue form](https://github.com/angular/angular/issues/new).
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
Before you submit your Pull Request (PR) consider the following guidelines:
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR that relates to your submission.
You don't want to duplicate existing efforts.
2. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add.
Discussing the design upfront helps to ensure that we're ready to accept your work.
3. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
We cannot accept code without a signed CLA.
Make sure you author all contributed Git commits with email address associated with your CLA signature.
4. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the angular/angular repo.
5. In your forked repository, make your changes in a new git branch:
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
that relates to your submission. You don't want to duplicate effort.
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
We cannot accept code without this.
1. Fork the angular/angular repo.
1. Make your changes in a new git branch:
```shell
git checkout -b my-fix-branch main
git checkout -b my-fix-branch master
```
6. Create your patch, **including appropriate test cases**.
7. Follow our [Coding Rules](#rules).
8. Run the full Angular test suite, as described in the [developer documentation][dev-doc], and ensure that all tests pass.
9. Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit).
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
1. Create your patch, **including appropriate test cases**.
1. Follow our [Coding Rules](#rules).
1. Run the full Angular test suite, as described in the [developer documentation][dev-doc],
and ensure that all tests pass.
1. Commit your changes using a descriptive commit message that follows our
[commit message conventions](#commit). Adherence to these conventions
is necessary because release notes are automatically generated from these messages.
```shell
git commit --all
git commit -a
```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
10. Push your branch to GitHub:
1. Push your branch to GitHub:
```shell
git push origin my-fix-branch
```
11. In GitHub, send a pull request to `angular:main`.
### Reviewing a Pull Request
The Angular team reserves the right not to accept pull requests from community members who haven't been good citizens of the community. Such behavior includes not following the [Angular code of conduct](https://github.com/angular/code-of-conduct) and applies within or outside of Angular managed channels.
#### Addressing review feedback
If we ask for changes via code reviews then:
1. Make the required updates to the code.
2. Re-run the Angular test suites to ensure tests are still passing.
3. Create a fixup commit and push to your GitHub repository (this will update your Pull Request):
1. In GitHub, send a pull request to `angular:master`.
* If we suggest changes then:
* Make the required updates.
* Re-run the Angular test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
```shell
git commit --all --fixup HEAD
git push
git rebase master -i
git push -f
```
For more info on working with fixup commits see [here](docs/FIXUP_COMMITS.md).
That's it! Thank you for your contribution!
##### Updating the commit message
A reviewer might often suggest changes to a commit message (for example, to add more context for a change or adhere to our [commit message guidelines](#commit)).
In order to update the commit message of the last commit on your branch:
1. Check out your branch:
```shell
git checkout my-fix-branch
```
2. Amend the last commit and modify the commit message:
```shell
git commit --amend
```
3. Push to your GitHub repository:
```shell
git push --force-with-lease
```
> NOTE:<br />
> If you need to update the commit message of an earlier commit, you can use `git rebase` in interactive mode.
> See the [git docs](https://git-scm.com/docs/git-rebase#_interactive_mode) for more details.
#### After your pull request is merged
After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:
After your pull request is merged, you can safely delete your branch and pull the changes
from the main (upstream) repository:
* Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
@@ -181,10 +123,10 @@ After your pull request is merged, you can safely delete your branch and pull th
git push origin --delete my-fix-branch
```
* Check out the main branch:
* Check out the master branch:
```shell
git checkout main -f
git checkout master -f
```
* Delete the local branch:
@@ -193,216 +135,141 @@ After your pull request is merged, you can safely delete your branch and pull th
git branch -D my-fix-branch
```
* Update your local `main` with the latest upstream version:
* Update your master with the latest upstream version:
```shell
git pull --ff upstream main
git pull --ff upstream master
```
## <a name="rules"></a> Coding Rules
To ensure consistency throughout the source code, keep these rules in mind as you are working:
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
* All public API methods **must be documented**.
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at **100 characters**.
* All public API methods **must be documented**. (Details TBC).
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
**100 characters**. An automated formatter is available, see
[DEVELOPER.md](docs/DEVELOPER.md#clang-format).
An automated formatter is available, see [DEVELOPER.md](docs/DEVELOPER.md#clang-format).
## <a name="commit"></a> Commit Message Guidelines
We have very precise rules over how our git commit messages can be formatted. This leads to **more
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the Angular change log**.
## <a name="commit"></a> Commit Message Format
*This specification is inspired by and supersedes the [AngularJS commit message format][commit-message-format].*
We have very precise rules over how our Git commit messages must be formatted.
This format leads to **easier to read commit history**.
Each commit message consists of a **header**, a **body**, and a **footer**.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<header>
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The `header` is mandatory and must conform to the [Commit Message Header](#commit-header) format.
The **header** is mandatory and the **scope** of the header is optional.
The `body` is mandatory for all commits except for those of type "docs".
When the body is present it must be at least 20 characters long and must conform to the [Commit Message Body](#commit-body) format.
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on GitHub as well as in various git tools.
The `footer` is optional. The [Commit Message Footer](#commit-footer) format describes what the footer is used for and the structure it must have.
Footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
#### <a name="commit-header"></a>Commit Message Header
Samples: (even more [samples](https://github.com/angular/angular/commits/master))
```
<type>(<scope>): <short summary>
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
│ elements|forms|http|language-service|localize|platform-browser|
│ platform-browser-dynamic|platform-server|router|service-worker|
│ upgrade|zone.js|packaging|changelog|docs-infra|migrations|ngcc|ve|
│ devtools
│
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test
docs(changelog): update change log to beta.5
```
```
fix(release): need to depend on latest rxjs and zone.js
The version in our package.json gets copied to the one we publish, and users need the latest of these.
```
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
##### Type
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
* **ci**: Changes to our CI configuration files and scripts (examples: CircleCi, SauceLabs)
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
* **docs**: Documentation only changes
* **feat**: A new feature
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests
##### Scope
The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages).
### Scope
The scope should be the name of the npm package affected (as perceived by person reading changelog generated from commit messages.
The following is the list of supported scopes:
* `animations`
* `bazel`
* `benchpress`
* `common`
* `compiler`
* `compiler-cli`
* `core`
* `elements`
* `forms`
* `http`
* `language-service`
* `localize`
* `platform-browser`
* `platform-browser-dynamic`
* `platform-server`
* `router`
* `service-worker`
* `upgrade`
* `zone.js`
* **animations**
* **common**
* **compiler**
* **compiler-cli**
* **core**
* **forms**
* **http**
* **language-service**
* **platform-browser**
* **platform-browser-dynamic**
* **platform-server**
* **platform-webworker**
* **platform-webworker-dynamic**
* **router**
* **service-worker**
* **upgrade**
There are currently a few exceptions to the "use package name" rule:
* `packaging`: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
* **changelog**: used for updating the release notes in CHANGELOG.md
* **aio**: used for docs-app (angular.io) related changes within the /aio directory of the repo
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
* `changelog`: used for updating the release notes in CHANGELOG.md
* `dev-infra`: used for dev-infra related changes within the directories /scripts and /tools
* `docs-infra`: used for docs-app (angular.io) related changes within the /aio directory of the repo
* `migrations`: used for changes to the `ng update` migrations.
* `ngcc`: used for changes to the [Angular Compatibility Compiler](./packages/compiler-cli/ngcc/README.md)
* `ve`: used for changes specific to ViewEngine (legacy compiler/renderer).
* `devtools`: used for changes in the [browser extension](./devtools/README.md).
* none/empty string: useful for `test` and `refactor` changes that are done across all packages (e.g. `test: add missing unit tests`) and for docs changes that are not related to a specific package (e.g. `docs: fix typo in tutorial`).
##### Summary
Use the summary field to provide a succinct description of the change:
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize the first letter
* don't capitalize first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
#### <a name="commit-body"></a>Commit Message Body
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
Explain the motivation for the change in the commit message body. This commit message should explain _why_ you are making the change.
You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.
#### <a name="commit-footer"></a>Commit Message Footer
The footer can contain information about breaking changes and deprecations and is also the place to reference GitHub issues, Jira tickets, and other PRs that this commit closes or is related to.
For example:
```
BREAKING CHANGE: <breaking change summary>
<BLANK LINE>
<breaking change description + migration instructions>
<BLANK LINE>
<BLANK LINE>
Fixes #<issue number>
```
or
```
DEPRECATED: <what is deprecated>
<BLANK LINE>
<deprecation description + recommended update path>
<BLANK LINE>
<BLANK LINE>
Closes #<pr number>
```
Breaking Change section should start with the phrase "BREAKING CHANGE: " followed by a summary of the breaking change, a blank line, and a detailed description of the breaking change that also includes migration instructions.
Similarly, a Deprecation section should start with "DEPRECATED: " followed by a short description of what is deprecated, a blank line, and a detailed description of the deprecation that also mentions the recommended update path.
### Revert commits
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit.
The content of the commit message body should contain:
- information about the SHA of the commit being reverted in the following format: `This reverts commit <SHA>`,
- a clear description of the reason for reverting the commit message.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
A detailed explanation can be found in this [document][commit-message-format].
## <a name="cla"></a> Signing the CLA
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code
changes to be accepted, the CLA must be signed. It's a quick process, we promise!
* For individuals, we have a [simple click-through form][individual-cla].
* For corporations, we'll need you to
* For individuals we have a [simple click-through form][individual-cla].
* For corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
If you have more than one GitHub accounts, or multiple email addresses associated with a single GitHub account, you must sign the CLA using the primary email address of the GitHub account used to author Git commits and send pull requests.
The following documents can help you sort out issues with GitHub accounts and multiple email addresses:
* https://help.github.com/articles/setting-your-commit-email-address-in-git/
* https://stackoverflow.com/questions/37245303/what-does-usera-committed-with-userb-13-days-ago-on-github-mean
* https://help.github.com/articles/about-commit-email-addresses/
* https://help.github.com/articles/blocking-command-line-pushes-that-expose-your-personal-email-address/
[angular-group]: https://groups.google.com/forum/#!forum/angular
[coc]: https://github.com/angular/code-of-conduct/blob/main/CODE_OF_CONDUCT.md
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[corporate-cla]: https://cla.developers.google.com/about/google-corporate
[dev-doc]: https://github.com/angular/angular/blob/main/docs/DEVELOPER.md
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[dev-doc]: https://github.com/angular/angular/blob/master/docs/DEVELOPER.md
[github]: https://github.com/angular/angular
[discord]: https://discord.gg/angular
[individual-cla]: https://cla.developers.google.com/about/google-individual
[gitter]: https://gitter.im/angular/angular
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[jsfiddle]: https://jsfiddle.net/
[plunker]: https://plnkr.co/edit
[runnable]: https://runnable.com/
[stackoverflow]: https://stackoverflow.com/questions/tagged/angular
[jsfiddle]: http://jsfiddle.net
[plunker]: http://plnkr.co/edit
[runnable]: http://runnable.com
[stackoverflow]: http://stackoverflow.com/questions/tagged/angular
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2010-2022 Google LLC. https://angular.io/license
Copyright (c) 2014-2018 Google, Inc. http://angular.io
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+16 -155
View File
@@ -1,167 +1,28 @@
<h1 align="center">Angular - The modern web developer's platform.</h1>
[![Build Status](https://travis-ci.org/angular/angular.svg?branch=master)](https://travis-ci.org/angular/angular)
[![CircleCI](https://circleci.com/gh/angular/angular/tree/master.svg?style=shield)](https://circleci.com/gh/angular/angular/tree/master)
[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)
[![Join the chat at https://gitter.im/angular/angular](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://www.npmjs.com/@angular/core)
<p align="center">
<img src="aio/src/assets/images/logos/angular/angular.png" alt="angular-logo" width="120px" height="120px"/>
<br>
<i>Angular is a development platform for building mobile and desktop web applications
<br> using Typescript/JavaScript and other languages.</i>
<br>
</p>
<p align="center">
<a href="https://www.angular.io"><strong>www.angular.io</strong></a>
<br>
</p>
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
<p align="center">
<a href="CONTRIBUTING.md">Contributing Guidelines</a>
·
<a href="https://github.com/angular/angular/issues">Submit an Issue</a>
·
<a href="https://blog.angular.io/">Blog</a>
<br>
<br>
</p>
*Safari (7+), iOS (7+) and IE mobile (11) are tested on [BrowserStack][browserstack].*
<p align="center">
<a href="https://circleci.com/gh/angular/workflows/angular/tree/main">
<img src="https://img.shields.io/circleci/build/github/angular/angular/main.svg?logo=circleci&logoColor=fff&label=CircleCI" alt="CI status" />
</a>&nbsp;
<a href="https://www.npmjs.com/@angular/core">
<img src="https://img.shields.io/npm/v/@angular/core.svg?logo=npm&logoColor=fff&label=NPM+package&color=limegreen" alt="Angular on npm" />
</a>&nbsp;
<a href="https://discord.gg/angular">
<img src="https://img.shields.io/discord/463752820026376202.svg?logo=discord&logoColor=fff&label=Discord&color=7389d8" alt="Discord conversation" />
</a>
</p>
# Angular
<p align="center">
<a href="https://app.circleci.com/insights/github/angular/angular/workflows/default_workflow?branch=main">
<img src="https://dl.circleci.com/insights-snapshot/gh/angular/angular/main/default_workflow/badge.svg" alt="InsightsSnapshot" />
</a>
</p>
<hr>
## Documentation
Get started with Angular, learn the fundamentals and explore advanced topics on our documentation website.
- [Getting Started][quickstart]
- [Architecture][architecture]
- [Components and Templates][componentstemplates]
- [Forms][forms]
- [API][api]
### Advanced
- [Angular Elements][angularelements]
- [Server Side Rendering][ssr]
- [Schematics][schematics]
- [Lazy Loading][lazyloading]
- [Animations][animations]
## Development Setup
### Prerequisites
- Install [Node.js] which includes [Node Package Manager][npm]
### Setting Up a Project
Install the Angular CLI globally:
```
npm install -g @angular/cli
```
Create workspace:
```
ng new [PROJECT NAME]
```
Run the application:
```
cd [PROJECT NAME]
ng serve
```
Angular is cross-platform, fast, scalable, has incredible tooling, and is loved by millions.
Angular is a development platform for building mobile and desktop web applications using Typescript/JavaScript and other languages.
## Quickstart
[Get started in 5 minutes][quickstart].
## Ecosystem
## Want to help?
<p>
<img src="/docs/images/angular-ecosystem-logos.png" alt="angular ecosystem logos" width="500px" height="auto">
</p>
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
- [Angular Command Line (CLI)][cli]
- [Angular Material][angularmaterial]
## Changelog
[Learn about the latest improvements][changelog].
## Upgrading
Check out our [upgrade guide](https://update.angular.io/) to find out the best way to upgrade your project.
## Contributing
### Contributing Guidelines
Read through our [contributing guidelines][contributing] to learn about our submission process, coding rules, and more.
### Want to Help?
Want to report a bug, contribute some code, or improve the documentation? Excellent! Read up on our guidelines for [contributing][contributing] and then check out one of our issues labeled as <kbd>[help wanted](https://github.com/angular/angular/labels/help%20wanted)</kbd> or <kbd>[good first issue](https://github.com/angular/angular/labels/good%20first%20issue)</kbd>.
### Code of Conduct
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][codeofconduct].
## Community
Join the conversation and help the community.
- [Twitter][twitter]
- [Discord][discord]
- [Gitter][gitter]
- [YouTube][youtube]
- [StackOverflow][stackoverflow]
- Find a Local [Meetup][meetup]
[![Love Angular badge](https://img.shields.io/badge/angular-love-blue?logo=angular&angular=love)](https://www.github.com/angular/angular)
**Love Angular? Give our repo a star :star: :arrow_up:.**
[contributing]: CONTRIBUTING.md
[quickstart]: https://angular.io/start
[changelog]: CHANGELOG.md
[ng]: https://angular.io
[documentation]: https://angular.io/docs
[angularmaterial]: https://material.angular.io/
[cli]: https://cli.angular.io/
[architecture]: https://angular.io/guide/architecture
[componentstemplates]: https://angular.io/guide/displaying-data
[forms]: https://angular.io/guide/forms-overview
[api]: https://angular.io/api
[angularelements]: https://angular.io/guide/elements
[ssr]: https://angular.io/guide/universal
[schematics]: https://angular.io/guide/schematics
[lazyloading]: https://angular.io/guide/lazy-loading-ngmodules
[node.js]: https://nodejs.org/
[npm]: https://www.npmjs.com/get-npm
[codeofconduct]: CODE_OF_CONDUCT.md
[twitter]: https://www.twitter.com/angular
[discord]: https://discord.gg/angular
[gitter]: https://gitter.im/angular/angular
[stackoverflow]: https://stackoverflow.com/questions/tagged/angular
[youtube]: https://youtube.com/angular
[meetup]: https://www.meetup.com/find/?keywords=angular
[animations]: https://angular.io/guide/animations
[browserstack]: https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
[ng]: http://angular.io
-3
View File
@@ -1,3 +0,0 @@
To report vulnerabilities in Angular itself, email us at security@angular.io.
For more information on Angular's security policy visit: https://angular.io/guide/security
+52 -161
View File
@@ -1,173 +1,64 @@
workspace(
name = "angular",
managed_directories = {
"@npm": ["node_modules"],
"@aio_npm": ["aio/node_modules"],
},
)
workspace(name = "angular_src")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
# Add a patch fix for rules_webtesting v0.3.5 required for enabling runfiles on Windows.
# TODO: Remove the http_archive for this transitive dependency when a release is cut
# for https://github.com/bazelbuild/rules_webtesting/commit/581b1557e382f93419da6a03b91a45c2ac9a9ec8
# and the version is updated in rules_nodejs.
http_archive(
name = "io_bazel_rules_webtesting",
patch_args = ["-p1"],
patches = [
"//:tools/bazel-repo-patches/rules_webtesting__windows_runfiles_fix.patch",
],
sha256 = "e9abb7658b6a129740c0b3ef6f5a2370864e102a5ba5ffca2cea565829ed825a",
urls = ["https://github.com/bazelbuild/rules_webtesting/releases/download/0.3.5/rules_webtesting.tar.gz"],
)
http_archive(
git_repository(
name = "build_bazel_rules_nodejs",
sha256 = "c78216f5be5d451a42275b0b7dc809fb9347e2b04a68f68bad620a2b01f5c774",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.5.2/rules_nodejs-5.5.2.tar.gz"],
remote = "https://github.com/bazelbuild/rules_nodejs.git",
tag = "0.3.1",
)
load("@build_bazel_rules_nodejs//:repositories.bzl", "build_bazel_rules_nodejs_dependencies")
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
build_bazel_rules_nodejs_dependencies()
check_bazel_version("0.9.0")
node_repositories(package_json = ["//:package.json"])
git_repository(
name = "build_bazel_rules_typescript",
remote = "https://github.com/bazelbuild/rules_typescript.git",
# tag = "0.7.1+",
commit = "89d2c75066bea3d9c942f29dd1d2ea543c58d6d5"
)
load("@build_bazel_rules_typescript//:setup.bzl", "ts_setup_workspace")
ts_setup_workspace()
local_repository(
name = "angular",
path = "packages/bazel",
)
local_repository(
name = "rxjs",
path = "node_modules/rxjs/src",
)
git_repository(
name = "com_github_bazelbuild_buildtools",
remote = "https://github.com/bazelbuild/buildtools.git",
# Note, this commit matches the version of buildifier in angular/ngcontainer
# If you change this, also check if it matches the version in the angular/ngcontainer
# version in /.circleci/config.yml
commit = "b3b620e8bcff18ed3378cd3f35ebeb7016d71f71",
)
# The PKG rules are needed to build tar packages for integration tests. The builtin
# rule in `@bazel_tools` is not Windows compatible and outdated.
http_archive(
name = "rules_pkg",
sha256 = "62eeb544ff1ef41d786e329e1536c1d541bb9bcad27ae984d57f18f314018e66",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.6.0/rules_pkg-0.6.0.tar.gz",
"https://github.com/bazelbuild/rules_pkg/releases/download/0.6.0/rules_pkg-0.6.0.tar.gz",
],
name = "io_bazel_rules_go",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.7.1/rules_go-0.7.1.tar.gz",
sha256 = "341d5eacef704415386974bc82a1783a8b7ffbff2ab6ba02375e1ca20d9b031c",
)
# Fetch Aspect lib for utilities like write_source_files
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
go_rules_dependencies()
go_register_toolchains()
# Fetching the Bazel source code allows us to compile the Skylark linter
http_archive(
name = "aspect_bazel_lib",
sha256 = "5f5f1237601d41d61608ad0b9541614935839232940010f9e62163c3e53dc1b7",
strip_prefix = "bazel-lib-0.5.0",
url = "https://github.com/aspect-build/bazel-lib/archive/refs/tags/v0.5.0.tar.gz",
)
# Setup the Node.js toolchain.
load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")
nodejs_register_toolchains(
name = "nodejs",
node_version = "16.10.0",
)
# Download npm dependencies.
load("@build_bazel_rules_nodejs//:index.bzl", "yarn_install")
load("//integration:npm_package_archives.bzl", "npm_package_archives")
yarn_install(
name = "npm",
# Note that we add the postinstall scripts here so that the dependencies are re-installed
# when the postinstall patches are modified.
data = [
"//:.yarn/releases/yarn-1.22.17.cjs",
"//:.yarnrc",
"//:scripts/puppeteer-chromedriver-versions.js",
"//:scripts/webdriver-manager-update.js",
"//tools:postinstall-patches.js",
],
# Currently disabled due to:
# 1. Missing Windows support currently.
# 2. Incompatibilites with the `ts_library` rule.
exports_directories_only = False,
manual_build_file_contents = npm_package_archives(),
package_json = "//:package.json",
# We prefer to symlink the `node_modules` to only maintain a single install.
# See https://github.com/angular/dev-infra/pull/446#issuecomment-1059820287 for details.
symlink_node_modules = True,
yarn = "//:.yarn/releases/yarn-1.22.17.cjs",
yarn_lock = "//:yarn.lock",
)
yarn_install(
name = "aio_npm",
# Note that we add the postinstall scripts here so that the dependencies are re-installed
# when the postinstall patches are modified.
data = [
"//:.yarn/releases/yarn-1.22.17.cjs",
"//:.yarnrc",
"//aio:tools/cli-patches/patch.js",
],
# Currently disabled due to:
# 1. Missing Windows support currently.
# 2. Incompatibilites with the `ts_library` rule.
exports_directories_only = False,
manual_build_file_contents = npm_package_archives(),
package_json = "//aio:package.json",
# We prefer to symlink the `node_modules` to only maintain a single install.
# See https://github.com/angular/dev-infra/pull/446#issuecomment-1059820287 for details.
symlink_node_modules = True,
yarn = "//:.yarn/releases/yarn-1.22.17.cjs",
yarn_lock = "//aio:yarn.lock",
)
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies")
aspect_bazel_lib_dependencies()
# Load protractor dependencies
load("@npm//@bazel/protractor:package.bzl", "npm_bazel_protractor_dependencies")
npm_bazel_protractor_dependencies()
# Setup the rules_webtesting toolchain
load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories")
web_test_repositories()
load("@npm//@angular/build-tooling/bazel/browsers:browser_repositories.bzl", "browser_repositories")
browser_repositories()
load("@build_bazel_rules_nodejs//toolchains/esbuild:esbuild_repositories.bzl", "esbuild_repositories")
esbuild_repositories(
npm_repository = "npm",
)
load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
rules_pkg_dependencies()
load("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_json_data_repository", "cldr_xml_data_repository")
cldr_major_version = "41"
cldr_json_data_repository(
name = "cldr_json_data",
urls = {
"https://github.com/unicode-org/cldr-json/releases/download/%s.0.0/cldr-%s.0.0-json-full.zip" % (cldr_major_version, cldr_major_version): "649b76647269e32b1b0a5f7b6eed52e9e63a1581f1afdcf4f6771e49c9713614",
},
)
cldr_xml_data_repository(
name = "cldr_xml_data",
urls = {
"https://github.com/unicode-org/cldr/releases/download/release-%s/cldr-common-%s.0.zip" % (cldr_major_version, cldr_major_version): "823c6170c41e2de2c229574e8a436332d25f1c9723409867fe721e00bc92d853",
},
)
# sass rules
http_archive(
name = "io_bazel_rules_sass",
sha256 = "0cde2dd9ff34994f27ba4d5c74d34cca3c727bf41bc6024cf66ad298a1f5e5c2",
strip_prefix = "rules_sass-f6ceac7f5e11424880ae41f9c1a5cfd02968376c",
urls = [
"https://github.com/bazelbuild/rules_sass/archive/f6ceac7f5e11424880ae41f9c1a5cfd02968376c.zip",
],
)
# Setup the rules_sass toolchain
load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
sass_repositories(
yarn_script = "//:.yarn/releases/yarn-1.22.17.cjs",
name = "io_bazel",
url = "https://github.com/bazelbuild/bazel/archive/9755c72b48866ed034bd28aa033e9abd27431b1e.zip",
strip_prefix = "bazel-9755c72b48866ed034bd28aa033e9abd27431b1e",
sha256 = "5b8443fc3481b5fcd9e7f348e1dd93c1397f78b223623c39eb56494c55f41962",
)
+70
View File
@@ -0,0 +1,70 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "site"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"generated",
"app/search/search-worker.js",
"favicon.ico",
"pwa-manifest.json",
"google385281288605d160.html"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "aio",
"serviceWorker": false,
"styles": [
"styles.scss"
],
"scripts": [
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"next": "environments/environment.next.ts",
"stable": "environments/environment.stable.ts",
"archive": "environments/environment.archive.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "scss",
"component": {
"inlineStyle": true
},
"build": {
"namedChunks": true
}
}
}
-16
View File
@@ -1,16 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
-94
View File
@@ -1,94 +0,0 @@
{
"root": true,
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"tests/e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@typescript-eslint/ban-types": "error",
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "aio",
"style": "kebab-case"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "aio",
"style": "camelCase"
}
],
"dot-notation": "error",
"indent": "off",
"max-len": ["error", 120],
"@typescript-eslint/member-delimiter-style": ["error", {
"singleline": {
"delimiter": "comma",
"requireLast": false
}
}],
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/naming-convention": "off",
"no-console": ["error", {"allow": ["log", "warn", "error"]}],
"no-empty-function": "off",
"@angular-eslint/no-host-metadata-property": "off",
"no-restricted-syntax": [
"error",
{
"selector": "CallExpression[callee.name=/^(fdescribe|fit)$/]",
"message": "Don't keep jasmine focus methods."
}
],
"no-shadow": "off",
"@typescript-eslint/no-shadow": ["error"],
"no-tabs": "error",
"no-underscore-dangle": "off",
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": ["error"],
"no-use-before-define": "off",
"prefer-arrow/prefer-arrow-functions": "off",
"quotes": "off",
"@typescript-eslint/quotes": ["error", "single", {"avoidEscape": true}],
"semi": "error"
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {
"@angular-eslint/template/accessibility-alt-text": "error",
"@angular-eslint/template/accessibility-elements-content": "error",
"@angular-eslint/template/accessibility-label-has-associated-control": "error",
"@angular-eslint/template/accessibility-table-scope": "error",
"@angular-eslint/template/accessibility-valid-aria": "error",
"@angular-eslint/template/click-events-have-key-events": "error",
"@angular-eslint/template/eqeqeq": "off",
"@angular-eslint/template/mouse-events-have-key-events": "error",
"@angular-eslint/template/no-autofocus": "error",
"@angular-eslint/template/no-distracting-elements": "error",
"@angular-eslint/template/no-positive-tabindex": "error"
}
}
]
}
+16 -16
View File
@@ -1,19 +1,16 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
# compiled output
/dist
/tmp
/out-tsc
/bazel-out
/src/generated
/tmp
# Node
# dependencies
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
/.idea
.project
.classpath
.c9/
@@ -21,28 +18,31 @@ yarn-error.log
.settings/
*.sublime-workspace
# Visual Studio Code
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
/.firebase/
.sass-cache/
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
firebase-debug.log
npm-debug.log
testem.log
/typings
yarn-error.log
# e2e
/e2e/*.js
/e2e/*.map
protractor-results*.txt
# System files
# System Files
.DS_Store
Thumbs.db
# copied dependencies
src/assets/js/lunr*
-1
View File
@@ -1 +0,0 @@
engine-strict = true
-116
View File
@@ -1,116 +0,0 @@
load("@aio_npm//@angular-devkit/architect-cli:index.bzl", "architect", "architect_test")
load("//tools:defaults.bzl", "npm_package_bin")
# The write_source_files macro is used to write bazel outputs to the source tree and test that they are up to date.
# See: https://docs.aspect.build/aspect-build/bazel-lib/v0.5.0/docs/docs/write_source_files-docgen.html
load("@aspect_bazel_lib//lib:write_source_files.bzl", generated_files_test = "write_source_files")
exports_files([
"firebase.json",
"ngsw-config.template.json",
])
# Generate ngsw-config
npm_package_bin(
name = "ngsw-config",
outs = ["ngsw-config_generated.json"],
args = ["$@"],
tool = "//aio/scripts:build-ngsw-config",
)
# Write ngsw-config to the source directory and test that it's up to date
generated_files_test(
name = "write-ngsw-config",
files = {
"ngsw-config.json": ":ngsw-config",
},
)
# All source and configuration files required to build the docs app
APPLICATION_FILES = [
"angular.json",
"ngsw-config.json",
"package.json",
"tsconfig.app.json",
"tsconfig.json",
"tsconfig.worker.json",
] + glob(
["src/**/*"],
exclude = [
"src/**/*.spec.ts",
# Temporarily exclude generated sources produced by the non-bazel
# build until the whole project is built by bazel and this directory
# isn't needed.
"src/generated/**/*",
],
)
# External dependencies from aio/package.json required to build the docs app.
APPLICATION_DEPS = [
"@aio_npm//@angular-devkit/build-angular",
"@aio_npm//@angular/animations",
"@aio_npm//@angular/cdk",
"@aio_npm//@angular/cli",
"@aio_npm//@angular/common",
"@aio_npm//@angular/compiler",
"@aio_npm//@angular/core",
"@aio_npm//@angular/elements",
"@aio_npm//@angular/forms",
"@aio_npm//@angular/material",
"@aio_npm//@angular/platform-browser",
"@aio_npm//@angular/platform-browser-dynamic",
"@aio_npm//@angular/router",
"@aio_npm//@angular/service-worker",
"@aio_npm//@types/lunr",
"@aio_npm//@types/trusted-types",
"@aio_npm//lunr",
"@aio_npm//rxjs",
"@aio_npm//safevalues",
"@aio_npm//tslib",
"@aio_npm//zone.js",
]
# All sources, specs, and config files required to test the docs app
TEST_FILES = APPLICATION_FILES + [
"karma.conf.js",
"tsconfig.spec.json",
] + glob(
["src/**/*.spec.ts"],
)
# External dependencies from aio/package.json required to test the docs app
TEST_DEPS = APPLICATION_DEPS + [
"@aio_npm//@types/jasmine",
"@aio_npm//@types/node",
"@aio_npm//assert",
"@aio_npm//jasmine",
"@aio_npm//jasmine-core",
"@aio_npm//karma-chrome-launcher",
"@aio_npm//karma-coverage",
"@aio_npm//karma-jasmine",
"@aio_npm//karma-jasmine-html-reporter",
"@aio_npm//puppeteer",
]
architect(
name = "build",
args = [
"site:build:stable",
"--outputPath=../$(@D)",
],
chdir = package_name(),
configuration_env_vars = ["NG_BUILD_CACHE"],
data = APPLICATION_FILES + APPLICATION_DEPS,
output_dir = True,
)
architect_test(
name = "test",
args = [
"site:test",
"--no-watch",
],
chdir = package_name(),
configuration_env_vars = ["NG_BUILD_CACHE"],
data = TEST_FILES + TEST_DEPS,
)
+26 -32
View File
@@ -1,29 +1,28 @@
# Angular documentation project (https://angular.io)
Everything in this folder is part of the documentation project. This includes:
Everything in this folder is part of the documentation project. This includes
* the web site for displaying the documentation.
* the web site for displaying the documentation
* the dgeni configuration for converting source files to rendered files that can be viewed in the web site.
* the tooling for setting up examples for development; and generating live-example and zip files from the examples.
* the tooling for setting up examples for development; and generating plunkers and zip files from the examples.
<a name="developer-tasks"></a>
## Developer tasks
We use [Yarn](https://yarnpkg.com) to manage the dependencies and to run build tasks.
We use `yarn` to manage the dependencies and to run build tasks.
You should run all these tasks from the `angular/aio` folder.
Here are the most important tasks you might need to use:
* `yarn` - install all the dependencies.
* `yarn setup` - install all the dependencies, boilerplate, stackblitz, zips and run dgeni on the docs.
* `yarn setup-local` - same as `setup`, but build the Angular packages from the source code and use these locally built versions (instead of the ones fetched from npm) for aio and docs examples boilerplate.
* `yarn setup` - install all the dependencies, boilerplate, plunkers, zips and run dgeni on the docs.
* `yarn setup-local` - same as `setup`, but use the locally built Angular packages for aio and docs examples boilerplate.
* `yarn build` - create a production build of the application (after installing dependencies, boilerplate, etc).
* `yarn build-local` - same as `build`, but use `setup-local` instead of `setup`.
* `yarn start` - run a development web server that watches the files; then builds the doc-viewer and reloads the page, as necessary.
* `yarn serve-and-sync` - run both the `docs-watch` and `start` in the same console.
* `yarn lint` - check that the doc-viewer code follows our style rules.
* `yarn test` - watch all the source files, for the doc-viewer, and run all the unit tests when any change.
* `yarn test --watch=false` - run all the unit tests once.
* `yarn e2e` - run all the e2e tests for the doc-viewer.
* `yarn docs` - generate all the docs from the source files.
@@ -31,41 +30,35 @@ Here are the most important tasks you might need to use:
* `yarn docs-lint` - check that the doc gen code follows our style rules.
* `yarn docs-test` - run the unit tests for the doc generation code.
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally.
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally. Add the option `--local` to use your local version of Angular contained in the "dist" folder.
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
* `yarn create-example` - create a new example directory containing initial source files.
* `yarn generate-stackblitz` - generate the stackblitz files that are used by the `live-example` tags in the docs.
* `yarn generate-plunkers` - generate the plunker files that are used by the `live-example` tags in the docs.
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
* `yarn example-e2e` - run all e2e tests for examples. Available options:
- `--setup`: generate boilerplate, force webdriver update & other setup, then run tests.
- `--local`: run e2e tests with the local version of Angular contained in the "dist" folder.
_Requires `--setup` in order to take effect._
- `--filter=foo`: limit e2e tests to those containing the word "foo".
* `yarn example-e2e` - run all e2e tests for examples
- `yarn example-e2e --setup` - force webdriver update & other setup, then run tests
- `yarn example-e2e --filter=foo` - limit e2e tests to those containing the word "foo"
- `yarn example-e2e --setup --local` - run e2e tests with the local version of Angular contained in the "dist" folder
> **Note for Windows users**
>
> Setting up the examples involves creating some [symbolic links](https://en.wikipedia.org/wiki/Symbolic_link) (see [here](./tools/examples/README.md#symlinked-node_modules) for details). On Windows, this requires to either have [Developer Mode enabled](https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10) (supported on Windows 10 or newer) or run the setup commands as administrator.
>
> The affected commands are:
> - `yarn setup` / `yarn setup-*`
> - `yarn build` / `yarn build-*`
> - `yarn boilerplate:add`
> - `yarn example-e2e --setup`
* `yarn build-ie-polyfills` - generates a js file of polyfills that can be loaded in Internet Explorer.
## Using ServiceWorker locally
Running `yarn start` (even when explicitly targeting production mode) does not set up the
ServiceWorker. If you want to test the ServiceWorker locally, you can use `yarn build` and then
serve the files in `dist/` with `yarn http-server dist -p 4200`.
Since abb36e3cb, running `yarn start --prod` will no longer set up the ServiceWorker, which
would require manually running `yarn sw-manifest` and `yarn sw-copy` (something that is not possible
with webpack serving the files from memory).
If you want to test ServiceWorker locally, you can use `yarn build` and serve the files in `dist/`
with `yarn http-server dist -p 4200`.
For more details see #16745.
## Guide to authoring
There are two types of content in the documentation:
* **API docs**: descriptions of all that make up the Angular platform, such as the modules, classes, interfaces or decorators.
* **API docs**: descriptions of the modules, classes, interfaces, decorators, etc that make up the Angular platform.
API docs are generated directly from the source code.
The source code is contained in TypeScript files, located in the `angular/packages` folder.
Each API item may have a preceding comment, which contains JSDoc style tags and content.
@@ -101,7 +94,7 @@ You also want to see those changes displayed properly in the doc viewer
with a quick, edit/view cycle time.
For this purpose, use the `yarn docs-watch` task, which watches for changes to source files and only
re-processes the files necessary to generate the docs that are related to the file that has changed.
re-processes the the files necessary to generate the docs that are related to the file that has changed.
Since this task takes shortcuts, it is much faster (often less than 1 second) but it won't produce full
fidelity content. For example, links to other docs and code examples may not render correctly. This is
most particularly noticed in links to other docs and in the embedded examples, which may not always render
@@ -112,7 +105,8 @@ The general setup is as follows:
* Open a terminal, ensure the dependencies are installed; run an initial doc generation; then start the doc-viewer:
```bash
yarn setup
yarn
yarn docs
yarn start
```
-42
View File
@@ -1,42 +0,0 @@
# Update the angular.io app
The dependencies of the angular.io app (including Angular, Angular Material and Angular CLI) are automatically updated using [Renovate](https://renovatebot.com/).
However, it is useful to periodically also manually update the app to more closely match (in file layout, configs, etc.) what a new Angular CLI app would look like.
This is typically only needed once for each new major Angular version.
Since angular.io is an Angular CLI app, we can take advantage of `ng update` to apply migrations.
Follow these steps to align the angular.io app with new CLI apps.
> **Note:**
> The following steps assume that the related Angular dependencies have already been updated in [aio/package.json](./package.json) (for example, automatically by Renovate).
> **Note:**
> All commands shown below are expected to be executed from inside the [aio/](./) directory (unless specified otherwise).
- Determine (for example, by examining git history) what is the last versions for which this process was performed.
These will be referred to as `<FROM_VERSION_*>`.
If you can't determine these, use arbitrary versions, such as the previous major version.
- Run the following commands to automatically apply any available migrations to the project:
```sh
# Ensure dependencies are installed.
yarn install
# Migrate project to new versions.
yarn ng update @angular/cli --allow-dirty --migrate-only --from=<FROM_VERSION_CLI>
yarn ng update @angular/core --allow-dirty --migrate-only --from=<FROM_VERSION_ANGULAR>
yarn ng update @angular/material --allow-dirty --migrate-only --from=<FROM_VERSION_MATERIAL>
```
> **Note:**
> Depending on the number of changes generated from each `ng update` command, it might make sense to create a separate commit for each update.
- Inspect [package.json](./package.json) to determine what is the current version of Angular CLI (i.e. `@angular/cli`) used in the app.
This will be referred to as `<TO_VERSION_CLI>`.
- Use the [angular-cli-diff](https://github.com/cexbrayat/angular-cli-diff) repository to discover more changes (which are not automatically applied via `ng update` migrations) between Angular CLI apps of different versions.
Visit https://github.com/cexbrayat/angular-cli-diff/compare/<FROM_VERSION_CLI>...<TO_VERSION_CLI>, inspect the changes between the two versions and apply the ones that make sense to the angular.io source code.
- Commit all changes and [submit a pull request](../CONTRIBUTING.md#submit-pr).
+48 -59
View File
@@ -1,5 +1,5 @@
# Image metadata and config
FROM debian:bullseye
FROM debian:jessie
LABEL name="angular.io PR preview" \
description="This image implements the PR preview functionality for angular.io." \
@@ -8,62 +8,53 @@ LABEL name="angular.io PR preview" \
VOLUME /aio-secrets
VOLUME /var/www/aio-builds
VOLUME /dockerbuild
EXPOSE 80 443
# Build-time args and env vars
# The AIO_ARTIFACT_PATH path needs to be kept in synch with the value of
# `aio_preview->steps->store_artifacts->destination` property in `.circleci/config.yml`
ARG AIO_ARTIFACT_PATH=aio/dist/aio-snapshot.tgz
ARG TEST_AIO_ARTIFACT_PATH=$AIO_ARTIFACT_PATH
ARG AIO_BUILDS_DIR=/var/www/aio-builds
ARG TEST_AIO_BUILDS_DIR=/tmp/aio-builds
ARG AIO_DOMAIN_NAME=ngbuilds.io
ARG TEST_AIO_DOMAIN_NAME=$AIO_DOMAIN_NAME.localhost
ARG AIO_GITHUB_ORGANIZATION=angular
ARG TEST_AIO_GITHUB_ORGANIZATION=test-org
ARG AIO_GITHUB_REPO=angular
ARG TEST_AIO_GITHUB_REPO=test-repo
ARG AIO_GITHUB_TEAM_SLUGS=aio-auto-previews,aio-contributors
ARG TEST_AIO_GITHUB_TEAM_SLUGS=test-team-1,test-team-2
ARG TEST_AIO_GITHUB_ORGANIZATION=angular
ARG AIO_GITHUB_TEAM_SLUGS=angular-core,aio-contributors
ARG TEST_AIO_GITHUB_TEAM_SLUGS=angular-core,aio-contributors
ARG AIO_NGINX_HOSTNAME=$AIO_DOMAIN_NAME
ARG TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_DOMAIN_NAME
ARG AIO_NGINX_PORT_HTTP=80
ARG TEST_AIO_NGINX_PORT_HTTP=8080
ARG AIO_NGINX_PORT_HTTPS=443
ARG TEST_AIO_NGINX_PORT_HTTPS=4433
ARG AIO_SIGNIFICANT_FILES_PATTERN='^(?:aio|packages)/(?!.*[._]spec\\.[jt]s$)'
ARG TEST_AIO_SIGNIFICANT_FILES_PATTERN=$AIO_SIGNIFICANT_FILES_PATTERN
ARG AIO_REPO_SLUG=angular/angular
ARG TEST_AIO_REPO_SLUG=test-repo/test-slug
ARG AIO_TRUSTED_PR_LABEL="aio: preview"
ARG TEST_AIO_TRUSTED_PR_LABEL=$AIO_TRUSTED_PR_LABEL
ARG AIO_PREVIEW_SERVER_HOSTNAME=preview.localhost
ARG TEST_AIO_PREVIEW_SERVER_HOSTNAME=$AIO_PREVIEW_SERVER_HOSTNAME
ARG AIO_ARTIFACT_MAX_SIZE=36700160
ARG TEST_AIO_ARTIFACT_MAX_SIZE=200
ARG AIO_PREVIEW_SERVER_PORT=3000
ARG TEST_AIO_PREVIEW_SERVER_PORT=3001
ARG TEST_AIO_TRUSTED_PR_LABEL="aio: preview"
ARG AIO_UPLOAD_HOSTNAME=upload.localhost
ARG TEST_AIO_UPLOAD_HOSTNAME=upload.localhost
ARG AIO_UPLOAD_MAX_SIZE=20971520
ARG TEST_AIO_UPLOAD_MAX_SIZE=20971520
ARG AIO_UPLOAD_PORT=3000
ARG TEST_AIO_UPLOAD_PORT=3001
ENV AIO_ARTIFACT_PATH=$AIO_ARTIFACT_PATH TEST_AIO_ARTIFACT_PATH=$TEST_AIO_ARTIFACT_PATH \
AIO_BUILDS_DIR=$AIO_BUILDS_DIR TEST_AIO_BUILDS_DIR=$TEST_AIO_BUILDS_DIR \
AIO_DOMAIN_NAME=$AIO_DOMAIN_NAME TEST_AIO_DOMAIN_NAME=$TEST_AIO_DOMAIN_NAME \
AIO_GITHUB_ORGANIZATION=$AIO_GITHUB_ORGANIZATION TEST_AIO_GITHUB_ORGANIZATION=$TEST_AIO_GITHUB_ORGANIZATION \
AIO_GITHUB_REPO=$AIO_GITHUB_REPO TEST_AIO_GITHUB_REPO=$TEST_AIO_GITHUB_REPO \
AIO_GITHUB_TEAM_SLUGS=$AIO_GITHUB_TEAM_SLUGS TEST_AIO_GITHUB_TEAM_SLUGS=$TEST_AIO_GITHUB_TEAM_SLUGS \
AIO_LOCALCERTS_DIR=/etc/ssl/localcerts TEST_AIO_LOCALCERTS_DIR=/etc/ssl/localcerts-test \
AIO_NGINX_HOSTNAME=$AIO_NGINX_HOSTNAME TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_NGINX_HOSTNAME \
AIO_NGINX_LOGS_DIR=/var/log/aio/nginx TEST_AIO_NGINX_LOGS_DIR=/var/log/aio/nginx-test \
AIO_NGINX_PORT_HTTP=$AIO_NGINX_PORT_HTTP TEST_AIO_NGINX_PORT_HTTP=$TEST_AIO_NGINX_PORT_HTTP \
AIO_NGINX_PORT_HTTPS=$AIO_NGINX_PORT_HTTPS TEST_AIO_NGINX_PORT_HTTPS=$TEST_AIO_NGINX_PORT_HTTPS \
AIO_SCRIPTS_JS_DIR=/usr/share/aio-scripts-js \
AIO_SCRIPTS_SH_DIR=/usr/share/aio-scripts-sh \
AIO_SIGNIFICANT_FILES_PATTERN=$AIO_SIGNIFICANT_FILES_PATTERN TEST_AIO_SIGNIFICANT_FILES_PATTERN=$TEST_AIO_SIGNIFICANT_FILES_PATTERN \
AIO_TRUSTED_PR_LABEL=$AIO_TRUSTED_PR_LABEL TEST_AIO_TRUSTED_PR_LABEL=$TEST_AIO_TRUSTED_PR_LABEL \
AIO_PREVIEW_SERVER_HOSTNAME=$AIO_PREVIEW_SERVER_HOSTNAME TEST_AIO_PREVIEW_SERVER_HOSTNAME=$TEST_AIO_PREVIEW_SERVER_HOSTNAME \
AIO_ARTIFACT_MAX_SIZE=$AIO_ARTIFACT_MAX_SIZE TEST_AIO_ARTIFACT_MAX_SIZE=$TEST_AIO_ARTIFACT_MAX_SIZE \
AIO_PREVIEW_SERVER_PORT=$AIO_PREVIEW_SERVER_PORT TEST_AIO_PREVIEW_SERVER_PORT=$TEST_AIO_PREVIEW_SERVER_PORT \
AIO_WWW_USER=www-data \
ENV AIO_BUILDS_DIR=$AIO_BUILDS_DIR TEST_AIO_BUILDS_DIR=$TEST_AIO_BUILDS_DIR \
AIO_DOMAIN_NAME=$AIO_DOMAIN_NAME TEST_AIO_DOMAIN_NAME=$TEST_AIO_DOMAIN_NAME \
AIO_GITHUB_ORGANIZATION=$AIO_GITHUB_ORGANIZATION TEST_AIO_GITHUB_ORGANIZATION=$TEST_AIO_GITHUB_ORGANIZATION \
AIO_GITHUB_TEAM_SLUGS=$AIO_GITHUB_TEAM_SLUGS TEST_AIO_GITHUB_TEAM_SLUGS=$TEST_AIO_GITHUB_TEAM_SLUGS \
AIO_LOCALCERTS_DIR=/etc/ssl/localcerts TEST_AIO_LOCALCERTS_DIR=/etc/ssl/localcerts-test \
AIO_NGINX_HOSTNAME=$AIO_NGINX_HOSTNAME TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_NGINX_HOSTNAME \
AIO_NGINX_LOGS_DIR=/var/log/aio/nginx TEST_AIO_NGINX_LOGS_DIR=/var/log/aio/nginx-test \
AIO_NGINX_PORT_HTTP=$AIO_NGINX_PORT_HTTP TEST_AIO_NGINX_PORT_HTTP=$TEST_AIO_NGINX_PORT_HTTP \
AIO_NGINX_PORT_HTTPS=$AIO_NGINX_PORT_HTTPS TEST_AIO_NGINX_PORT_HTTPS=$TEST_AIO_NGINX_PORT_HTTPS \
AIO_REPO_SLUG=$AIO_REPO_SLUG TEST_AIO_REPO_SLUG=$TEST_AIO_REPO_SLUG \
AIO_SCRIPTS_JS_DIR=/usr/share/aio-scripts-js \
AIO_SCRIPTS_SH_DIR=/usr/share/aio-scripts-sh \
AIO_TRUSTED_PR_LABEL=$AIO_TRUSTED_PR_LABEL TEST_AIO_TRUSTED_PR_LABEL=$TEST_AIO_TRUSTED_PR_LABEL \
AIO_UPLOAD_HOSTNAME=$AIO_UPLOAD_HOSTNAME TEST_AIO_UPLOAD_HOSTNAME=$TEST_AIO_UPLOAD_HOSTNAME \
AIO_UPLOAD_MAX_SIZE=$AIO_UPLOAD_MAX_SIZE TEST_AIO_UPLOAD_MAX_SIZE=$TEST_AIO_UPLOAD_MAX_SIZE \
AIO_UPLOAD_PORT=$AIO_UPLOAD_PORT TEST_AIO_UPLOAD_PORT=$TEST_AIO_UPLOAD_PORT \
AIO_WWW_USER=www-data \
NODE_ENV=production
@@ -73,28 +64,24 @@ RUN mkdir /var/log/aio
# Add extra package sources
RUN apt-get update -y && apt-get install -y curl
RUN curl --silent --show-error --location https://deb.nodesource.com/setup_14.x | bash -
RUN curl --silent --show-error --location https://deb.nodesource.com/setup_6.x | bash -
RUN curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/backports.list
# Install packages
# NOTE: Many packages make older versions unavailable on the repositories, so we cannot pin to
# specific versions :(
# See, for example:
# - https://github.com/nodesource/distributions/issues/33
# - https://askubuntu.com/questions/715104/how-can-i-downgrade-openssl-via-apt-get
RUN apt-get update -y && apt-get install -y \
chkconfig \
cron \
dnsmasq \
nano \
nginx \
nodejs \
openssl \
rsyslog \
vim \
yarn=1.22.18-1
RUN yarn global add pm2@5.2.0
yarn
RUN apt-get install -t jessie-backports -y nginx
RUN yarn global add pm2@2
# Set up log rotation
@@ -112,9 +99,9 @@ RUN printenv | grep AIO_ >> /etc/environment
# Set up dnsmasq
COPY dnsmasq/dnsmasq.conf /etc/
RUN sed -i "s|{{\$AIO_NGINX_HOSTNAME}}|$AIO_NGINX_HOSTNAME|g" /etc/dnsmasq.conf
RUN sed -i "s|{{\$AIO_PREVIEW_SERVER_HOSTNAME}}|$AIO_PREVIEW_SERVER_HOSTNAME|g" /etc/dnsmasq.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$AIO_UPLOAD_HOSTNAME|g" /etc/dnsmasq.conf
RUN sed -i "s|{{\$TEST_AIO_NGINX_HOSTNAME}}|$TEST_AIO_NGINX_HOSTNAME|g" /etc/dnsmasq.conf
RUN sed -i "s|{{\$TEST_AIO_PREVIEW_SERVER_HOSTNAME}}|$TEST_AIO_PREVIEW_SERVER_HOSTNAME|g" /etc/dnsmasq.conf
RUN sed -i "s|{{\$TEST_AIO_UPLOAD_HOSTNAME}}|$TEST_AIO_UPLOAD_HOSTNAME|g" /etc/dnsmasq.conf
# Set up SSL/TLS certificates
@@ -138,9 +125,9 @@ RUN sed -i "s|{{\$AIO_LOCALCERTS_DIR}}|$AIO_LOCALCERTS_DIR|g" /etc/nginx/conf.d/
RUN sed -i "s|{{\$AIO_NGINX_LOGS_DIR}}|$AIO_NGINX_LOGS_DIR|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTP}}|$AIO_NGINX_PORT_HTTP|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTPS}}|$AIO_NGINX_PORT_HTTPS|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_PREVIEW_SERVER_HOSTNAME}}|$AIO_PREVIEW_SERVER_HOSTNAME|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_ARTIFACT_MAX_SIZE}}|$AIO_ARTIFACT_MAX_SIZE|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_PREVIEW_SERVER_PORT}}|$AIO_PREVIEW_SERVER_PORT|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$AIO_UPLOAD_HOSTNAME|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_MAX_SIZE}}|$AIO_UPLOAD_MAX_SIZE|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$AIO_UPLOAD_PORT|g" /etc/nginx/conf.d/aio-builds-prod.conf
COPY nginx/aio-builds.conf /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_BUILDS_DIR}}|$TEST_AIO_BUILDS_DIR|g" /etc/nginx/conf.d/aio-builds-test.conf
@@ -149,13 +136,14 @@ RUN sed -i "s|{{\$AIO_LOCALCERTS_DIR}}|$TEST_AIO_LOCALCERTS_DIR|g" /etc/nginx/co
RUN sed -i "s|{{\$AIO_NGINX_LOGS_DIR}}|$TEST_AIO_NGINX_LOGS_DIR|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTP}}|$TEST_AIO_NGINX_PORT_HTTP|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTPS}}|$TEST_AIO_NGINX_PORT_HTTPS|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_PREVIEW_SERVER_HOSTNAME}}|$TEST_AIO_PREVIEW_SERVER_HOSTNAME|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_ARTIFACT_MAX_SIZE}}|$TEST_AIO_ARTIFACT_MAX_SIZE|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_PREVIEW_SERVER_PORT}}|$TEST_AIO_PREVIEW_SERVER_PORT|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$TEST_AIO_UPLOAD_HOSTNAME|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_MAX_SIZE}}|$TEST_AIO_UPLOAD_MAX_SIZE|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$TEST_AIO_UPLOAD_PORT|g" /etc/nginx/conf.d/aio-builds-test.conf
# Set up pm2
RUN pm2 startup --user root > /dev/null
RUN pm2 startup systemv -u root > /dev/null
RUN chkconfig pm2-root on
# Set up the shell scripts
@@ -167,7 +155,8 @@ RUN find $AIO_SCRIPTS_SH_DIR -maxdepth 1 -type f -printf "%P\n" \
# Set up the Node.js scripts
COPY scripts-js/ $AIO_SCRIPTS_JS_DIR/
RUN yarn --cwd="$AIO_SCRIPTS_JS_DIR/" install --production --frozen-lockfile
WORKDIR $AIO_SCRIPTS_JS_DIR/
RUN yarn install --production --frozen-lockfile
# Set up health check
@@ -1,2 +1,2 @@
# Periodically clean up builds that do not correspond to currently open PRs
0 12 * * * /usr/local/bin/aio-clean-up >> /var/log/cron.log 2>&1
0 12 * * * root /usr/local/bin/aio-clean-up >> /var/log/cron.log 2>&1
@@ -8,9 +8,9 @@ listen-address=127.0.0.1
# Force an IP address for these domains.
address=/{{$AIO_NGINX_HOSTNAME}}/127.0.0.1
address=/{{$AIO_PREVIEW_SERVER_HOSTNAME}}/127.0.0.1
address=/{{$AIO_UPLOAD_HOSTNAME}}/127.0.0.1
address=/{{$TEST_AIO_NGINX_HOSTNAME}}/127.0.0.1
address=/{{$TEST_AIO_PREVIEW_SERVER_HOSTNAME}}/127.0.0.1
address=/{{$TEST_AIO_UPLOAD_HOSTNAME}}/127.0.0.1
# Run as root (required from inside docker container).
user=root
@@ -1,9 +0,0 @@
/var/log/aio/preview-server-*.log {
compress
copytruncate
delaycompress
missingok
monthly
notifempty
rotate 6
}
@@ -0,0 +1,9 @@
/var/log/aio/upload-server-*.log {
compress
copytruncate
delaycompress
missingok
monthly
notifempty
rotate 6
}
@@ -36,11 +36,6 @@ server {
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
error_page 404 /404.html;
location "=/404.html" {
internal;
}
location "~/[^/]+\.[^/]+$" {
try_files $uri $uri/ =404;
}
@@ -71,32 +66,24 @@ server {
return 200 '';
}
# Check PRs previewability
location "~^/can-have-public-preview/\d+/?$" {
if ($request_method != "GET") {
add_header Allow "GET";
return 405;
}
proxy_pass_request_headers on;
proxy_redirect off;
proxy_method GET;
proxy_pass http://{{$AIO_PREVIEW_SERVER_HOSTNAME}}:{{$AIO_PREVIEW_SERVER_PORT}}$request_uri;
resolver 127.0.0.1;
}
# Notify about CircleCI builds
location "~^/circle-build/?$" {
# Upload builds
location "~^/create-build/(?<pr>[1-9][0-9]*)/(?<sha>[0-9a-f]{40})/?$" {
if ($request_method != "POST") {
add_header Allow "POST";
return 405;
}
client_body_temp_path /tmp/aio-create-builds;
client_body_buffer_size 128K;
client_max_body_size {{$AIO_UPLOAD_MAX_SIZE}};
client_body_in_file_only on;
proxy_pass_request_headers on;
proxy_set_header X-FILE $request_body_file;
proxy_set_body off;
proxy_redirect off;
proxy_method POST;
proxy_pass http://{{$AIO_PREVIEW_SERVER_HOSTNAME}}:{{$AIO_PREVIEW_SERVER_PORT}}$request_uri;
proxy_method GET;
proxy_pass http://{{$AIO_UPLOAD_HOSTNAME}}:{{$AIO_UPLOAD_PORT}}$request_uri;
resolver 127.0.0.1;
}
@@ -111,7 +98,7 @@ server {
proxy_pass_request_headers on;
proxy_redirect off;
proxy_method POST;
proxy_pass http://{{$AIO_PREVIEW_SERVER_HOSTNAME}}:{{$AIO_PREVIEW_SERVER_PORT}}$request_uri;
proxy_pass http://{{$AIO_UPLOAD_HOSTNAME}}:{{$AIO_UPLOAD_PORT}}$request_uri;
resolver 127.0.0.1;
}
@@ -3,54 +3,29 @@ import * as fs from 'fs';
import * as path from 'path';
import * as shell from 'shelljs';
import {HIDDEN_DIR_PREFIX} from '../common/constants';
import {GithubApi} from '../common/github-api';
import {GithubPullRequests} from '../common/github-pull-requests';
import {assertNotMissingOrEmpty, getPrInfoFromDownloadPath, Logger} from '../common/utils';
import {assertNotMissingOrEmpty} from '../common/utils';
// Classes
export class BuildCleaner {
private logger = new Logger('BuildCleaner');
// Constructor
constructor(protected buildsDir: string, protected githubOrg: string, protected githubRepo: string,
protected githubToken: string, protected downloadsDir: string, protected artifactPath: string) {
constructor(protected buildsDir: string, protected repoSlug: string, protected githubToken: string) {
assertNotMissingOrEmpty('buildsDir', buildsDir);
assertNotMissingOrEmpty('githubOrg', githubOrg);
assertNotMissingOrEmpty('githubRepo', githubRepo);
assertNotMissingOrEmpty('repoSlug', repoSlug);
assertNotMissingOrEmpty('githubToken', githubToken);
assertNotMissingOrEmpty('downloadsDir', downloadsDir);
assertNotMissingOrEmpty('artifactPath', artifactPath);
}
// Methods - Public
public async cleanUp(): Promise<void> {
try {
this.logger.log('Cleaning up builds and downloads');
const openPrs = await this.getOpenPrNumbers();
this.logger.log(`Open pull requests: ${openPrs.length}`);
await Promise.all([
this.cleanBuilds(openPrs),
this.cleanDownloads(openPrs),
]);
} catch (error) {
this.logger.error('ERROR:', error);
throw error;
}
public cleanUp(): Promise<void> {
return Promise.all([
this.getExistingBuildNumbers(),
this.getOpenPrNumbers(),
]).then(([existingBuilds, openPrs]) => this.removeUnnecessaryBuilds(existingBuilds, openPrs));
}
public async cleanBuilds(openPrs: number[]): Promise<void> {
const existingBuilds = await this.getExistingBuildNumbers();
await this.removeUnnecessaryBuilds(existingBuilds, openPrs);
}
public async cleanDownloads(openPrs: number[]): Promise<void> {
const existingDownloads = await this.getExistingDownloads();
await this.removeUnnecessaryDownloads(existingDownloads, openPrs);
}
public getExistingBuildNumbers(): Promise<number[]> {
return new Promise<number[]>((resolve, reject) => {
// Methods - Protected
protected getExistingBuildNumbers(): Promise<number[]> {
return new Promise((resolve, reject) => {
fs.readdir(this.buildsDir, (err, files) => {
if (err) {
return reject(err);
@@ -66,29 +41,32 @@ export class BuildCleaner {
});
}
public async getOpenPrNumbers(): Promise<number[]> {
const api = new GithubApi(this.githubToken);
const githubPullRequests = new GithubPullRequests(api, this.githubOrg, this.githubRepo);
const prs = await githubPullRequests.fetchAll('open');
return prs.map(pr => pr.number);
protected getOpenPrNumbers(): Promise<number[]> {
const githubPullRequests = new GithubPullRequests(this.githubToken, this.repoSlug);
return githubPullRequests.
fetchAll('open').
then(prs => prs.map(pr => pr.number));
}
public removeDir(dir: string): void {
protected removeDir(dir: string) {
try {
if (shell.test('-d', dir)) {
shell.chmod('-R', 'a+w', dir);
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
(shell as any).chmod('-R', 'a+w', dir);
shell.rm('-rf', dir);
}
} catch (err) {
this.logger.error(`ERROR: Unable to remove '${dir}' due to:`, err);
console.error(`ERROR: Unable to remove '${dir}' due to:`, err);
}
}
public removeUnnecessaryBuilds(existingBuildNumbers: number[], openPrNumbers: number[]): void {
protected removeUnnecessaryBuilds(existingBuildNumbers: number[], openPrNumbers: number[]) {
const toRemove = existingBuildNumbers.filter(num => !openPrNumbers.includes(num));
this.logger.log(`Existing builds: ${existingBuildNumbers.length}`);
this.logger.log(`Removing ${toRemove.length} build(s): ${toRemove.join(', ')}`);
console.log(`Existing builds: ${existingBuildNumbers.length}`);
console.log(`Open pull requests: ${openPrNumbers.length}`);
console.log(`Removing ${toRemove.length} build(s): ${toRemove.join(', ')}`);
// Try removing public dirs.
toRemove.
@@ -100,29 +78,4 @@ export class BuildCleaner {
map(num => path.join(this.buildsDir, HIDDEN_DIR_PREFIX + String(num))).
forEach(dir => this.removeDir(dir));
}
public getExistingDownloads(): Promise<string[]> {
const artifactFile = path.basename(this.artifactPath);
return new Promise<string[]>((resolve, reject) => {
fs.readdir(this.downloadsDir, (err, files) => {
if (err) {
return reject(err);
}
files = files.filter(file => file.endsWith(artifactFile));
resolve(files);
});
});
}
public removeUnnecessaryDownloads(existingDownloads: string[], openPrNumbers: number[]): void {
const toRemove = existingDownloads.filter(filePath => {
const {pr} = getPrInfoFromDownloadPath(filePath);
return !openPrNumbers.includes(pr);
});
this.logger.log(`Existing downloads: ${existingDownloads.length}`);
this.logger.log(`Removing ${toRemove.length} download(s): ${toRemove.join(', ')}`);
toRemove.forEach(filePath => shell.rm(path.join(this.downloadsDir, filePath)));
}
}
@@ -1,26 +1,23 @@
// Imports
import {AIO_DOWNLOADS_DIR} from '../common/constants';
import {
AIO_ARTIFACT_PATH,
AIO_BUILDS_DIR,
AIO_GITHUB_ORGANIZATION,
AIO_GITHUB_REPO,
AIO_GITHUB_TOKEN,
} from '../common/env-variables';
import {getEnvVar} from '../common/utils';
import {BuildCleaner} from './build-cleaner';
// Constants
const AIO_BUILDS_DIR = getEnvVar('AIO_BUILDS_DIR');
const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN', true);
const AIO_REPO_SLUG = getEnvVar('AIO_REPO_SLUG');
// Run
_main();
// Functions
function _main(): void {
const buildCleaner = new BuildCleaner(
AIO_BUILDS_DIR,
AIO_GITHUB_ORGANIZATION,
AIO_GITHUB_REPO,
AIO_GITHUB_TOKEN,
AIO_DOWNLOADS_DIR,
AIO_ARTIFACT_PATH);
function _main() {
console.log(`[${new Date()}] - Cleaning up builds...`);
buildCleaner.cleanUp().catch(() => process.exit(1));
const buildCleaner = new BuildCleaner(AIO_BUILDS_DIR, AIO_REPO_SLUG, AIO_GITHUB_TOKEN);
buildCleaner.cleanUp().catch(err => {
console.error('ERROR:', err);
process.exit(1);
});
}
@@ -1,151 +0,0 @@
// Imports
import fetch, {RequestInit} from 'node-fetch';
import {assertNotMissingOrEmpty} from './utils';
// Constants
const CIRCLE_CI_BASE_API_URL = 'https://circleci.com/api/v2';
const CIRCLE_CI_BUILD_API_URL = `${CIRCLE_CI_BASE_API_URL}/project/gh`;
const CIRCLE_CI_PIPELINE_API_URL = `${CIRCLE_CI_BASE_API_URL}/pipeline`;
// Interfaces - Types
// API docs: https://circleci.com/docs/api/v2#operation/getJobArtifacts
// Example: https://circleci.com/api/v2/project/gh/angular/angular/1163941/artifacts
export interface ArtifactInfo {
/** The path of this build artifacts. */
path: string;
/** The full URL where this artifact can be downloaded from. */
url: string;
// There are other fields but they are not used in this code.
}
export type ArtifactResponse = {items: ArtifactInfo[]};
// API docs: https://circleci.com/docs/api/v2#operation/getJobDetails
// Example: https://circleci.com/api/v2/project/gh/angular/angular/job/1163941
export interface BuildInfo {
/** The job number. */
number: number;
/** The job name (e.g. `'aio_preview'`). */
name: string;
/** Info about the organization which the project related to this job belongs to. */
organization: {
name: string;
};
/** Info about the project related to this job. */
project: {
name: string;
};
/** Info about the [pipeline](https://circleci.com/docs/2.0/pipelines/) that this job is part of. */
pipeline: {
id: string;
};
// There are other fields but they are not used in this code.
}
// API docs: https://circleci.com/docs/api/v2#operation/getPipelineById
// https://circleci.com/api/v2/pipeline/356227c0-32f6-4f99-bfc2-3938db90a147
export interface PipelineInfo {
/** The pipeline ID. */
id: string;
/** Info related to/retrieved from the version control system provider (e.g. GitHub). */
vcs: {
/** The PR number. */
review_id: string;
/** The HEAD SHA. */
revision: string;
};
// There are other fields but they are not used in this code.
}
/**
* A Helper that can interact with the CircleCI API.
*/
export class CircleCiApi {
/**
* Construct a helper that can interact with the CircleCI REST API.
* @param githubOrg The Github organisation whose repos we want to access in CircleCI (e.g.
* angular).
* @param githubRepo The Github repo whose builds we want to access in CircleCI (e.g. angular).
* @param circleCiToken The CircleCI API access token (secret).
*/
constructor(
private githubOrg: string,
private githubRepo: string,
private circleCiToken: string,
) {
assertNotMissingOrEmpty('githubOrg', githubOrg);
assertNotMissingOrEmpty('githubRepo', githubRepo);
assertNotMissingOrEmpty('circleCiToken', circleCiToken);
}
public async fetchFromCircleCi(url: string, params: RequestInit = {}) {
params.headers = {...params.headers, 'Circle-Token': this.circleCiToken};
const response = await fetch(url, params);
if (response.status !== 200) {
throw new Error(`${url}: ${response.status} - ${response.statusText}`);
}
return response;
}
/**
* Get the info for a build (aka job) from the CircleCI API.
* @param buildNumber The CircleCI build number that generated the artifact.
* @returns A promise to the info about the build.
*/
public async getBuildInfo(buildNumber: number): Promise<BuildInfo> {
try {
const url = `${CIRCLE_CI_BUILD_API_URL}/${this.githubOrg}/${this.githubRepo}/job/${buildNumber}`;
const response = await this.fetchFromCircleCi(url);
return response.json();
} catch (error) {
throw new Error(`CircleCI build info request failed (${(error as Error).message})`);
}
}
/**
* Query the CircleCI API to get a URL for a specified artifact from a specified build.
* @param artifactPath The path, within the build to the artifact.
* @returns A promise to the URL that can be requested to download the actual build artifact file.
*/
public async getBuildArtifactUrl(buildNumber: number, artifactPath: string): Promise<string> {
const baseUrl = `${CIRCLE_CI_BUILD_API_URL}/${this.githubOrg}/${this.githubRepo}/${buildNumber}`;
try {
const response = await this.fetchFromCircleCi(`${baseUrl}/artifacts`);
const artifacts = await response.json() as ArtifactResponse;
const artifact = artifacts.items.find(item => item.path === artifactPath);
if (!artifact) {
throw new Error(`Missing artifact (${artifactPath}) for CircleCI build: ${buildNumber}`);
}
return artifact.url;
} catch (error) {
throw new Error(`CircleCI artifact URL request failed (${(error as Error).message})`);
}
}
/**
* Get the info for a [pipeline](https://circleci.com/docs/2.0/pipelines/) from the CircleCI API.
* @param pipelineId The CircleCI pipeline ID that generated the artifact.
* @returns A promise to the info about the pipeline.
*/
public async getPipelineInfo(pipelineId: string): Promise<PipelineInfo> {
try {
const url = `${CIRCLE_CI_PIPELINE_API_URL}/${pipelineId}`;
const response = await this.fetchFromCircleCi(url);
return response.json();
} catch (error) {
throw new Error(`CircleCI pipeline info request failed (${(error as Error).message})`);
}
}
}
@@ -1,4 +1,3 @@
// Constants
export const AIO_DOWNLOADS_DIR = '/tmp/aio-downloads';
export const HIDDEN_DIR_PREFIX = 'hidden--';
export const SHORT_SHA_LEN = 7;
@@ -1,19 +0,0 @@
import {getEnvVar} from './utils';
export const AIO_ARTIFACT_PATH = getEnvVar('AIO_ARTIFACT_PATH');
export const AIO_BUILDS_DIR = getEnvVar('AIO_BUILDS_DIR');
export const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN');
export const AIO_CIRCLE_CI_TOKEN = getEnvVar('AIO_CIRCLE_CI_TOKEN');
export const AIO_DOMAIN_NAME = getEnvVar('AIO_DOMAIN_NAME');
export const AIO_GITHUB_ORGANIZATION = getEnvVar('AIO_GITHUB_ORGANIZATION');
export const AIO_GITHUB_REPO = getEnvVar('AIO_GITHUB_REPO');
export const AIO_GITHUB_TEAM_SLUGS = getEnvVar('AIO_GITHUB_TEAM_SLUGS');
export const AIO_NGINX_HOSTNAME = getEnvVar('AIO_NGINX_HOSTNAME');
export const AIO_NGINX_PORT_HTTP = +getEnvVar('AIO_NGINX_PORT_HTTP');
export const AIO_NGINX_PORT_HTTPS = +getEnvVar('AIO_NGINX_PORT_HTTPS');
export const AIO_SIGNIFICANT_FILES_PATTERN = getEnvVar('AIO_SIGNIFICANT_FILES_PATTERN');
export const AIO_TRUSTED_PR_LABEL = getEnvVar('AIO_TRUSTED_PR_LABEL');
export const AIO_PREVIEW_SERVER_HOSTNAME = getEnvVar('AIO_PREVIEW_SERVER_HOSTNAME');
export const AIO_PREVIEW_SERVER_PORT = +getEnvVar('AIO_PREVIEW_SERVER_PORT');
export const AIO_ARTIFACT_MAX_SIZE = +getEnvVar('AIO_ARTIFACT_MAX_SIZE');
export const AIO_WWW_USER = getEnvVar('AIO_WWW_USER');
@@ -28,18 +28,29 @@ export class GithubApi {
}
// Methods - Public
public get<T = any>(pathname: string, params?: RequestParamsOrNull): Promise<T> {
public get<T>(pathname: string, params?: RequestParamsOrNull): Promise<T> {
const path = this.buildPath(pathname, params);
return this.request<T>('get', path);
}
public post<T = any>(pathname: string, params?: RequestParamsOrNull, data?: any): Promise<T> {
public post<T>(pathname: string, params?: RequestParamsOrNull, data?: any): Promise<T> {
const path = this.buildPath(pathname, params);
return this.request<T>('post', path, data);
}
// In GitHub API paginated requests, page numbering is 1-based. (https://developer.github.com/v3/#pagination)
public getPaginated<T>(pathname: string, baseParams: RequestParams = {}, currentPage: number = 1): Promise<T[]> {
// Methods - Protected
protected buildPath(pathname: string, params?: RequestParamsOrNull): string {
if (params == null) {
return pathname;
}
const search = (params === null) ? '' : this.serializeSearchParams(params);
const joiner = search && '?';
return `${pathname}${joiner}${search}`;
}
protected getPaginated<T>(pathname: string, baseParams: RequestParams = {}, currentPage: number = 0): Promise<T[]> {
const perPage = 100;
const params = {
...baseParams,
@@ -56,18 +67,6 @@ export class GithubApi {
});
}
// Methods - Protected
protected buildPath(pathname: string, params?: RequestParamsOrNull): string {
if (params == null) {
return pathname;
}
const search = (params === null) ? '' : this.serializeSearchParams(params);
const joiner = search && '?';
return `${pathname}${joiner}${search}`;
}
protected request<T>(method: string, path: string, data: any = null): Promise<T> {
return new Promise<T>((resolve, reject) => {
const options = {
@@ -82,7 +81,7 @@ export class GithubApi {
reject(`Request to '${url}' failed (status: ${statusCode}): ${responseText}`);
};
const onSuccess = (responseText: string) => {
try { resolve(responseText && JSON.parse(responseText)); } catch (err) { reject(err); }
try { resolve(JSON.parse(responseText)); } catch (err) { reject(err); }
};
const onResponse = (res: IncomingMessage) => {
const statusCode = res.statusCode || -1;
@@ -1,79 +1,46 @@
// Imports
import {assertNotMissingOrEmpty} from '../common/utils';
import {GithubApi} from './github-api';
import {assert, assertNotMissingOrEmpty} from './utils';
export interface PullRequest {
// Interfaces - Types
export interface PullRequest {
number: number;
user: {login: string};
labels: {name: string}[];
}
export interface FileInfo {
sha: string;
filename: string;
}
export type PullRequestState = 'all' | 'closed' | 'open';
/**
* Access pull requests on GitHub.
*/
export class GithubPullRequests {
public repoSlug: string;
/**
* Create an instance of this helper
* @param api An instance of the Github API helper.
* @param githubOrg The organisation on GitHub whose repo we will interrogate.
* @param githubRepo The repository on Github with whose PRs we will interact.
*/
constructor(private api: GithubApi, githubOrg: string, githubRepo: string) {
assertNotMissingOrEmpty('githubOrg', githubOrg);
assertNotMissingOrEmpty('githubRepo', githubRepo);
this.repoSlug = `${githubOrg}/${githubRepo}`;
// Classes
export class GithubPullRequests extends GithubApi {
// Constructor
constructor(githubToken: string, protected repoSlug: string) {
super(githubToken);
assertNotMissingOrEmpty('repoSlug', repoSlug);
}
/**
* Post a comment on a PR.
* @param pr The number of the PR on which to comment.
* @param body The body of the comment to post.
* @returns A promise that resolves when the comment has been posted.
*/
public addComment(pr: number, body: string): Promise<any> {
assert(pr > 0, `Invalid PR number: ${pr}`);
assert(!!body, `Invalid or empty comment body: ${body}`);
return this.api.post<any>(`/repos/${this.repoSlug}/issues/${pr}/comments`, null, {body});
// Methods - Public
public addComment(pr: number, body: string): Promise<void> {
if (!(pr > 0)) {
throw new Error(`Invalid PR number: ${pr}`);
} else if (!body) {
throw new Error(`Invalid or empty comment body: ${body}`);
}
return this.post<void>(`/repos/${this.repoSlug}/issues/${pr}/comments`, null, {body});
}
/**
* Request information about a PR.
* @param pr The number of the PR for which to request info.
* @returns A promise that is resolves with information about the specified PR.
*/
public fetch(pr: number): Promise<PullRequest> {
assert(pr > 0, `Invalid PR number: ${pr}`);
// Using the `/issues/` URL, because the `/pulls/` one does not provide labels.
return this.api.get<PullRequest>(`/repos/${this.repoSlug}/issues/${pr}`);
return this.get<PullRequest>(`/repos/${this.repoSlug}/issues/${pr}`);
}
/**
* Request information about all PRs that match the given state.
* @param state Only retrieve PRs that have this state.
* @returns A promise that is resolved with information about the requested PRs.
*/
public fetchAll(state: PullRequestState = 'all'): Promise<PullRequest[]> {
console.log(`Fetching ${state} pull requests...`);
const pathname = `/repos/${this.repoSlug}/pulls`;
const params = {state};
return this.api.getPaginated<PullRequest>(pathname, params);
}
/**
* Request a list of files for the given PR.
* @param pr The number of the PR for which to request files.
* @returns A promise that resolves to an array of file information
*/
public fetchFiles(pr: number): Promise<FileInfo[]> {
assert(pr > 0, `Invalid PR number: ${pr}`);
return this.api.getPaginated<FileInfo>(`/repos/${this.repoSlug}/pulls/${pr}/files`);
return this.getPaginated<PullRequest>(pathname, params);
}
}
@@ -1,72 +1,45 @@
// Imports
import {assertNotMissingOrEmpty} from '../common/utils';
import {GithubApi} from './github-api';
import {assertNotMissingOrEmpty} from './utils';
export interface Team {
// Interfaces - Types
interface Team {
id: number;
slug: string;
}
export interface TeamMembership {
interface TeamMembership {
state: string;
}
export class GithubTeams {
/**
* Create an instance of this helper
* @param api An instance of the Github API helper.
* @param githubOrg The organisation on GitHub whose repo we will interrogate.
*/
constructor(private api: GithubApi, protected githubOrg: string) {
assertNotMissingOrEmpty('githubOrg', githubOrg);
// Classes
export class GithubTeams extends GithubApi {
// Constructor
constructor(githubToken: string, protected organization: string) {
super(githubToken);
assertNotMissingOrEmpty('organization', organization);
}
/**
* Request information about all the organisation's teams in GitHub.
* @returns A promise that is resolved with information about the teams.
*/
// Methods - Public
public fetchAll(): Promise<Team[]> {
return this.api.getPaginated<Team>(`/orgs/${this.githubOrg}/teams`);
return this.getPaginated<Team>(`/orgs/${this.organization}/teams`);
}
/**
* Check whether the specified username is a member of the specified team.
* @param username The usernane to check for in the team.
* @param teamIds The team to check for the username.
* @returns a Promise that resolves to `true` if the username is a member of the team.
*/
public async isMemberById(username: string, teamIds: number[]): Promise<boolean> {
public isMemberById(username: string, teamIds: number[]): Promise<boolean> {
const getMembership = (teamId: number) =>
this.get<TeamMembership>(`/teams/${teamId}/memberships/${username}`).
then(membership => membership.state === 'active').
catch(() => false);
const reduceFn = (promise: Promise<boolean>, teamId: number) =>
promise.then(isMember => isMember || getMembership(teamId));
const getMembership = async (teamId: number) => {
try {
const {state} = await this.api.get<TeamMembership>(`/teams/${teamId}/memberships/${username}`);
return state === 'active';
} catch (error) {
return false;
}
};
for (const teamId of teamIds) {
if (await getMembership(teamId)) {
return true;
}
}
return false;
return teamIds.reduce(reduceFn, Promise.resolve(false));
}
/**
* Check whether the given username is a member of the teams specified by the team slugs.
* @param username The username to check for in the teams.
* @param teamSlugs A collection of slugs that represent the teams to check for the username.
* @returns a Promise that resolves to `true` if the usernane is a member of at least one of the specified teams.
*/
public async isMemberBySlug(username: string, teamSlugs: string[]): Promise<boolean> {
try {
const teams = await this.fetchAll();
const teamIds = teams.filter(team => teamSlugs.includes(team.slug)).map(team => team.id);
return await this.isMemberById(username, teamIds);
} catch (error) {
return false;
}
public isMemberBySlug(username: string, teamSlugs: string[]): Promise<boolean> {
return this.fetchAll().
then(teams => teams.filter(team => teamSlugs.includes(team.slug)).map(team => team.id)).
then(teamIds => this.isMemberById(username, teamIds)).
catch(() => false);
}
}
@@ -1,14 +1,14 @@
// We can't use `import...from` here, because of the following mess:
// - GitHub project `jasmine/jasmine` is `jasmine-core` on npm and its typings `@types/jasmine`.
// - GitHub project `jasmine/jasmine-npm` is `jasmine` on npm and has no typings.
//
// Using `import...from 'jasmine'` here, would import from `@types/jasmine` (which refers to the
// `jasmine-core` module and the `jasmine` module).
import Jasmine = require('jasmine');
import 'source-map-support/register';
export const runTests = (specFiles: string[]) => {
export const runTests = (specFiles: string[], helpers?: string[]) => {
// We can't use `import` here, because of the following mess:
// - GitHub project `jasmine/jasmine` is `jasmine-core` on npm and its typings `@types/jasmine`.
// - GitHub project `jasmine/jasmine-npm` is `jasmine` on npm and has no typings.
//
// Using `import...from 'jasmine'` here, would import from `@types/jasmine` (which refers to the
// `jasmine-core` module and the `jasmine` module).
// tslint:disable-next-line: no-var-requires variable-name
const Jasmine = require('jasmine');
const config = {
helpers,
random: true,
spec_files: specFiles,
stopSpecOnExpectationFailure: true,
@@ -16,7 +16,8 @@ export const runTests = (specFiles: string[]) => {
process.on('unhandledRejection', (reason: any) => console.log('Unhandled rejection:', reason));
const runner = new Jasmine({});
const runner = new Jasmine();
runner.loadConfig(config);
runner.onComplete((passed: boolean) => process.exit(passed ? 0 : 1));
runner.execute();
};
@@ -1,109 +1,17 @@
import {basename, resolve as resolvePath} from 'path';
import {SHORT_SHA_LEN} from './constants';
/**
* Shorten a SHA to make it more readable
* @param sha The SHA to shorten.
*/
export function computeShortSha(sha: string) {
return sha.slice(0, SHORT_SHA_LEN);
}
/**
* Compute the path for a downloaded artifact file.
* @param downloadsDir The directory where artifacts are downloaded
* @param pr The PR associated with this artifact.
* @param sha The SHA associated with the build for this artifact.
* @param artifactPath The path to the artifact on CircleCI.
* @returns The fully resolved location for the specified downloaded artifact.
*/
export function computeArtifactDownloadPath(
downloadsDir: string, pr: number, sha: string, artifactPath: string) {
return resolvePath(downloadsDir, `${pr}-${computeShortSha(sha)}-${basename(artifactPath)}`);
}
/**
* Extract the PR number and latest commit SHA from a downloaded file path.
* @param downloadPath the path to the downloaded file.
* @returns An object whose keys are the PR and SHA extracted from the file path.
*/
export function getPrInfoFromDownloadPath(downloadPath: string) {
const file = basename(downloadPath);
const [pr, sha] = file.split('-');
return {pr: +pr, sha};
}
/**
* Assert that a value is true.
* @param value The value to assert.
* @param message The message if the value is not true.
*/
export function assert(value: boolean, message: string) {
// Functions
export const assertNotMissingOrEmpty = (name: string, value: string | null | undefined) => {
if (!value) {
throw new Error(message);
throw new Error(`Missing or empty required parameter '${name}'!`);
}
}
/**
* Assert that a parameter is not equal to "".
* @param name The name of the parameter.
* @param value The value of the parameter.
*/
export const assertNotMissingOrEmpty = (name: string, value: string|null|undefined) => {
assert(!!value, `Missing or empty required parameter '${name}'!`);
};
/**
* Get an environment variable.
* @param name The name of the environment variable.
* @param isOptional True if the variable is optional.
* @returns The value of the variable or "" if it is optional and falsy.
* @throws `Error` if the variable is falsy and not optional.
*/
export const getEnvVar = (name: string, isOptional = false): string => {
const value = process.env[name];
if (!isOptional && !value) {
try {
throw new Error(`ERROR: Missing required environment variable '${name}'!`);
} catch (error) {
console.error((error as Error).stack);
process.exit(1);
}
console.error(`ERROR: Missing required environment variable '${name}'!`);
process.exit(1);
}
return value || '';
};
/**
* A basic logger implementation.
* Delegates to `console`, but prepends each message with the current date and specified scope (i.e
* caller).
*/
export class Logger {
private padding = ' '.repeat(20 - this.scope.length);
/**
* Create a new `Logger` instance for the specified `scope`.
* @param scope The logger's scope (added to all messages).
*/
constructor(private scope: string) {}
public error(...args: any[]) {
this.callMethod('error', args);
}
public info(...args: any[]) {
this.callMethod('info', args);
}
public log(...args: any[]) {
this.callMethod('log', args);
}
public warn(...args: any[]) {
this.callMethod('warn', args);
}
private callMethod(method: 'error'|'info'|'log'|'warn', args: any[]) {
console[method](`[${new Date()}]`, `${this.scope}:${this.padding}`, ...args);
}
}
@@ -1,144 +0,0 @@
// Imports
import * as cp from 'child_process';
import {EventEmitter} from 'events';
import * as fs from 'fs';
import * as path from 'path';
import * as shell from 'shelljs';
import {HIDDEN_DIR_PREFIX} from '../common/constants';
import {assertNotMissingOrEmpty, computeShortSha, Logger} from '../common/utils';
import {ChangedPrVisibilityEvent, CreatedBuildEvent} from './build-events';
import {PreviewServerError} from './preview-error';
// Classes
export class BuildCreator extends EventEmitter {
private logger = new Logger('BuildCreator');
// Constructor
constructor(protected buildsDir: string) {
super();
assertNotMissingOrEmpty('buildsDir', buildsDir);
}
// Methods - Public
public create(pr: number, sha: string, archivePath: string, isPublic: boolean): Promise<void> {
// Use only part of the SHA for more readable URLs.
sha = computeShortSha(sha);
const {newPrDir: prDir} = this.getCandidatePrDirs(pr, isPublic);
const shaDir = path.join(prDir, sha);
let dirToRemoveOnError: string;
return Promise.resolve().
// If the same PR exists with different visibility, update the visibility first.
then(() => this.updatePrVisibility(pr, isPublic)).
then(() => Promise.all([this.exists(prDir), this.exists(shaDir)])).
then(([prDirExisted, shaDirExisted]) => {
if (shaDirExisted) {
const publicOrNot = isPublic ? 'public' : 'non-public';
throw new PreviewServerError(409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`);
}
dirToRemoveOnError = prDirExisted ? shaDir : prDir;
return Promise.resolve().
then(() => shell.mkdir('-p', shaDir)).
then(() => this.extractArchive(archivePath, shaDir)).
then(() => this.emit(CreatedBuildEvent.type, new CreatedBuildEvent(+pr, sha, isPublic))).
then(() => undefined);
}).
catch(err => {
if (dirToRemoveOnError) {
shell.rm('-rf', dirToRemoveOnError);
}
if (!(err instanceof PreviewServerError)) {
err = new PreviewServerError(500, `Error while creating preview at: ${shaDir}\n${err}`);
}
throw err;
});
}
public updatePrVisibility(pr: number, makePublic: boolean): Promise<boolean> {
const {oldPrDir: otherVisPrDir, newPrDir: targetVisPrDir} = this.getCandidatePrDirs(pr, makePublic);
return Promise.
all([this.exists(otherVisPrDir), this.exists(targetVisPrDir)]).
then(([otherVisPrDirExisted, targetVisPrDirExisted]) => {
if (!otherVisPrDirExisted) {
// No visibility change: Either the visibility is up-to-date or the PR does not exist.
return false;
} else if (targetVisPrDirExisted) {
// Error: Directories for both visibilities exist.
throw new PreviewServerError(409,
`Request to move '${otherVisPrDir}' to existing directory '${targetVisPrDir}'.`);
}
// Visibility change: Moving `otherVisPrDir` to `targetVisPrDir`.
return Promise.resolve().
then(() => shell.mv(otherVisPrDir, targetVisPrDir)).
then(() => this.listShasByDate(targetVisPrDir)).
then(shas => this.emit(ChangedPrVisibilityEvent.type, new ChangedPrVisibilityEvent(+pr, shas, makePublic))).
then(() => true);
}).
catch(err => {
if (!(err instanceof PreviewServerError)) {
err = new PreviewServerError(500, `Error while making PR ${pr} ${makePublic ? 'public' : 'hidden'}.\n${err}`);
}
throw err;
});
}
// Methods - Protected
protected exists(fileOrDir: string): Promise<boolean> {
return new Promise(resolve => fs.access(fileOrDir, err => resolve(!err)));
}
protected extractArchive(inputFile: string, outputDir: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
const cmd = `tar --extract --gzip --directory "${outputDir}" --file "${inputFile}"`;
cp.exec(cmd, (err, _stdout, stderr) => {
if (err) {
return reject(err);
}
if (stderr) {
this.logger.warn(stderr);
}
try {
shell.chmod('-R', 'a-w', outputDir);
shell.rm('-f', inputFile);
resolve();
} catch (err) {
reject(err);
}
});
});
}
protected getCandidatePrDirs(pr: number, isPublic: boolean): {oldPrDir: string, newPrDir: string} {
const hiddenPrDir = path.join(this.buildsDir, HIDDEN_DIR_PREFIX + pr);
const publicPrDir = path.join(this.buildsDir, `${pr}`);
const oldPrDir = isPublic ? hiddenPrDir : publicPrDir;
const newPrDir = isPublic ? publicPrDir : hiddenPrDir;
return {oldPrDir, newPrDir};
}
protected listShasByDate(inputDir: string): Promise<string[]> {
return Promise.resolve().
then(() => shell.ls('-l', inputDir) as any as Promise<(fs.Stats & {name: string})[]>).
// Keep directories only.
// (Also, convert to standard Array - ShellJS provides custom `sort()` method for sorting file contents.)
then(items => items.filter(item => item.isDirectory())).
// Sort by modification date.
then(items => items.sort((a, b) => a.mtime.getTime() - b.mtime.getTime())).
// Return directory names.
then(items => items.map(item => item.name));
}
}
@@ -1,77 +0,0 @@
import * as fs from 'fs';
import {dirname} from 'path';
import {mkdir} from 'shelljs';
import {promisify} from 'util';
import {CircleCiApi} from '../common/circle-ci-api';
import {assert, assertNotMissingOrEmpty, computeArtifactDownloadPath, Logger} from '../common/utils';
import {PreviewServerError} from './preview-error';
export interface GithubInfo {
org: string;
pr: number;
repo: string;
sha: string;
}
/**
* A helper that can get information about builds and download build artifacts.
*/
export class BuildRetriever {
private logger = new Logger('BuildRetriever');
constructor(
private api: CircleCiApi, private downloadSizeLimit: number, private downloadDir: string) {
assert(
downloadSizeLimit > 0,
'Invalid parameter "downloadSizeLimit" should be a number greater than 0.');
assertNotMissingOrEmpty('downloadDir', downloadDir);
}
/**
* Get GitHub information about a build
* @param buildNum The number of the build for which to retrieve the info.
* @returns The Github org, repo, PR and latest SHA for the specified build.
*/
public async getGithubInfo(buildNum: number): Promise<GithubInfo> {
const buildInfo = await this.api.getBuildInfo(buildNum);
const pipelineInfo = await this.api.getPipelineInfo(buildInfo.pipeline.id);
const githubInfo: GithubInfo = {
org: buildInfo.organization.name,
pr: +pipelineInfo.vcs.review_id,
repo: buildInfo.project.name,
sha: pipelineInfo.vcs.revision,
};
return githubInfo;
}
/**
* Make a request to the given URL for a build artifact and store it locally.
* @param buildNum the number of the CircleCI build whose artifact we want to download.
* @param pr the number of the PR that triggered the CircleCI build.
* @param sha the commit in the PR that triggered the CircleCI build.
* @param artifactPath the path on CircleCI where the artifact was stored.
* @returns A promise to the file path where the downloaded file was stored.
*/
public async downloadBuildArtifact(
buildNum: number, pr: number, sha: string, artifactPath: string): Promise<string> {
try {
const outPath = computeArtifactDownloadPath(this.downloadDir, pr, sha, artifactPath);
const downloadExists =
await new Promise(resolve => fs.exists(outPath, exists => resolve(exists)));
if (!downloadExists) {
const url = await this.api.getBuildArtifactUrl(buildNum, artifactPath);
const response = await this.api.fetchFromCircleCi(url, {size: this.downloadSizeLimit});
const buffer = await response.buffer();
mkdir('-p', dirname(outPath));
await promisify(fs.writeFile)(outPath, buffer);
}
return outPath;
} catch (error: any) {
this.logger.warn(error);
const status = (error.type === 'max-size') ? 413 : 500;
throw new PreviewServerError(
status, `CircleCI artifact download failed (${error.message || error})`);
}
}
}
@@ -1,46 +0,0 @@
import {GithubPullRequests, PullRequest} from '../common/github-pull-requests';
import {GithubTeams} from '../common/github-teams';
import {assertNotMissingOrEmpty} from '../common/utils';
/**
* A helper to verify whether builds are trusted.
*/
export class BuildVerifier {
/**
* Construct a new BuildVerifier instance.
* @param prs A helper to access PR information.
* @param teams A helper to access Github team information.
* @param allowedTeamSlugs The teams that are trusted.
* @param trustedPrLabel The github label that indicates that a PR is trusted.
*/
constructor(protected prs: GithubPullRequests, protected teams: GithubTeams,
protected allowedTeamSlugs: string[], protected trustedPrLabel: string) {
assertNotMissingOrEmpty('allowedTeamSlugs', allowedTeamSlugs && allowedTeamSlugs.join(''));
assertNotMissingOrEmpty('trustedPrLabel', trustedPrLabel);
}
/**
* Check whether a PR contains files that are significant to the build.
* @param pr The number of the PR to check
* @param significantFilePattern A regex that selects files that are significant.
*/
public async getSignificantFilesChanged(pr: number, significantFilePattern: RegExp): Promise<boolean> {
const files = await this.prs.fetchFiles(pr);
return files.some(file => significantFilePattern.test(file.filename));
}
/**
* Check whether a PR is trusted.
* @param pr The number of the PR to check.
* @returns true if the PR is trusted.
*/
public async getPrIsTrusted(pr: number): Promise<boolean> {
const prInfo = await this.prs.fetch(pr);
return this.hasLabel(prInfo, this.trustedPrLabel) ||
(await this.teams.isMemberBySlug(prInfo.user.login, this.allowedTeamSlugs));
}
protected hasLabel(prInfo: PullRequest, label: string): boolean {
return prInfo.labels.some(labelObj => labelObj.name === label);
}
}
@@ -1,41 +0,0 @@
// Imports
import {AIO_DOWNLOADS_DIR} from '../common/constants';
import {
AIO_ARTIFACT_MAX_SIZE,
AIO_ARTIFACT_PATH,
AIO_BUILDS_DIR,
AIO_CIRCLE_CI_TOKEN,
AIO_DOMAIN_NAME,
AIO_GITHUB_ORGANIZATION,
AIO_GITHUB_REPO,
AIO_GITHUB_TEAM_SLUGS,
AIO_GITHUB_TOKEN,
AIO_PREVIEW_SERVER_HOSTNAME,
AIO_PREVIEW_SERVER_PORT,
AIO_SIGNIFICANT_FILES_PATTERN,
AIO_TRUSTED_PR_LABEL,
} from '../common/env-variables';
import {PreviewServerFactory} from './preview-server-factory';
// Run
_main();
// Functions
function _main(): void {
PreviewServerFactory
.create({
buildArtifactPath: AIO_ARTIFACT_PATH,
buildsDir: AIO_BUILDS_DIR,
circleCiToken: AIO_CIRCLE_CI_TOKEN,
domainName: AIO_DOMAIN_NAME,
downloadSizeLimit: AIO_ARTIFACT_MAX_SIZE,
downloadsDir: AIO_DOWNLOADS_DIR,
githubOrg: AIO_GITHUB_ORGANIZATION,
githubRepo: AIO_GITHUB_REPO,
githubTeamSlugs: AIO_GITHUB_TEAM_SLUGS.split(','),
githubToken: AIO_GITHUB_TOKEN,
significantFilesPattern: AIO_SIGNIFICANT_FILES_PATTERN,
trustedPrLabel: AIO_TRUSTED_PR_LABEL,
})
.listen(AIO_PREVIEW_SERVER_PORT, AIO_PREVIEW_SERVER_HOSTNAME);
}
@@ -1,8 +0,0 @@
// Classes
export class PreviewServerError extends Error {
// Constructor
constructor(public status: number = 500, message?: string) {
super(message);
Object.setPrototypeOf(this, PreviewServerError.prototype);
}
}
@@ -1,207 +0,0 @@
// Imports
import * as bodyParser from 'body-parser';
import * as express from 'express';
import * as http from 'http';
import {AddressInfo} from 'net';
import {CircleCiApi} from '../common/circle-ci-api';
import {GithubApi} from '../common/github-api';
import {GithubPullRequests} from '../common/github-pull-requests';
import {GithubTeams} from '../common/github-teams';
import {assert, assertNotMissingOrEmpty, computeShortSha, Logger} from '../common/utils';
import {BuildCreator} from './build-creator';
import {ChangedPrVisibilityEvent, CreatedBuildEvent} from './build-events';
import {BuildRetriever} from './build-retriever';
import {BuildVerifier} from './build-verifier';
import {respondWithError, throwRequestError} from './utils';
const AIO_PREVIEW_JOB = 'aio_preview';
// Interfaces - Types
export interface PreviewServerConfig {
downloadsDir: string;
downloadSizeLimit: number;
buildArtifactPath: string;
buildsDir: string;
domainName: string;
githubOrg: string;
githubRepo: string;
githubTeamSlugs: string[];
circleCiToken: string;
githubToken: string;
significantFilesPattern: string;
trustedPrLabel: string;
}
const logger = new Logger('PreviewServer');
// Classes
export class PreviewServerFactory {
// Methods - Public
public static create(cfg: PreviewServerConfig): http.Server {
assertNotMissingOrEmpty('domainName', cfg.domainName);
const circleCiApi = new CircleCiApi(cfg.githubOrg, cfg.githubRepo, cfg.circleCiToken);
const githubApi = new GithubApi(cfg.githubToken);
const prs = new GithubPullRequests(githubApi, cfg.githubOrg, cfg.githubRepo);
const teams = new GithubTeams(githubApi, cfg.githubOrg);
const buildRetriever = new BuildRetriever(circleCiApi, cfg.downloadSizeLimit, cfg.downloadsDir);
const buildVerifier = new BuildVerifier(prs, teams, cfg.githubTeamSlugs, cfg.trustedPrLabel);
const buildCreator = PreviewServerFactory.createBuildCreator(prs, cfg.buildsDir, cfg.domainName);
const middleware = PreviewServerFactory.createMiddleware(buildRetriever, buildVerifier, buildCreator, cfg);
const httpServer = http.createServer(middleware as any);
httpServer.on('listening', () => {
const info = httpServer.address() as AddressInfo;
logger.info(`Up and running (and listening on ${info.address}:${info.port})...`);
});
return httpServer;
}
public static createMiddleware(buildRetriever: BuildRetriever, buildVerifier: BuildVerifier,
buildCreator: BuildCreator, cfg: PreviewServerConfig): express.Express {
const middleware = express();
const jsonParser = bodyParser.json();
const significantFilesRe = new RegExp(cfg.significantFilesPattern);
// RESPOND TO IS-ALIVE PING
middleware.get(/^\/health-check\/?$/, (_req, res) => res.sendStatus(200));
// RESPOND TO CAN-HAVE-PUBLIC-PREVIEW CHECK
const canHavePublicPreviewRe = /^\/can-have-public-preview\/(\d+)\/?$/;
middleware.get(canHavePublicPreviewRe, async (req, res) => {
try {
const pr = +canHavePublicPreviewRe.exec(req.url)![1];
if (!await buildVerifier.getSignificantFilesChanged(pr, significantFilesRe)) {
// Cannot have preview: PR did not touch relevant files: `aio/` or `packages/` (except for spec files).
res.send({canHavePublicPreview: false, reason: 'No significant files touched.'});
logger.log(`PR:${pr} - Cannot have a public preview, because it did not touch any significant files.`);
} else if (!await buildVerifier.getPrIsTrusted(pr)) {
// Cannot have preview: PR not automatically verifiable as "trusted".
res.send({canHavePublicPreview: false, reason: 'Not automatically verifiable as "trusted".'});
logger.log(`PR:${pr} - Cannot have a public preview, because not automatically verifiable as "trusted".`);
} else {
// Can have preview.
res.send({canHavePublicPreview: true, reason: null});
logger.log(`PR:${pr} - Can have a public preview.`);
}
} catch (err) {
logger.error('Previewability check error', err);
respondWithError(res, err);
}
});
// CIRCLE_CI BUILD COMPLETE WEBHOOK
middleware.post(/^\/circle-build\/?$/, jsonParser, async (req, res) => {
try {
if (!(
req.is('json') &&
req.body &&
req.body.payload &&
req.body.payload.build_num > 0 &&
req.body.payload.build_parameters &&
req.body.payload.build_parameters.CIRCLE_JOB
)) {
throwRequestError(400, `Incorrect body content. Expected JSON`, req);
}
const job = req.body.payload.build_parameters.CIRCLE_JOB;
const buildNum = req.body.payload.build_num;
logger.log(`Build:${buildNum}, Job:${job} - processing web-hook trigger`);
if (job !== AIO_PREVIEW_JOB) {
res.sendStatus(204);
logger.log(`Build:${buildNum}, Job:${job} -`,
`Skipping preview processing because this is not the "${AIO_PREVIEW_JOB}" job.`);
return;
}
const { pr, sha, org, repo } = await buildRetriever.getGithubInfo(buildNum);
assert(cfg.githubOrg === org,
`Invalid webhook: expected "githubOrg" property to equal "${cfg.githubOrg}" but got "${org}".`);
assert(cfg.githubRepo === repo,
`Invalid webhook: expected "githubRepo" property to equal "${cfg.githubRepo}" but got "${repo}".`);
// Do not deploy unless this PR has touched relevant files: `aio/` or `packages/` (except for spec files)
if (!await buildVerifier.getSignificantFilesChanged(pr, significantFilesRe)) {
res.sendStatus(204);
logger.log(`PR:${pr}, Build:${buildNum} - ` +
`Skipping preview processing because this PR did not touch any significant files.`);
return;
}
const artifactPath = await buildRetriever.downloadBuildArtifact(buildNum, pr, sha, cfg.buildArtifactPath);
const isPublic = await buildVerifier.getPrIsTrusted(pr);
await buildCreator.create(pr, sha, artifactPath, isPublic);
res.sendStatus(isPublic ? 201 : 202);
logger.log(`PR:${pr}, SHA:${computeShortSha(sha)}, Build:${buildNum} - ` +
`Successfully created ${isPublic ? 'public' : 'non-public'} preview.`);
} catch (err) {
logger.error('CircleCI webhook error', err);
respondWithError(res, err);
}
});
// GITHUB PR UPDATED WEBHOOK
middleware.post(/^\/pr-updated\/?$/, jsonParser, async (req, res) => {
const { action, number: prNo }: { action?: string, number?: number } = req.body;
const visMayHaveChanged = !action || (action === 'labeled') || (action === 'unlabeled');
try {
if (!visMayHaveChanged) {
res.sendStatus(200);
} else if (!prNo) {
throwRequestError(400, `Missing or empty 'number' field`, req);
} else {
const isPublic = await buildVerifier.getPrIsTrusted(prNo);
await buildCreator.updatePrVisibility(prNo, isPublic);
res.sendStatus(200);
}
} catch (err) {
logger.error('PR update hook error', err);
respondWithError(res, err);
}
});
// ALL OTHER REQUESTS
middleware.all('*', req => throwRequestError(404, 'Unknown resource', req));
middleware.use((err: any, _req: any, res: express.Response, _next: any) => {
const statusText = http.STATUS_CODES[err.status] || '???';
logger.error(`Preview server error: ${err.status} - ${statusText}:`, err.message);
respondWithError(res, err);
});
return middleware;
}
public static createBuildCreator(prs: GithubPullRequests, buildsDir: string, domainName: string): BuildCreator {
const buildCreator = new BuildCreator(buildsDir);
const postPreviewsComment = (pr: number, shas: string[]) => {
const body = shas.
map(sha => `You can preview ${sha} at https://pr${pr}-${sha}.${domainName}/.`).
join('\n');
return prs.addComment(pr, body);
};
buildCreator.on(CreatedBuildEvent.type, ({pr, sha, isPublic}: CreatedBuildEvent) => {
if (isPublic) {
postPreviewsComment(pr, [sha]);
}
});
buildCreator.on(ChangedPrVisibilityEvent.type, ({pr, shas, isPublic}: ChangedPrVisibilityEvent) => {
if (isPublic && shas.length) {
postPreviewsComment(pr, shas);
}
});
return buildCreator;
}
}

Some files were not shown because too many files have changed in this diff Show More