mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c4b6d474f8 | |||
| 78efc406ba | |||
| c277e88b22 | |||
| 574b1c276d | |||
| 40eb5e3207 | |||
| 8ef145fa1b | |||
| 94f2daaa1c | |||
| ffc61749ff | |||
| f70d80c8c7 | |||
| a4cb2e671c | |||
| dc7882cf97 | |||
| 5f9bd59b14 | |||
| cfd466dfbb | |||
| 61ce057a09 | |||
| 8dc6c9fe22 | |||
| e71e900708 | |||
| 1168fd585f | |||
| 18ea007390 | |||
| bd23af0639 | |||
| 6b0e1c7703 | |||
| 6b89ce9e27 | |||
| 0bf724f4d4 | |||
| 7acf163f51 | |||
| 6808375e50 | |||
| 97d6781be7 | |||
| f12e8e3ea2 | |||
| f5638c25e6 | |||
| d82eb27f69 | |||
| 3b5218b768 | |||
| 5fa6ce3e61 | |||
| d88ac6db12 | |||
| 46efe02e48 | |||
| cd76360ea8 | |||
| 09ad1ef5a2 | |||
| 48f4f86835 | |||
| 183c92baed | |||
| e03ccb60ed | |||
| c402bb81f5 | |||
| 0a7a8e496e | |||
| 779e1d872f | |||
| 193a32e5c1 | |||
| 41f8584aad | |||
| 4b8e6b36ab | |||
| 4c58b2f8cf | |||
| 0e96528a70 | |||
| 1d1338fced | |||
| 1344da62ad | |||
| 0c821b28f3 | |||
| ebef1a592a | |||
| 4c97f56223 | |||
| 71e8bd8791 | |||
| fcf9edbc78 | |||
| 626d3ab586 | |||
| 3a607f51d6 | |||
| ccf0dc1884 | |||
| ebf646a9c9 | |||
| 732e45a730 | |||
| 6697d6ba2f | |||
| 399e173d8c | |||
| 05ecc619fc | |||
| 52f508ab4d | |||
| 2a61fea64b | |||
| 10c1ae5b6e | |||
| 9208e64e74 | |||
| 65d45e4919 | |||
| 080bdfa77f | |||
| 977bd97717 | |||
| a90dc4310c | |||
| 2426b2e1f1 | |||
| 912c7252f8 | |||
| 8e64d9e1d8 | |||
| 4d7b23e99e | |||
| 59d278c07c | |||
| 7e1de8cb6a | |||
| f6bda0eb4d | |||
| c7c4b9e390 | |||
| a77924ff38 | |||
| d04408d67d | |||
| f556b29d05 | |||
| a9be2b3628 | |||
| a34a479ee5 | |||
| f0c9eeceba | |||
| e737d45ad0 | |||
| c7bede629b | |||
| 992f51bc6d | |||
| f2658e34a2 | |||
| 89813aea70 | |||
| e6e5021eb9 |
+4
-4
@@ -5,6 +5,10 @@
|
||||
.git
|
||||
node_modules
|
||||
dist
|
||||
aio/node_modules
|
||||
aio/content/example-playground
|
||||
aio/tools/examples/shared/node_modules
|
||||
aio/tools/examples/shared/example-scaffold
|
||||
|
||||
# All integration test node_modules folders
|
||||
integration/animations/node_modules
|
||||
@@ -13,9 +17,6 @@ integration/cli-hello-world/node_modules
|
||||
integration/cli-hello-world-ivy-i18n/node_modules
|
||||
integration/cli-hello-world-lazy/node_modules
|
||||
integration/cli-hello-world-mocha/node_modules
|
||||
integration/cli-signal-inputs/node_modules
|
||||
integration/platform-server-hydration/node_modules
|
||||
integration/defer/node_modules
|
||||
integration/dynamic-compiler/node_modules
|
||||
integration/forms/node_modules
|
||||
integration/injectable-def/node_modules
|
||||
@@ -36,4 +37,3 @@ integration/typings_test_rxjs7/node_modules
|
||||
integration/typings_test_ts49/node_modules
|
||||
integration/typings_test_ts50/node_modules
|
||||
integration/typings_test_ts51/node_modules
|
||||
integration/typings_test_ts52/node_modules
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 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 --spawn_strategy=local
|
||||
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
|
||||
|
||||
# Do not attempt to de-flake locally.
|
||||
# On CI we might set this to `3` to run with deflaking.
|
||||
@@ -56,16 +56,31 @@ build --enable_runfiles
|
||||
build:release --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=release"
|
||||
build:release --stamp
|
||||
|
||||
# Building AIO against local Angular deps requires stamping
|
||||
# versions in Angular packages due to CLI version checks.
|
||||
build:aio_local_deps --stamp
|
||||
build:aio_local_deps --workspace_status_command="yarn -s --cwd aio local-workspace-status"
|
||||
|
||||
# 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
|
||||
|
||||
# Angular DevTools for Firefox releases *cannot* be stamped and `--config snapshot-build-firefox` is a no-op.
|
||||
# This is because Mozilla requires add-on source code to be uploaded and then they manually reproduce the build.
|
||||
# If we stamp the build based on Git information such as the current commit, then reproducing the build would require
|
||||
# uploading the entire `.git` directory. We already must upload the entire monorepo, and uploading `.git` as well
|
||||
# exceeds the max source file size. To address this, we just *don't* stamp Firefox builds of Angular DevTools.
|
||||
build:snapshot-build-firefox --nostamp
|
||||
##########################################################
|
||||
# AIO architect build configuration #
|
||||
# See aio/angular.json for available configurations. #
|
||||
# To build with a partiular configuration: #
|
||||
# bazel build //aio:build --aio_build_config=<config> #
|
||||
# Default config is `stable``. #
|
||||
##########################################################
|
||||
build --flag_alias=aio_build_config=//aio:flag_aio_build_config
|
||||
|
||||
####################################
|
||||
# AIO first party dep substitution #
|
||||
# Turn on with #
|
||||
# --config=aio_local_deps #
|
||||
####################################
|
||||
|
||||
build:aio_local_deps --//aio:flag_aio_local_deps
|
||||
|
||||
###############################
|
||||
# Output #
|
||||
@@ -103,6 +118,10 @@ common:remote --jobs=200
|
||||
|
||||
build:remote --google_default_credentials
|
||||
|
||||
# Limit the number of test jobs for on an AIO local deps build. The example tests running
|
||||
# concurrently pushes the circleci executor RAM usage to its limits.
|
||||
test:aio_local_deps --jobs=24
|
||||
|
||||
# Force remote exeuctions to consider the entire run as linux
|
||||
build:remote --cpu=k8
|
||||
build:remote --host_cpu=k8
|
||||
@@ -116,16 +135,10 @@ build:remote --platforms=@npm//@angular/build-tooling/bazel/remote-execution:pla
|
||||
|
||||
# Remote instance and caching
|
||||
build:remote --remote_instance_name=projects/internal-200822/instances/primary_instance
|
||||
build:remote --bes_instance_name=internal-200822
|
||||
build:remote --project_id=internal-200822
|
||||
build:remote --remote_cache=remotebuildexecution.googleapis.com
|
||||
build:remote --remote_executor=remotebuildexecution.googleapis.com
|
||||
|
||||
# Use HTTP remote cache
|
||||
build:remote-cache --remote_cache=https://storage.googleapis.com/angular-team-cache
|
||||
build:remote-cache --remote_accept_cached=true
|
||||
build:remote-cache --remote_upload_local_results=true
|
||||
build:remote-cache --google_default_credentials
|
||||
|
||||
# Ensure that tags like "no-remote-exec" get propagated to actions created by rules,
|
||||
# even if the rule implementation does not explicitly pass them to the execution requirements.
|
||||
# https://bazel.build/reference/command-line-reference#flag--experimental_allow_tags_propagation
|
||||
@@ -158,8 +171,6 @@ test:saucelabs --flaky_test_attempts=1
|
||||
|
||||
# --ng_perf will ask the Ivy compiler to produce performance results for each build.
|
||||
build --flag_alias=ng_perf=//packages/compiler-cli:ng_perf
|
||||
# --prerender_adev will run adev build/serve in a full mode, performing prerendering
|
||||
build --flag_alias=prerender_adev=//adev:prerender_adev
|
||||
|
||||
####################################################
|
||||
# User bazel configuration
|
||||
|
||||
+715
-6
@@ -1,16 +1,725 @@
|
||||
# This config is remaining in place to prevent pull requests failing because of CircleCI config missing.
|
||||
# Configuration file for https://circleci.com/gh/angular/angular
|
||||
|
||||
# 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
|
||||
# To validate changes, use an online parser, eg.
|
||||
# https://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
|
||||
|
||||
jobs:
|
||||
pass:
|
||||
# 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.
|
||||
# **NOTE 4 **: To make sure modified patches can be applied without needing to manually update the cache key,
|
||||
# the fallback cache key will not match if patches have been modified.
|
||||
# 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 "patches.hash"}}-{{ 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 "patches.hash"}}-{{ checksum ".bazelversion" }}
|
||||
|
||||
# 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 "patches.hash"}}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}
|
||||
var_4_win: &cache_key_win_fallback v10-angular-win-node-16-{{ checksum "month.txt" }}-{{ checksum "patches.hash"}}-{{ checksum ".bazelversion" }}
|
||||
|
||||
# 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_5: &workspace_location ~/
|
||||
|
||||
# Filter to run a job on builds for pull requests only.
|
||||
var_6: &only_on_pull_requests
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /pull\/\d+/
|
||||
|
||||
# Filter to skip a job on builds for pull requests.
|
||||
var_7: &skip_on_pull_requests
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- /pull\/\d+/
|
||||
|
||||
# Filter to run a job on builds for the main branch only.
|
||||
var_8: &only_on_main_branch
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
|
||||
# Filter to run a job on all releasable branches.
|
||||
var_9: &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.8
|
||||
|
||||
# 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/base:2022.05
|
||||
- image: cimg/node:16.14.0
|
||||
resource_class: << parameters.resource_class >>
|
||||
working_directory: ~/ng
|
||||
|
||||
test-browser-executor:
|
||||
parameters:
|
||||
resource_class:
|
||||
type: string
|
||||
default: medium
|
||||
docker:
|
||||
- image: cimg/node:16.14.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:
|
||||
- run: echo "This too shall pass (always)"
|
||||
- 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 AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=' >> ~/.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
|
||||
|
||||
capture_patches_for_cache_key:
|
||||
description: Hashes all patches so that the cache can be reset upon changes.
|
||||
steps:
|
||||
- run: |
|
||||
md5sum tools/esm-interop/patches/npm/* > patches.hash
|
||||
|
||||
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
|
||||
jobs:
|
||||
setup:
|
||||
executor: default-executor
|
||||
steps:
|
||||
- checkout
|
||||
- save_month_to_file
|
||||
- capture_patches_for_cache_key
|
||||
- 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
|
||||
|
||||
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+
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- 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
|
||||
- notify_webhook_on_fail:
|
||||
webhook_url_env_var: SLACK_REACTIVITY_CHANNEL_WEBHOOK_URL
|
||||
|
||||
# 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
|
||||
environment:
|
||||
NUMBER_OF_PARALLEL_BROWSERS: 2
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- init_saucelabs_environment
|
||||
- run:
|
||||
name: Start Saucelabs daemon service
|
||||
command: yarn bazel run //tools/saucelabs-daemon/background-service -- ${NUMBER_OF_PARALLEL_BROWSERS}
|
||||
background: true
|
||||
- run:
|
||||
name: Run Bazel tests on Saucelabs
|
||||
command: |
|
||||
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 --jobs=${NUMBER_OF_PARALLEL_BROWSERS} ${TESTS}
|
||||
no_output_timeout: 40m
|
||||
- notify_webhook_on_fail:
|
||||
webhook_url_env_var: SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
|
||||
|
||||
test_aio:
|
||||
executor:
|
||||
name: test-browser-executor
|
||||
resource_class: 2xlarge+
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
|
||||
# Run all aio tests
|
||||
- run:
|
||||
command: yarn --cwd aio test:ci
|
||||
no_output_timeout: 20m
|
||||
|
||||
# Check the bundle sizes.
|
||||
- run: yarn --cwd aio payload-size
|
||||
|
||||
deploy_aio:
|
||||
executor:
|
||||
name: test-browser-executor
|
||||
resource_class: 2xlarge+
|
||||
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:
|
||||
name: test-browser-executor
|
||||
resource_class: 2xlarge+
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
# Run all aio tests (with local Angular packages)
|
||||
- run:
|
||||
command: yarn --cwd aio test-local:ci
|
||||
no_output_timeout: 20m
|
||||
|
||||
# Check the bundle sizes.
|
||||
- run: yarn --cwd aio payload-size aio-local
|
||||
|
||||
# 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: Prepare GitHub credentials
|
||||
command: echo "https://${SNAPSHOT_BUILDS_GITHUB_TOKEN}:@github.com" > ${HOME}/.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 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
|
||||
|
||||
test_zonejs:
|
||||
executor:
|
||||
name: default-executor
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- install_java
|
||||
|
||||
- run: |
|
||||
yarn bazel build -- \
|
||||
//packages/zone.js/bundles:zone.umd.js \
|
||||
//packages/zone.js:npm_package \
|
||||
//packages/zone.js/test/closure:closure_js \
|
||||
//packages/zone.js:zone_externs
|
||||
|
||||
- run: |
|
||||
mkdir -p packages/zone.js/build/
|
||||
mkdir -p packages/zone.js/build/test/
|
||||
mkdir -p packages/zone.js/test/
|
||||
|
||||
cp dist/bin/packages/zone.js/bundles/zone.umd.js packages/zone.js/build/zone.umd.js
|
||||
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/test/closure/zone.closure.mjs ./packages/zone.js/build/test/zone.closure.mjs
|
||||
cp dist/bin/packages/zone.js/zone_externs.js ./packages/zone.js/build/zone_externs.js
|
||||
|
||||
# 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 --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
|
||||
|
||||
# Setup the proper NodeJS version. The image comes pre-installed with `nvm-windows`.
|
||||
# Note: This happens immediately after checkout because environment initialization logic
|
||||
# might rely on Node and shouldn't use the older image-provided NodeJS version.
|
||||
- run:
|
||||
name: Install NodeJS version from `.nvmrc`.
|
||||
command: |
|
||||
nvm on
|
||||
nvm install $(cat .nvmrc)
|
||||
nvm use $(cat .nvmrc)
|
||||
- run:
|
||||
name: Debug information for flakiness of Windows job
|
||||
command: |
|
||||
node -v
|
||||
yarn -v
|
||||
which node
|
||||
which yarn
|
||||
echo "Path: $PATH"
|
||||
yarn node -v
|
||||
|
||||
- save_month_to_file
|
||||
- capture_patches_for_cache_key
|
||||
- init_environment
|
||||
- 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
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
default_workflow:
|
||||
jobs:
|
||||
- pass
|
||||
- setup:
|
||||
filters:
|
||||
branches:
|
||||
ignore: g3
|
||||
- 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:
|
||||
- setup
|
||||
- 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
|
||||
# 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
|
||||
- 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 * * *'
|
||||
|
||||
@@ -44,7 +44,7 @@ function setSecretVar() {
|
||||
# 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 computations and may not be needed. When needed, you can call this function to set
|
||||
# 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:
|
||||
|
||||
@@ -16,6 +16,7 @@ echo "source $envHelpersPath;" >> $BASH_ENV;
|
||||
####################################################################################################
|
||||
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";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 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:18.13.0@sha256:45d0ee279f522c4562a464df71108104cc9b2187205333ffd0707d4f05589731
|
||||
FROM cimg/node:16.13-browsers
|
||||
|
||||
|
||||
LABEL name="Angular dev environment" \
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
"postCreateCommand": "yarn install",
|
||||
"extensions": [
|
||||
"devondcarew.bazel-code",
|
||||
"ms-vscode.vscode-typescript-tslint-plugin"
|
||||
"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,4 +1,4 @@
|
||||
name: 'Docs or angular.dev Bug Report'
|
||||
name: 'Docs or angular.io Bug Report'
|
||||
description: Report an issue in Angular's documentation or angular.io application
|
||||
|
||||
body:
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
load("//tools:defaults.bzl", "esbuild_checked_in")
|
||||
|
||||
exports_files([
|
||||
"tsconfig.json",
|
||||
])
|
||||
|
||||
esbuild_checked_in(
|
||||
name = "main",
|
||||
entry_point = "//.github/actions/deploy-docs-site/lib:main.ts",
|
||||
external = [
|
||||
"undici",
|
||||
],
|
||||
platform = "node",
|
||||
target = "node14",
|
||||
deps = [
|
||||
"//.github/actions/deploy-docs-site/lib",
|
||||
],
|
||||
)
|
||||
@@ -1,19 +0,0 @@
|
||||
name: 'Deploy angular.dev site'
|
||||
description: 'Automatically deploy and set up redirects for angular.dev'
|
||||
author: 'Angular'
|
||||
inputs:
|
||||
serviceKey:
|
||||
description: 'The service key used for firebase deployments.'
|
||||
required: true
|
||||
githubReleaseTrainReadToken:
|
||||
description: 'GitHub access token for reading release trains without rate limits.'
|
||||
required: true
|
||||
configPath:
|
||||
description: 'The path to the firebase config file.'
|
||||
required: true
|
||||
distDir:
|
||||
description: 'The path to the firebase dist directory.'
|
||||
required: true
|
||||
runs:
|
||||
using: 'node20'
|
||||
main: 'main.js'
|
||||
@@ -1,23 +0,0 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
package(default_visibility = ["//.github/actions/deploy-docs-site:__subpackages__"])
|
||||
|
||||
exports_files([
|
||||
"main.ts",
|
||||
])
|
||||
|
||||
ts_library(
|
||||
name = "lib",
|
||||
srcs = glob(
|
||||
["*.ts"],
|
||||
),
|
||||
#tsconfig = "//.github/actions/deploy-docs-site:tsconfig.json",
|
||||
deps = [
|
||||
"@npm//@actions/core",
|
||||
"@npm//@actions/github",
|
||||
"@npm//@angular/ng-dev",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/tmp",
|
||||
"@npm//tmp",
|
||||
],
|
||||
)
|
||||
@@ -1,20 +0,0 @@
|
||||
import {fileSync} from 'tmp';
|
||||
import {writeSync} from 'fs';
|
||||
import {getInput, setSecret} from '@actions/core';
|
||||
|
||||
let credentialFilePath: undefined | string;
|
||||
|
||||
export function getCredentialFilePath(): string {
|
||||
if (credentialFilePath === undefined) {
|
||||
const tmpFile = fileSync({postfix: '.json'});
|
||||
writeSync(tmpFile.fd, getInput('serviceKey', {required: true}));
|
||||
setSecret(tmpFile.name);
|
||||
credentialFilePath = tmpFile.name;
|
||||
}
|
||||
return credentialFilePath;
|
||||
}
|
||||
|
||||
/** Github access token. Used for querying the active release trains. */
|
||||
export const githubReleaseTrainReadToken: string = getInput('githubReleaseTrainReadToken', {
|
||||
required: true,
|
||||
});
|
||||
@@ -1,116 +0,0 @@
|
||||
import {cp, mkdtemp, readFile, rm, writeFile} from 'fs/promises';
|
||||
import {Deployment} from './deployments';
|
||||
import {join} from 'path';
|
||||
|
||||
import {tmpdir} from 'os';
|
||||
import {spawnSync} from 'child_process';
|
||||
import {getCredentialFilePath} from './credential';
|
||||
|
||||
export async function deployToFirebase(
|
||||
deployment: Deployment,
|
||||
configPath: string,
|
||||
distDirPath: string,
|
||||
) {
|
||||
if (deployment.destination == undefined) {
|
||||
console.log(`No deployment necessary for docs created from: ${deployment.branch}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Preparing for deployment to firebase...');
|
||||
|
||||
const tmpDeployDir = await mkdtemp(join(tmpdir(), 'deploy-directory'));
|
||||
const deployConfigPath = join(tmpDeployDir, 'firebase.json');
|
||||
|
||||
const config = JSON.parse(await readFile(configPath, {encoding: 'utf-8'})) as {
|
||||
hosting: {public: string};
|
||||
};
|
||||
config['hosting']['public'] = './dist';
|
||||
|
||||
await writeFile(deployConfigPath, JSON.stringify(config, null, 2));
|
||||
|
||||
await cp(distDirPath, join(tmpDeployDir, 'dist'), {recursive: true});
|
||||
spawnSync(`chmod 777 -R ${tmpDeployDir}`, {encoding: 'utf-8', shell: true});
|
||||
|
||||
firebase(
|
||||
`target:clear --config ${deployConfigPath} --project angular-dev-site hosting angular-docs`,
|
||||
tmpDeployDir,
|
||||
);
|
||||
firebase(
|
||||
`target:apply --config ${deployConfigPath} --project angular-dev-site hosting angular-docs ${deployment.destination}`,
|
||||
tmpDeployDir,
|
||||
);
|
||||
firebase(
|
||||
`deploy --config ${deployConfigPath} --project angular-dev-site --only hosting --non-interactive`,
|
||||
tmpDeployDir,
|
||||
);
|
||||
firebase(
|
||||
`target:clear --config ${deployConfigPath} --project angular-dev-site hosting angular-docs`,
|
||||
tmpDeployDir,
|
||||
);
|
||||
|
||||
await rm(tmpDeployDir, {recursive: true});
|
||||
}
|
||||
|
||||
export async function setupRedirect(deployment: Deployment) {
|
||||
if (deployment.redirect === undefined) {
|
||||
console.log(`No redirect necessary for docs created from: ${deployment.branch}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Preparing to set up redirect on firebase...');
|
||||
|
||||
const redirectConfig = JSON.stringify(
|
||||
{
|
||||
hosting: {
|
||||
target: 'angular-docs',
|
||||
redirects: [
|
||||
{
|
||||
type: 302,
|
||||
regex: '^(.*)$',
|
||||
destination: `${deployment.redirect.to}:1`,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
|
||||
const tmpRedirectDir = await mkdtemp(join(tmpdir(), 'redirect-directory'));
|
||||
const redirectConfigPath = join(tmpRedirectDir, 'firebase.json');
|
||||
|
||||
await writeFile(redirectConfigPath, redirectConfig);
|
||||
spawnSync(`chmod 777 -R ${tmpRedirectDir}`, {encoding: 'utf-8', shell: true});
|
||||
|
||||
firebase(
|
||||
`target:clear --config ${redirectConfigPath} --project angular-dev-site hosting angular-docs`,
|
||||
tmpRedirectDir,
|
||||
);
|
||||
firebase(
|
||||
`target:apply --config ${redirectConfigPath} --project angular-dev-site hosting angular-docs ${deployment.redirect.from}`,
|
||||
tmpRedirectDir,
|
||||
);
|
||||
firebase(
|
||||
`deploy --config ${redirectConfigPath} --project angular-dev-site --only hosting --non-interactive`,
|
||||
tmpRedirectDir,
|
||||
);
|
||||
firebase(
|
||||
`target:clear --config ${redirectConfigPath} --project angular-dev-site hosting angular-docs`,
|
||||
tmpRedirectDir,
|
||||
);
|
||||
|
||||
await rm(tmpRedirectDir, {recursive: true});
|
||||
}
|
||||
|
||||
function firebase(cmd: string, cwd?: string) {
|
||||
spawnSync('npx', `-y firebase-tools@latest ${cmd}`.split(' '), {
|
||||
cwd,
|
||||
encoding: 'utf-8',
|
||||
shell: true,
|
||||
stdio: 'inherit',
|
||||
env: {
|
||||
...process.env,
|
||||
GOOGLE_APPLICATION_CREDENTIALS: getCredentialFilePath(),
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import {fetchLongTermSupportBranchesFromNpm, ActiveReleaseTrains} from '@angular/ng-dev';
|
||||
import {ReleaseConfig} from '@angular/ng-dev';
|
||||
import {AuthenticatedGitClient} from '@angular/ng-dev';
|
||||
|
||||
export interface Deployment {
|
||||
branch: string;
|
||||
redirect?: {
|
||||
from: string;
|
||||
to: string;
|
||||
};
|
||||
destination?: string;
|
||||
}
|
||||
|
||||
export type Deployments = Map<string, Deployment>;
|
||||
|
||||
export async function getDeployments(): Promise<Deployments> {
|
||||
const {github} = await AuthenticatedGitClient.get();
|
||||
const releaseTrains = await ActiveReleaseTrains.fetch({
|
||||
api: github,
|
||||
name: 'angular',
|
||||
owner: 'angular',
|
||||
nextBranchName: 'main',
|
||||
});
|
||||
const ltsBranches = await fetchLongTermSupportBranchesFromNpm({
|
||||
representativeNpmPackage: '@angular/core',
|
||||
} as ReleaseConfig);
|
||||
|
||||
const docSites = new Map<string, Deployment>();
|
||||
|
||||
[...ltsBranches.active, ...ltsBranches.inactive].forEach((branch) => {
|
||||
docSites.set(branch.name, {
|
||||
branch: branch.name,
|
||||
destination: `v${branch.version.major}-angular-dev`,
|
||||
});
|
||||
});
|
||||
|
||||
docSites.set(releaseTrains.latest.branchName, {
|
||||
branch: releaseTrains.latest.branchName,
|
||||
redirect: {
|
||||
from: `v${releaseTrains.latest.version.major}-angular-dev`,
|
||||
to: 'https://angular.dev',
|
||||
},
|
||||
destination: 'angular-dev-site',
|
||||
});
|
||||
|
||||
if (releaseTrains.releaseCandidate) {
|
||||
docSites.set(releaseTrains.next.branchName, {
|
||||
branch: releaseTrains.next.branchName,
|
||||
});
|
||||
|
||||
docSites.set(releaseTrains.releaseCandidate.branchName, {
|
||||
branch: releaseTrains.releaseCandidate.branchName,
|
||||
destination: 'next-angular-dev',
|
||||
redirect: {
|
||||
from: `v${releaseTrains.releaseCandidate.version.major}-angular-dev`,
|
||||
to: 'https://next.angular.dev',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
docSites.set(releaseTrains.next.branchName, {
|
||||
branch: releaseTrains.next.branchName,
|
||||
destination: 'next-angular-dev',
|
||||
});
|
||||
}
|
||||
|
||||
return docSites;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import {getInput, setFailed} from '@actions/core';
|
||||
import {context} from '@actions/github';
|
||||
import {deployToFirebase, setupRedirect} from './deploy';
|
||||
import {getDeployments} from './deployments';
|
||||
import {AuthenticatedGitClient, GithubConfig, setConfig} from '@angular/ng-dev';
|
||||
import {githubReleaseTrainReadToken} from './credential';
|
||||
|
||||
const refMatcher = /refs\/heads\/(.*)/;
|
||||
|
||||
async function deployDocs() {
|
||||
setConfig({
|
||||
github: <GithubConfig>{
|
||||
mainBranchName: 'main',
|
||||
name: 'angular',
|
||||
owner: 'angular',
|
||||
},
|
||||
});
|
||||
|
||||
AuthenticatedGitClient.configure(githubReleaseTrainReadToken);
|
||||
|
||||
if (context.eventName !== 'push') {
|
||||
throw Error();
|
||||
}
|
||||
const matchedRef = context.ref.match(refMatcher);
|
||||
if (matchedRef === null) {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
const currentBranch = matchedRef[1];
|
||||
const configPath = getInput('configPath');
|
||||
const distDir = getInput('distDir');
|
||||
|
||||
const deployment = (await getDeployments()).get(currentBranch);
|
||||
if (deployment === undefined) {
|
||||
console.log(`Current branch (${currentBranch}) does not deploy a documentation site.`);
|
||||
console.log(`Exiting...`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log('Doc site deployment information');
|
||||
console.log('');
|
||||
console.log('Current Branch:');
|
||||
console.log(` ${deployment.branch}`);
|
||||
console.log('');
|
||||
console.log('Firebase Site:');
|
||||
if (deployment.destination === undefined) {
|
||||
console.log(' No deployment of a documenation site is necessary');
|
||||
} else {
|
||||
console.log(` Deploying to: ${deployment.destination}`);
|
||||
}
|
||||
console.log('');
|
||||
console.log('Redirect Configuration:');
|
||||
if (deployment.redirect === undefined) {
|
||||
console.log(' No redirects are necessary');
|
||||
} else {
|
||||
console.log(` From: ${deployment.redirect.from}`);
|
||||
console.log(` To: ${deployment.redirect.to}`);
|
||||
}
|
||||
|
||||
await deployToFirebase(deployment, configPath, distDir);
|
||||
await setupRedirect(deployment);
|
||||
}
|
||||
|
||||
// Only run if the action is executed in a repository with is in the Angular org. This is in place
|
||||
// to prevent the action from actually running in a fork of a repository with this action set up.
|
||||
if (context.repo.owner === 'angular') {
|
||||
deployDocs().catch((e: Error) => {
|
||||
setFailed(e.message);
|
||||
console.error(e);
|
||||
});
|
||||
} else {
|
||||
console.warn(
|
||||
'The action was skipped as this action is only meant to run in repos belonging to the Angular organization.',
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "Node16",
|
||||
"target": "es2020",
|
||||
"lib": ["es2021", "dom"],
|
||||
"experimentalDecorators": true,
|
||||
"strict": true,
|
||||
"outDir": "../../../dist/tsc-non-bazel-out",
|
||||
"skipLibCheck": true,
|
||||
"noImplicitOverride": true,
|
||||
// TODO(ESM): Remove this when Bazel also uses the Node resolution.
|
||||
"esModuleInterop": true,
|
||||
"noImplicitReturns": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "h",
|
||||
"jsxFragmentFactory": "Fragment"
|
||||
},
|
||||
"exclude": []
|
||||
}
|
||||
@@ -4,7 +4,7 @@ description: 'Installs the dependencies using Yarn'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
|
||||
- uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3
|
||||
with:
|
||||
path: |
|
||||
./node_modules/
|
||||
|
||||
@@ -68,6 +68,7 @@ merge:
|
||||
|
||||
# list of PR statuses that need to be successful
|
||||
requiredStatuses:
|
||||
- 'ci/circleci: build'
|
||||
- 'google-internal-tests'
|
||||
- 'pullapprove'
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow builds the previews for pull requests when a certain label is applied.
|
||||
# The actual deployment happens as part of a dedicated second workflow to avoid security
|
||||
# issues where the building would otherwise occur in an authorized context where secrets
|
||||
# could be leaked. More details can be found here:
|
||||
|
||||
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
|
||||
|
||||
name: Build adev for preview deployment
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [synchronize, labeled]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
adev-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
(github.event.action == 'labeled' && github.event.label.name == 'adev: preview') ||
|
||||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'adev: preview'))
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --prerender_adev --config=release
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
pull-number: '${{github.event.pull_request.number}}'
|
||||
artifact-build-revision: '${{github.event.pull_request.head.sha}}'
|
||||
deploy-directory: './dist/bin/adev/build/browser'
|
||||
@@ -1,50 +0,0 @@
|
||||
# This workflow runs whenever the ADEV build workflow has completed. Deployment happens
|
||||
# as part of a dedicated second workflow to avoid security issues where the building would
|
||||
# otherwise occur in an authorized context where secrets could be leaked.
|
||||
#
|
||||
# More details can be found here:
|
||||
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
|
||||
|
||||
name: Deploying adev preview to Firebase
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Build adev for preview deployment']
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
# Needed in order to be able to comment on the pull request.
|
||||
pull-requests: write
|
||||
# Needed in order to checkout the repository
|
||||
contents: read
|
||||
# Needed in order to retrieve the artifacts from the previous job
|
||||
actions: read
|
||||
|
||||
env:
|
||||
PREVIEW_PROJECT: ng-dev-previews
|
||||
PREVIEW_SITE: ng-dev-previews-fw
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
token: '${{secrets.GITHUB_TOKEN}}'
|
||||
|
||||
- name: Configure Firebase deploy target
|
||||
working-directory: ./
|
||||
run: |
|
||||
# We can use `npx` as the Firebase deploy actions uses it too.
|
||||
npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
|
||||
npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}}
|
||||
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
github-token: '${{secrets.GITHUB_TOKEN}}'
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
firebase-config-dir: './adev'
|
||||
firebase-public-dir: './adev/build/browser'
|
||||
firebase-project-id: '${{env.PREVIEW_PROJECT}}'
|
||||
firebase-service-key: '${{secrets.FIREBASE_PREVIEW_SERVICE_TOKEN}}'
|
||||
@@ -0,0 +1,42 @@
|
||||
# This workflow builds the AIO previews for pull requests when a certain label is applied.
|
||||
# The actual deployment happens as part of a dedicated second workflow to avoid security
|
||||
# issues where the building would otherwise occur in an authorized context where secrets
|
||||
# could be leaked. More details can be found here:
|
||||
|
||||
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
|
||||
|
||||
name: Build AIO app for preview deployment
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [synchronize, labeled]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
aio-build:
|
||||
runs-on: ubuntu-latest
|
||||
# We only want to build and deploy the AIO app if the `aio: preview` label has been
|
||||
# added, or if the label is already applied and new changes have been made in the PR.
|
||||
if: |
|
||||
(github.event.action == 'labeled' && github.event.label.name == 'aio: preview') ||
|
||||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'aio: preview'))
|
||||
steps:
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- uses: ./.github/actions/yarn-install
|
||||
|
||||
- uses: angular/dev-infra/github-actions/setup-bazel-remote-exec@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
# Build the web package. Note: We run Bazel from a low-resource Github action container,
|
||||
# so we manually need to instruct Bazel to run more actions concurrently as by default
|
||||
# the number of concurrent actions is determined based on the host resources.
|
||||
- run: bazel build //aio:build --jobs=32 --announce_rc --verbose_failures
|
||||
|
||||
- uses: angular/dev-infra/github-actions/deploy-previews/pack-and-upload-artifact@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
workflow-artifact-name: 'aio'
|
||||
pull-number: '${{github.event.pull_request.number}}'
|
||||
artifact-build-revision: '${{github.event.pull_request.head.sha}}'
|
||||
deploy-directory: './dist/bin/aio/build'
|
||||
@@ -0,0 +1,44 @@
|
||||
# This workflow runs whenever the AIO build workflow has completed. Deployment happens
|
||||
# as part of a dedicated second workflow to avoid security issues where the building would
|
||||
# otherwise occur in an authorized context where secrets could be leaked.
|
||||
#
|
||||
# More details can be found here:
|
||||
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
|
||||
|
||||
name: Deploying AIO preview to Firebase
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Build AIO app for preview deployment']
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
# Needed in order to be able to comment on the pull request.
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
PREVIEW_PROJECT: ng-dev-previews
|
||||
PREVIEW_SITE: ng-dev-previews-fw
|
||||
|
||||
jobs:
|
||||
aio-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
|
||||
- name: Configure Firebase deploy target
|
||||
working-directory: aio/
|
||||
run: |
|
||||
# We can use `npx` as the Firebase deploy actions uses it too.
|
||||
npx -y firebase-tools@latest target:clear --project ${{env.PREVIEW_PROJECT}} hosting aio
|
||||
npx -y firebase-tools@latest target:apply --project ${{env.PREVIEW_PROJECT}} hosting aio ${{env.PREVIEW_SITE}}
|
||||
|
||||
- uses: angular/dev-infra/github-actions/deploy-previews/upload-artifacts-to-firebase@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
github-token: '${{secrets.GITHUB_TOKEN}}'
|
||||
workflow-artifact-name: 'aio'
|
||||
firebase-config-dir: './aio/'
|
||||
firebase-public-dir: './aio/dist'
|
||||
firebase-project-id: '${{env.PREVIEW_PROJECT}}'
|
||||
firebase-service-key: '${{secrets.FIREBASE_PREVIEW_SERVICE_TOKEN}}'
|
||||
@@ -13,9 +13,9 @@ jobs:
|
||||
assistant_to_the_branch_manager:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
exit: true
|
||||
|
||||
# Indicate that the benchmark command was received.
|
||||
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||
- uses: peter-evans/create-or-update-comment@c6c9a1a66007646a28c153e2a8580a5bad27bcfa # v3
|
||||
with:
|
||||
comment-id: ${{github.event.comment.id}}
|
||||
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- uses: alessbell/pull-request-comment-branch@aad01d65d6982b8eacabed5e9a684cd8ceb98da6 # v1.1
|
||||
id: comment-branch
|
||||
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
# Specify repository as the PR branch might be from a fork.
|
||||
repository: ${{steps.comment-branch.outputs.head_owner}}/${{steps.comment-branch.outputs.head_repo}}
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- uses: ./.github/actions/yarn-install
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- uses: angular/dev-infra/github-actions/setup-bazel-remote-exec@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
id: benchmark
|
||||
name: Running benchmark
|
||||
|
||||
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||
- uses: peter-evans/create-or-update-comment@c6c9a1a66007646a28c153e2a8580a5bad27bcfa # v3
|
||||
with:
|
||||
issue-number: ${{github.event.issue.number}}
|
||||
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
|
||||
|
||||
+20
-165
@@ -5,6 +5,8 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- '[0-9]+.[0-9]+.x'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -21,13 +23,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@852c3d1898775ec9fbc87213e519f16e78805b57
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./node_modules
|
||||
./aio/node_modules
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Install node modules in aio
|
||||
run: yarn install --frozen-lockfile --cwd aio
|
||||
- name: Check code lint
|
||||
run: yarn -s tslint
|
||||
- name: Check code lint in aio
|
||||
run: yarn -s --cwd aio lint
|
||||
- name: Check for circular dependencies
|
||||
run: yarn -s ts-circular-deps:check
|
||||
- name: Validate pull approve configuration
|
||||
@@ -36,167 +45,13 @@ jobs:
|
||||
run: yarn -s ng-dev ngbot verify
|
||||
- name: Confirm code builds with typescript as expected
|
||||
run: yarn -s check-tooling-setup
|
||||
|
||||
devtools:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
run: yarn devtools:test
|
||||
- name: Test build
|
||||
run: yarn devtools:build:chrome
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
run: yarn test:ci
|
||||
|
||||
adev:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev in fast mode to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --config=release
|
||||
- name: Run tests
|
||||
run: yarn bazel test //adev:test
|
||||
|
||||
publish-snapshots:
|
||||
runs-on:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
|
||||
- run: yarn build
|
||||
- run: ./scripts/ci/publish-build-artifacts.sh
|
||||
|
||||
zone-js:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./node_modules
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
yarn bazel build \
|
||||
//packages/zone.js/bundles:zone.umd.js \
|
||||
//packages/zone.js:npm_package \
|
||||
//packages/zone.js/test/closure:closure_js \
|
||||
|
||||
- run: |
|
||||
rm -Rf packages/zone.js/build
|
||||
rm -Rf packages/zone.js/test/extra/*.umd.js
|
||||
|
||||
mkdir -p packages/zone.js/build/
|
||||
mkdir -p packages/zone.js/build/test/
|
||||
|
||||
cp dist/bin/packages/zone.js/bundles/zone.umd.js packages/zone.js/build/zone.umd.js
|
||||
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/test/closure/zone.closure.mjs ./packages/zone.js/build/test/zone.closure.mjs
|
||||
|
||||
# Install
|
||||
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive
|
||||
# Run zone.js tools tests
|
||||
- run: yarn --cwd packages/zone.js promisefinallytest
|
||||
- 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/test/typings install --frozen-lockfile --non-interactive
|
||||
- run: yarn --cwd packages/zone.js/test/typings test
|
||||
|
||||
bazel-saucelabs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
env:
|
||||
JOBS: 2
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Set up Sauce Tunnel Daemon
|
||||
run: yarn bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
|
||||
env:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
- name: Run all saucelabs bazel tests
|
||||
run: |
|
||||
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 --jobs=$JOBS ${TESTS}
|
||||
|
||||
adev-deploy:
|
||||
needs: [adev]
|
||||
if: needs.adev.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --prerender_adev --config=release
|
||||
- name: Deploy to firebase
|
||||
uses: ./.github/actions/deploy-docs-site
|
||||
with:
|
||||
serviceKey: ${{ secrets.ANGULAR_DEV_SITE_DEPLOY }}
|
||||
githubReleaseTrainReadToken: ${{ secrets.DOCS_DEPLOY_GITHUB_RELEASE_TRAIN_TOKEN }}
|
||||
configPath: 'adev/firebase.json'
|
||||
distDir: 'dist/bin/adev/build/browser'
|
||||
- name: Check commit message
|
||||
# Commit message validation is only done on pull requests as its too late to validate once
|
||||
# it has been merged.
|
||||
if: github.event_name == 'pull_request'
|
||||
run: yarn ng-dev commit-message validate-range ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
|
||||
- name: Check code format
|
||||
# Code formatting checks are only done on pull requests as its too late to validate once
|
||||
# it has been merged.
|
||||
if: github.event_name == 'pull_request'
|
||||
run: yarn ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
|
||||
|
||||
@@ -12,14 +12,14 @@ jobs:
|
||||
labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@11bd341a82719997a59039363f716bea76b88459
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
post_approval_changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
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@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
@@ -4,17 +4,16 @@ on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
permissions: {}
|
||||
permissions:
|
||||
pull-requests: read
|
||||
statuses: write
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
permissions:
|
||||
pull-requests: read
|
||||
statuses: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
run-tests-guide-url: http://go/angular-g3sync-start
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -9,6 +9,6 @@ jobs:
|
||||
status:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
name: Pull Request
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Check code lint
|
||||
run: yarn -s tslint
|
||||
- name: Check for circular dependencies
|
||||
run: yarn -s ts-circular-deps:check
|
||||
- name: Validate pull approve configuration
|
||||
run: yarn -s ng-dev pullapprove verify
|
||||
- name: Validate angular robot configuration
|
||||
run: yarn -s ng-dev ngbot verify
|
||||
- name: Confirm code builds with typescript as expected
|
||||
run: yarn -s check-tooling-setup
|
||||
- name: Check commit message
|
||||
run: yarn ng-dev commit-message validate-range ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
|
||||
- name: Check code format
|
||||
run: yarn ng-dev format changed --check ${{ github.event.pull_request.base.sha }}
|
||||
- name: Check Package Licenses
|
||||
uses: angular/dev-infra/github-actions/linting/licenses@56966c765e97f463c4795fac85d46543d1e6b342
|
||||
with:
|
||||
allow-dependencies-licenses: 'pkg:npm/google-protobuf@'
|
||||
|
||||
devtools:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
run: yarn devtools:test
|
||||
- name: Test build
|
||||
run: yarn devtools:build:chrome
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
run: yarn test:ci
|
||||
|
||||
artifacts:
|
||||
needs: [test]
|
||||
if: needs.test.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
run: yarn tsx ./scripts/build/build-packages-dist.mts
|
||||
- name: Archive build artifacts
|
||||
uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4.3.5
|
||||
with:
|
||||
name: pr-artifacts-${{ github.event.number }}
|
||||
path: dist/packages-dist/
|
||||
|
||||
adev:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev in fast mode to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --config=release
|
||||
- name: Run tests
|
||||
run: yarn bazel test //adev:test
|
||||
|
||||
zone-js:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./node_modules
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
yarn bazel build \
|
||||
//packages/zone.js/bundles:zone.umd.js \
|
||||
//packages/zone.js:npm_package \
|
||||
//packages/zone.js/test/closure:closure_js \
|
||||
|
||||
- run: |
|
||||
rm -Rf packages/zone.js/build
|
||||
rm -Rf packages/zone.js/test/extra/*.umd.js
|
||||
|
||||
mkdir -p packages/zone.js/build/
|
||||
mkdir -p packages/zone.js/build/test/
|
||||
|
||||
cp dist/bin/packages/zone.js/bundles/zone.umd.js packages/zone.js/build/zone.umd.js
|
||||
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/test/closure/zone.closure.mjs ./packages/zone.js/build/test/zone.closure.mjs
|
||||
|
||||
# Install
|
||||
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive
|
||||
# Run zone.js tools tests
|
||||
- run: yarn --cwd packages/zone.js promisefinallytest
|
||||
- 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/test/typings install --frozen-lockfile --non-interactive
|
||||
- run: yarn --cwd packages/zone.js/test/typings test
|
||||
|
||||
saucelabs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
env:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
- name: Starting Saucelabs tunnel service
|
||||
run: ./tools/saucelabs/sauce-service.sh run &
|
||||
# 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.
|
||||
- name: Preparing Bazel-generated fixtures required in legacy tests
|
||||
run: |
|
||||
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
|
||||
- name: Build bundle of tests to run on Saucelabs
|
||||
run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
|
||||
- name: Wait and confirm Saucelabs tunnel has connected
|
||||
run: ./tools/saucelabs/sauce-service.sh ready-wait
|
||||
timeout-minutes: 3
|
||||
- name: Running tests on Saucelabs.
|
||||
run: KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
|
||||
- name: Stop Saucelabs tunnel service
|
||||
run: ./tools/saucelabs/sauce-service.sh stop
|
||||
@@ -25,12 +25,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: 'Run analysis'
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
# Upload the results as artifacts.
|
||||
- name: 'Upload artifact'
|
||||
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -47,6 +47,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5
|
||||
uses: github/codeql-action/upload-sarif@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2.20.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Update ADEV Angular CLI help
|
||||
name: Update AIO Angular CLI help
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
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
|
||||
@@ -28,11 +28,11 @@ jobs:
|
||||
# This is needed as otherwise the PR creation will fail with `shallow update not allowed` when the forked branch is not in sync.
|
||||
fetch-depth: 0
|
||||
- name: Generate CLI help
|
||||
run: node adev/scripts/update-cli-help/index.mjs
|
||||
run: node aio/scripts/update-cli-help/index.mjs
|
||||
env:
|
||||
ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN }}
|
||||
- name: Create a PR (if necessary)
|
||||
uses: angular/dev-infra/github-actions/create-pr-for-changes@03b8a7dffd1205e061f0bee949024ebefc2a6592
|
||||
uses: angular/dev-infra/github-actions/create-pr-for-changes@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
with:
|
||||
branch-prefix: update-cli-help
|
||||
pr-title: 'docs: update Angular CLI help [${{github.ref_name}}]'
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# 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@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
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
|
||||
# This is needed as otherwise the PR creation will fail with `shallow update not allowed` when the forked branch is not in sync.
|
||||
fetch-depth: 0
|
||||
- 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@97cb376945b07e37671e3b38ee727ff00dc1394b
|
||||
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 }}
|
||||
+1
-8
@@ -56,11 +56,4 @@ baseline.json
|
||||
|
||||
# Husky
|
||||
.husky/_
|
||||
|
||||
|
||||
# Ignore cache created with the Angular CLI.
|
||||
.angular/
|
||||
|
||||
# Ignore AIO files, useful when changing branches
|
||||
aio/node_modules
|
||||
aio/out-tsc
|
||||
aio/content/examples/.DS_Store
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname $0)/_/husky.sh"
|
||||
|
||||
set +e
|
||||
|
||||
yarn -s ng-dev commit-message pre-commit-validate --file $1 2>/dev/null
|
||||
|
||||
+4
-1
@@ -1,8 +1,11 @@
|
||||
set +e
|
||||
#!/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;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname $0)/_/husky.sh"
|
||||
|
||||
set +e
|
||||
|
||||
yarn -s ng-dev commit-message restore-commit-message-draft $1 $2 2>/dev/null
|
||||
|
||||
+13
-9
@@ -5,26 +5,30 @@ import {FormatConfig} from '@angular/ng-dev';
|
||||
*/
|
||||
export const format: FormatConfig = {
|
||||
'prettier': {
|
||||
'matchers': ['**/*.{yaml,yml}'],
|
||||
},
|
||||
'clang-format': {
|
||||
'matchers': [
|
||||
'**/*.{yaml,yml}',
|
||||
'**/*.{js,ts}',
|
||||
|
||||
// Do not format d.ts files as they are generated
|
||||
'!**/*.d.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',
|
||||
// Test cases contain non valid code.
|
||||
'!packages/compiler-cli/test/compliance/test_cases/**/*.{js,ts}',
|
||||
|
||||
// Ignore generated javascript file(s)
|
||||
'!.github/actions/deploy-docs-site/main.js',
|
||||
],
|
||||
},
|
||||
'buildifier': true,
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
{
|
||||
"syncedFilePatterns": [
|
||||
"LICENSE",
|
||||
"modules/benchmarks/**",
|
||||
"packages/**"
|
||||
],
|
||||
"separateFilePatterns": [
|
||||
"packages/core/primitives/**"
|
||||
],
|
||||
"syncedFilePatterns": ["LICENSE", "modules/benchmarks/**", "packages/**"],
|
||||
"alwaysExternalFilePatterns": [
|
||||
"packages/*",
|
||||
"packages/bazel/*",
|
||||
@@ -29,6 +22,7 @@
|
||||
"packages/docs/**",
|
||||
"packages/elements/schematics/**",
|
||||
"packages/examples/**",
|
||||
"packages/language-service/**",
|
||||
"packages/localize/**",
|
||||
"packages/private/**",
|
||||
"packages/service-worker/**",
|
||||
@@ -37,6 +31,8 @@
|
||||
"packages/http/**",
|
||||
"**/.gitignore",
|
||||
"**/.gitkeep",
|
||||
"**/yarn.lock",
|
||||
"**/package.json",
|
||||
"**/third_party/**",
|
||||
"**/tsconfig-build.json",
|
||||
"**/tsconfig-tsec.json",
|
||||
|
||||
@@ -17,9 +17,4 @@ export const pullRequest: PullRequestConfig = {
|
||||
// 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'],
|
||||
// enables specific validations during the pull request merge process
|
||||
validators: {
|
||||
assertEnforceTested: true,
|
||||
assertIsolatedSeparateFiles: true,
|
||||
},
|
||||
};
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ export const release: ReleaseConfig = {
|
||||
return performNpmReleaseBuild();
|
||||
},
|
||||
releaseNotes: {
|
||||
hiddenScopes: ['bazel', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
|
||||
hiddenScopes: ['aio', 'bazel', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
|
||||
},
|
||||
releasePrLabels: ['area: build & ci', 'action: merge', 'PullApprove: disable'],
|
||||
};
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"embeddedLanguageFormatting": "off",
|
||||
"tabs": false,
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"semicolon": true,
|
||||
"quoteProps": "preserve",
|
||||
"bracketSpacing": false
|
||||
}
|
||||
|
||||
+573
-107
@@ -57,7 +57,8 @@
|
||||
version: 3
|
||||
|
||||
availability:
|
||||
users_unavailable: []
|
||||
users_unavailable:
|
||||
- atscott
|
||||
|
||||
# Meta field that goes unused by PullApprove to allow for defining aliases to be
|
||||
# used throughout the config.
|
||||
@@ -121,13 +122,26 @@ groups:
|
||||
contains_any_globs(files, [
|
||||
'packages/animations/**/{*,.*}',
|
||||
'packages/platform-browser/animations/**/{*,.*}',
|
||||
'aio/content/guide/animations.md',
|
||||
'aio/content/guide/add-an-animation.md',
|
||||
'aio/content/guide/animate-state-style.md',
|
||||
'aio/content/guide/animation-api-summary.md',
|
||||
'aio/content/guide/understanding-angular-animation.md',
|
||||
'aio/content/examples/animations/**/{*,.*}',
|
||||
'aio/content/images/guide/animations/**/{*,.*}',
|
||||
'aio/content/guide/complex-animation-sequences.md',
|
||||
'aio/content/guide/reusable-animations.md',
|
||||
'aio/content/guide/route-animations.md',
|
||||
'aio/content/guide/transition-and-triggers.md',
|
||||
'aio/content/guide/animations-attach-to-html-template.md',
|
||||
'aio/content/guide/animation-transition-timing.md'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- alxhub
|
||||
- crisbeto
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
|
||||
# =========================================================
|
||||
# Framework: Compiler
|
||||
@@ -139,7 +153,13 @@ groups:
|
||||
contains_any_globs(files, [
|
||||
'packages/compiler/**/{*,.*}',
|
||||
'packages/examples/compiler/**/{*,.*}',
|
||||
'aio/content/examples/angular-compiler-options/**/{*,.*}',
|
||||
'packages/compiler-cli/**/{*,.*}',
|
||||
'aio/content/guide/angular-compiler-options.md',
|
||||
'aio/content/guide/aot-compiler.md',
|
||||
'aio/content/guide/aot-metadata-errors.md',
|
||||
'aio/content/guide/template-typecheck.md',
|
||||
'aio/content/extended-diagnostics/*.md'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -147,8 +167,6 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- crisbeto
|
||||
- devversion
|
||||
- dylhunn
|
||||
- JoostK
|
||||
|
||||
# =========================================================
|
||||
@@ -164,8 +182,6 @@ groups:
|
||||
- crisbeto
|
||||
- devversion
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- AndrewKushnir
|
||||
|
||||
# =========================================================
|
||||
# Framework: Core
|
||||
@@ -174,13 +190,154 @@ groups:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files.exclude("packages/core/schematics/*").exclude('packages/core/primitives/*'), [
|
||||
contains_any_globs(files.exclude("packages/core/schematics/*"), [
|
||||
'packages/core/**/{*,.*}',
|
||||
'packages/examples/core/**/{*,.*}',
|
||||
'packages/platform-browser/**/{*,.*}',
|
||||
'packages/examples/platform-browser/**/{*,.*}',
|
||||
'packages/platform-browser-dynamic/**/{*,.*}',
|
||||
'packages/docs/**/{*,.*}',
|
||||
'aio/content/guide/accessibility.md',
|
||||
'aio/content/examples/accessibility/**/{*,.*}',
|
||||
'aio/content/guide/architecture-components.md',
|
||||
'aio/content/guide/architecture-modules.md',
|
||||
'aio/content/guide/architecture-next-steps.md',
|
||||
'aio/content/guide/architecture-services.md',
|
||||
'aio/content/guide/architecture.md',
|
||||
'aio/content/examples/architecture/**/{*,.*}',
|
||||
'aio/content/guide/rxjs-interop.md',
|
||||
'aio/content/images/guide/architecture/**/{*,.*}',
|
||||
'aio/content/guide/attribute-directives.md',
|
||||
'aio/content/examples/attribute-directives/**/{*,.*}',
|
||||
'aio/content/images/guide/attribute-directives/**/{*,.*}',
|
||||
'aio/content/guide/bootstrapping.md',
|
||||
'aio/content/examples/bootstrapping/**/{*,.*}',
|
||||
'aio/content/guide/change-detection.md',
|
||||
'aio/content/guide/change-detection-zone-pollution.md',
|
||||
'aio/content/guide/change-detection-slow-computations.md',
|
||||
'aio/content/guide/change-detection-skipping-subtrees.md',
|
||||
'aio/content/images/guide/change-detection/**/{*,.*}',
|
||||
'aio/content/guide/class-binding.md',
|
||||
'aio/content/guide/cheatsheet.md',
|
||||
'aio/content/guide/component-interaction.md',
|
||||
'aio/content/examples/component-interaction/**/{*,.*}',
|
||||
'aio/content/images/guide/component-interaction/**/{*,.*}',
|
||||
'aio/content/guide/component-overview.md',
|
||||
'aio/content/errors/*.md',
|
||||
'aio/content/examples/errors/**/{*,.*}',
|
||||
'aio/content/examples/component-overview/**/{*,.*}',
|
||||
'aio/content/guide/component-styles.md',
|
||||
'aio/content/guide/developer-guide-overview.md',
|
||||
'aio/content/guide/view-encapsulation.md',
|
||||
'aio/content/examples/component-styles/**/{*,.*}',
|
||||
'aio/content/examples/content-projection/**/{*,.*}',
|
||||
'aio/content/guide/content-projection.md',
|
||||
'aio/content/guide/creating-injectable-service.md',
|
||||
'aio/content/guide/dependency-injection-overview.md',
|
||||
'aio/content/guide/dependency-injection.md',
|
||||
'aio/content/examples/dependency-injection/**/{*,.*}',
|
||||
'aio/content/images/guide/dependency-injection/**/{*,.*}',
|
||||
'aio/content/guide/dependency-injection-in-action.md',
|
||||
'aio/content/examples/dependency-injection-in-action/**/{*,.*}',
|
||||
'aio/content/images/guide/dependency-injection-in-action/**/{*,.*}',
|
||||
'aio/content/guide/dependency-injection-navtree.md',
|
||||
'aio/content/guide/dependency-injection-providers.md',
|
||||
'aio/content/guide/dependency-injection-context.md',
|
||||
'aio/content/guide/lightweight-injection-tokens.md',
|
||||
'aio/content/guide/displaying-data.md',
|
||||
'aio/content/examples/displaying-data/**/{*,.*}',
|
||||
'aio/content/images/guide/displaying-data/**/{*,.*}',
|
||||
'aio/content/guide/dynamic-component-loader.md',
|
||||
'aio/content/examples/dynamic-component-loader/**/{*,.*}',
|
||||
'aio/content/images/guide/dynamic-component-loader/**/{*,.*}',
|
||||
'aio/content/guide/example-apps-list.md',
|
||||
'aio/content/guide/feature-modules.md',
|
||||
'aio/content/examples/feature-modules/**/{*,.*}',
|
||||
'aio/content/images/guide/feature-modules/**/{*,.*}',
|
||||
'aio/content/guide/frequent-ngmodules.md',
|
||||
'aio/content/images/guide/frequent-ngmodules/**/{*,.*}',
|
||||
'aio/content/guide/hierarchical-dependency-injection.md',
|
||||
'aio/content/examples/hierarchical-dependency-injection/**/{*,.*}',
|
||||
'aio/content/guide/image-directive.md',
|
||||
'aio/content/guide/image-directive-setup.md',
|
||||
'aio/content/examples/providers-viewproviders/**/{*,.*}',
|
||||
'aio/content/examples/resolution-modifiers/**/{*,.*}',
|
||||
'aio/content/guide/lazy-loading-ngmodules.md',
|
||||
'aio/content/examples/lazy-loading-ngmodules/**/{*,.*}',
|
||||
'aio/content/images/guide/lazy-loading-ngmodules/**/{*,.*}',
|
||||
'aio/content/guide/lifecycle-hooks.md',
|
||||
'aio/content/examples/lifecycle-hooks/**/{*,.*}',
|
||||
'aio/content/images/guide/lifecycle-hooks/**/{*,.*}',
|
||||
'aio/content/examples/ngcontainer/**/{*,.*}',
|
||||
'aio/content/guide/ngmodules.md',
|
||||
'aio/content/examples/ngmodules/**/{*,.*}',
|
||||
'aio/content/guide/ngmodule-api.md',
|
||||
'aio/content/guide/ngmodule-faq.md',
|
||||
'aio/content/guide/ngmodule-vs-jsmodule.md',
|
||||
'aio/content/guide/module-types.md',
|
||||
'aio/content/guide/template-overview.md',
|
||||
'aio/content/guide/template-syntax.md',
|
||||
'aio/content/guide/built-in-template-functions.md',
|
||||
'aio/content/examples/built-in-template-functions/**/{*,.*}',
|
||||
'aio/content/guide/event-binding.md',
|
||||
'aio/content/guide/event-binding-concepts.md',
|
||||
'aio/content/examples/event-binding/**/{*,.*}',
|
||||
'aio/content/guide/interpolation.md',
|
||||
'aio/content/examples/interpolation/**/{*,.*}',
|
||||
'aio/content/examples/template-syntax/**/{*,.*}',
|
||||
'aio/content/images/guide/template-syntax/**/{*,.*}',
|
||||
'aio/content/guide/binding-overview.md',
|
||||
'aio/content/guide/binding-syntax.md',
|
||||
'aio/content/examples/binding-syntax/**/{*,.*}',
|
||||
'aio/content/guide/property-binding.md',
|
||||
'aio/content/examples/property-binding/**/{*,.*}',
|
||||
'aio/content/guide/property-binding-best-practices.md',
|
||||
'aio/content/guide/attribute-binding.md',
|
||||
'aio/content/examples/attribute-binding/**/{*,.*}',
|
||||
'aio/content/guide/two-way-binding.md',
|
||||
'aio/content/examples/two-way-binding/**/{*,.*}',
|
||||
'aio/content/guide/built-in-directives.md',
|
||||
'aio/content/guide/directive-composition-api.md',
|
||||
'aio/content/examples/built-in-directives/**/{*,.*}',
|
||||
'aio/content/images/guide/built-in-directives/**/{*,.*}',
|
||||
'aio/content/guide/template-reference-variables.md',
|
||||
'aio/content/examples/template-reference-variables/**/{*,.*}',
|
||||
'aio/content/guide/inputs-outputs.md',
|
||||
'aio/content/examples/inputs-outputs/**/{*,.*}',
|
||||
'aio/content/images/guide/inputs-outputs/**/{*,.*}',
|
||||
'aio/content/guide/understanding-template-expr-overview.md',
|
||||
'aio/content/guide/template-expression-operators.md',
|
||||
'aio/content/examples/template-expression-operators/**/{*,.*}',
|
||||
'aio/content/guide/pipes.md',
|
||||
'aio/content/guide/pipes-custom-data-trans.md',
|
||||
'aio/content/guide/pipes-overview.md',
|
||||
'aio/content/guide/pipes-transform-data.md',
|
||||
'aio/content/guide/pipe-template.md',
|
||||
'aio/content/examples/pipes/**/{*,.*}',
|
||||
'aio/content/images/guide/pipes/**/{*,.*}',
|
||||
'aio/content/guide/providers.md',
|
||||
'aio/content/examples/providers/**/{*,.*}',
|
||||
'aio/content/images/guide/providers/**/{*,.*}',
|
||||
'aio/content/guide/singleton-services.md',
|
||||
'aio/content/guide/sharing-ngmodules.md',
|
||||
'aio/content/guide/standalone-components.md',
|
||||
'aio/content/guide/standalone-migration.md',
|
||||
'aio/content/guide/structural-directives.md',
|
||||
'aio/content/examples/structural-directives/**/{*,.*}',
|
||||
'aio/content/guide/svg-in-templates.md',
|
||||
'aio/content/guide/style-precedence.md',
|
||||
'aio/content/images/guide/structural-directives/**/{*,.*}',
|
||||
'aio/content/guide/template-statements.md',
|
||||
'aio/content/guide/understanding-angular-overview.md',
|
||||
'aio/content/guide/user-input.md',
|
||||
'aio/content/examples/user-input/**/{*,.*}',
|
||||
'aio/content/images/guide/user-input/**/{*,.*}',
|
||||
'aio/content/guide/view-encapsulation.md',
|
||||
'aio/content/examples/view-encapsulation/**/{*,.*}',
|
||||
'aio/content/images/guide/view-encapsulation/**/{*,.*}',
|
||||
'aio/content/special-elements/**/{*,.*}',
|
||||
'aio/content/guide/hydration.md',
|
||||
'aio/content/guide/signals.md'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -188,9 +345,8 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- crisbeto
|
||||
- devversion
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -210,7 +366,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -223,6 +379,23 @@ groups:
|
||||
contains_any_globs(files, [
|
||||
'packages/common/http/**/{*,.*}',
|
||||
'packages/examples/http/**/{*,.*}',
|
||||
'aio/content/guide/understanding-communicating-with-http.md',
|
||||
'aio/content/guide/http-configure-http-url-parameters.md',
|
||||
'aio/content/guide/http-handle-request-errors.md',
|
||||
'aio/content/guide/http-intercept-requests-and-responses.md',
|
||||
'aio/content/guide/http-interceptor-use-cases.md',
|
||||
'aio/content/guide/http-make-jsonp-request.md',
|
||||
'aio/content/guide/http-optimize-server-interaction.md',
|
||||
'aio/content/guide/http-pass-metadata-to-interceptors.md',
|
||||
'aio/content/guide/http-request-data-from-server.md',
|
||||
'aio/content/guide/http-security-xsrf-protection.md',
|
||||
'aio/content/guide/http-send-data-to-server.md',
|
||||
'aio/content/guide/http-server-communication.md',
|
||||
'aio/content/guide/http-setup-server-communication.md',
|
||||
'aio/content/guide/http-test-requests.md',
|
||||
'aio/content/guide/http-track-show-request-progress.md',
|
||||
'aio/content/examples/http/**/{*,.*}',
|
||||
'aio/content/images/guide/http/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -230,7 +403,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -242,6 +415,9 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/elements/**/{*,.*}',
|
||||
'aio/content/examples/elements/**/{*,.*}',
|
||||
'aio/content/images/guide/elements/**/{*,.*}',
|
||||
'aio/content/guide/elements.md'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -250,7 +426,7 @@ groups:
|
||||
- andrewseguin
|
||||
- atscott
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -263,6 +439,22 @@ groups:
|
||||
contains_any_globs(files, [
|
||||
'packages/forms/**/{*,.*}',
|
||||
'packages/examples/forms/**/{*,.*}',
|
||||
'aio/content/guide/forms.md',
|
||||
'aio/content/examples/forms/**/{*,.*}',
|
||||
'aio/content/images/guide/forms/**/{*,.*}',
|
||||
'aio/content/guide/forms-overview.md',
|
||||
'aio/content/examples/forms-overview/**/{*,.*}',
|
||||
'aio/content/images/guide/forms-overview/**/{*,.*}',
|
||||
'aio/content/guide/form-validation.md',
|
||||
'aio/content/guide/typed-forms.md',
|
||||
'aio/content/examples/form-validation/**/{*,.*}',
|
||||
'aio/content/images/guide/form-validation/**/{*,.*}',
|
||||
'aio/content/guide/dynamic-form.md',
|
||||
'aio/content/examples/dynamic-form/**/{*,.*}',
|
||||
'aio/content/images/guide/dynamic-form/**/{*,.*}',
|
||||
'aio/content/guide/reactive-forms.md',
|
||||
'aio/content/examples/reactive-forms/**/{*,.*}',
|
||||
'aio/content/images/guide/reactive-forms/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -291,6 +483,21 @@ groups:
|
||||
'packages/compiler/src/render3/view/i18n/**/{*,.*}',
|
||||
'packages/compiler-cli/src/extract_i18n.ts',
|
||||
'packages/localize/**/{*,.*}',
|
||||
'aio/content/guide/i18n-overview.md',
|
||||
'aio/content/guide/i18n-common-overview.md',
|
||||
'aio/content/guide/i18n-common-add-package.md',
|
||||
'aio/content/guide/i18n-common-locale-id.md',
|
||||
'aio/content/guide/i18n-common-format-data-locale.md',
|
||||
'aio/content/guide/i18n-common-prepare.md',
|
||||
'aio/content/guide/i18n-common-translation-files.md',
|
||||
'aio/content/guide/i18n-common-merge.md',
|
||||
'aio/content/guide/i18n-common-deploy.md',
|
||||
'aio/content/guide/i18n-example.md',
|
||||
'aio/content/guide/i18n-optional-overview.md',
|
||||
'aio/content/guide/i18n-optional-manual-runtime-locale.md',
|
||||
'aio/content/guide/i18n-optional-import-global-variants.md',
|
||||
'aio/content/guide/i18n-optional-manage-marked-text.md',
|
||||
'aio/content/examples/i18n/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -306,6 +513,9 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/platform-server/**/{*,.*}',
|
||||
'aio/content/guide/prerendering.md',
|
||||
'aio/content/guide/universal.md',
|
||||
'aio/content/examples/universal/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -314,7 +524,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -327,6 +537,16 @@ groups:
|
||||
contains_any_globs(files, [
|
||||
'packages/router/**/{*,.*}',
|
||||
'packages/examples/router/**/{*,.*}',
|
||||
'aio/content/guide/router.md',
|
||||
'aio/content/guide/router-tutorial.md',
|
||||
'aio/content/guide/router-tutorial-toh.md',
|
||||
'aio/content/guide/routing-overview.md',
|
||||
'aio/content/guide/router-reference.md',
|
||||
'aio/content/examples/router-tutorial/**/{*,.*}',
|
||||
'aio/content/examples/router/**/{*,.*}',
|
||||
'aio/content/images/guide/router/**/{*,.*}',
|
||||
'aio/content/guide/routing-with-urlmatcher.md',
|
||||
'aio/content/examples/routing-with-urlmatcher/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -343,6 +563,15 @@ groups:
|
||||
contains_any_globs(files, [
|
||||
'packages/service-worker/**/{*,.*}',
|
||||
'packages/examples/service-worker/**/{*,.*}',
|
||||
'aio/content/guide/service-worker-getting-started.md',
|
||||
'aio/content/examples/service-worker-getting-started/**/{*,.*}',
|
||||
'aio/content/guide/app-shell.md',
|
||||
'aio/content/guide/service-worker-communications.md',
|
||||
'aio/content/guide/service-worker-config.md',
|
||||
'aio/content/guide/service-worker-devops.md',
|
||||
'aio/content/guide/service-worker-intro.md',
|
||||
'aio/content/guide/service-worker-notifications.md',
|
||||
'aio/content/images/guide/service-worker/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -359,11 +588,22 @@ groups:
|
||||
'packages/upgrade/**/{*,.*}',
|
||||
'packages/common/upgrade/**/{*,.*}',
|
||||
'packages/examples/upgrade/**/{*,.*}',
|
||||
'aio/content/guide/upgrade.md',
|
||||
'aio/content/examples/upgrade-lazy-load-ajs/**/{*,.*}',
|
||||
'aio/content/examples/upgrade-module/**/{*,.*}',
|
||||
'aio/content/images/guide/upgrade/**/{*,.*}',
|
||||
'aio/content/examples/upgrade-phonecat-1-typescript/**/{*,.*}',
|
||||
'aio/content/examples/upgrade-phonecat-2-hybrid/**/{*,.*}',
|
||||
'aio/content/examples/upgrade-phonecat-3-final/**/{*,.*}',
|
||||
'aio/content/guide/upgrade-performance.md',
|
||||
'aio/content/guide/upgrade-setup.md',
|
||||
'aio/content/guide/ajs-quick-reference.md',
|
||||
'aio/content/examples/ajs-quick-reference/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- alxhub
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
|
||||
# =========================================================
|
||||
# Framework: Testing
|
||||
@@ -372,8 +612,19 @@ groups:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files.exclude('packages/compiler-cli/*').exclude('packages/language-service/*').exclude('packages/service-worker/*').exclude('packages/core/schematics/*'), [
|
||||
contains_any_globs(files.exclude('packages/compiler-cli/*').exclude('packages/language-service/*').exclude('packages/service-worker/*'), [
|
||||
'packages/**/testing/**/{*,.*}',
|
||||
'aio/content/guide/testing.md',
|
||||
'aio/content/guide/test-debugging.md',
|
||||
'aio/content/guide/testing-attribute-directives.md',
|
||||
'aio/content/guide/testing-code-coverage.md',
|
||||
'aio/content/guide/testing-components-basics.md',
|
||||
'aio/content/guide/testing-components-scenarios.md',
|
||||
'aio/content/guide/testing-pipes.md',
|
||||
'aio/content/guide/testing-services.md',
|
||||
'aio/content/guide/testing-utility-apis.md',
|
||||
'aio/content/examples/testing/**/{*,.*}',
|
||||
'aio/content/images/guide/testing/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -381,7 +632,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -400,7 +651,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -419,7 +670,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -437,6 +688,9 @@ groups:
|
||||
'packages/tsconfig-tsec-base.json',
|
||||
'packages/tsec-exemption.json',
|
||||
'tools/tsec.bzl',
|
||||
'aio/content/guide/security.md',
|
||||
'aio/content/examples/security/**/{*,.*}',
|
||||
'aio/content/images/guide/security/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -473,12 +727,13 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/language-service/**/{*,.*}',
|
||||
'aio/content/guide/language-service.md',
|
||||
'aio/content/images/guide/language-service/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- alxhub
|
||||
- atscott
|
||||
- dylhunn
|
||||
|
||||
# =========================================================
|
||||
# zone.js
|
||||
@@ -489,6 +744,7 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/zone.js/**/{*,.*}',
|
||||
'aio/content/guide/zone.md'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -510,7 +766,7 @@ groups:
|
||||
- atscott
|
||||
- crisbeto
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -545,8 +801,108 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- josephperrott
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
# Docs: Contributors
|
||||
# =========================================================
|
||||
docs-contributors:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'aio/content/marketing/contributors.json',
|
||||
'aio/content/images/bios/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- MarkTechson
|
||||
- mgechev
|
||||
- twerske
|
||||
|
||||
# =========================================================
|
||||
# Docs: Gettings Started & Tutorial
|
||||
# =========================================================
|
||||
docs-getting-started-and-tutorial:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'aio/content/guide/setup-local.md',
|
||||
'aio/content/images/guide/setup-local/**/{*,.*}',
|
||||
'aio/content/tutorial/**/{*,.*}',
|
||||
'aio/content/images/guide/toh/**/{*,.*}',
|
||||
'aio/content/demos/first-app/**/{*,.*}',
|
||||
'aio/content/examples/first-app-*/**/{*,.*}',
|
||||
'aio/content/images/guide/faa/**/{*,.*}',
|
||||
'aio/content/examples/toh-pt0/**/{*,.*}',
|
||||
'aio/content/examples/toh-pt1/**/{*,.*}',
|
||||
'aio/content/examples/toh-pt2/**/{*,.*}',
|
||||
'aio/content/examples/toh-pt3/**/{*,.*}',
|
||||
'aio/content/examples/toh-pt4/**/{*,.*}',
|
||||
'aio/content/examples/toh-pt5/**/{*,.*}',
|
||||
'aio/content/examples/toh-pt6/**/{*,.*}',
|
||||
'aio/content/examples/getting-started-v0/**/{*,.*}',
|
||||
'aio/content/examples/getting-started/**/{*,.*}',
|
||||
'aio/content/start/**/{*,.*}',
|
||||
'aio/content/guide/quick-start.md',
|
||||
'aio/content/images/guide/start/**/{*,.*}',
|
||||
'aio/content/examples/what-is-angular/**/{*,.*}',
|
||||
'aio/content/guide/what-is-angular.md'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- AndrewKushnir
|
||||
- jessicajaniuk
|
||||
|
||||
# =========================================================
|
||||
# Docs: Marketing
|
||||
# =========================================================
|
||||
docs-marketing:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files.exclude("aio/content/marketing/contributors.json"), [
|
||||
'aio/content/examples/marketing-first-app/**/{*,.*}',
|
||||
'aio/content/guide/roadmap.md',
|
||||
'aio/content/marketing/**/{*,.*}',
|
||||
'aio/content/images/marketing/**/{*,.*}',
|
||||
'aio/content/file-not-found.md',
|
||||
'aio/content/license.md',
|
||||
'aio/content/navigation.json'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- MarkTechson
|
||||
- mgechev
|
||||
- twerske
|
||||
|
||||
# =========================================================
|
||||
# Docs: Observables
|
||||
# =========================================================
|
||||
docs-observables:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'aio/content/guide/observables.md',
|
||||
'aio/content/examples/observables/**/{*,.*}',
|
||||
'aio/content/guide/comparing-observables.md',
|
||||
'aio/content/examples/comparing-observables/**/{*,.*}',
|
||||
'aio/content/guide/observables-in-angular.md',
|
||||
'aio/content/examples/observables-in-angular/**/{*,.*}',
|
||||
'aio/content/guide/practical-observable-usage.md',
|
||||
'aio/content/examples/practical-observable-usage/**/{*,.*}',
|
||||
'aio/content/guide/rx-library.md',
|
||||
'aio/content/examples/rx-library/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- alxhub
|
||||
- atscott
|
||||
- dylhunn
|
||||
|
||||
# =========================================================
|
||||
# Docs: Packaging, Tooling, Releasing
|
||||
@@ -556,16 +912,52 @@ groups:
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'contributing-docs/public-api-surface.md',
|
||||
'docs/PUBLIC_API.md',
|
||||
'docs/RELEASE_SCHEDULE.md',
|
||||
'aio/content/guide/npm-packages.md',
|
||||
'aio/content/guide/browser-support.md',
|
||||
'aio/content/guide/releases.md',
|
||||
'aio/content/guide/updating.md',
|
||||
'aio/content/guide/deprecations.md',
|
||||
'aio/content/guide/migration-legacy-message-id.md',
|
||||
'aio/content/examples/deprecation-guide/**/{*,.*}',
|
||||
'aio/content/guide/migration-renderer.md',
|
||||
'aio/content/guide/migration-undecorated-classes.md',
|
||||
'aio/content/guide/migration-dynamic-flag.md',
|
||||
'aio/content/guide/migration-injectable.md',
|
||||
'aio/content/guide/migration-localize.md',
|
||||
'aio/content/guide/migration-module-with-providers.md',
|
||||
'aio/content/guide/static-query-migration.md',
|
||||
'aio/content/guide/update-to-latest-version.md',
|
||||
'aio/content/guide/versions.md',
|
||||
'aio/content/guide/update-to-version-14.md',
|
||||
'aio/content/guide/update-to-version-15.md',
|
||||
'aio/content/guide/update-to-version-16.md',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- alxhub
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- thePunderWoman
|
||||
- jelbourn
|
||||
|
||||
# =========================================================
|
||||
# Docs: Angular DevTools
|
||||
# =========================================================
|
||||
docs-devtools:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'aio/content/guide/devtools.md',
|
||||
'aio/content/images/guide/devtools/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- MarkTechson
|
||||
- mgechev
|
||||
- twerske
|
||||
|
||||
# =========================================================
|
||||
# Tooling: Compiler API shared with Angular CLI
|
||||
#
|
||||
@@ -590,30 +982,137 @@ groups:
|
||||
reviewed_for: required
|
||||
|
||||
# =========================================================
|
||||
# Docs: Angular Dev Site
|
||||
# Docs: CLI
|
||||
# =========================================================
|
||||
angular-dev:
|
||||
docs-cli:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'adev/**/{.*,*}',
|
||||
'aio/**/{.*,*}'
|
||||
'aio/content/cli/**/{*,.*}',
|
||||
'aio/content/guide/typescript-configuration.md',
|
||||
'aio/content/examples/setup/**/{*,.*}',
|
||||
'aio/content/guide/build.md',
|
||||
'aio/content/images/guide/build/**/{*,.*}',
|
||||
'aio/content/images/guide/cli/**/{*,.*}',
|
||||
'aio/content/guide/cli-builder.md',
|
||||
'aio/content/examples/cli-builder/**/{*,.*}',
|
||||
'aio/content/guide/deployment.md',
|
||||
'aio/content/images/guide/deployment/**/{*,.*}',
|
||||
'aio/content/guide/file-structure.md',
|
||||
'aio/content/guide/ivy.md',
|
||||
'aio/content/guide/strict-mode.md',
|
||||
'aio/content/guide/web-worker.md',
|
||||
'aio/content/guide/workspace-config.md',
|
||||
'aio/content/guide/migration-solution-style-tsconfig.md',
|
||||
'aio/content/guide/migration-update-libraries-tslib.md',
|
||||
'aio/content/guide/esbuild.md',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- josephperrott
|
||||
- jelbourn
|
||||
- bencodezen
|
||||
- thePunderWoman
|
||||
- dylhunn
|
||||
- AndrewKushnir
|
||||
- alan-agius4
|
||||
- clydin
|
||||
- dgp1130
|
||||
- mgechev
|
||||
|
||||
# =========================================================
|
||||
# Docs: CLI Libraries
|
||||
# =========================================================
|
||||
docs-libraries:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'aio/content/examples/angular-linker-plugin/webpack.config.mjs',
|
||||
'aio/content/guide/creating-libraries.md',
|
||||
'aio/content/guide/libraries.md',
|
||||
'aio/content/guide/using-libraries.md',
|
||||
'aio/content/guide/angular-package-format.md'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- alan-agius4
|
||||
- alxhub
|
||||
- crisbeto
|
||||
- devversion
|
||||
- atscott
|
||||
- pkozlowski-opensource
|
||||
- ~JeanMeche
|
||||
- mgechev
|
||||
|
||||
# =========================================================
|
||||
# Docs: Schematics
|
||||
# =========================================================
|
||||
docs-schematics:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'aio/content/guide/schematics.md',
|
||||
'aio/content/guide/schematics-authoring.md',
|
||||
'aio/content/guide/schematics-for-libraries.md',
|
||||
'aio/content/images/guide/schematics/**/{*,.*}',
|
||||
'aio/content/examples/schematics-for-libraries/**/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- alan-agius4
|
||||
- dylhunn
|
||||
- mgechev
|
||||
|
||||
# =========================================================
|
||||
# Docs-infra
|
||||
# =========================================================
|
||||
docs-infra:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'aio/{*,.*}',
|
||||
'aio/aio-builds-setup/**/{*,.*}',
|
||||
'aio/content/cli-src/**/{*,.*}',
|
||||
'aio/content/examples/{*,.*}',
|
||||
'aio/scripts/**/{*,.*}',
|
||||
'aio/src/**/{*,.*}',
|
||||
'aio/tests/**/{*,.*}',
|
||||
'aio/tools/**/{*,.*}',
|
||||
'aio/tools/examples/shared/boilerplate/cli/.vscode/**/{*,.*}',
|
||||
'aio/content/BUILD.bazel',
|
||||
'aio/content/images/guide/contributors-guide/**/{*,.*}',
|
||||
'aio/content/guide/contributors-guide-overview.md',
|
||||
'aio/content/guide/docs-style-guide.md',
|
||||
'aio/content/examples/docs-style-guide/**/{*,.*}',
|
||||
'aio/content/images/guide/docs-style-guide/**/{*,.*}',
|
||||
'aio/content/guide/docs-lint-errors.md',
|
||||
'aio/content/images/guide/docs-lint-errors/**/{*,.*}',
|
||||
'aio/content/guide/localized-documentation.md',
|
||||
'aio/content/guide/localizing-angular.md',
|
||||
'aio/content/guide/reviewing-content.md',
|
||||
'aio/content/guide/updating-content-github-ui.md',
|
||||
'aio/content/guide/updating-search-keywords.md',
|
||||
'aio/content/guide/doc-build-test.md',
|
||||
'aio/content/guide/doc-edit-finish.md',
|
||||
'aio/content/guide/doc-editing.md',
|
||||
'aio/content/guide/doc-github-tasks.md',
|
||||
'aio/content/guide/doc-pr-open.md',
|
||||
'aio/content/guide/doc-pr-prep.md',
|
||||
'aio/content/guide/doc-pr-update.md',
|
||||
'aio/content/guide/doc-prepare-to-edit.md',
|
||||
'aio/content/guide/doc-select-issue.md',
|
||||
'aio/content/guide/doc-tasks.md',
|
||||
'aio/content/guide/doc-update-overview.md',
|
||||
'aio/content/guide/doc-update-start.md',
|
||||
'aio/content/guide/docs-lint-errors.md',
|
||||
'aio/content/images/guide/preparing-to-edit-docs/**/{*,.*}',
|
||||
'aio/content/images/guide/github-for-docs/**/{*,.*}',
|
||||
'aio/content/images/guide/doc-update-start/**/{*,.*}',
|
||||
'aio/content/images/guide/doc-update-overview/**/{*,.*}',
|
||||
'aio/content/images/guide/doc-pr-update/**/{*,.*}',
|
||||
'aio/content/images/guide/doc-pr-prep/**/{*,.*}',
|
||||
'aio/content/images/guide/doc-pr-open/**/{*,.*}',
|
||||
'aio/content/images/guide/doc-github-tasks/**/{*,.*}',
|
||||
'aio/content/images/guide/doc-prepare-to-edit/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- AndrewKushnir
|
||||
- jessicajaniuk
|
||||
- josephperrott
|
||||
|
||||
# =========================================================
|
||||
# Angular DevTools
|
||||
@@ -629,11 +1128,9 @@ groups:
|
||||
users:
|
||||
- AleksanderBodurri
|
||||
- devversion
|
||||
- dgp1130
|
||||
- josephperrott
|
||||
- mgechev
|
||||
- twerske
|
||||
- ~JeanMeche
|
||||
|
||||
# =========================================================
|
||||
# Dev-infra
|
||||
@@ -651,8 +1148,8 @@ groups:
|
||||
'.ng-dev/**/{*,.*}',
|
||||
'.vscode/**/{*,.*}',
|
||||
'.yarn/**/{*,.*}',
|
||||
'contributing-docs/*.md',
|
||||
'contributing-docs/images/**/{*,.*}',
|
||||
'docs/*.md',
|
||||
'docs/images/**/{*,.*}',
|
||||
'goldens/{*,.*}',
|
||||
'goldens/public-api/manage.js',
|
||||
'modules/{*,.*}',
|
||||
@@ -668,11 +1165,9 @@ groups:
|
||||
'tools/esm-interop/**/{*,.*}',
|
||||
'tools/gulp-tasks/**/{*,.*}',
|
||||
'tools/legacy-saucelabs/**/{*,.*}',
|
||||
'tools/manual_api_docs/**/{*,.*}',
|
||||
'tools/npm-patches/**/{*,.*}',
|
||||
'tools/rxjs/**/{*,.*}',
|
||||
'tools/saucelabs-daemon/**/{*,.*}',
|
||||
'tools/saucelabs/**/{*,.*}',
|
||||
'tools/saucelabs-daemon/**/{*,.*}',
|
||||
'tools/symbol-extractor/**/{*,.*}',
|
||||
'tools/testing/**/{*,.*}',
|
||||
'tools/tslint/**/{*,.*}',
|
||||
@@ -697,6 +1192,12 @@ groups:
|
||||
- >
|
||||
contains_any_globs(files.exclude("goldens/public-api/manage.js"), [
|
||||
'goldens/public-api/**/{*,.*}',
|
||||
'docs/NAMING.md',
|
||||
'aio/content/guide/angular-package-format.md',
|
||||
'aio/content/guide/glossary.md',
|
||||
'aio/content/guide/styleguide.md',
|
||||
'aio/content/examples/styleguide/**/{*,.*}',
|
||||
'aio/content/images/guide/styleguide/{*,.*}'
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -705,11 +1206,8 @@ groups:
|
||||
- atscott
|
||||
- dylhunn
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
- ~iteriani
|
||||
- ~tbondwilkinson
|
||||
- ~rahatarmanahmed
|
||||
reviews:
|
||||
request: 3 # Request reviews from 3 people
|
||||
required: 2 # Require that 2 people approve
|
||||
@@ -734,7 +1232,7 @@ groups:
|
||||
- atscott
|
||||
- dylhunn
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
reviews:
|
||||
request: 2 # Request reviews from 2 people
|
||||
@@ -760,7 +1258,7 @@ groups:
|
||||
- atscott
|
||||
- dylhunn
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- pkozlowski-opensource
|
||||
|
||||
####################################################################################
|
||||
@@ -784,61 +1282,9 @@ groups:
|
||||
- andrewseguin
|
||||
- dgp1130
|
||||
- ~jelbourn
|
||||
- thePunderWoman
|
||||
- jessicajaniuk
|
||||
- josephperrott
|
||||
|
||||
# =========================================================
|
||||
# Primitives
|
||||
# =========================================================
|
||||
|
||||
# Angular team required reviews
|
||||
primitives:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/core/primitives/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- pkozlowski-opensource # Pawel Kozlowski
|
||||
- alxhub # Alex Rickabaugh
|
||||
- thePunderWoman # Jessica Janiuk
|
||||
- dylhunn # Dylan Hunn
|
||||
- AndrewKushnir # Andrew Kushnir
|
||||
- atscott # Andrew Scott
|
||||
labels:
|
||||
pending: 'requires: TGP'
|
||||
approved: 'requires: TGP'
|
||||
rejected: 'requires: TGP'
|
||||
|
||||
# External team required reviews
|
||||
primitives-shared:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/core/primitives/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- csmick # Cameron Smick
|
||||
- lannka # Hongfei Ding
|
||||
- eduhmc # Eduardo Huerta-Mercado
|
||||
- ehlemur # Edward Lesmes
|
||||
- ellenyuan # Ellen Yuan
|
||||
- jatraman # Jatin Ramanathan
|
||||
- jesse-good # Jesse Costello-Good
|
||||
- mturco # Matt Turco
|
||||
- neonstalwart # Ben Hockey
|
||||
- iteriani # Thomas Nguyen
|
||||
- tbondwilkinson # Tom Wilkinson
|
||||
- rahatarmanahmed # Rahat Ahmed
|
||||
labels:
|
||||
pending: 'requires: TGP'
|
||||
approved: 'requires: TGP'
|
||||
rejected: 'requires: TGP'
|
||||
|
||||
####################################################################################
|
||||
# Override managed result groups
|
||||
#
|
||||
@@ -915,6 +1361,26 @@ groups:
|
||||
author_value: 0 # The author of the PR cannot provide an approval for themself
|
||||
reviewed_for: ignored # All reviews apply to this group whether noted via Reviewed-for or not
|
||||
reviewers:
|
||||
teams:
|
||||
# Any member of the team can provide a review to perform the minimum review required
|
||||
- team
|
||||
users:
|
||||
- alan-agius4 # Alan Agius
|
||||
- AleksanderBodurri # Aleksander Bodurri
|
||||
- alxhub # Alex Rickabaugh
|
||||
- AndrewKushnir # Andrew Kushnir
|
||||
- andrewseguin # Andrew Seguin
|
||||
- atscott # Andrew Scott
|
||||
- clydin # Charles Lyding
|
||||
- crisbeto # Kristiyan Kostadinov
|
||||
- devversion # Paul Gschwendtner
|
||||
- dgp1130 # Doug Parker
|
||||
- dylhunn # Dylan Hunn
|
||||
- jelbourn # Jeremy Elbourn
|
||||
- jessicajaniuk # Jessica Janiuk
|
||||
- JiaLiPassion # Jia Li
|
||||
- JoostK # Joost Koehoorn
|
||||
- josephperrott # Joey Perrott
|
||||
- MarkTechson # Mark Thompson (Techson)
|
||||
- mgechev # Minko Gechev
|
||||
- mmalerba # Miles Malerba
|
||||
- pkozlowski-opensource # Pawel Kozlowski
|
||||
- twerske # Emma Twersky
|
||||
- zarend # Zach Arend
|
||||
|
||||
Vendored
+7
-1
@@ -4,7 +4,13 @@
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"BazelBuild.vscode-bazel",
|
||||
"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",
|
||||
],
|
||||
}
|
||||
|
||||
Vendored
+8
@@ -1,10 +1,16 @@
|
||||
{
|
||||
// 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,
|
||||
@@ -12,12 +18,14 @@
|
||||
"**/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,
|
||||
|
||||
+1
-1
@@ -13,7 +13,6 @@ exports_files([
|
||||
"scripts/ci/payload-size.sh",
|
||||
"scripts/ci/payload-size.js",
|
||||
"package.json",
|
||||
"angular.json",
|
||||
])
|
||||
|
||||
filegroup(
|
||||
@@ -67,6 +66,7 @@ nodejs_binary(
|
||||
data = [".yarn/releases/yarn-1.22.19.cjs"],
|
||||
entry_point = ".yarn/releases/yarn-1.22.19.cjs",
|
||||
visibility = [
|
||||
"//aio/tools/examples/shared:__pkg__",
|
||||
"//integration:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
+1097
-4050
File diff suppressed because it is too large
Load Diff
+13
-8
@@ -32,7 +32,7 @@ Stack Overflow is a much better place to ask questions since:
|
||||
|
||||
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 [the Angular community Discord server][discord].
|
||||
If you would like to chat about the question in real-time, you can reach out via [our Discord server][discord].
|
||||
|
||||
|
||||
## <a name="issue"></a> Found a Bug?
|
||||
@@ -109,7 +109,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
```shell
|
||||
git commit --all
|
||||
```
|
||||
Note: the optional commit `--all` command line option will automatically "add" and "rm" edited files.
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
|
||||
10. Push your branch to GitHub:
|
||||
|
||||
@@ -138,7 +138,7 @@ If we ask for changes via code reviews then:
|
||||
git push
|
||||
```
|
||||
|
||||
For more info on working with fixup commits see [here](./contributing-docs/using-fixup-commits.md).
|
||||
For more info on working with fixup commits see [here](docs/FIXUP_COMMITS.md).
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
@@ -207,7 +207,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
|
||||
* All public API methods **must be documented**.
|
||||
* 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](contributing-docs/building-and-testing-angular#formatting-your-source-code).
|
||||
An automated formatter is available, see [DEVELOPER.md](docs/DEVELOPER.md#clang-format).
|
||||
|
||||
|
||||
## <a name="commit"></a> Commit Message Format
|
||||
@@ -302,7 +302,7 @@ There are currently a few exceptions to the "use package name" rule:
|
||||
|
||||
* `dev-infra`: used for dev-infra related changes within the directories /scripts and /tools
|
||||
|
||||
* `docs-infra`: used for docs-app (angular.dev) related changes within the /adev directory of the repo
|
||||
* `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.
|
||||
|
||||
@@ -353,9 +353,9 @@ DEPRECATED: <what is deprecated>
|
||||
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.
|
||||
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.
|
||||
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
|
||||
@@ -389,11 +389,16 @@ The following documents can help you sort out issues with GitHub accounts and mu
|
||||
|
||||
|
||||
|
||||
[angular-group]: https://groups.google.com/forum/#!forum/angular
|
||||
[coc]: https://github.com/angular/code-of-conduct/blob/main/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]: ./contributing-docs/building-and-testing-angular.md
|
||||
[dev-doc]: https://github.com/angular/angular/blob/main/docs/DEVELOPER.md
|
||||
[github]: https://github.com/angular/angular
|
||||
[discord]: https://discord.gg/angular
|
||||
[individual-cla]: https://cla.developers.google.com/about/google-individual
|
||||
[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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2010-2024 Google LLC. https://angular.io/license
|
||||
Copyright (c) 2010-2023 Google LLC. https://angular.io/license
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<h1 align="center">Angular - The modern web developer's platform</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="adev/src/assets/images/press-kit/angular_icon_gradient.gif" alt="angular-logo" width="120px" height="120px"/>
|
||||
<img src="aio/src/assets/images/logos/angular/angular.png" alt="angular-logo" width="120px" height="120px"/>
|
||||
<br>
|
||||
<em>Angular is a development platform for building mobile and desktop web applications
|
||||
<br> using TypeScript/JavaScript and other languages.</em>
|
||||
@@ -9,7 +9,7 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://angular.dev/"><strong>angular.dev</strong></a>
|
||||
<a href="https://www.angular.io"><strong>www.angular.io</strong></a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
·
|
||||
<a href="https://github.com/angular/angular/issues">Submit an Issue</a>
|
||||
·
|
||||
<a href="https://blog.angular.dev/">Blog</a>
|
||||
<a href="https://blog.angular.io/">Blog</a>
|
||||
<br>
|
||||
<br>
|
||||
</p>
|
||||
@@ -61,10 +61,6 @@ Get started with Angular, learn the fundamentals and explore advanced topics on
|
||||
- [Lazy Loading][lazyloading]
|
||||
- [Animations][animations]
|
||||
|
||||
### Local Development
|
||||
|
||||
To contribute to the Angular Docs, check out the [Angular.dev README](adev/README.md)
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
@@ -101,7 +97,7 @@ Angular is cross-platform, fast, scalable, has incredible tooling, and is loved
|
||||
## Ecosystem
|
||||
|
||||
<p>
|
||||
<img src="/contributing-docs/images/angular-ecosystem-logos.png" alt="angular ecosystem logos" width="500px" height="auto">
|
||||
<img src="/docs/images/angular-ecosystem-logos.png" alt="angular ecosystem logos" width="500px" height="auto">
|
||||
</p>
|
||||
|
||||
- [Angular Command Line (CLI)][cli]
|
||||
@@ -113,7 +109,7 @@ Angular is cross-platform, fast, scalable, has incredible tooling, and is loved
|
||||
|
||||
## Upgrading
|
||||
|
||||
Check out our [upgrade guide](https://angular.dev/update-guide/) to find out the best way to upgrade your project.
|
||||
Check out our [upgrade guide](https://update.angular.io/) to find out the best way to upgrade your project.
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -133,7 +129,7 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
|
||||
|
||||
Join the conversation and help the community.
|
||||
|
||||
- [X (formerly Twitter)][X (formerly Twitter)]
|
||||
- [Twitter][twitter]
|
||||
- [Discord][discord]
|
||||
- [Gitter][gitter]
|
||||
- [YouTube][youtube]
|
||||
@@ -145,27 +141,27 @@ Join the conversation and help the community.
|
||||
**Love Angular? Give our repo a star :star: :arrow_up:.**
|
||||
|
||||
[contributing]: CONTRIBUTING.md
|
||||
[quickstart]: https://angular.dev/tutorials/learn-angular
|
||||
[quickstart]: https://angular.io/start
|
||||
[changelog]: CHANGELOG.md
|
||||
[ng]: https://angular.dev
|
||||
[documentation]: https://angular.dev/overview
|
||||
[ng]: https://angular.io
|
||||
[documentation]: https://angular.io/docs
|
||||
[angularmaterial]: https://material.angular.io/
|
||||
[cli]: https://angular.dev/tools/cli
|
||||
[architecture]: https://angular.dev/essentials
|
||||
[componentstemplates]: https://angular.dev/tutorials/learn-angular/1-components-in-angular
|
||||
[forms]: https://angular.dev/tutorials/learn-angular/15-forms
|
||||
[api]: https://angular.dev/api
|
||||
[angularelements]: https://angular.dev/guide/elements
|
||||
[ssr]: https://angular.dev/guide/ssr
|
||||
[schematics]: https://angular.dev/tools/cli/schematics
|
||||
[lazyloading]: https://angular.dev/guide/ngmodules/lazy-loading
|
||||
[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
|
||||
[X (formerly Twitter)]: https://www.twitter.com/angular
|
||||
[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.dev/guide/animations
|
||||
[animations]: https://angular.io/guide/animations
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
Angular is part of Google [Open Source Software Vulnerability Reward Program](https://bughunters.google.com/about/rules/6521337925468160/google-open-source-software-vulnerability-reward-program-rules). For vulnerabilities in Angular, please submit your report [here](https://bughunters.google.com/report).
|
||||
|
||||
For more information, check out [Angular's security policy](https://angular.dev/best-practices/security).
|
||||
For more information, check out [Angular's security policy](https://angular.io/guide/security).
|
||||
|
||||
@@ -2,12 +2,27 @@ workspace(
|
||||
name = "angular",
|
||||
managed_directories = {
|
||||
"@npm": ["node_modules"],
|
||||
"@aio_npm": ["aio/node_modules"],
|
||||
},
|
||||
)
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
load("//:yarn.bzl", "YARN_LABEL")
|
||||
|
||||
# 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(
|
||||
name = "build_bazel_rules_nodejs",
|
||||
patches = [
|
||||
@@ -49,17 +64,12 @@ load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")
|
||||
|
||||
nodejs_register_toolchains(
|
||||
name = "nodejs",
|
||||
node_repositories = {
|
||||
"18.20.0-darwin_arm64": ("node-v18.20.0-darwin-arm64.tar.gz", "node-v18.20.0-darwin-arm64", "10066ad4dd9e03ea5c4c45ef8775420ff37b860de09bbdf87b97e0c07b1ea036"),
|
||||
"18.20.0-darwin_amd64": ("node-v18.20.0-darwin-x64.tar.gz", "node-v18.20.0-darwin-x64", "062ba71618e88e06321de5caa038843c350aababa2d315f3ca7b8551f8e66c1c"),
|
||||
"18.20.0-linux_arm64": ("node-v18.20.0-linux-arm64.tar.xz", "node-v18.20.0-linux-arm64", "afe51da9ffb38ac1e3a20d9a06efd403ced4bf8831ab554a02a088dd8392fd79"),
|
||||
"18.20.0-linux_ppc64le": ("node-v18.20.0-linux-ppc64le.tar.xz", "node-v18.20.0-linux-ppc64le", "9e652bbf53a3e37285b11dfb9d6a9bb8b02010c3b50e5c8229d4cc10e72681da"),
|
||||
"18.20.0-linux_s390x": ("node-v18.20.0-linux-s390x.tar.xz", "node-v18.20.0-linux-s390x", "a6c2a5796b9d9e9bf21da62ec89ff30b41a8108880b9eaa3c912f1ce795a7743"),
|
||||
"18.20.0-linux_amd64": ("node-v18.20.0-linux-x64.tar.xz", "node-v18.20.0-linux-x64", "03eea148e56785babb27930b05ed6bf311aaa3bc573c0399dd63cad2fe5713c7"),
|
||||
"18.20.0-windows_amd64": ("node-v18.20.0-win-x64.zip", "node-v18.20.0-win-x64", "1c0aab05cc6836a8f5148cca345b92ebc948a4a2013f18d117b7ade6ff05aca6"),
|
||||
},
|
||||
# We need at least Node 18.17 due to some transitive dependencies.
|
||||
node_version = "18.20.0",
|
||||
node_version = "16.14.0",
|
||||
)
|
||||
|
||||
nodejs_register_toolchains(
|
||||
name = "node18",
|
||||
node_version = "18.10.0",
|
||||
)
|
||||
|
||||
# Download npm dependencies.
|
||||
@@ -73,9 +83,8 @@ yarn_install(
|
||||
data = [
|
||||
YARN_LABEL,
|
||||
"//:.yarnrc",
|
||||
"//:tools/npm-patches/@bazel+jasmine+5.8.1.patch",
|
||||
"//tools:postinstall-patches.js",
|
||||
"//tools/esm-interop:patches/npm/@angular+build-tooling+0.0.0-d30a56c19bafaac67cf44e605ed8c2c0e45b0a51.patch",
|
||||
"//tools/esm-interop:patches/npm/@angular+build-tooling+0.0.0-8d4803573edc70b90a1134ffa996303d1dcc18a9.patch",
|
||||
"//tools/esm-interop:patches/npm/@bazel+concatjs+5.8.1.patch",
|
||||
"//tools/esm-interop:patches/npm/@bazel+esbuild+5.7.1.patch",
|
||||
"//tools/esm-interop:patches/npm/@bazel+protractor+5.7.1.patch",
|
||||
@@ -94,6 +103,53 @@ yarn_install(
|
||||
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_LABEL,
|
||||
"//:.yarnrc",
|
||||
"//aio:tools/cli-patches/bazel-architect-output.patch",
|
||||
"//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_LABEL,
|
||||
yarn_lock = "//aio:yarn.lock",
|
||||
)
|
||||
|
||||
yarn_install(
|
||||
name = "aio_example_deps",
|
||||
# Rename the default js_library target from "node_modules" as this obscures the
|
||||
# the source directory stamped as a filegroup in the manual BUILD contents below.
|
||||
all_node_modules_target_name = "node_modules_all",
|
||||
data = [
|
||||
YARN_LABEL,
|
||||
"//:.yarnrc",
|
||||
],
|
||||
# Disabled because, when False, yarn_install preserves the node_modules folder
|
||||
# with bin symlinks in the external repository. This is needed to link the shared
|
||||
# set of deps for example e2es.
|
||||
exports_directories_only = False,
|
||||
manual_build_file_contents = """\
|
||||
filegroup(
|
||||
name = "node_modules_files",
|
||||
srcs = ["node_modules"],
|
||||
)
|
||||
""",
|
||||
package_json = "//aio/tools/examples/shared:package.json",
|
||||
yarn = YARN_LABEL,
|
||||
yarn_lock = "//aio/tools/examples/shared:yarn.lock",
|
||||
)
|
||||
|
||||
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies")
|
||||
|
||||
aspect_bazel_lib_dependencies()
|
||||
@@ -143,10 +199,10 @@ cldr_xml_data_repository(
|
||||
# sass rules
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "cd83736ea65d0df064283aea5922dbaf132dd2b3aa54e7151aae7edaa9572c3e",
|
||||
strip_prefix = "rules_sass-83022b98114c07e9588089c7fe8f76bc0262c7e7",
|
||||
sha256 = "4bb36a654166e1b629717e55a9c0cc30590f6615c122c054f38409c20ee5ec6f",
|
||||
strip_prefix = "rules_sass-f89fc59345a5074cf184ec215e9858152b7258e7",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_sass/archive/83022b98114c07e9588089c7fe8f76bc0262c7e7.zip",
|
||||
"https://github.com/bazelbuild/rules_sass/archive/f89fc59345a5074cf184ec215e9858152b7258e7.zip",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
load("@npm//@angular/build-tooling/bazel/http-server:index.bzl", "http_server")
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
|
||||
load("@npm//@angular-devkit/architect-cli:index.bzl", "architect", "architect_test")
|
||||
load("@bazel_skylib//lib:collections.bzl", "collections")
|
||||
load("//adev/tools/local_deps:index.bzl", "ensure_local_package_deps", "link_local_packages")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
exports_files([
|
||||
"tsconfig.json",
|
||||
])
|
||||
|
||||
# All source and configuration files required to build the docs app
|
||||
APPLICATION_FILES = [
|
||||
"angular.json",
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.json",
|
||||
"tsconfig.worker.json",
|
||||
] + glob(
|
||||
["src/**/*"],
|
||||
exclude = [
|
||||
"src/**/*.spec.ts",
|
||||
],
|
||||
)
|
||||
|
||||
TEST_FILES = APPLICATION_FILES + [
|
||||
"karma.conf.js",
|
||||
"test-main.ts",
|
||||
"tsconfig.spec.json",
|
||||
] + glob(
|
||||
["src/**/*.spec.ts"],
|
||||
)
|
||||
|
||||
APPLICATION_ASSETS = [
|
||||
"//adev/src/assets/images",
|
||||
"//adev/src/assets/textures",
|
||||
"//adev/src/assets/previews",
|
||||
"//adev/src/assets:tutorials",
|
||||
"//adev/src/assets/icons",
|
||||
"//adev/src/assets:api",
|
||||
"//adev/src/assets:content",
|
||||
]
|
||||
|
||||
APPLICATION_DEPS = [
|
||||
"@npm//@angular/docs",
|
||||
"@npm//@angular/build",
|
||||
"@npm//@angular-devkit/build-angular",
|
||||
"@npm//@angular/animations",
|
||||
"@npm//@angular/cdk",
|
||||
"@npm//@angular/common",
|
||||
"@npm//@angular/compiler",
|
||||
"@npm//@angular/compiler-cli",
|
||||
"@npm//@angular/core",
|
||||
"@npm//@angular/forms",
|
||||
"@npm//@angular/material",
|
||||
"@npm//@angular/platform-browser",
|
||||
"@npm//@angular/platform-server",
|
||||
"@npm//@angular/router",
|
||||
"@npm//gsap",
|
||||
"@npm//marked",
|
||||
"@npm//ngx-progressbar",
|
||||
"@npm//ogl",
|
||||
"@npm//rxjs",
|
||||
"@npm//typescript",
|
||||
"@npm//@typescript/vfs",
|
||||
"@npm//@codemirror/state",
|
||||
"@npm//@codemirror/view",
|
||||
"@npm//@codemirror/language",
|
||||
"@npm//@codemirror/commands",
|
||||
"@npm//@codemirror/search",
|
||||
"@npm//@codemirror/autocomplete",
|
||||
"@npm//@codemirror/lint",
|
||||
"@npm//@codemirror/lang-html",
|
||||
"@npm//@codemirror/lang-angular",
|
||||
"@npm//@codemirror/lang-css",
|
||||
"@npm//@codemirror/lang-sass",
|
||||
"@npm//@codemirror/lang-javascript",
|
||||
"@npm//@lezer/highlight",
|
||||
"@npm//@lezer/javascript",
|
||||
"@npm//@lezer/common",
|
||||
"@npm//@stackblitz/sdk",
|
||||
"@npm//open-in-idx",
|
||||
"@npm//@webcontainer/api",
|
||||
"@npm//@xterm/xterm",
|
||||
"@npm//@xterm/addon-fit",
|
||||
"@npm//algoliasearch",
|
||||
"@npm//angular-split",
|
||||
"@npm//zone.js",
|
||||
]
|
||||
|
||||
TEST_DEPS = APPLICATION_DEPS + [
|
||||
"@npm//@angular/platform-browser-dynamic",
|
||||
"@npm//@types/jasmine",
|
||||
"@npm//@types/node",
|
||||
"@npm//jasmine",
|
||||
"@npm//jasmine-core",
|
||||
"@npm//karma-chrome-launcher",
|
||||
"@npm//karma-coverage",
|
||||
"@npm//karma-jasmine",
|
||||
"@npm//karma-jasmine-html-reporter",
|
||||
]
|
||||
|
||||
# Create `npm_link` targets for all dependencies that correspond to a
|
||||
# first-party Angular package that can be built from `HEAD`.
|
||||
link_local_packages(
|
||||
all_deps = collections.uniq(APPLICATION_DEPS + TEST_DEPS),
|
||||
)
|
||||
|
||||
copy_to_bin(
|
||||
name = "application_files_bin",
|
||||
srcs = APPLICATION_FILES,
|
||||
)
|
||||
|
||||
bool_flag(
|
||||
name = "prerender_adev",
|
||||
build_setting_default = False,
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "no_prerender",
|
||||
flag_values = {
|
||||
":prerender_adev": "false",
|
||||
},
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "prerender",
|
||||
flag_values = {
|
||||
":prerender_adev": "true",
|
||||
},
|
||||
)
|
||||
|
||||
config_based_architect_flags = select({
|
||||
":no_prerender": ["--no-prerender"],
|
||||
":prerender": ["--prerender"],
|
||||
})
|
||||
|
||||
architect(
|
||||
name = "build",
|
||||
args = [
|
||||
"angular-dev:build",
|
||||
"--output-path=build",
|
||||
] + config_based_architect_flags,
|
||||
chdir = "$(RULEDIR)",
|
||||
data = ensure_local_package_deps(APPLICATION_DEPS) + APPLICATION_ASSETS + [
|
||||
":application_files_bin",
|
||||
],
|
||||
# Network is required to inline fonts.
|
||||
exec_properties = ENABLE_NETWORK,
|
||||
output_dir = True,
|
||||
tags = [
|
||||
"no-remote-exec",
|
||||
],
|
||||
)
|
||||
|
||||
http_server(
|
||||
name = "serve",
|
||||
additional_root_paths = [
|
||||
"angular/adev/build/browser",
|
||||
],
|
||||
enable_dev_ui = True,
|
||||
deps = [":build"],
|
||||
)
|
||||
|
||||
architect_test(
|
||||
name = "test",
|
||||
args = [
|
||||
"angular-dev:test",
|
||||
"--no-watch",
|
||||
],
|
||||
chdir = package_name(),
|
||||
data = ensure_local_package_deps(TEST_DEPS) + TEST_FILES + APPLICATION_ASSETS + [
|
||||
"//adev/tools:windows-chromium-path",
|
||||
"@npm//@angular/build-tooling/bazel/browsers/chromium",
|
||||
],
|
||||
env = {
|
||||
"CHROME_BIN": "../$(CHROMIUM)",
|
||||
},
|
||||
toolchains = [
|
||||
"@npm//@angular/build-tooling/bazel/browsers/chromium:toolchain_alias",
|
||||
],
|
||||
)
|
||||
@@ -1,53 +0,0 @@
|
||||
# [Angular.dev](https://www.angular.dev)
|
||||
|
||||
This site is built with Angular.
|
||||
|
||||
The content is written primarily in Markdown format located in `src/content`. For simple edits, you can directly edit the file on GitHub and generate a Pull Request.
|
||||
|
||||
## Local Development
|
||||
|
||||
For local development, [yarn](https://yarnpkg.com/) is the preferred package manager. You can setup a local environment with the following commands
|
||||
:
|
||||
|
||||
```bash
|
||||
# Clone Angular repo
|
||||
git clone https://github.com/angular/angular.git
|
||||
|
||||
# Navigate to project directory
|
||||
cd angular
|
||||
|
||||
# Install dependencies
|
||||
yarn
|
||||
|
||||
# Build and run local dev server
|
||||
# Note: Initial build will take some time
|
||||
yarn docs
|
||||
```
|
||||
|
||||
If you are having issues with the docs building, see the [FAQs](#faqs) section.
|
||||
|
||||
## Contributing
|
||||
|
||||
Want to report a bug, contribute some code, or improve the documentation? Excellent!
|
||||
|
||||
Read through our [contributing guidelines](/CONTRIBUTING.md) to learn about our submission process, coding rules, and more.
|
||||
|
||||
And if you're new, 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](CODE_OF_CONDUCT.md).
|
||||
|
||||
## FAQs
|
||||
|
||||
### The build is failing and I'm seeing `bazel:bazel failed: missing input file` messages.
|
||||
|
||||
This is most likely due to a bazel dependency / caching issue. To resolve this, run the following command:
|
||||
|
||||
```
|
||||
# Try this first
|
||||
yarn bazel clean
|
||||
|
||||
# If that doesn't work, try it with the expunge flag
|
||||
yarn bazel clean --expunge
|
||||
```
|
||||
@@ -1,109 +0,0 @@
|
||||
{
|
||||
"$schema": "../node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": ".",
|
||||
"projects": {
|
||||
"angular-dev": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss",
|
||||
"standalone": true,
|
||||
"changeDetection": "OnPush"
|
||||
}
|
||||
},
|
||||
"root": ".",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "adev",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"externalDependencies": ["path"],
|
||||
"define": {
|
||||
// We need this until xterm 5.6.0 is released
|
||||
// see https://github.com/xtermjs/xterm.js/pull/4940
|
||||
"self": "this"
|
||||
},
|
||||
"outputPath": "dist/angular-dev",
|
||||
"index": "src/index.html",
|
||||
"browser": "src/main.ts",
|
||||
"server": "src/main.server.ts",
|
||||
"ssr": true,
|
||||
"polyfills": [],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/robots.txt", "src/assets"],
|
||||
"styles": ["@angular/docs/styles/global-styles.scss", "./src/local-styles.scss"],
|
||||
"scripts": [],
|
||||
"webWorkerTsConfig": "tsconfig.worker.json",
|
||||
"optimization": {
|
||||
"fonts": {
|
||||
// TODO(josephperrott): enabled inline scripts
|
||||
"inline": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "angular-dev:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "angular-dev:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"options": {
|
||||
"buildTarget": "web-ui:build",
|
||||
"headers": {
|
||||
"Cross-Origin-Opener-Policy": "same-origin",
|
||||
"Cross-Origin-Embedder-Policy": "require-corp"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "angular-dev:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"include": ["src/app"],
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"main": "test-main.ts",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["@angular/docs/styles/global-styles.scss"],
|
||||
"scripts": [],
|
||||
"webWorkerTsConfig": "tsconfig.worker.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": "dca119a9-da31-47f7-a6cb-b60541037021",
|
||||
"cache": {
|
||||
// Disable build caching as the cache folder will just be dropped
|
||||
// when run under Bazel sandboxed execution.
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
{
|
||||
"hosting": {
|
||||
"target": "angular-docs",
|
||||
"public": "./build/browser",
|
||||
"ignore": ["**/.*"],
|
||||
"headers": [
|
||||
{
|
||||
"source": "assets/images/tutorials/common/*.jpg",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cross-Origin-Resource-Policy",
|
||||
"value": "cross-origin"
|
||||
},
|
||||
{
|
||||
"key": "Access-Control-Allow-Origin",
|
||||
"value": "*"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public,max-age=31536000,immutable"
|
||||
},
|
||||
{
|
||||
"key": "Access-Control-Allow-Origin",
|
||||
"value": "*"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/[0-9a-f][0-9a-f][0-9a-f].[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].js",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cross-Origin-Embedder-Policy",
|
||||
"value": "require-corp"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/@(ngsw-worker.js|ngsw.json)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "no-cache"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/**",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cross-Origin-Opener-Policy",
|
||||
"value": "same-origin"
|
||||
},
|
||||
|
||||
{
|
||||
"key": "Cross-Origin-Embedder-Policy",
|
||||
"value": "require-corp"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
const {getAdjustedChromeBinPathForWindows} = require('../adev/tools/windows-chromium-path');
|
||||
|
||||
process.env.CHROME_BIN = getAdjustedChromeBinPathForWindows();
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
{'reporter:jasmine-seed': ['type', JasmineSeedReporter]},
|
||||
],
|
||||
proxies: {
|
||||
'/dummy/image': 'src/assets/images/logos/angular/angular.png',
|
||||
},
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
random: true,
|
||||
seed: '',
|
||||
},
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/site'),
|
||||
subdir: '.',
|
||||
reporters: [{type: 'html'}, {type: 'text-summary'}],
|
||||
},
|
||||
reporters: ['progress', 'kjhtml', 'jasmine-seed'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
customLaunchers: {
|
||||
ChromeHeadlessNoSandbox: {
|
||||
base: 'ChromeHeadless',
|
||||
// See /integration/README.md#browser-tests for more info on these args
|
||||
flags: [
|
||||
'--no-sandbox',
|
||||
'--headless',
|
||||
'--disable-gpu',
|
||||
'--disable-dev-shm-usage',
|
||||
'--hide-scrollbars',
|
||||
'--mute-audio',
|
||||
],
|
||||
},
|
||||
},
|
||||
browsers: ['ChromeHeadlessNoSandbox'],
|
||||
browserNoActivityTimeout: 60000,
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
|
||||
// Helpers
|
||||
function JasmineSeedReporter(baseReporterDecorator) {
|
||||
baseReporterDecorator(this);
|
||||
|
||||
this.onBrowserComplete = (browser, result) => {
|
||||
const seed = result.order && result.order.random && result.order.seed;
|
||||
if (seed) this.write(`${browser}: Randomized with seed ${seed}.\n`);
|
||||
};
|
||||
|
||||
this.onRunComplete = () => undefined;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Generating data for `angular.dev/cli`
|
||||
|
||||
This script updates the Angular CLI help JSON files stored in `adev/src/content/cli/help`. This files are used to generate the [angular.dev CLI](https://angular.dev/cli) pages.
|
||||
@@ -1,154 +0,0 @@
|
||||
import {execSync} from 'node:child_process';
|
||||
import {readFile, writeFile, readdir, mkdtemp, realpath, copyFile, unlink} from 'node:fs/promises';
|
||||
import {tmpdir} from 'node:os';
|
||||
import {get} from 'node:https';
|
||||
import {dirname, resolve as resolvePath, posix, join} from 'node:path';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import {existsSync, constants as fsConstants} from 'node:fs';
|
||||
|
||||
const GITHUB_API = 'https://api.github.com/repos/';
|
||||
const CLI_BUILDS_REPO = 'angular/cli-builds';
|
||||
const GITHUB_API_CLI_BUILDS = posix.join(GITHUB_API, CLI_BUILDS_REPO);
|
||||
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
const CLI_HELP_CONTENT_PATH = resolvePath(scriptDir, '../../src/content/cli/help');
|
||||
const CLI_SHA_PATH = join(CLI_HELP_CONTENT_PATH, 'build-info.json');
|
||||
|
||||
async function main() {
|
||||
if (!existsSync(CLI_SHA_PATH)) {
|
||||
throw new Error(`${CLI_SHA_PATH} does not exist.`);
|
||||
}
|
||||
|
||||
const branch = process.env.GITHUB_REF;
|
||||
const {sha: currentSha} = JSON.parse(await readFile(CLI_SHA_PATH, 'utf-8'));
|
||||
const latestSha = await getShaFromCliBuilds(branch);
|
||||
|
||||
console.log(`Comparing ${currentSha}...${latestSha}.`);
|
||||
const affectedFiles = await getAffectedFiles(currentSha, latestSha);
|
||||
const changedHelpFiles = affectedFiles.filter((file) => file.startsWith('help/'));
|
||||
|
||||
if (changedHelpFiles.length === 0) {
|
||||
console.log(`No 'help/**' files changed between ${currentSha} and ${latestSha}.`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`The below help files changed between ${currentSha} and ${latestSha}:\n` +
|
||||
changedHelpFiles.map((f) => '* ' + f).join('\n'),
|
||||
);
|
||||
|
||||
const temporaryDir = await realpath(await mkdtemp(join(tmpdir(), 'cli-src-')));
|
||||
const execOptions = {cwd: temporaryDir, stdio: 'inherit'};
|
||||
execSync('git init', execOptions);
|
||||
execSync('git remote add origin https://github.com/angular/cli-builds.git', execOptions);
|
||||
// fetch a commit
|
||||
execSync(`git fetch origin ${latestSha}`, execOptions);
|
||||
// reset this repository's main branch to the commit of interest
|
||||
execSync('git reset --hard FETCH_HEAD', execOptions);
|
||||
// get sha when files where changed
|
||||
const shaWhenFilesChanged = execSync(`git rev-list -1 ${latestSha} "help/"`, {
|
||||
encoding: 'utf8',
|
||||
cwd: temporaryDir,
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
}).trim();
|
||||
|
||||
// Delete existing JSON help files.
|
||||
const helpFilesUnlink = (await readdir(CLI_HELP_CONTENT_PATH))
|
||||
.filter((f) => f.endsWith('.json'))
|
||||
.map((f) => unlink(join(CLI_HELP_CONTENT_PATH, f)));
|
||||
|
||||
await Promise.allSettled(helpFilesUnlink);
|
||||
|
||||
// Copy new help files
|
||||
const tempHelpDir = join(temporaryDir, 'help');
|
||||
const helpFilesCopy = (await readdir(tempHelpDir)).map((f) => {
|
||||
const src = join(tempHelpDir, f);
|
||||
const dest = join(CLI_HELP_CONTENT_PATH, f);
|
||||
|
||||
return copyFile(src, dest, fsConstants.COPYFILE_FICLONE);
|
||||
});
|
||||
|
||||
await Promise.allSettled(helpFilesCopy);
|
||||
|
||||
// Write SHA to file.
|
||||
await writeFile(
|
||||
CLI_SHA_PATH,
|
||||
JSON.stringify(
|
||||
{
|
||||
branchName: branch,
|
||||
sha: shaWhenFilesChanged,
|
||||
},
|
||||
undefined,
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
console.log('\nChanges: ');
|
||||
execSync(`git status --porcelain`, {stdio: 'inherit'});
|
||||
|
||||
console.log(`Successfully updated help files in '${CLI_HELP_CONTENT_PATH}'.\n`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SHA of a branch.
|
||||
*
|
||||
* @param {string} branch
|
||||
* @param {string} headSha
|
||||
* @returns Promise<string>
|
||||
*/
|
||||
async function getShaFromCliBuilds(branch) {
|
||||
const sha = await httpGet(`${GITHUB_API_CLI_BUILDS}/commits/${branch}`, {
|
||||
headers: {Accept: 'application/vnd.github.VERSION.sha'},
|
||||
});
|
||||
|
||||
if (!sha) {
|
||||
throw new Error(`Unable to extract the SHA for '${branch}'.`);
|
||||
}
|
||||
|
||||
return sha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the affected files.
|
||||
*
|
||||
* @param {string} baseSha
|
||||
* @param {string} headSha
|
||||
* @returns Promise<string[]>
|
||||
*/
|
||||
async function getAffectedFiles(baseSha, headSha) {
|
||||
const {files} = JSON.parse(
|
||||
await httpGet(`${GITHUB_API_CLI_BUILDS}/compare/${baseSha}...${headSha}`),
|
||||
);
|
||||
return files.map((f) => f.filename);
|
||||
}
|
||||
|
||||
function httpGet(url, options = {}) {
|
||||
options.headers ??= {};
|
||||
options.headers[
|
||||
'Authorization'
|
||||
] = `token ${process.env.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN}`;
|
||||
// User agent is required
|
||||
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#user-agent-required
|
||||
options.headers['User-Agent'] = `ADEV_Angular_CLI_Sources_Update`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
get(url, options, (res) => {
|
||||
let data = '';
|
||||
res
|
||||
.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
})
|
||||
.on('end', () => {
|
||||
resolve(data);
|
||||
});
|
||||
}).on('error', (e) => {
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
load("//tools:defaults.bzl", "ng_module", "ng_package")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "docs",
|
||||
srcs = [
|
||||
"index.ts",
|
||||
],
|
||||
module_name = "@angular/docs",
|
||||
deps = [
|
||||
"//adev/shared-docs/components",
|
||||
"//adev/shared-docs/constants",
|
||||
"//adev/shared-docs/directives",
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/pipes",
|
||||
"//adev/shared-docs/providers",
|
||||
"//adev/shared-docs/services",
|
||||
"//adev/shared-docs/testing",
|
||||
"//adev/shared-docs/utils",
|
||||
],
|
||||
)
|
||||
|
||||
ng_package(
|
||||
name = "npm_package",
|
||||
srcs = [
|
||||
"package.json",
|
||||
"//adev/shared-docs/icons",
|
||||
"//adev/shared-docs/pipeline:BUILD.bazel",
|
||||
"//adev/shared-docs/pipeline:_guides.bzl",
|
||||
"//adev/shared-docs/pipeline:_playground.bzl",
|
||||
"//adev/shared-docs/pipeline:_stackblitz.bzl",
|
||||
"//adev/shared-docs/pipeline:_tutorial.bzl",
|
||||
"//adev/shared-docs/pipeline:guides.mjs",
|
||||
"//adev/shared-docs/pipeline:guides-no-mermaid.mjs",
|
||||
"//adev/shared-docs/pipeline:playground.mjs",
|
||||
"//adev/shared-docs/pipeline:stackblitz.mjs",
|
||||
"//adev/shared-docs/pipeline:tutorial.mjs",
|
||||
"//adev/shared-docs/pipeline/examples/template:files",
|
||||
"//adev/shared-docs/pipeline/tutorials/common:files",
|
||||
"//adev/shared-docs/styles",
|
||||
],
|
||||
visibility = [
|
||||
"//adev:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":docs",
|
||||
],
|
||||
)
|
||||
@@ -1,28 +0,0 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ts_library(
|
||||
name = "components",
|
||||
srcs = [
|
||||
"index.ts",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//adev/shared-docs/components/algolia-icon",
|
||||
"//adev/shared-docs/components/breadcrumb",
|
||||
"//adev/shared-docs/components/cookie-popup",
|
||||
"//adev/shared-docs/components/copy-source-code-button",
|
||||
"//adev/shared-docs/components/icon",
|
||||
"//adev/shared-docs/components/navigation-list",
|
||||
"//adev/shared-docs/components/search-dialog",
|
||||
"//adev/shared-docs/components/select",
|
||||
"//adev/shared-docs/components/slide-toggle",
|
||||
"//adev/shared-docs/components/table-of-contents",
|
||||
"//adev/shared-docs/components/text-field",
|
||||
"//adev/shared-docs/components/top-level-banner",
|
||||
"//adev/shared-docs/components/viewers",
|
||||
],
|
||||
)
|
||||
@@ -1,20 +0,0 @@
|
||||
load("//tools:defaults.bzl", "ng_module")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "algolia-icon",
|
||||
srcs = [
|
||||
"algolia-icon.component.ts",
|
||||
],
|
||||
assets = [
|
||||
"algolia-icon.component.html",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs/components:__pkg__",
|
||||
"//adev/shared-docs/components/search-dialog:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//packages/core",
|
||||
],
|
||||
)
|
||||
@@ -1,52 +0,0 @@
|
||||
<!-- Algolia logo -->
|
||||
<svg
|
||||
id="Layer_1"
|
||||
class="docs-algolia-logo"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 2196.2 500"
|
||||
>
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1,
|
||||
.cls-2 {
|
||||
fill: #003dff;
|
||||
}
|
||||
.cls-2 {
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
class="cls-2"
|
||||
d="M1070.38,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"
|
||||
/>
|
||||
<rect class="cls-1" x="1845.88" y="104.73" width="62.58" height="277.9" rx="5.9" ry="5.9" />
|
||||
<path
|
||||
class="cls-2"
|
||||
d="M1851.78,71.38h50.77c3.26,0,5.9-2.64,5.9-5.9V5.9c0-3.62-3.24-6.39-6.82-5.83l-50.77,7.95c-2.87,.45-4.99,2.92-4.99,5.83v51.62c0,3.26,2.64,5.9,5.9,5.9Z"
|
||||
/>
|
||||
<path
|
||||
class="cls-2"
|
||||
d="M1764.03,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"
|
||||
/>
|
||||
<path
|
||||
class="cls-2"
|
||||
d="M1631.95,142.72c-11.14-12.25-24.83-21.65-40.78-28.31-15.92-6.53-33.26-9.85-52.07-9.85-18.78,0-36.15,3.17-51.92,9.85-15.59,6.66-29.29,16.05-40.76,28.31-11.47,12.23-20.38,26.87-26.76,44.03-6.38,17.17-9.24,37.37-9.24,58.36,0,20.99,3.19,36.87,9.55,54.21,6.38,17.32,15.14,32.11,26.45,44.36,11.29,12.23,24.83,21.62,40.6,28.46,15.77,6.83,40.12,10.33,52.4,10.48,12.25,0,36.78-3.82,52.7-10.48,15.92-6.68,29.46-16.23,40.78-28.46,11.29-12.25,20.05-27.04,26.25-44.36,6.22-17.34,9.24-33.22,9.24-54.21,0-20.99-3.34-41.19-10.03-58.36-6.38-17.17-15.14-31.8-26.43-44.03Zm-44.43,163.75c-11.47,15.75-27.56,23.7-48.09,23.7-20.55,0-36.63-7.8-48.1-23.7-11.47-15.75-17.21-34.01-17.21-61.2,0-26.89,5.59-49.14,17.06-64.87,11.45-15.75,27.54-23.52,48.07-23.52,20.55,0,36.63,7.78,48.09,23.52,11.47,15.57,17.36,37.98,17.36,64.87,0,27.19-5.72,45.3-17.19,61.2Z"
|
||||
/>
|
||||
<path
|
||||
class="cls-2"
|
||||
d="M894.42,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"
|
||||
/>
|
||||
<path
|
||||
class="cls-2"
|
||||
d="M2133.97,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"
|
||||
/>
|
||||
<path
|
||||
class="cls-2"
|
||||
d="M1314.05,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-11.79,18.34-19.6,39.64-22.11,62.59-.58,5.3-.88,10.68-.88,16.14s.31,11.15,.93,16.59c4.28,38.09,23.14,71.61,50.66,94.52,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47h0c17.99,0,34.61-5.93,48.16-15.97,16.29-11.58,28.88-28.54,34.48-47.75v50.26h-.11v11.08c0,21.84-5.71,38.27-17.34,49.36-11.61,11.08-31.04,16.63-58.25,16.63-11.12,0-28.79-.59-46.6-2.41-2.83-.29-5.46,1.5-6.27,4.22l-12.78,43.11c-1.02,3.46,1.27,7.02,4.83,7.53,21.52,3.08,42.52,4.68,54.65,4.68,48.91,0,85.16-10.75,108.89-32.21,21.48-19.41,33.15-48.89,35.2-88.52V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,64.1s.65,139.13,0,143.36c-12.08,9.77-27.11,13.59-43.49,14.7-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-1.32,0-2.63-.03-3.94-.1-40.41-2.11-74.52-37.26-74.52-79.38,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33Z"
|
||||
/>
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M249.83,0C113.3,0,2,110.09,.03,246.16c-2,138.19,110.12,252.7,248.33,253.5,42.68,.25,83.79-10.19,120.3-30.03,3.56-1.93,4.11-6.83,1.08-9.51l-23.38-20.72c-4.75-4.21-11.51-5.4-17.36-2.92-25.48,10.84-53.17,16.38-81.71,16.03-111.68-1.37-201.91-94.29-200.13-205.96,1.76-110.26,92-199.41,202.67-199.41h202.69V407.41l-115-102.18c-3.72-3.31-9.42-2.66-12.42,1.31-18.46,24.44-48.53,39.64-81.93,37.34-46.33-3.2-83.87-40.5-87.34-86.81-4.15-55.24,39.63-101.52,94-101.52,49.18,0,89.68,37.85,93.91,85.95,.38,4.28,2.31,8.27,5.52,11.12l29.95,26.55c3.4,3.01,8.79,1.17,9.63-3.3,2.16-11.55,2.92-23.58,2.07-35.92-4.82-70.34-61.8-126.93-132.17-131.26-80.68-4.97-148.13,58.14-150.27,137.25-2.09,77.1,61.08,143.56,138.19,145.26,32.19,.71,62.03-9.41,86.14-26.95l150.26,133.2c6.44,5.71,16.61,1.14,16.61-7.47V9.48C499.66,4.25,495.42,0,490.18,0H249.83Z"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.0 KiB |
@@ -1,18 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-algolia-icon',
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [],
|
||||
templateUrl: './algolia-icon.component.html',
|
||||
})
|
||||
export class AlgoliaIcon {}
|
||||
@@ -1,54 +0,0 @@
|
||||
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
|
||||
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "breadcrumb",
|
||||
srcs = [
|
||||
"breadcrumb.component.ts",
|
||||
],
|
||||
assets = [
|
||||
":breadcrumb.component.css",
|
||||
"breadcrumb.component.html",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs/components:__pkg__",
|
||||
"//adev/shared-docs/components/viewers:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/services",
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
"//packages/router",
|
||||
],
|
||||
)
|
||||
|
||||
sass_binary(
|
||||
name = "style",
|
||||
src = "breadcrumb.component.scss",
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
["*.spec.ts"],
|
||||
),
|
||||
deps = [
|
||||
":breadcrumb",
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/services",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
"//packages/platform-browser",
|
||||
"//packages/router",
|
||||
"//packages/router/testing",
|
||||
],
|
||||
)
|
||||
|
||||
karma_web_test_suite(
|
||||
name = "test",
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
@@ -1,13 +0,0 @@
|
||||
@for (breadcrumb of breadcrumbItems(); track breadcrumb) {
|
||||
<div class="docs-breadcrumb">
|
||||
@if (breadcrumb.path) {
|
||||
@if (breadcrumb.isExternal) {
|
||||
<a [href]="breadcrumb.path">{{ breadcrumb.label }}</a>
|
||||
} @else {
|
||||
<a [routerLink]="'/' + breadcrumb.path">{{ breadcrumb.label }}</a>
|
||||
}
|
||||
} @else {
|
||||
<span>{{ breadcrumb.label }}</span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-block-end: 1.5rem;
|
||||
}
|
||||
|
||||
.docs-breadcrumb {
|
||||
span {
|
||||
color: var(--quaternary-contrast);
|
||||
font-size: 0.875rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
span {
|
||||
&::after {
|
||||
content: 'chevron_right';
|
||||
font-family: var(--icons);
|
||||
margin-inline: 0.5rem;
|
||||
color: var(--quinary-contrast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {Breadcrumb} from './breadcrumb.component';
|
||||
import {NavigationState} from '../../services';
|
||||
import {NavigationItem} from '../../interfaces';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {provideExperimentalZonelessChangeDetection} from '@angular/core';
|
||||
|
||||
describe('Breadcrumb', () => {
|
||||
let fixture: ComponentFixture<Breadcrumb>;
|
||||
let navigationStateSpy: jasmine.SpyObj<NavigationState>;
|
||||
|
||||
beforeEach(() => {
|
||||
navigationStateSpy = jasmine.createSpyObj('NavigationState', ['activeNavigationItem']);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [Breadcrumb, RouterTestingModule],
|
||||
providers: [
|
||||
provideExperimentalZonelessChangeDetection(),
|
||||
{
|
||||
provide: NavigationState,
|
||||
useValue: navigationStateSpy,
|
||||
},
|
||||
],
|
||||
});
|
||||
fixture = TestBed.createComponent(Breadcrumb);
|
||||
});
|
||||
|
||||
it('should display proper breadcrumb structure based on navigation state', () => {
|
||||
navigationStateSpy.activeNavigationItem.and.returnValue(item);
|
||||
|
||||
fixture.detectChanges();
|
||||
const breadcrumbs = fixture.debugElement.queryAll(By.css('.docs-breadcrumb span'));
|
||||
|
||||
expect(breadcrumbs.length).toBe(2);
|
||||
expect(breadcrumbs[0].nativeElement.innerText).toEqual('Grandparent');
|
||||
expect(breadcrumbs[1].nativeElement.innerText).toEqual('Parent');
|
||||
});
|
||||
|
||||
it('should display breadcrumb links when navigation item has got path', () => {
|
||||
navigationStateSpy.activeNavigationItem.and.returnValue(exampleItemWithPath);
|
||||
|
||||
fixture.detectChanges();
|
||||
const breadcrumbs = fixture.debugElement.queryAll(By.css('.docs-breadcrumb a'));
|
||||
|
||||
expect(breadcrumbs.length).toBe(1);
|
||||
expect(breadcrumbs[0].nativeElement.innerText).toEqual('Parent');
|
||||
expect(breadcrumbs[0].nativeElement.href).toEqual(`${window.origin}/example`);
|
||||
});
|
||||
});
|
||||
|
||||
const grandparent: NavigationItem = {
|
||||
label: 'Grandparent',
|
||||
};
|
||||
|
||||
const parent: NavigationItem = {
|
||||
label: 'Parent',
|
||||
parent: grandparent,
|
||||
};
|
||||
|
||||
const item: NavigationItem = {
|
||||
label: 'Active Item',
|
||||
parent: parent,
|
||||
};
|
||||
|
||||
const parentWithPath: NavigationItem = {
|
||||
label: 'Parent',
|
||||
path: '/example',
|
||||
};
|
||||
|
||||
const exampleItemWithPath: NavigationItem = {
|
||||
label: 'Active Item',
|
||||
parent: parentWithPath,
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, OnInit, inject, signal} from '@angular/core';
|
||||
import {NavigationState} from '../../services/index';
|
||||
import {NavigationItem} from '../../interfaces/index';
|
||||
import {NgFor, NgIf} from '@angular/common';
|
||||
import {RouterLink} from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-breadcrumb',
|
||||
standalone: true,
|
||||
imports: [NgIf, NgFor, RouterLink],
|
||||
templateUrl: './breadcrumb.component.html',
|
||||
styleUrls: ['./breadcrumb.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class Breadcrumb implements OnInit {
|
||||
private readonly navigationState = inject(NavigationState);
|
||||
|
||||
breadcrumbItems = signal<NavigationItem[]>([]);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.setBreadcrumbItemsBasedOnNavigationStructure();
|
||||
}
|
||||
|
||||
private setBreadcrumbItemsBasedOnNavigationStructure(): void {
|
||||
let breadcrumbs: NavigationItem[] = [];
|
||||
|
||||
const traverse = (node: NavigationItem | null) => {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.parent) {
|
||||
breadcrumbs = [node.parent, ...breadcrumbs];
|
||||
traverse(node.parent);
|
||||
}
|
||||
};
|
||||
|
||||
traverse(this.navigationState.activeNavigationItem());
|
||||
|
||||
this.breadcrumbItems.set(breadcrumbs);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
|
||||
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "cookie-popup",
|
||||
srcs = [
|
||||
"cookie-popup.component.ts",
|
||||
],
|
||||
assets = [
|
||||
":cookie-popup.component.css",
|
||||
"cookie-popup.component.html",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs/components:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//adev/shared-docs/providers",
|
||||
"//adev/shared-docs/utils",
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
],
|
||||
)
|
||||
|
||||
sass_binary(
|
||||
name = "style",
|
||||
src = "cookie-popup.component.scss",
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
["*.spec.ts"],
|
||||
),
|
||||
deps = [
|
||||
":cookie-popup",
|
||||
"//adev/shared-docs/providers",
|
||||
"//adev/shared-docs/testing",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
],
|
||||
)
|
||||
|
||||
karma_web_test_suite(
|
||||
name = "test",
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
@@ -1,22 +0,0 @@
|
||||
@if (!hasAccepted()) {
|
||||
<div class="docs-cookies-popup docs-invert-mode">
|
||||
<p>This site uses cookies from Google to deliver its services and to analyze traffic.</p>
|
||||
|
||||
<div>
|
||||
<a href="https://policies.google.com/technologies/cookies" target="_blank" rel="noopener">
|
||||
<button class="docs-primary-btn" [attr.text]="'Learn more'" aria-label="Learn More">
|
||||
Learn more
|
||||
</button>
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
(click)="accept()"
|
||||
class="docs-primary-btn"
|
||||
[attr.text]="'Ok, Got it'"
|
||||
aria-label="Ok, Got it"
|
||||
>
|
||||
Ok, Got it
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
:host {
|
||||
position: fixed;
|
||||
bottom: 0.5rem;
|
||||
right: 0.5rem;
|
||||
z-index: var(--z-index-cookie-consent);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
animation: 1s linear forwards 0.5s fadeIn;
|
||||
}
|
||||
|
||||
.docs-cookies-popup {
|
||||
padding: 1rem;
|
||||
background-color: var(--page-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.875rem;
|
||||
max-width: 265px;
|
||||
transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease;
|
||||
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-block-start: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-block: 0;
|
||||
color: var(--primary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
100% {
|
||||
opacity: 100%;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {CookiePopup, STORAGE_KEY} from './cookie-popup.component';
|
||||
import {LOCAL_STORAGE} from '../../providers/index';
|
||||
import {MockLocalStorage} from '../../testing/index';
|
||||
import {provideExperimentalZonelessChangeDetection} from '@angular/core';
|
||||
|
||||
describe('CookiePopup', () => {
|
||||
let fixture: ComponentFixture<CookiePopup>;
|
||||
let mockLocalStorage = new MockLocalStorage();
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CookiePopup],
|
||||
providers: [
|
||||
provideExperimentalZonelessChangeDetection(),
|
||||
{
|
||||
provide: LOCAL_STORAGE,
|
||||
useValue: mockLocalStorage,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should make the popup visible by default', () => {
|
||||
initComponent(false);
|
||||
|
||||
expect(getCookiesPopup()).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should hide the cookies popup if the user has already accepted cookies', () => {
|
||||
initComponent(true);
|
||||
|
||||
expect(getCookiesPopup()).toBeNull();
|
||||
});
|
||||
|
||||
it('should hide the cookies popup', () => {
|
||||
initComponent(false);
|
||||
|
||||
accept();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getCookiesPopup()).toBeNull();
|
||||
});
|
||||
|
||||
it('should store the user confirmation', () => {
|
||||
initComponent(false);
|
||||
|
||||
expect(mockLocalStorage.getItem(STORAGE_KEY)).toBeNull();
|
||||
|
||||
accept();
|
||||
|
||||
expect(mockLocalStorage.getItem(STORAGE_KEY)).toBe('true');
|
||||
});
|
||||
|
||||
// Helpers
|
||||
function getCookiesPopup() {
|
||||
return (fixture.nativeElement as HTMLElement).querySelector('.docs-cookies-popup');
|
||||
}
|
||||
|
||||
function accept() {
|
||||
(fixture.nativeElement as HTMLElement)
|
||||
.querySelector<HTMLButtonElement>('button[text="Ok, Got it"]')
|
||||
?.click();
|
||||
}
|
||||
|
||||
function initComponent(cookiesAccepted: boolean) {
|
||||
mockLocalStorage.setItem(STORAGE_KEY, cookiesAccepted ? 'true' : null);
|
||||
fixture = TestBed.createComponent(CookiePopup);
|
||||
|
||||
fixture.detectChanges();
|
||||
}
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, inject, signal} from '@angular/core';
|
||||
import {NgIf} from '@angular/common';
|
||||
import {LOCAL_STORAGE} from '../../providers/index';
|
||||
import {setCookieConsent} from '../../utils';
|
||||
|
||||
/**
|
||||
* Decelare gtag as part of the window in this file as gtag is expected to already be loaded.
|
||||
*/
|
||||
declare const window: Window & typeof globalThis & {gtag?: Function};
|
||||
|
||||
export const STORAGE_KEY = 'docs-accepts-cookies';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-cookie-popup',
|
||||
standalone: true,
|
||||
imports: [NgIf],
|
||||
templateUrl: './cookie-popup.component.html',
|
||||
styleUrls: ['./cookie-popup.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CookiePopup {
|
||||
private readonly localStorage = inject(LOCAL_STORAGE);
|
||||
|
||||
/** Whether the user has accepted the cookie disclaimer. */
|
||||
hasAccepted = signal<boolean>(false);
|
||||
|
||||
constructor() {
|
||||
// Needs to be in a try/catch, because some browsers will
|
||||
// throw when using `localStorage` in private mode.
|
||||
try {
|
||||
this.hasAccepted.set(this.localStorage?.getItem(STORAGE_KEY) === 'true');
|
||||
} catch {
|
||||
this.hasAccepted.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
/** Accepts the cookie disclaimer. */
|
||||
protected accept(): void {
|
||||
try {
|
||||
this.localStorage?.setItem(STORAGE_KEY, 'true');
|
||||
} catch {}
|
||||
|
||||
this.hasAccepted.set(true);
|
||||
|
||||
// Enable Google Analytics consent properties
|
||||
setCookieConsent('granted');
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "copy-source-code-button",
|
||||
srcs = [
|
||||
"copy-source-code-button.component.ts",
|
||||
],
|
||||
assets = [
|
||||
"copy-source-code-button.component.html",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs/components:__pkg__",
|
||||
"//adev/shared-docs/components/viewers:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//adev/shared-docs/components/icon",
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
"@npm//@angular/cdk",
|
||||
],
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
["*.spec.ts"],
|
||||
),
|
||||
deps = [
|
||||
":copy-source-code-button",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
"//packages/platform-browser",
|
||||
"@npm//@angular/cdk",
|
||||
],
|
||||
)
|
||||
|
||||
karma_web_test_suite(
|
||||
name = "test",
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
<i>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="docs-copy"
|
||||
>
|
||||
<path
|
||||
d="M5 22C4.45 22 3.97917 21.8042 3.5875 21.4125C3.19583 21.0208 3 20.55 3 20V6H5V20H16V22H5ZM9 18C8.45 18 7.97917 17.8042 7.5875 17.4125C7.19583 17.0208 7 16.55 7 16V4C7 3.45 7.19583 2.97917 7.5875 2.5875C7.97917 2.19583 8.45 2 9 2H18C18.55 2 19.0208 2.19583 19.4125 2.5875C19.8042 2.97917 20 3.45 20 4V16C20 16.55 19.8042 17.0208 19.4125 17.4125C19.0208 17.8042 18.55 18 18 18H9ZM9 16H18V4H9V16Z"
|
||||
fill="#A39FA9"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
|
||||
<docs-icon class="docs-check">check</docs-icon>
|
||||
-127
@@ -1,127 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
|
||||
|
||||
import {
|
||||
CONFIRMATION_DISPLAY_TIME_MS,
|
||||
CopySourceCodeButton,
|
||||
} from './copy-source-code-button.component';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
provideExperimentalZonelessChangeDetection,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {Clipboard} from '@angular/cdk/clipboard';
|
||||
|
||||
const SUCCESSFULLY_COPY_CLASS_NAME = 'docs-copy-source-code-button-success';
|
||||
const FAILED_COPY_CLASS_NAME = 'docs-copy-source-code-button-failed';
|
||||
|
||||
describe('CopySourceCodeButton', () => {
|
||||
let component: CodeSnippetWrapper;
|
||||
let fixture: ComponentFixture<CodeSnippetWrapper>;
|
||||
let copySpy: jasmine.Spy<(text: string) => boolean>;
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CodeSnippetWrapper],
|
||||
providers: [provideExperimentalZonelessChangeDetection()],
|
||||
});
|
||||
fixture = TestBed.createComponent(CodeSnippetWrapper);
|
||||
component = fixture.componentInstance;
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const clipboardService = TestBed.inject(Clipboard);
|
||||
copySpy = spyOn(clipboardService, 'copy');
|
||||
});
|
||||
|
||||
it('should call clipboard service when clicked on copy source code', async () => {
|
||||
const expectedCodeToBeCopied = 'npm install -g @angular/cli';
|
||||
component.code.set(expectedCodeToBeCopied);
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
const button = fixture.debugElement.query(By.directive(CopySourceCodeButton)).nativeElement;
|
||||
button.click();
|
||||
|
||||
expect(copySpy.calls.argsFor(0)[0].trim()).toBe(expectedCodeToBeCopied);
|
||||
});
|
||||
|
||||
it('should not copy lines marked as deleted when code snippet contains diff', async () => {
|
||||
const codeInHtmlFormat = `
|
||||
<code>
|
||||
<div class="line remove"><span class="hljs-tag"><<span class="hljs-name">div</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let product of products"</span>></span></div>
|
||||
<div class="line add"><span class="hljs-tag"><<span class="hljs-name">div</span> *<span class="hljs-attr">ngFor</span>=<span class="hljs-string">"let product of products()"</span>></span></div>
|
||||
</code>
|
||||
`;
|
||||
const expectedCodeToBeCopied = `<div *ngFor="let product of products()">`;
|
||||
component.code.set(codeInHtmlFormat);
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
const button = fixture.debugElement.query(By.directive(CopySourceCodeButton)).nativeElement;
|
||||
button.click();
|
||||
|
||||
expect(copySpy.calls.argsFor(0)[0].trim()).toBe(expectedCodeToBeCopied);
|
||||
});
|
||||
|
||||
it(`should set ${SUCCESSFULLY_COPY_CLASS_NAME} for ${CONFIRMATION_DISPLAY_TIME_MS} ms when copy was executed properly`, fakeAsync(() => {
|
||||
component.code.set('example');
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = fixture.debugElement.query(By.directive(CopySourceCodeButton)).nativeElement;
|
||||
button.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(button).toHaveClass(SUCCESSFULLY_COPY_CLASS_NAME);
|
||||
|
||||
tick(CONFIRMATION_DISPLAY_TIME_MS);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(button).not.toHaveClass(SUCCESSFULLY_COPY_CLASS_NAME);
|
||||
}));
|
||||
|
||||
it(`should set ${FAILED_COPY_CLASS_NAME} for ${CONFIRMATION_DISPLAY_TIME_MS} ms when copy failed`, fakeAsync(() => {
|
||||
component.code.set('example');
|
||||
copySpy.and.throwError('Fake copy error');
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = fixture.debugElement.query(By.directive(CopySourceCodeButton)).nativeElement;
|
||||
button.click();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(button).toHaveClass(FAILED_COPY_CLASS_NAME);
|
||||
|
||||
tick(CONFIRMATION_DISPLAY_TIME_MS);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(button).not.toHaveClass(FAILED_COPY_CLASS_NAME);
|
||||
}));
|
||||
});
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<pre>
|
||||
<code [innerHtml]="code()"></code>
|
||||
</pre>
|
||||
<button docs-copy-source-code></button>
|
||||
`,
|
||||
imports: [CopySourceCodeButton],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
})
|
||||
class CodeSnippetWrapper {
|
||||
code = signal('');
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
WritableSignal,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Clipboard} from '@angular/cdk/clipboard';
|
||||
import {IconComponent} from '../icon/icon.component';
|
||||
|
||||
export const REMOVED_LINE_CLASS_NAME = '.line.remove';
|
||||
export const CONFIRMATION_DISPLAY_TIME_MS = 2000;
|
||||
|
||||
@Component({
|
||||
selector: 'button[docs-copy-source-code]',
|
||||
standalone: true,
|
||||
imports: [CommonModule, IconComponent],
|
||||
templateUrl: './copy-source-code-button.component.html',
|
||||
host: {
|
||||
'type': 'button',
|
||||
'aria-label': 'Copy example source to clipboard',
|
||||
'title': 'Copy example source',
|
||||
'(click)': 'copySourceCode()',
|
||||
'[class.docs-copy-source-code-button-success]': 'showCopySuccess()',
|
||||
'[class.docs-copy-source-code-button-failed]': 'showCopyFailure()',
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CopySourceCodeButton {
|
||||
private readonly changeDetector = inject(ChangeDetectorRef);
|
||||
private readonly clipboard = inject(Clipboard);
|
||||
private readonly elementRef = inject(ElementRef);
|
||||
|
||||
protected readonly showCopySuccess = signal(false);
|
||||
protected readonly showCopyFailure = signal(false);
|
||||
|
||||
copySourceCode(): void {
|
||||
try {
|
||||
const codeElement = this.elementRef.nativeElement.parentElement.querySelector(
|
||||
'code',
|
||||
) as HTMLElement;
|
||||
const sourceCode = this.getSourceCode(codeElement);
|
||||
this.clipboard.copy(sourceCode);
|
||||
this.showResult(this.showCopySuccess);
|
||||
} catch {
|
||||
this.showResult(this.showCopyFailure);
|
||||
}
|
||||
}
|
||||
|
||||
private getSourceCode(codeElement: HTMLElement): string {
|
||||
this.showCopySuccess.set(false);
|
||||
this.showCopyFailure.set(false);
|
||||
|
||||
const removedLines: NodeList = codeElement.querySelectorAll(REMOVED_LINE_CLASS_NAME);
|
||||
|
||||
if (removedLines.length) {
|
||||
// Get only those lines which are not marked as removed
|
||||
const formattedText = Array.from(codeElement.querySelectorAll('.line:not(.remove)'))
|
||||
.map((line) => (line as HTMLDivElement).innerText)
|
||||
.join('\n');
|
||||
|
||||
return formattedText.trim();
|
||||
} else {
|
||||
const text: string = codeElement.innerText || '';
|
||||
return text.replace(/\n\n\n/g, ``).trim();
|
||||
}
|
||||
}
|
||||
|
||||
private showResult(messageState: WritableSignal<boolean>) {
|
||||
messageState.set(true);
|
||||
|
||||
setTimeout(() => {
|
||||
messageState.set(false);
|
||||
// It's required for code snippets embedded in the ExampleViewer.
|
||||
this.changeDetector.markForCheck();
|
||||
}, CONFIRMATION_DISPLAY_TIME_MS);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
load("//tools:defaults.bzl", "ng_module")
|
||||
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "icon",
|
||||
srcs = [
|
||||
"icon.component.ts",
|
||||
],
|
||||
assets = [
|
||||
":icon.component.css",
|
||||
"icon.component.html",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs/components:__pkg__",
|
||||
"//adev/shared-docs/components/copy-source-code-button:__pkg__",
|
||||
"//adev/shared-docs/components/navigation-list:__pkg__",
|
||||
"//adev/shared-docs/components/table-of-contents:__pkg__",
|
||||
"//adev/shared-docs/components/text-field:__pkg__",
|
||||
"//adev/shared-docs/components/top-level-banner:__pkg__",
|
||||
"//adev/shared-docs/components/viewers:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
],
|
||||
)
|
||||
|
||||
sass_binary(
|
||||
name = "style",
|
||||
src = "icon.component.scss",
|
||||
)
|
||||
@@ -1 +0,0 @@
|
||||
<ng-content></ng-content>
|
||||
@@ -1,3 +0,0 @@
|
||||
.docs-icon_high-contrast {
|
||||
color: var(--primary-contrast);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {DOCUMENT} from '@angular/common';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
afterNextRender,
|
||||
computed,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-icon',
|
||||
standalone: true,
|
||||
templateUrl: './icon.component.html',
|
||||
styleUrl: './icon.component.scss',
|
||||
host: {
|
||||
'[class]': 'MATERIAL_SYMBOLS_OUTLINED',
|
||||
'[style.font-size.px]': 'fontSize()',
|
||||
'aria-hidden': 'true',
|
||||
'translate': 'no',
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class IconComponent {
|
||||
fontSize = computed(() => {
|
||||
return IconComponent.isFontLoaded() ? null : 0;
|
||||
});
|
||||
|
||||
protected readonly MATERIAL_SYMBOLS_OUTLINED = 'material-symbols-outlined';
|
||||
|
||||
private static isFontLoaded = signal(false);
|
||||
/** Share the same promise across different instances of the component */
|
||||
private static whenFontLoad?: Promise<FontFace[]> | undefined;
|
||||
|
||||
constructor() {
|
||||
if (IconComponent.isFontLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const document = inject(DOCUMENT);
|
||||
afterNextRender(async () => {
|
||||
IconComponent.whenFontLoad ??= document.fonts.load('normal 1px "Material Symbols Outlined"');
|
||||
await IconComponent.whenFontLoad;
|
||||
IconComponent.isFontLoaded.set(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
export * from './viewers/docs-viewer/docs-viewer.component';
|
||||
export * from './cookie-popup/cookie-popup.component';
|
||||
export * from './navigation-list/navigation-list.component';
|
||||
export * from './select/select.component';
|
||||
export * from './slide-toggle/slide-toggle.component';
|
||||
export * from './table-of-contents/table-of-contents.component';
|
||||
export * from './text-field/text-field.component';
|
||||
export * from './icon/icon.component';
|
||||
export * from './search-dialog/search-dialog.component';
|
||||
export * from './top-level-banner/top-level-banner.component';
|
||||
@@ -1,58 +0,0 @@
|
||||
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
|
||||
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "navigation-list",
|
||||
srcs = [
|
||||
"navigation-list.component.ts",
|
||||
],
|
||||
assets = [
|
||||
":navigation-list.component.css",
|
||||
"navigation-list.component.html",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs/components:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//adev/shared-docs/components/icon",
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/pipes",
|
||||
"//adev/shared-docs/services",
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
"//packages/router",
|
||||
],
|
||||
)
|
||||
|
||||
sass_binary(
|
||||
name = "style",
|
||||
src = "navigation-list.component.scss",
|
||||
deps = [
|
||||
"//adev/shared-docs/styles",
|
||||
],
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
["*.spec.ts"],
|
||||
),
|
||||
deps = [
|
||||
":navigation-list",
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/services",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
"//packages/platform-browser",
|
||||
"//packages/router",
|
||||
"//packages/router/testing",
|
||||
],
|
||||
)
|
||||
|
||||
karma_web_test_suite(
|
||||
name = "test",
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
@@ -1,76 +0,0 @@
|
||||
<ng-template #navigationList let-navigationItems>
|
||||
<ul
|
||||
class="docs-navigation-list docs-faceted-list"
|
||||
[class.docs-navigation-list-dropdown]="isDropdownView"
|
||||
>
|
||||
@for (item of navigationItems; track $index) {
|
||||
<li
|
||||
class="docs-faceted-list-item"
|
||||
[class.docs-navigation-link-hidden]="displayItemsToLevel && item.level > displayItemsToLevel"
|
||||
>
|
||||
@if (item.path) { @if (item.isExternal) {
|
||||
<a [href]="item.path" target="_blank">
|
||||
<span [class.docs-external-link]="item.isExternal">{{ item.label }}</span>
|
||||
@if (item.children && item.level! > 1 && !item.isExpanded) {
|
||||
<docs-icon>chevron_right</docs-icon>
|
||||
}
|
||||
</a>
|
||||
} @else {
|
||||
<a
|
||||
[routerLink]="'/' + item.path"
|
||||
[routerLinkActiveOptions]="{
|
||||
queryParams: 'ignored',
|
||||
fragment: 'ignored',
|
||||
matrixParams: 'exact',
|
||||
paths: 'exact',
|
||||
exact: false
|
||||
}"
|
||||
routerLinkActive="docs-faceted-list-item-active"
|
||||
(click)="emitClickOnLink()"
|
||||
>
|
||||
<span>{{ item.label }}</span>
|
||||
@if (item.children && !item.isExpanded) {
|
||||
<docs-icon>chevron_right</docs-icon>
|
||||
}
|
||||
</a>
|
||||
} } @else {
|
||||
<!-- Nav Section Header -->
|
||||
@if (item.level !== collapsableLevel && item.level !== expandableLevel) {
|
||||
<div class="docs-secondary-nav-header">
|
||||
<span>{{ item.label }}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Nav Button Expand/Collapse -->
|
||||
@if ((item.children && item.level === expandableLevel) || item.level === collapsableLevel) {
|
||||
<button
|
||||
type="button"
|
||||
(click)="toggle(item)"
|
||||
attr.aria-label="{{ item.isExpanded ? 'Collapse' : 'Expand' }} {{ item.label }}"
|
||||
[attr.aria-expanded]="item.isExpanded"
|
||||
class="docs-secondary-nav-button"
|
||||
[class.docs-faceted-list-item-active]="item | isActiveNavigationItem: activeItem()"
|
||||
[class.docs-expanded-button]="item.children && item.level == collapsableLevel"
|
||||
[class.docs-not-expanded-button]="item.children && item.level === expandableLevel"
|
||||
[class.docs-nav-item-has-icon]="
|
||||
item.children && item.level === expandableLevel && !item.isExpanded
|
||||
"
|
||||
>
|
||||
@if (item.children && item.level === collapsableLevel) {
|
||||
<docs-icon>arrow_back</docs-icon>
|
||||
}
|
||||
<span>{{ item.label }}</span>
|
||||
</button>
|
||||
} } @if (item.children?.length > 0) {
|
||||
<ng-container
|
||||
*ngTemplateOutlet="navigationList; context: {$implicit: item.children}"
|
||||
></ng-container>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</ng-template>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="navigationList; context: {$implicit: navigationItems}"
|
||||
></ng-container>
|
||||
@@ -1,148 +0,0 @@
|
||||
@use '../../styles/media-queries' as mq;
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
min-width: var(--secondary-nav-width);
|
||||
list-style: none;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 100vh;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding-block: 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--septenary-contrast);
|
||||
@include mq.for-tablet-landscape-down {
|
||||
background-color: var(--quinary-contrast);
|
||||
}
|
||||
|
||||
border-radius: 10px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background-color: var(--quinary-contrast);
|
||||
}
|
||||
|
||||
.docs-nav-secondary & {
|
||||
padding-block: 2rem;
|
||||
}
|
||||
|
||||
> .docs-faceted-list {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.docs-navigation-link-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.docs-nav-item-has-icon {
|
||||
&::after {
|
||||
// FIXME: for some reason this disappears when transformed
|
||||
content: 'chevron_right';
|
||||
font-size: 1.25rem;
|
||||
font-family: var(--icons);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.docs-secondary-nav-header {
|
||||
padding-block: 1.25rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.docs-secondary-nav-button {
|
||||
width: 15rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border: none;
|
||||
padding-block: 1.25rem;
|
||||
padding-inline-start: 0;
|
||||
color: var(--primary-contrast);
|
||||
font-size: 0.875rem;
|
||||
font-family: var(--inter-font);
|
||||
line-height: 160%;
|
||||
letter-spacing: -0.00875rem;
|
||||
transition: color 0.3s ease, background 0.3s ease;
|
||||
text-align: left; // forces left alignment of text in button
|
||||
|
||||
&.docs-secondary-nav-button-active {
|
||||
// font gradient
|
||||
background-image: var(--pink-to-purple-vertical-gradient);
|
||||
&::before {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
background: var(--pink-to-purple-vertical-gradient);
|
||||
}
|
||||
&:hover {
|
||||
&::before {
|
||||
opacity: 1;
|
||||
transform: scaleY(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.docs-expanded-button {
|
||||
justify-content: start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
a,
|
||||
.docs-not-expanded-button {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
line-height: 1.4rem;
|
||||
letter-spacing: -0.00875rem;
|
||||
padding: 0.5rem;
|
||||
padding-inline-start: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
// Add padding-bottom to last item in the list
|
||||
.docs-navigation-list {
|
||||
width: 100%;
|
||||
|
||||
li:last-of-type {
|
||||
ul:last-of-type {
|
||||
li:last-of-type {
|
||||
padding-block-end: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:first-child {
|
||||
margin-inline-start: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-external-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
gap: 0.5rem;
|
||||
&::after {
|
||||
content: 'open_in_new';
|
||||
font-family: var(--icons);
|
||||
font-size: 1.1rem;
|
||||
color: var(--quinary-contrast);
|
||||
transition: color 0.3s ease;
|
||||
margin-inline-end: 0.4rem;
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {NavigationList} from './navigation-list.component';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {NavigationItem} from '../../interfaces';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {provideExperimentalZonelessChangeDetection, signal} from '@angular/core';
|
||||
import {NavigationState} from '../../services';
|
||||
|
||||
const navigationItems: NavigationItem[] = [
|
||||
{
|
||||
label: 'Introduction',
|
||||
path: 'guide',
|
||||
level: 1,
|
||||
},
|
||||
{
|
||||
label: 'Getting Started',
|
||||
level: 1,
|
||||
children: [
|
||||
{label: 'What is Angular?', path: 'guide/what-is-angular', level: 2},
|
||||
{label: 'Setup', path: 'guide/setup', level: 2},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
describe('NavigationList', () => {
|
||||
let component: NavigationList;
|
||||
let fixture: ComponentFixture<NavigationList>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [NavigationList, RouterTestingModule],
|
||||
providers: [
|
||||
{provide: NavigationState, useClass: FakeNavigationListState},
|
||||
provideExperimentalZonelessChangeDetection(),
|
||||
],
|
||||
}).compileComponents();
|
||||
fixture = TestBed.createComponent(NavigationList);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should display provided navigation structure', () => {
|
||||
component.navigationItems = [...navigationItems];
|
||||
fixture.detectChanges();
|
||||
|
||||
const links = fixture.debugElement.queryAll(By.css('a'));
|
||||
const nonClickableItem = fixture.debugElement.queryAll(By.css('.docs-secondary-nav-header'));
|
||||
|
||||
expect(links.length).toBe(3);
|
||||
expect(nonClickableItem.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should append `docs-navigation-list-dropdown` when isDropdownView is true', () => {
|
||||
component.isDropdownView = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const ulElement = fixture.debugElement.query(By.css('ul.docs-navigation-list-dropdown'));
|
||||
|
||||
expect(ulElement).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not append `docs-navigation-list-dropdown` when isDropdownView is false', () => {
|
||||
component.isDropdownView = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
const ulElement = fixture.debugElement.query(By.css('ul.docs-navigation-list-dropdown'));
|
||||
|
||||
expect(ulElement).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should emit linkClicked when user clicked on link', () => {
|
||||
const emitClickOnLinkSpy = spyOn(component, 'emitClickOnLink');
|
||||
component.navigationItems = [...navigationItems];
|
||||
fixture.detectChanges(true);
|
||||
|
||||
const guideLink = fixture.debugElement.query(By.css('a[href="/guide"]'));
|
||||
guideLink.nativeElement.click();
|
||||
|
||||
expect(emitClickOnLinkSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it(`should not call navigationState.toggleItem() when item's level is equal to 1 and is not neither expandable or collapsable level`, () => {
|
||||
const navigationState = TestBed.inject(NavigationState);
|
||||
const toggleItemSpy = spyOn(navigationState, 'toggleItem');
|
||||
const itemToToggle = navigationItems[1];
|
||||
|
||||
component.toggle(itemToToggle);
|
||||
|
||||
expect(toggleItemSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it(`should call navigationState.toggleItem() when item's level is expandable`, () => {
|
||||
const navigationState = TestBed.inject(NavigationState);
|
||||
const toggleItemSpy = spyOn(navigationState, 'toggleItem');
|
||||
const itemToToggle = navigationItems[1];
|
||||
|
||||
component.expandableLevel = 1;
|
||||
component.toggle(itemToToggle);
|
||||
|
||||
expect(toggleItemSpy).toHaveBeenCalledOnceWith(itemToToggle);
|
||||
});
|
||||
|
||||
it(`should call navigationState.toggleItem() when item's level is collapsable`, () => {
|
||||
const navigationState = TestBed.inject(NavigationState);
|
||||
const toggleItemSpy = spyOn(navigationState, 'toggleItem');
|
||||
const itemToToggle = navigationItems[1].children![1];
|
||||
|
||||
component.collapsableLevel = 2;
|
||||
component.toggle(itemToToggle);
|
||||
|
||||
expect(toggleItemSpy).toHaveBeenCalledOnceWith(itemToToggle);
|
||||
});
|
||||
|
||||
it('should display items to provided level', () => {
|
||||
component.navigationItems = [...navigationItems];
|
||||
component.displayItemsToLevel = 1;
|
||||
fixture.detectChanges(true);
|
||||
|
||||
const visibleItems = fixture.debugElement.queryAll(
|
||||
By.css('li.docs-faceted-list-item:not(.docs-navigation-link-hidden)'),
|
||||
);
|
||||
const hiddenItems = fixture.debugElement.queryAll(
|
||||
By.css('li.docs-faceted-list-item.docs-navigation-link-hidden'),
|
||||
);
|
||||
|
||||
expect(visibleItems.length).toBe(2);
|
||||
expect(visibleItems[0].nativeElement.innerText).toBe(navigationItems[0].label);
|
||||
expect(visibleItems[1].nativeElement.innerText).toBe(navigationItems[1].label);
|
||||
expect(hiddenItems.length).toBe(2);
|
||||
expect(hiddenItems[0].nativeElement.innerText).toBe(navigationItems[1].children![0].label);
|
||||
expect(hiddenItems[1].nativeElement.innerText).toBe(navigationItems[1].children![1].label);
|
||||
});
|
||||
});
|
||||
|
||||
class FakeNavigationListState {
|
||||
isOpened = signal(true);
|
||||
activeNavigationItem = signal(navigationItems.at(1));
|
||||
toggleItem(item: NavigationItem) {}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import {NavigationItem} from '../../interfaces/index';
|
||||
import {NavigationState} from '../../services/index';
|
||||
import {RouterLink, RouterLinkActive} from '@angular/router';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {IconComponent} from '../icon/icon.component';
|
||||
import {IsActiveNavigationItem} from '../../pipes/is-active-navigation-item.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-navigation-list',
|
||||
standalone: true,
|
||||
imports: [CommonModule, RouterLink, RouterLinkActive, IconComponent, IsActiveNavigationItem],
|
||||
templateUrl: './navigation-list.component.html',
|
||||
styleUrls: ['./navigation-list.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class NavigationList {
|
||||
@Input({required: true}) navigationItems: NavigationItem[] = [];
|
||||
@Input() displayItemsToLevel: number = 2;
|
||||
@Input() collapsableLevel: number | undefined = undefined;
|
||||
@Input() expandableLevel: number = 2;
|
||||
@Input() isDropdownView = false;
|
||||
|
||||
@Output() linkClicked = new EventEmitter<void>();
|
||||
|
||||
private readonly navigationState = inject(NavigationState);
|
||||
|
||||
expandedItems = this.navigationState.expandedItems;
|
||||
activeItem = this.navigationState.activeNavigationItem;
|
||||
|
||||
toggle(item: NavigationItem): void {
|
||||
if (
|
||||
item.level === 1 &&
|
||||
item.level !== this.expandableLevel &&
|
||||
item.level !== this.collapsableLevel
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.navigationState.toggleItem(item);
|
||||
}
|
||||
|
||||
emitClickOnLink(): void {
|
||||
this.linkClicked.emit();
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
|
||||
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "search-dialog",
|
||||
srcs = [
|
||||
"search-dialog.component.ts",
|
||||
],
|
||||
assets = [
|
||||
":search-dialog.component.css",
|
||||
"search-dialog.component.html",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs/components:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//adev/shared-docs/components/algolia-icon",
|
||||
"//adev/shared-docs/components/text-field",
|
||||
"//adev/shared-docs/directives",
|
||||
"//adev/shared-docs/interfaces",
|
||||
"//adev/shared-docs/pipes",
|
||||
"//adev/shared-docs/services",
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
"//packages/forms",
|
||||
"//packages/router",
|
||||
],
|
||||
)
|
||||
|
||||
sass_binary(
|
||||
name = "style",
|
||||
src = "search-dialog.component.scss",
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
["*.spec.ts"],
|
||||
),
|
||||
deps = [
|
||||
":search-dialog",
|
||||
"//adev/shared-docs/components/algolia-icon",
|
||||
"//adev/shared-docs/providers",
|
||||
"//adev/shared-docs/services",
|
||||
"//adev/shared-docs/testing",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
"//packages/platform-browser",
|
||||
"//packages/router",
|
||||
"//packages/router/testing",
|
||||
],
|
||||
)
|
||||
|
||||
karma_web_test_suite(
|
||||
name = "test",
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
@@ -1,89 +0,0 @@
|
||||
<dialog #searchDialog>
|
||||
<div class="docs-search-container" (docsClickOutside)="closeSearchDialog()">
|
||||
<docs-text-field
|
||||
[autofocus]="true"
|
||||
[hideIcon]="true"
|
||||
[ngModel]="searchQuery()"
|
||||
(ngModelChange)="updateSearchQuery($event)"
|
||||
class="docs-search-input"
|
||||
placeholder="Search docs"
|
||||
></docs-text-field>
|
||||
|
||||
@if (searchResults() && searchResults()!.length > 0) {
|
||||
<ul class="docs-search-results docs-mini-scroll-track">
|
||||
@for (result of searchResults(); track result.objectID) {
|
||||
<li docsSearchItem [item]="result">
|
||||
<a
|
||||
[routerLink]="'/' + result.url | relativeLink: 'pathname'"
|
||||
[fragment]="result.url | relativeLink: 'hash'"
|
||||
>
|
||||
<div>
|
||||
<div class="docs-result-icon-and-type">
|
||||
<!-- Icon -->
|
||||
<span class="docs-search-result-icon" aria-hidden="true">
|
||||
<i role="presentation" class="material-symbols-outlined docs-icon-small">
|
||||
{{ result.hierarchy.lvl0 === 'Tutorials' ? 'code' : 'description'}}
|
||||
</i>
|
||||
</span>
|
||||
<!-- Results type -->
|
||||
<span class="docs-search-results__type">
|
||||
@let snippet = result._snippetResult.hierarchy?.lvl1?.value ?? '';
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="highlightSnippet"
|
||||
[ngTemplateOutletContext]="{snippet}"
|
||||
></ng-container>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@let content = result._snippetResult.content;
|
||||
@let hierarchy = result._snippetResult.hierarchy;
|
||||
@if (content || hierarchy?.lvl2 || hierarchy?.lvl3 || hierarchy?.lvl4) {
|
||||
<span class="docs-search-results__type docs-search-results__lvl2">
|
||||
@let snippet = getBestSnippetForMatch(result);
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="highlightSnippet"
|
||||
[ngTemplateOutletContext]="{snippet}"
|
||||
></ng-container>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Page title -->
|
||||
<span class="docs-result-page-title">{{ result.hierarchy?.lvl0 }}</span>
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
} @else {
|
||||
<div class="docs-search-results docs-mini-scroll-track">
|
||||
@if (searchResults() === undefined) {
|
||||
<div class="docs-search-results__start-typing">
|
||||
<span>Start typing to see results</span>
|
||||
</div>
|
||||
} @else if (searchResults()?.length === 0) {
|
||||
<div class="docs-search-results__no-results">
|
||||
<span>No results found</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="docs-algolia">
|
||||
<span>Search by</span>
|
||||
<a href="https://www.algolia.com/developers/" target="_blank" rel="noopener">
|
||||
<docs-algolia-icon />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<ng-template #highlightSnippet let-snippet="snippet">
|
||||
@let parts = splitMarkedText(snippet);
|
||||
@for (part of parts; track $index) {
|
||||
@if (part.highlight) {
|
||||
<mark>{{part.text}}</mark>
|
||||
} @else {
|
||||
<span>{{part.text}}</span>
|
||||
}
|
||||
}
|
||||
</ng-template>
|
||||
@@ -1,155 +0,0 @@
|
||||
dialog {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding-block-end: 3rem;
|
||||
|
||||
&::backdrop {
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
}
|
||||
|
||||
.docs-search-container {
|
||||
width: 750px;
|
||||
max-width: 90vw;
|
||||
background-color: var(--page-background);
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.25rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.docs-search-input {
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
border: none;
|
||||
border-block-end: 1px solid var(--senary-contrast);
|
||||
height: 2.6875rem; // 43px;
|
||||
padding-inline-start: 1rem;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: 'Esc';
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
color: var(--gray-400);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
max-height: 50vh;
|
||||
overflow-y: auto;
|
||||
list-style-type: none;
|
||||
padding-inline: 0;
|
||||
padding-block-start: 1rem;
|
||||
margin: 0;
|
||||
border-block-end: 1px solid var(--senary-contrast);
|
||||
|
||||
li {
|
||||
border-inline-start: 2px solid var(--senary-contrast);
|
||||
margin-inline-start: 1rem;
|
||||
padding-inline-end: 1rem;
|
||||
padding-block: 0.25rem;
|
||||
|
||||
mark {
|
||||
background: #e62600;
|
||||
background: var(--red-to-orange-horizontal-gradient);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--secondary-contrast);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
|
||||
.docs-search-result-icon {
|
||||
i {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: var(--septenary-contrast); // stylelint-disable-line
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
background-color: var(--octonary-contrast); // stylelint-disable-line
|
||||
border-inline-start: 2px solid var(--primary-contrast);
|
||||
a {
|
||||
span:not(.docs-result-page-title),
|
||||
.docs-search-results__type {
|
||||
color: var(--primary-contrast);
|
||||
i {
|
||||
color: var(--primary-contrast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.docs-search-result-icon,
|
||||
.docs-search-results__type,
|
||||
.docs-result-page-title {
|
||||
color: var(--quaternary-contrast);
|
||||
display: inline-block;
|
||||
font-size: 0.875rem;
|
||||
transition: color 0.3s ease;
|
||||
padding: 0.75rem;
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
|
||||
.docs-search-results__lvl2 {
|
||||
display: inline-block;
|
||||
margin-inline-start: 2rem;
|
||||
padding-block-start: 0;
|
||||
}
|
||||
|
||||
.docs-search-results__lvl3 {
|
||||
margin-inline-start: 2rem;
|
||||
padding-block-start: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-result-page-title {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-search-results__start-typing,
|
||||
.docs-search-results__no-results {
|
||||
padding: 0.75rem;
|
||||
color: var(--gray-400);
|
||||
}
|
||||
|
||||
.docs-result-icon-and-type {
|
||||
display: flex;
|
||||
|
||||
.docs-search-results__type {
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-algolia {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
color: var(--gray-400);
|
||||
padding: 1rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
gap: 0.25rem;
|
||||
background-color: var(--page-background);
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
|
||||
docs-algolia-icon {
|
||||
display: inline-flex;
|
||||
margin-block-start: 0.12rem;
|
||||
margin-inline-start: 0.15rem;
|
||||
width: 4rem;
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {SearchDialog} from './search-dialog.component';
|
||||
import {WINDOW} from '../../providers';
|
||||
import {Search} from '../../services';
|
||||
import {FakeEventTarget} from '../../testing/index';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {AlgoliaIcon} from '../algolia-icon/algolia-icon.component';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {Router} from '@angular/router';
|
||||
import {provideExperimentalZonelessChangeDetection} from '@angular/core';
|
||||
|
||||
describe('SearchDialog', () => {
|
||||
let fixture: ComponentFixture<SearchDialog>;
|
||||
|
||||
const fakeSearch = {
|
||||
searchQuery: jasmine.createSpy(),
|
||||
searchResults: jasmine.createSpy(),
|
||||
};
|
||||
const fakeWindow = new FakeEventTarget();
|
||||
|
||||
beforeEach(async () => {
|
||||
fakeSearch.searchResults.and.returnValue([]);
|
||||
fakeSearch.searchQuery.and.returnValue('');
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SearchDialog, RouterTestingModule],
|
||||
providers: [
|
||||
provideExperimentalZonelessChangeDetection(),
|
||||
{
|
||||
provide: Search,
|
||||
useValue: fakeSearch,
|
||||
},
|
||||
{
|
||||
provide: WINDOW,
|
||||
useValue: fakeWindow,
|
||||
},
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SearchDialog);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should navigate to active item when user pressed Enter', () => {
|
||||
const router = TestBed.inject(Router);
|
||||
const navigateByUrlSpy = spyOn(router, 'navigateByUrl');
|
||||
|
||||
fakeSearch.searchResults.and.returnValue(fakeSearchResults);
|
||||
fixture.detectChanges();
|
||||
|
||||
fakeWindow.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
code: 'Enter',
|
||||
key: 'Enter',
|
||||
charCode: 13,
|
||||
keyCode: 13,
|
||||
view: window,
|
||||
bubbles: true,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(navigateByUrlSpy).toHaveBeenCalledOnceWith('fakeUrl1#h1');
|
||||
});
|
||||
|
||||
it('should always display algolia logo', () => {
|
||||
const algoliaIcon = fixture.debugElement.query(By.directive(AlgoliaIcon));
|
||||
|
||||
expect(algoliaIcon).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should display `No results found` message when there are no results for provided query', () => {
|
||||
fakeSearch.searchResults.and.returnValue([]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const noResultsContainer = fixture.debugElement.query(
|
||||
By.css('.docs-search-results__no-results'),
|
||||
);
|
||||
|
||||
expect(noResultsContainer).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should display `Start typing to see results` message when there are no provided query', () => {
|
||||
fakeSearch.searchResults.and.returnValue(undefined);
|
||||
fixture.detectChanges();
|
||||
|
||||
const startTypingContainer = fixture.debugElement.query(
|
||||
By.css('.docs-search-results__start-typing'),
|
||||
);
|
||||
|
||||
expect(startTypingContainer).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should display list of the search results when results exist', () => {
|
||||
fakeSearch.searchResults.and.returnValue(fakeSearchResults);
|
||||
fixture.detectChanges();
|
||||
|
||||
const resultListContainer = fixture.debugElement.query(By.css('ul.docs-search-results'));
|
||||
const resultItems = fixture.debugElement.queryAll(By.css('ul.docs-search-results li a'));
|
||||
|
||||
expect(resultListContainer).toBeTruthy();
|
||||
expect(resultItems.length).toBe(2);
|
||||
expect(resultItems[0].nativeElement.href).toBe(`${window.origin}/fakeUrl1#h1`);
|
||||
expect(resultItems[1].nativeElement.href).toBe(`${window.origin}/fakeUrl2#h1`);
|
||||
});
|
||||
|
||||
it('should close search dialog when user clicked outside `.docs-search-container`', () => {
|
||||
const dialogContainer = fixture.debugElement.query(By.css('dialog'));
|
||||
const closeSearchDialogSpy = spyOn(fixture.componentInstance, 'closeSearchDialog');
|
||||
|
||||
dialogContainer.nativeElement.click();
|
||||
|
||||
expect(closeSearchDialogSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
const fakeSearchResults = [
|
||||
{
|
||||
'url': 'https://angular.dev/fakeUrl1#h1',
|
||||
'hierarchy': {
|
||||
'lvl0': 'FakeLvl0',
|
||||
'lvl1': 'FakeLvl1',
|
||||
'lvl2': 'FakeLvl2',
|
||||
'lvl3': null,
|
||||
'lvl4': null,
|
||||
'lvl5': null,
|
||||
'lvl6': null,
|
||||
},
|
||||
'objectID': 'fakeObjectId1',
|
||||
},
|
||||
{
|
||||
'url': 'https://angular.dev/fakeUrl2#h1',
|
||||
'hierarchy': {
|
||||
'lvl0': 'FakeLvl0',
|
||||
'lvl1': 'FakeLvl1',
|
||||
'lvl2': 'FakeLvl2',
|
||||
'lvl3': null,
|
||||
'lvl4': null,
|
||||
'lvl5': null,
|
||||
'lvl6': null,
|
||||
},
|
||||
'objectID': 'fakeObjectId2',
|
||||
},
|
||||
];
|
||||
@@ -1,173 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
Injector,
|
||||
OnDestroy,
|
||||
Signal,
|
||||
afterNextRender,
|
||||
effect,
|
||||
inject,
|
||||
output,
|
||||
viewChild,
|
||||
viewChildren,
|
||||
} from '@angular/core';
|
||||
import {NgTemplateOutlet} from '@angular/common';
|
||||
|
||||
import {WINDOW} from '../../providers/index';
|
||||
import {ClickOutside} from '../../directives/index';
|
||||
import {Search} from '../../services/index';
|
||||
|
||||
import {TextField} from '../text-field/text-field.component';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
|
||||
import {SearchItem} from '../../directives/search-item/search-item.directive';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {Router, RouterLink} from '@angular/router';
|
||||
import {filter, fromEvent} from 'rxjs';
|
||||
import {AlgoliaIcon} from '../algolia-icon/algolia-icon.component';
|
||||
import {RelativeLink} from '../../pipes/relative-link.pipe';
|
||||
import {SearchResult, SnippetResult} from '../../interfaces';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-search-dialog',
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
ClickOutside,
|
||||
TextField,
|
||||
FormsModule,
|
||||
SearchItem,
|
||||
AlgoliaIcon,
|
||||
RelativeLink,
|
||||
RouterLink,
|
||||
NgTemplateOutlet,
|
||||
],
|
||||
templateUrl: './search-dialog.component.html',
|
||||
styleUrls: ['./search-dialog.component.scss'],
|
||||
})
|
||||
export class SearchDialog implements OnDestroy {
|
||||
onClose = output();
|
||||
dialog = viewChild.required<ElementRef<HTMLDialogElement>>('searchDialog');
|
||||
items = viewChildren(SearchItem);
|
||||
|
||||
private readonly search = inject(Search);
|
||||
private readonly relativeLink = new RelativeLink();
|
||||
private readonly router = inject(Router);
|
||||
private readonly window = inject(WINDOW);
|
||||
private readonly injector = inject(Injector);
|
||||
private readonly keyManager = new ActiveDescendantKeyManager(
|
||||
this.items,
|
||||
this.injector,
|
||||
).withWrap();
|
||||
|
||||
searchQuery = this.search.searchQuery;
|
||||
searchResults = this.search.searchResults;
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
this.items();
|
||||
afterNextRender(
|
||||
{
|
||||
write: () => this.keyManager.setFirstItemActive(),
|
||||
},
|
||||
{injector: this.injector},
|
||||
);
|
||||
});
|
||||
|
||||
this.keyManager.change.pipe(takeUntilDestroyed()).subscribe(() => {
|
||||
this.keyManager.activeItem?.scrollIntoView();
|
||||
});
|
||||
|
||||
afterNextRender({
|
||||
write: () => {
|
||||
if (!this.dialog().nativeElement.open) {
|
||||
this.dialog().nativeElement.showModal?.();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
fromEvent<KeyboardEvent>(this.window, 'keydown')
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe((event) => {
|
||||
// When user presses Enter we can navigate to currently selected item in the search result list.
|
||||
if (event.key === 'Enter') {
|
||||
this.navigateToTheActiveItem();
|
||||
} else {
|
||||
this.keyManager.onKeydown(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
splitMarkedText(snippet: string): Array<{highlight: boolean; text: string}> {
|
||||
const parts: Array<{highlight: boolean; text: string}> = [];
|
||||
while (snippet.indexOf('<ɵ>') !== -1) {
|
||||
const beforeMatch = snippet.substring(0, snippet.indexOf('<ɵ>'));
|
||||
const match = snippet.substring(snippet.indexOf('<ɵ>') + 3, snippet.indexOf('</ɵ>'));
|
||||
parts.push({highlight: false, text: beforeMatch});
|
||||
parts.push({highlight: true, text: match});
|
||||
snippet = snippet.substring(snippet.indexOf('</ɵ>') + 4);
|
||||
}
|
||||
parts.push({highlight: false, text: snippet});
|
||||
return parts;
|
||||
}
|
||||
|
||||
getBestSnippetForMatch(result: SearchResult): string {
|
||||
// if there is content, return it
|
||||
if (result._snippetResult.content !== undefined) {
|
||||
return result._snippetResult.content.value;
|
||||
}
|
||||
|
||||
const hierarchy = result._snippetResult.hierarchy;
|
||||
if (hierarchy === undefined) {
|
||||
return '';
|
||||
}
|
||||
function matched(snippet: SnippetResult | undefined) {
|
||||
return snippet?.matchLevel !== undefined && snippet.matchLevel !== 'none';
|
||||
}
|
||||
// return the most specific subheader match
|
||||
if (matched(hierarchy.lvl4)) {
|
||||
return hierarchy.lvl4!.value;
|
||||
}
|
||||
if (matched(hierarchy.lvl3)) {
|
||||
return hierarchy.lvl3!.value;
|
||||
}
|
||||
if (matched(hierarchy.lvl2)) {
|
||||
return hierarchy.lvl2!.value;
|
||||
}
|
||||
// if no subheader matched the query, fall back to just returning the most specific one
|
||||
return hierarchy.lvl3?.value ?? hierarchy.lvl2?.value ?? '';
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.keyManager.destroy();
|
||||
}
|
||||
|
||||
closeSearchDialog() {
|
||||
this.dialog().nativeElement.close();
|
||||
this.onClose.emit();
|
||||
}
|
||||
|
||||
updateSearchQuery(query: string) {
|
||||
this.search.updateSearchQuery(query);
|
||||
}
|
||||
|
||||
private navigateToTheActiveItem(): void {
|
||||
const activeItemLink: string | undefined = this.keyManager.activeItem?.item?.url;
|
||||
|
||||
if (!activeItemLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.router.navigateByUrl(this.relativeLink.transform(activeItemLink));
|
||||
this.onClose.emit();
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
load("//tools:defaults.bzl", "karma_web_test_suite", "ng_module", "ts_library")
|
||||
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
|
||||
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
ng_module(
|
||||
name = "select",
|
||||
srcs = [
|
||||
"select.component.ts",
|
||||
],
|
||||
assets = [
|
||||
":select.component.css",
|
||||
"select.component.html",
|
||||
],
|
||||
visibility = [
|
||||
"//adev/shared-docs/components:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//packages/common",
|
||||
"//packages/core",
|
||||
"//packages/forms",
|
||||
],
|
||||
)
|
||||
|
||||
sass_binary(
|
||||
name = "style",
|
||||
src = "select.component.scss",
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
["*.spec.ts"],
|
||||
),
|
||||
deps = [
|
||||
":select",
|
||||
"//packages/core",
|
||||
"//packages/core/testing",
|
||||
],
|
||||
)
|
||||
|
||||
karma_web_test_suite(
|
||||
name = "test",
|
||||
deps = [":test_lib"],
|
||||
)
|
||||
@@ -1,5 +0,0 @@
|
||||
<select [attr.id]="id" [attr.name]="name" [ngModel]="selectedOption()" (ngModelChange)="setOption($event)">
|
||||
@for (item of options; track item) {
|
||||
<option [value]="item.value">{{ item.label }}</option>
|
||||
}
|
||||
</select>
|
||||
@@ -1,31 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {Select} from './select.component';
|
||||
import {provideExperimentalZonelessChangeDetection} from '@angular/core';
|
||||
|
||||
describe('Select', () => {
|
||||
let component: Select;
|
||||
let fixture: ComponentFixture<Select>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [Select],
|
||||
providers: [provideExperimentalZonelessChangeDetection()],
|
||||
});
|
||||
fixture = TestBed.createComponent(Select);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,79 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR, FormsModule} from '@angular/forms';
|
||||
import {ChangeDetectionStrategy, Component, Input, forwardRef, signal} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
type SelectOptionValue = string | number | boolean;
|
||||
|
||||
export interface SelectOption {
|
||||
label: string;
|
||||
value: SelectOptionValue;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'docs-select',
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, FormsModule],
|
||||
templateUrl: './select.component.html',
|
||||
styleUrls: ['./select.component.scss'],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => Select),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
host: {
|
||||
class: 'docs-form-element',
|
||||
},
|
||||
})
|
||||
export class Select implements ControlValueAccessor {
|
||||
@Input({required: true, alias: 'selectId'}) id!: string;
|
||||
@Input({required: true}) name!: string;
|
||||
@Input({required: true}) options!: SelectOption[];
|
||||
@Input() disabled = false;
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
private onChange: (value: SelectOptionValue) => void = (_: SelectOptionValue) => {};
|
||||
private onTouched: () => void = () => {};
|
||||
|
||||
protected readonly selectedOption = signal<SelectOptionValue | null>(null);
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
writeValue(value: SelectOptionValue): void {
|
||||
this.selectedOption.set(value);
|
||||
}
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
registerOnChange(fn: any): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
registerOnTouched(fn: any): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
// Implemented as part of ControlValueAccessor.
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled;
|
||||
}
|
||||
|
||||
setOption($event: SelectOptionValue): void {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedOption.set($event);
|
||||
this.onChange($event);
|
||||
this.onTouched();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user