mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 95efcdd019 |
+9
-7
@@ -5,10 +5,12 @@
|
||||
.git
|
||||
node_modules
|
||||
dist
|
||||
aio/node_modules
|
||||
aio/tools/examples/shared/node_modules
|
||||
aio/tools/examples/shared/example-scaffold
|
||||
|
||||
# All integration test node_modules folders
|
||||
integration/animations/node_modules
|
||||
integration/animations-async/node_modules
|
||||
integration/cli-elements-universal/node_modules
|
||||
integration/cli-hello-world/node_modules
|
||||
integration/cli-hello-world-ivy-i18n/node_modules
|
||||
@@ -20,20 +22,20 @@ integration/dynamic-compiler/node_modules
|
||||
integration/forms/node_modules
|
||||
integration/injectable-def/node_modules
|
||||
integration/ivy-i18n/node_modules
|
||||
integration/ng-add-localize/node_modules
|
||||
integration/ng_elements/node_modules
|
||||
integration/ng_update/node_modules
|
||||
integration/ng_update_migrations/node_modules
|
||||
integration/ng-add-localize/node_modules
|
||||
integration/nodenext_resolution/node_modules
|
||||
integration/npm_package_archives.bzl/node_modules
|
||||
integration/platform-server/node_modules
|
||||
integration/platform-server-hydration/node_modules
|
||||
integration/service-worker-schema/node_modules
|
||||
integration/side-effects/node_modules
|
||||
integration/standalone-bootstrap/node_modules
|
||||
integration/terser/node_modules
|
||||
integration/trusted-types/node_modules
|
||||
integration/typings_test_rxjs7/node_modules
|
||||
integration/typings_test_ts55/node_modules
|
||||
integration/typings_test_ts56/node_modules
|
||||
integration/typings_test_ts57/node_modules
|
||||
modules/ssr-benchmarks/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 #
|
||||
@@ -78,6 +93,12 @@ query --output=label_kind
|
||||
# By default, failing tests don't print any output, it goes to the log file
|
||||
test --test_output=errors
|
||||
|
||||
################################
|
||||
# Settings for CircleCI #
|
||||
################################
|
||||
|
||||
# Bazel flags for CircleCI are in /.circleci/bazel.linux.rc and /.circleci/bazel.windows.rc
|
||||
|
||||
##################################
|
||||
# Remote Build Execution support #
|
||||
# Turn on these settings with #
|
||||
@@ -97,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
|
||||
@@ -152,8 +177,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
|
||||
# --full_build_adev will run adev build/serve in a full mode, performing prerendering and DCE.
|
||||
build --flag_alias=full_build_adev=//adev:full_build_adev
|
||||
|
||||
####################################################
|
||||
# User bazel configuration
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Encryption
|
||||
|
||||
Based on https://github.com/circleci/encrypted-files
|
||||
|
||||
In the CircleCI web UI, we have a secret variable called `KEY`
|
||||
https://circleci.com/gh/angular/angular/edit#env-vars
|
||||
which is only exposed to non-fork builds
|
||||
(see "Pass secrets to builds from forked pull requests" under
|
||||
https://circleci.com/gh/angular/angular/edit#advanced-settings)
|
||||
|
||||
We use this as a symmetric AES encryption key to encrypt tokens like
|
||||
a GitHub token that enables publishing snapshots.
|
||||
|
||||
To create the github_token file, we take this approach:
|
||||
- Find the angular-builds:token in the internal pw database
|
||||
- Go inside the CircleCI default docker image so you use the same version of openssl as we will at runtime: `docker run --rm -it circleci/node:10.12`
|
||||
- echo "https://[token]:@github.com" > credentials
|
||||
- openssl aes-256-cbc -e -in credentials -out .circleci/github_token -k $KEY
|
||||
- If needed, base64-encode the result so you can copy-paste it out of docker: `base64 github_token`
|
||||
@@ -0,0 +1,16 @@
|
||||
# Settings in this file should be OS agnostic. Use the bazel.<OS>.rc files for OS specific settings.
|
||||
|
||||
# Print all the options that apply to the build.
|
||||
# This helps us diagnose which options override others
|
||||
# (e.g. /etc/bazel.bazelrc vs. tools/bazel.rc)
|
||||
build --announce_rc
|
||||
|
||||
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
|
||||
# By default this is set in the project `.bazelrc` to `1`.
|
||||
test --flaky_test_attempts=3
|
||||
|
||||
# More details on failures
|
||||
build --verbose_failures=true
|
||||
|
||||
# CI supports colors but Bazel does not detect it.
|
||||
common --color=yes
|
||||
@@ -0,0 +1,23 @@
|
||||
# These options are enabled when running on CI
|
||||
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
|
||||
# See documentation in /docs/BAZEL.md
|
||||
|
||||
# Import config items common to both Linux and Windows setups.
|
||||
# https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics
|
||||
try-import %workspace%/.circleci/bazel.common.rc
|
||||
|
||||
# Save downloaded repositories in a location that can be cached by CircleCI. This helps us
|
||||
# speeding up the analysis time significantly with Bazel managed node dependencies on the CI.
|
||||
build --repository_cache=/home/circleci/bazel_repository_cache
|
||||
|
||||
# Workaround https://github.com/bazelbuild/bazel/issues/3645
|
||||
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
||||
# Limit Bazel to consuming resources that fit in CircleCI "2xlarge+" class
|
||||
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
|
||||
build --local_cpu_resources=20
|
||||
build --local_ram_resources=40960
|
||||
|
||||
# All build executed remotely should be done using our RBE configuration.
|
||||
build:remote --google_default_credentials
|
||||
|
||||
build --config=remote
|
||||
@@ -0,0 +1,17 @@
|
||||
# These options are enabled when running on CI
|
||||
# We do this by copying this file to $env:ProgramData\bazel.bazelrc at the start of the build.
|
||||
# See documentation in /docs/BAZEL.md
|
||||
|
||||
# Import config items common to both Linux and Windows setups.
|
||||
# https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics
|
||||
try-import %workspace%/.circleci/bazel.common.rc
|
||||
|
||||
# Manually set the local resources used in windows CI runs
|
||||
build --local_ram_resources=120000
|
||||
build --local_cpu_resources=32
|
||||
|
||||
# All windows jobs run on master and should use http caching
|
||||
build --remote_http_cache=https://storage.googleapis.com/angular-team-cache
|
||||
build --remote_accept_cached=true
|
||||
build --remote_upload_local_results=true
|
||||
build --google_default_credentials
|
||||
@@ -0,0 +1,16 @@
|
||||
# This config is remaining in place to prevent pull requests failing because of CircleCI config missing.
|
||||
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
pass:
|
||||
docker:
|
||||
- image: cimg/base:2022.05
|
||||
steps:
|
||||
- run: echo "This too shall pass (always)"
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
default_workflow:
|
||||
jobs:
|
||||
- pass
|
||||
@@ -0,0 +1,76 @@
|
||||
####################################################################################################
|
||||
# Helpers for defining environment variables for CircleCI.
|
||||
#
|
||||
# In CircleCI, each step runs in a new shell. The way to share ENV variables across steps is to
|
||||
# export them from `$BASH_ENV`, which is automatically sourced at the beginning of every step (for
|
||||
# the default `bash` shell).
|
||||
#
|
||||
# See also https://circleci.com/docs/2.0/env-vars/#using-bash_env-to-set-environment-variables.
|
||||
####################################################################################################
|
||||
|
||||
# Set and print an environment variable.
|
||||
#
|
||||
# Use this function for setting environment variables that are public, i.e. it is OK for them to be
|
||||
# visible to anyone through the CI logs.
|
||||
#
|
||||
# Usage: `setPublicVar <name> <value>`
|
||||
function setPublicVar() {
|
||||
setSecretVar $1 "$2";
|
||||
echo "$1=$2";
|
||||
}
|
||||
|
||||
# Set (without printing) an environment variable.
|
||||
#
|
||||
# Use this function for setting environment variables that are secret, i.e. should not be visible to
|
||||
# everyone through the CI logs.
|
||||
#
|
||||
# Usage: `setSecretVar <name> <value>`
|
||||
function setSecretVar() {
|
||||
# WARNING: Secrets (e.g. passwords, access tokens) should NOT be printed.
|
||||
# (Keep original shell options to restore at the end.)
|
||||
local -r originalShellOptions=$(set +o);
|
||||
set +x -eu -o pipefail;
|
||||
|
||||
local assignmentStatement="export $1=\"${2:-}\";"
|
||||
|
||||
echo "${assignmentStatement}" >> $BASH_ENV;
|
||||
eval "${assignmentStatement}"
|
||||
|
||||
# Restore original shell options.
|
||||
eval "$originalShellOptions";
|
||||
}
|
||||
|
||||
|
||||
# Create a function to set an environment variable, when called.
|
||||
#
|
||||
# Use this function for creating setter for public environment variables that require expensive or
|
||||
# time-consuming computaions and may not be needed. When needed, you can call this function to set
|
||||
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
|
||||
#
|
||||
# Arguments:
|
||||
# - `<name>`: The name of the environment variable. The generated setter function will be
|
||||
# `setPublicVar_<name>`.
|
||||
# - `<code>`: The code to run to compute the value for the variable. Since this code should be
|
||||
# executed lazily, it must be properly escaped. For example:
|
||||
# ```sh
|
||||
# # DO NOT do this:
|
||||
# createPublicVarSetter MY_VAR "$(whoami)"; # `whoami` will be evaluated eagerly
|
||||
#
|
||||
# # DO this isntead:
|
||||
# createPublicVarSetter MY_VAR "\$(whoami)"; # `whoami` will NOT be evaluated eagerly
|
||||
# ```
|
||||
#
|
||||
# Usage: `createPublicVarSetter <name> <code>`
|
||||
#
|
||||
# Example:
|
||||
# ```sh
|
||||
# createPublicVarSetter MY_VAR 'echo "FOO"';
|
||||
# echo $MY_VAR; # Not defined
|
||||
#
|
||||
# setPublicVar_MY_VAR;
|
||||
# source $BASH_ENV;
|
||||
# echo $MY_VAR; # FOO
|
||||
# ```
|
||||
function createPublicVarSetter() {
|
||||
echo "setPublicVar_$1() { setPublicVar $1 \"$2\"; }" >> $BASH_ENV;
|
||||
}
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
####################################################################################################
|
||||
# Set bazel configuration for CircleCI runs.
|
||||
####################################################################################################
|
||||
cp "${PROJECT_ROOT}/.circleci/bazel.linux.rc" ".bazelrc.user";
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Variables
|
||||
readonly projectDir=$(realpath "$(dirname ${BASH_SOURCE[0]})/..")
|
||||
readonly envHelpersPath="$projectDir/.circleci/env-helpers.inc.sh";
|
||||
|
||||
# Load helpers and make them available everywhere (through `$BASH_ENV`).
|
||||
source $envHelpersPath;
|
||||
echo "source $envHelpersPath;" >> $BASH_ENV;
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define PUBLIC environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
# See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info.
|
||||
####################################################################################################
|
||||
setPublicVar CI "$CI"
|
||||
setPublicVar PROJECT_ROOT "$projectDir";
|
||||
setPublicVar CI_AIO_MIN_PWA_SCORE "95";
|
||||
# This is the branch being built; e.g. `pull/12345` for PR builds.
|
||||
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
|
||||
setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL";
|
||||
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
|
||||
# `CI_COMMIT_RANGE` is only used on push builds (a.k.a. non-PR, non-scheduled builds and rerun
|
||||
# workflows of such builds).
|
||||
setPublicVar CI_GIT_BASE_REVISION "${CIRCLE_GIT_BASE_REVISION}";
|
||||
setPublicVar CI_GIT_REVISION "${CIRCLE_GIT_REVISION}";
|
||||
setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION";
|
||||
setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}";
|
||||
setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
|
||||
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
|
||||
setPublicVar CI_PR_REPONAME "$CIRCLE_PR_REPONAME";
|
||||
setPublicVar CI_PR_USERNAME "$CIRCLE_PR_USERNAME";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define "lazy" PUBLIC environment variables for CircleCI.
|
||||
# (I.e. functions to set an environment variable when called.)
|
||||
####################################################################################################
|
||||
createPublicVarSetter CI_STABLE_BRANCH "\$(npm info @angular/core dist-tags.latest | sed -r 's/^\\s*([0-9]+\\.[0-9]+)\\.[0-9]+.*$/\\1.x/')";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define SECRET environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN";
|
||||
setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define SauceLabs environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
setPublicVar SAUCE_USERNAME "angular-framework";
|
||||
setSecretVar SAUCE_ACCESS_KEY "f4bf7c639c5a-c6bb-d6a4-a4b5-800aa111";
|
||||
# TODO(josephperrott): Remove environment variables once all saucelabs tests are via bazel method.
|
||||
setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log
|
||||
setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock
|
||||
setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock
|
||||
setPublicVar SAUCE_TUNNEL_IDENTIFIER "angular-framework-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX}"
|
||||
# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not
|
||||
# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout.
|
||||
setPublicVar SAUCE_READY_FILE_TIMEOUT 120
|
||||
|
||||
####################################################################################################
|
||||
# Create shell script in /tmp for Bazel actions to access CI envs without
|
||||
# busting the cache. Used by payload-size.sh script in integration tests.
|
||||
####################################################################################################
|
||||
readonly bazelVarEnv="/tmp/bazel-ci-env.sh"
|
||||
echo "# Setup by /.circle/env.sh" > $bazelVarEnv
|
||||
echo "export PROJECT_ROOT=\"${PROJECT_ROOT}\";" >> $bazelVarEnv
|
||||
echo "export CI_BRANCH=\"${CI_BRANCH}\";" >> $bazelVarEnv
|
||||
echo "export CI_BUILD_URL=\"${CI_BUILD_URL}\";" >> $bazelVarEnv
|
||||
echo "export CI_COMMIT=\"${CI_COMMIT}\";" >> $bazelVarEnv
|
||||
echo "export CI_PULL_REQUEST=\"${CI_PULL_REQUEST}\";" >> $bazelVarEnv
|
||||
echo "export CI_REPO_NAME=\"${CI_REPO_NAME}\";" >> $bazelVarEnv
|
||||
echo "export CI_REPO_OWNER=\"${CI_REPO_OWNER}\";" >> $bazelVarEnv
|
||||
echo "export CI_SECRET_PAYLOAD_FIREBASE_TOKEN=\"${CI_SECRET_PAYLOAD_FIREBASE_TOKEN}\";" >> $bazelVarEnv
|
||||
|
||||
####################################################################################################
|
||||
# Platform-specific environment setup (which can leverage the base variables from here)
|
||||
####################################################################################################
|
||||
|
||||
# Conditionally, load additional environment settings based on the current VM
|
||||
# operating system running. We detect Windows by checking for `%AppData%`.
|
||||
if [[ -n "${APPDATA}" ]]; then
|
||||
source ${projectDir}/.circleci/env.windows.sh
|
||||
else
|
||||
source ${projectDir}/.circleci/env.linux.sh
|
||||
fi
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
####################################################################################################
|
||||
# Set bazel configuration for CircleCI runs.
|
||||
####################################################################################################
|
||||
cp "${PROJECT_ROOT}/.circleci/bazel.windows.rc" ".bazelrc.user";
|
||||
|
||||
# Override the `PATH` environment variable so that the windows-nvm NodeJS version
|
||||
# always has precedence over potential existing NodeJS versions from the image.
|
||||
setPublicVar PATH "/c/Program Files/nodejs/:$PATH"
|
||||
|
||||
# Expose the Bazelisk version. We need to run Bazelisk globally since Windows has problems launching
|
||||
# Bazel from a node modules directoy that might be modified by the Bazel Yarn install then.
|
||||
setPublicVar BAZELISK_VERSION \
|
||||
"$(cd ${PROJECT_ROOT}; node -p 'require("./package.json").devDependencies["@bazel/bazelisk"]')"
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
# Install bazel remote cache proxy
|
||||
# This is temporary until the feature is no longer experimental on CircleCI.
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
|
||||
set -u -e
|
||||
|
||||
readonly DOWNLOAD_URL="https://5-116431813-gh.circle-artifacts.com/0/pkg/bazel-remote-proxy-$(uname -s)_$(uname -m)"
|
||||
|
||||
curl --fail -o ~/bazel-remote-proxy "$DOWNLOAD_URL"
|
||||
chmod +x ~/bazel-remote-proxy
|
||||
@@ -1,5 +1,6 @@
|
||||
# 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
|
||||
|
||||
|
||||
@@ -11,7 +12,7 @@ LABEL name="Angular dev environment" \
|
||||
EXPOSE 4000 4200 4433 5000 8080 9876
|
||||
|
||||
|
||||
# Switch to `root`.
|
||||
# Switch to `root` (CircleCI images use `circleci` as the user).
|
||||
USER root
|
||||
|
||||
|
||||
|
||||
@@ -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,5 +1,5 @@
|
||||
name: 'Docs or angular.dev Bug Report'
|
||||
description: Report an issue in Angular's documentation or angular.dev application
|
||||
name: 'Docs or angular.io Bug Report'
|
||||
description: Report an issue in Angular's documentation or angular.io application
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Security issue disclosure
|
||||
url: https://angular.dev/best-practices/security#report-issues
|
||||
url: https://angular.io/guide/security#report-issues
|
||||
about: Report a security issue in Angular Framework, CDK, Material, or CLI
|
||||
- name: Angular CLI
|
||||
url: https://github.com/angular/angular-cli/issues/new/choose
|
||||
|
||||
@@ -18,7 +18,7 @@ What kind of change does this PR introduce?
|
||||
- [ ] Build related changes
|
||||
- [ ] CI related changes
|
||||
- [ ] Documentation content changes
|
||||
- [ ] angular.dev application / infrastructure changes
|
||||
- [ ] angular.io application / infrastructure changes
|
||||
- [ ] Other... Please describe:
|
||||
|
||||
|
||||
|
||||
@@ -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@13.15.1 ${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": []
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
name: 'Saucelabs legacy test job'
|
||||
description: 'Runs tests against Saucelabs (outside of Bazel)'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Starting Saucelabs tunnel service
|
||||
shell: bash
|
||||
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
|
||||
shell: bash
|
||||
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
|
||||
shell: bash
|
||||
run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
|
||||
- name: Wait and confirm Saucelabs tunnel has connected
|
||||
shell: bash
|
||||
run: ./tools/saucelabs/sauce-service.sh ready-wait
|
||||
- name: Running tests on Saucelabs.
|
||||
shell: bash
|
||||
run: KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
|
||||
- name: Stop Saucelabs tunnel service
|
||||
shell: bash
|
||||
run: ./tools/saucelabs/sauce-service.sh stop
|
||||
@@ -4,7 +4,7 @@ description: 'Installs the dependencies using Yarn'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
path: |
|
||||
./node_modules/
|
||||
|
||||
@@ -21,16 +21,16 @@ jobs:
|
||||
(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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --full_build_adev --config=release
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
run: yarn bazel build --config=aio_local_deps //adev:build
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
pull-number: '${{github.event.pull_request.number}}'
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3
|
||||
with:
|
||||
token: '${{secrets.GITHUB_TOKEN}}'
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
github-token: '${{secrets.GITHUB_TOKEN}}'
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
|
||||
@@ -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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: ./.github/actions/yarn-install
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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/previews/pack-and-upload-artifact@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
|
||||
- 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/previews/upload-artifacts-to-firebase@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # 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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3
|
||||
with:
|
||||
issue-number: ${{github.event.issue.number}}
|
||||
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
saucelabs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
env:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }}
|
||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
# Checking out the pull request commit is intended here as we need to run the changed code tests.
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- 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
|
||||
+147
-51
@@ -1,10 +1,12 @@
|
||||
name: CI (push)
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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,18 +45,28 @@ jobs:
|
||||
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
|
||||
# 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 }}
|
||||
|
||||
devtools:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -59,47 +78,132 @@ jobs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
run: yarn test:ci
|
||||
|
||||
aio:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules for aio
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Run AIO tests with upstream packages
|
||||
run: yarn --cwd aio test:ci
|
||||
- name: Check generated bundle sizes
|
||||
run: yarn --cwd aio payload-size
|
||||
|
||||
adev:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- 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/...
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: yarn bazel test --config=aio_local_deps //adev:test
|
||||
|
||||
publish-snapshots:
|
||||
aio-local:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Run AIO tests with local packages
|
||||
run: yarn --cwd aio test-local:ci
|
||||
- name: Check generated bundle sizes
|
||||
run: yarn --cwd aio payload-size aio-local
|
||||
|
||||
aio-deploy:
|
||||
needs: [aio]
|
||||
if: needs.aio.result == 'success' && github.event_name == 'push'
|
||||
runs-on:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules for aio
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Set the stable branch environment variable
|
||||
id: latest_version
|
||||
run: |
|
||||
echo "CI_STABLE_BRANCH=$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')" >> $GITHUB_OUTPUT
|
||||
echo "CI_BRANCH=$(echo ${{ github.event.ref }} | cut -d '/' -f 3)" >> $GITHUB_OUTPUT
|
||||
- name: Deploy aio to production
|
||||
env:
|
||||
CI_AIO_MIN_PWA_SCORE: '95'
|
||||
CI_COMMIT: ${{ github.event.after }}
|
||||
CI_REPO_NAME: 'angular'
|
||||
CI_PULL_REQUEST: 'false'
|
||||
CI_REPO_OWNER: 'angular'
|
||||
CI_BUILD_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
CI_STABLE_BRANCH: ${{ steps.latest_version.outputs.CI_STABLE_BRANCH }}
|
||||
CI_BRANCH: ${{ steps.latest_version.outputs.CI_BRANCH }}
|
||||
CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN: ${{ secrets.AIO_DEPLOY_TOKEN }}
|
||||
CI_SECRET_PAYLOAD_FIREBASE_TOKEN: ${{ secrets.AIO_PAYLOAD_TOKEN }}
|
||||
run: yarn --cwd aio deploy-production
|
||||
- name: Notify about failed deployment
|
||||
if: ${{ failure() }}
|
||||
uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v=v1.24.0
|
||||
with:
|
||||
channel-id: 'C07DT5M6V,CKV1F72BG'
|
||||
slack-message: 'Deploy to aio job failed for ${{ github.base_ref }} branch failed on build ${{ github.event.after }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.ANGULAR_ROBOT_SLACK_TOKEN }}
|
||||
|
||||
publish-snapshots:
|
||||
if: github.event_name == 'push'
|
||||
runs-on:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
|
||||
@@ -111,7 +215,7 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
@@ -119,9 +223,9 @@ jobs:
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
@@ -131,11 +235,9 @@ jobs:
|
||||
//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/
|
||||
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/
|
||||
@@ -152,38 +254,32 @@ jobs:
|
||||
- run: yarn --cwd packages/zone.js/test/typings install --frozen-lockfile --non-interactive
|
||||
- run: yarn --cwd packages/zone.js/test/typings test
|
||||
|
||||
saucelabs:
|
||||
bazel-saucelabs:
|
||||
# TODO: Replace legacy job with Bazel saucelabs job.
|
||||
if: github.event_name == 'push'
|
||||
runs-on: ubuntu-latest-4core
|
||||
env:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
JOBS: 2
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
# Checking out the pull request commit is intended here as we need to run the changed code tests.
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- uses: ./.github/actions/saucelabs-legacy
|
||||
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: yarn bazel build //adev:build --full_build_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'
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- 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 }}
|
||||
SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }}
|
||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
- 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}
|
||||
|
||||
@@ -12,14 +12,14 @@ jobs:
|
||||
labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
post_approval_changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
@@ -13,8 +13,8 @@ jobs:
|
||||
statuses: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
run-tests-guide-url: http://go/angular-g3sync-start
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Manual jobs
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
|
||||
jobs:
|
||||
# Bazel saucelabs job resides in `manual.yml` because it's currently unstable, but
|
||||
# kept as "runnable" for debugging/stabilization effort purposes.
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- 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}
|
||||
@@ -9,6 +9,6 @@ jobs:
|
||||
status:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
name: Monitoring
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run at 10:00AM every day.
|
||||
- cron: '0 10 * * *'
|
||||
|
||||
permissions: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check_aio:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
MINIMUM_PWA_SCORE: 95
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: ['https://next.angular.io/', 'https://angular.io/']
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
- name: Install node modules in aio
|
||||
run: yarn install --frozen-lockfile --cwd aio
|
||||
- name: Run basic e2e and deployment config tests.
|
||||
run: yarn --cwd aio test-production-url --test_env=TARGET_URL="${{ matrix.version }}"
|
||||
- name: Run PWA-score tests.
|
||||
run: yarn --cwd aio test-pwa-score "${{ matrix.version }}" "${{ env.MINIMUM_PWA_SCORE }}"
|
||||
- name: Run a11y tests.
|
||||
run: yarn --cwd aio test-a11y-score "${{ matrix.version }}"
|
||||
|
||||
check_contributor_links:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Install node modules in aio
|
||||
run: yarn install --frozen-lockfile --cwd aio
|
||||
- name: Check website provided in contributors.json file
|
||||
run: node aio/scripts/test-external-urls.js
|
||||
@@ -1,53 +0,0 @@
|
||||
name: Performance Tracking
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: 'read'
|
||||
id-token: 'write'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
list:
|
||||
timeout-minutes: 3
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
workflows: ${{ steps.workflows.outputs.workflows }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn -s install --frozen-lockfile
|
||||
- id: workflows
|
||||
run: echo "workflows=$(yarn -s ng-dev perf workflows --list)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
workflow:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
needs: list
|
||||
strategy:
|
||||
matrix:
|
||||
workflow: ${{ fromJSON(needs.list.outputs.workflows) }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Install node modules
|
||||
run: yarn -s install --frozen-lockfile
|
||||
# We utilize the google-github-actions/auth action to allow us to get an active credential using workflow
|
||||
# identity federation. This allows us to request short lived credentials on demand, rather than storing
|
||||
# credentials in secrets long term. More information can be found at:
|
||||
# https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-google-cloud-platform
|
||||
- uses: 'google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f' # v2
|
||||
with:
|
||||
project_id: 'internal-200822'
|
||||
workload_identity_provider: 'projects/823469418460/locations/global/workloadIdentityPools/measurables-tracking/providers/angular'
|
||||
service_account: 'measures-uploader@internal-200822.iam.gserviceaccount.com'
|
||||
- run: yarn ng-dev perf workflows --name ${{ matrix.workflow }} --commit-sha ${{github.sha}}
|
||||
@@ -1,177 +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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- 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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- 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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- 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@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- 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/...
|
||||
|
||||
zone-js:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
- 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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- uses: ./.github/actions/saucelabs-legacy
|
||||
@@ -25,12 +25,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: 'Run analysis'
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
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@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
|
||||
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@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
|
||||
uses: github/codeql-action/upload-sarif@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11
|
||||
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
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@9bf81f9c029a09347afb376b9e1ae12b33f1a1fa
|
||||
uses: angular/dev-infra/github-actions/create-pr-for-changes@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
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@ae9155d1083fd8390e98bfe09a5ccf89f0375b52
|
||||
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 }}
|
||||
+8
-3
@@ -4,8 +4,11 @@
|
||||
/bazel-out
|
||||
/integration/bazel/bazel-*
|
||||
*.log
|
||||
node_modules/
|
||||
modules/ssr-benchmarks/node_modules/
|
||||
/node_modules/
|
||||
|
||||
# CircleCI temporary file for cache key computation.
|
||||
# See `save_month_to_file` in `.circleci/config.yml`.
|
||||
month.txt
|
||||
|
||||
# Include when developing application packages.
|
||||
pubspec.lock
|
||||
@@ -53,6 +56,8 @@ baseline.json
|
||||
|
||||
# Husky
|
||||
.husky/_
|
||||
aio/content/examples/.DS_Store
|
||||
|
||||
|
||||
# Ignore cache created with the Angular CLI.
|
||||
.angular/
|
||||
.angular/
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
workflows:
|
||||
build-adev:
|
||||
name: Build adev
|
||||
prepare:
|
||||
- bazel clean
|
||||
workflow:
|
||||
- bazel build //adev:build
|
||||
+35
-8
@@ -7,25 +7,52 @@ export const format: FormatConfig = {
|
||||
'prettier': {
|
||||
'matchers': [
|
||||
'**/*.{yaml,yml}',
|
||||
'devtools/**/*.{js,ts}',
|
||||
'tools/**/*.{js,ts}',
|
||||
'modules/**/*.{js,ts}',
|
||||
'scripts/**/*.{js,ts}',
|
||||
'packages/animations/**/*.{js,ts}',
|
||||
'packages/bazel/**/*.{js,ts}',
|
||||
'packages/benchpress/**/*.{js,ts}',
|
||||
'packages/elements/**/*.{js,ts}',
|
||||
'packages/misc/**/*.{js,ts}',
|
||||
],
|
||||
},
|
||||
'clang-format': {
|
||||
'matchers': [
|
||||
'**/*.{js,ts}',
|
||||
'devtools/**/*.{js,ts,html,scss}',
|
||||
|
||||
// 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}',
|
||||
// Temporarily disable formatting for adev
|
||||
'!adev/**',
|
||||
|
||||
// Ignore generated javascript file(s)
|
||||
'!.github/actions/deploy-docs-site/main.js',
|
||||
// Migrated to prettier
|
||||
'!devtools/**/*.{js,ts}',
|
||||
'!tools/**/*.{js,ts}',
|
||||
'!modules/**/*.{js,ts}',
|
||||
'!scripts/**/*.{js,ts}',
|
||||
'!packages/animations/**/*.{js,ts}',
|
||||
'!packages/bazel/**/*.{js,ts}',
|
||||
'!packages/benchpress/**/*.{js,ts}',
|
||||
'!packages/elements/**/*.{js,ts}',
|
||||
'!packages/misc/**/*.{js,ts}',
|
||||
],
|
||||
},
|
||||
'buildifier': true,
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
{
|
||||
"syncedFilePatterns": ["LICENSE", "modules/benchmarks/**", "packages/**"],
|
||||
"separateFilePatterns": ["packages/core/primitives/**"],
|
||||
"alwaysExternalFilePatterns": [
|
||||
"packages/*",
|
||||
"packages/bazel/**",
|
||||
"packages/bazel/*",
|
||||
"packages/bazel/src/*",
|
||||
"packages/bazel/src/api-extractor/**",
|
||||
"packages/bazel/src/builders/**",
|
||||
"packages/bazel/src/ng_module/**",
|
||||
"packages/bazel/src/ng_package/**",
|
||||
"packages/bazel/src/protractor/**",
|
||||
"packages/bazel/src/schematics/**",
|
||||
"packages/bazel/src/types_bundle/**",
|
||||
"packages/compiler-cli/linker/**",
|
||||
"packages/compiler-cli/src/ngtsc/sourcemaps/**",
|
||||
"packages/compiler-cli/src/ngtsc/testing/**",
|
||||
@@ -12,14 +19,13 @@
|
||||
"packages/compiler-cli/private/tooling.ts",
|
||||
"packages/compiler-cli/private/babel.d.ts",
|
||||
"packages/compiler-cli/src/bin/**",
|
||||
"packages/core/schematics/utils/tsurge/helpers/angular_devkit/**",
|
||||
"packages/docs/**",
|
||||
"packages/elements/schematics/**",
|
||||
"packages/examples/**",
|
||||
"packages/language-service/**",
|
||||
"packages/localize/**",
|
||||
"packages/private/**",
|
||||
"packages/service-worker/**",
|
||||
"packages/ssr/BUILD.bazel",
|
||||
"packages/common/locales/generate-locales-tool/**",
|
||||
"packages/common/locales/index.bzl",
|
||||
"packages/http/**",
|
||||
|
||||
@@ -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'],
|
||||
};
|
||||
|
||||
+3
-5
@@ -1,11 +1,9 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"embeddedLanguageFormatting": "off",
|
||||
"tabs": false,
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"semicolon": true,
|
||||
"quoteProps": "preserve",
|
||||
"bracketSpacing": false,
|
||||
"trailingComma": "all"
|
||||
"bracketSpacing": false
|
||||
}
|
||||
|
||||
+605
-114
File diff suppressed because it is too large
Load Diff
Vendored
+6
@@ -5,6 +5,12 @@
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"BazelBuild.vscode-bazel",
|
||||
"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,
|
||||
|
||||
+147529
File diff suppressed because one or more lines are too long
Vendored
-148049
File diff suppressed because one or more lines are too long
@@ -2,4 +2,4 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
yarn-path ".yarn/releases/yarn-1.22.22.cjs"
|
||||
yarn-path ".yarn/releases/yarn-1.22.19.cjs"
|
||||
|
||||
+3
-3
@@ -64,11 +64,11 @@ config_setting(
|
||||
|
||||
nodejs_binary(
|
||||
name = "yarn_vendored",
|
||||
data = [".yarn/releases/yarn-1.22.22.cjs"],
|
||||
entry_point = ".yarn/releases/yarn-1.22.22.cjs",
|
||||
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__",
|
||||
"//modules/ssr-benchmarks:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
+79
-1496
File diff suppressed because it is too large
Load Diff
+14
-9
@@ -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?
|
||||
@@ -89,7 +89,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
We cannot accept code without a signed CLA.
|
||||
Make sure you author all contributed Git commits with email address associated with your CLA signature.
|
||||
|
||||
4. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the [angular/angular](https://github.com/angular/angular/fork) repo.
|
||||
4. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the angular/angular repo.
|
||||
|
||||
5. In your forked repository, make your changes in a new git branch:
|
||||
|
||||
@@ -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.md#formatting-your-source-code).
|
||||
An automated formatter is available, see [DEVELOPER.md](docs/DEVELOPER.md#clang-format).
|
||||
|
||||
|
||||
## <a name="commit"></a> Commit Message Format
|
||||
@@ -260,7 +260,7 @@ The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is opti
|
||||
Must be one of the following:
|
||||
|
||||
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
|
||||
* **ci**: Changes to our CI configuration files and scripts (examples: Github Actions, SauceLabs)
|
||||
* **ci**: Changes to our CI configuration files and scripts (examples: CircleCi, SauceLabs)
|
||||
* **docs**: Documentation only changes
|
||||
* **feat**: A new feature
|
||||
* **fix**: A bug fix
|
||||
@@ -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.dev/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_renaissance.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>
|
||||
@@ -18,12 +18,15 @@
|
||||
·
|
||||
<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>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://circleci.com/gh/angular/workflows/angular/tree/main">
|
||||
<img src="https://img.shields.io/circleci/build/github/angular/angular/main.svg?logo=circleci&logoColor=fff&label=CircleCI" alt="CI status" />
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/@angular/core">
|
||||
<img src="https://img.shields.io/npm/v/@angular/core.svg?logo=npm&logoColor=fff&label=NPM+package&color=limegreen" alt="Angular on npm" />
|
||||
</a>
|
||||
@@ -32,6 +35,12 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://app.circleci.com/insights/github/angular/angular/workflows/default_workflow?branch=main">
|
||||
<img src="https://dl.circleci.com/insights-snapshot/gh/angular/angular/main/default_workflow/badge.svg" alt="InsightsSnapshot" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
## Documentation
|
||||
@@ -54,7 +63,22 @@ Get started with Angular, learn the fundamentals and explore advanced topics on
|
||||
|
||||
### Local Development
|
||||
|
||||
To contribute to the Angular Docs, check out the [Angular.dev README](adev/README.md)
|
||||
To contribute to Angular docs, 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
|
||||
```
|
||||
|
||||
## Development Setup
|
||||
|
||||
@@ -92,7 +116,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]
|
||||
@@ -104,7 +128,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
|
||||
|
||||
@@ -143,8 +167,8 @@ Join the conversation and help the community.
|
||||
[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
|
||||
[componentstemplates]: https://angular.dev/tutorials/learn-angular/components-in-angular
|
||||
[forms]: https://angular.dev/tutorials/learn-angular/forms
|
||||
[api]: https://angular.dev/api
|
||||
[angularelements]: https://angular.dev/guide/elements
|
||||
[ssr]: https://angular.dev/guide/ssr
|
||||
|
||||
+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,7 @@ 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 = "18.13.0",
|
||||
)
|
||||
|
||||
# Download npm dependencies.
|
||||
@@ -75,7 +80,7 @@ yarn_install(
|
||||
"//:.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-e0ec7b60641d7f6369be45d8d02663fd50f320be.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 +99,54 @@ 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",
|
||||
"//:tools/npm-patches/@bazel+jasmine+5.8.1.patch",
|
||||
"//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 +196,10 @@ cldr_xml_data_repository(
|
||||
# sass rules
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "0c97c6d8f7a8697e53d91832117c91b71a23e6900acf530a22bf3de2e05179fc",
|
||||
strip_prefix = "rules_sass-35b1c3236a2b2a23c9d1eaeb82c5f7d030a892d1",
|
||||
sha256 = "7a90567717c3417a23ff4b21963a698a6e9aa669ac9e682121ea33f218a2816a",
|
||||
strip_prefix = "rules_sass-425ecafa8268bc013d684216363fe75bc802323e",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_sass/archive/35b1c3236a2b2a23c9d1eaeb82c5f7d030a892d1.zip",
|
||||
"https://github.com/bazelbuild/rules_sass/archive/425ecafa8268bc013d684216363fe75bc802323e.zip",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -181,15 +234,3 @@ http_archive(
|
||||
strip_prefix = "sc-4.8.2-osx",
|
||||
url = "https://saucelabs.com/downloads/sc-4.8.2-osx.zip",
|
||||
)
|
||||
|
||||
yarn_install(
|
||||
name = "npm_ts_versions",
|
||||
data = [
|
||||
YARN_LABEL,
|
||||
"//:.yarnrc",
|
||||
],
|
||||
exports_directories_only = False,
|
||||
package_json = "//packages/core/schematics/migrations/signal-migration/test/ts-versions:package.json",
|
||||
yarn = YARN_LABEL,
|
||||
yarn_lock = "//packages/core/schematics/migrations/signal-migration/test/ts-versions:yarn.lock",
|
||||
)
|
||||
|
||||
+37
-96
@@ -1,17 +1,9 @@
|
||||
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("//:packages.bzl", "link_packages")
|
||||
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",
|
||||
@@ -22,30 +14,21 @@ APPLICATION_FILES = [
|
||||
["src/**/*"],
|
||||
exclude = [
|
||||
"src/**/*.spec.ts",
|
||||
# Temporarily exclude generated sources produced by the non-bazel
|
||||
# build until the whole project is built by bazel and this directory
|
||||
# isn't needed.
|
||||
"src/generated/**/*",
|
||||
],
|
||||
)
|
||||
|
||||
TEST_FILES = APPLICATION_FILES + [
|
||||
"karma.conf.js",
|
||||
"test-main.ts",
|
||||
"tsconfig.spec.json",
|
||||
] + glob(
|
||||
["src/**/*.spec.ts"],
|
||||
["**/*.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",
|
||||
APPLICATION_DEPS = link_packages([
|
||||
"@npm//@angular-devkit/build-angular",
|
||||
"@npm//@angular/animations",
|
||||
"@npm//@angular/cdk",
|
||||
@@ -53,18 +36,25 @@ APPLICATION_DEPS = [
|
||||
"@npm//@angular/compiler",
|
||||
"@npm//@angular/compiler-cli",
|
||||
"@npm//@angular/core",
|
||||
"@npm//@angular/docs",
|
||||
"@npm//@angular/forms",
|
||||
"@npm//@angular/material",
|
||||
"@npm//@angular/platform-browser",
|
||||
"@npm//@angular/platform-server",
|
||||
"@npm//@angular/router",
|
||||
"@npm//@angular/ssr",
|
||||
"@npm//gsap",
|
||||
"@npm//marked",
|
||||
"@npm//ngx-progressbar",
|
||||
"@npm//ogl",
|
||||
"@npm//rxjs",
|
||||
"@npm//typescript",
|
||||
"//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",
|
||||
"@npm//@typescript/vfs",
|
||||
"@npm//@codemirror/state",
|
||||
"@npm//@codemirror/view",
|
||||
@@ -81,102 +71,56 @@ APPLICATION_DEPS = [
|
||||
"@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//xterm",
|
||||
"@npm//xterm-addon-fit",
|
||||
"@npm//angular-split",
|
||||
"@npm//zone.js",
|
||||
]
|
||||
])
|
||||
|
||||
TEST_DEPS = APPLICATION_DEPS + [
|
||||
TEST_DEPS = APPLICATION_DEPS + link_packages([
|
||||
"@npm//@angular/platform-browser-dynamic",
|
||||
"@npm//@angular/build-tooling/bazel/browsers/chromium",
|
||||
"@npm//@types/jasmine",
|
||||
"@npm//@types/node",
|
||||
"@npm//assert",
|
||||
"@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),
|
||||
)
|
||||
"//aio/tools:windows-chromium-path",
|
||||
])
|
||||
|
||||
copy_to_bin(
|
||||
name = "application_files_bin",
|
||||
srcs = APPLICATION_FILES,
|
||||
)
|
||||
|
||||
bool_flag(
|
||||
name = "full_build_adev",
|
||||
build_setting_default = False,
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "prod_build",
|
||||
flag_values = {
|
||||
":full_build_adev": "true",
|
||||
},
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "dev_build",
|
||||
flag_values = {
|
||||
":full_build_adev": "false",
|
||||
},
|
||||
)
|
||||
|
||||
config_based_architect_env = select({
|
||||
":dev_build": {
|
||||
"NG_BUILD_PARTIAL_SSR": "1",
|
||||
},
|
||||
":prod_build": {
|
||||
"NG_BUILD_OPTIMIZE_CHUNKS": "1",
|
||||
},
|
||||
})
|
||||
|
||||
config_based_architect_flags = select({
|
||||
":dev_build": [
|
||||
"angular-dev:build:development",
|
||||
],
|
||||
":prod_build": [
|
||||
"angular-dev:build:production",
|
||||
],
|
||||
})
|
||||
|
||||
architect(
|
||||
name = "build",
|
||||
args = config_based_architect_flags + [
|
||||
args = [
|
||||
"angular-dev:build",
|
||||
"--output-path=build",
|
||||
],
|
||||
chdir = "$(RULEDIR)",
|
||||
data = ensure_local_package_deps(APPLICATION_DEPS) + APPLICATION_ASSETS + [
|
||||
data = APPLICATION_DEPS + [
|
||||
":application_files_bin",
|
||||
],
|
||||
env = config_based_architect_env,
|
||||
# Network is required to inline fonts.
|
||||
exec_properties = ENABLE_NETWORK,
|
||||
output_dir = True,
|
||||
tags = [
|
||||
"no-remote-exec",
|
||||
],
|
||||
)
|
||||
|
||||
http_server(
|
||||
architect(
|
||||
name = "serve",
|
||||
additional_root_paths = [
|
||||
"angular/adev/build/browser",
|
||||
args = [
|
||||
"angular-dev:serve",
|
||||
"--poll=1000",
|
||||
"--live-reload",
|
||||
"--watch",
|
||||
],
|
||||
chdir = package_name(),
|
||||
data = APPLICATION_DEPS + [
|
||||
":application_files_bin",
|
||||
],
|
||||
enable_dev_ui = True,
|
||||
relax_cors = True,
|
||||
deps = [":build"],
|
||||
)
|
||||
|
||||
architect_test(
|
||||
@@ -186,10 +130,7 @@ architect_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",
|
||||
],
|
||||
data = TEST_DEPS + TEST_FILES,
|
||||
env = {
|
||||
"CHROME_BIN": "../$(CHROMIUM)",
|
||||
},
|
||||
|
||||
@@ -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
|
||||
```
|
||||
+14
-18
@@ -17,24 +17,25 @@
|
||||
"prefix": "adev",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"builder": "@angular-devkit/build-angular: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"
|
||||
},
|
||||
"outputMode": "static",
|
||||
"externalDependencies": [
|
||||
"path"
|
||||
],
|
||||
"outputPath": "dist/angular-dev",
|
||||
"index": "src/index.html",
|
||||
"browser": "src/main.ts",
|
||||
"server": "src/main.server.ts",
|
||||
"polyfills": [],
|
||||
"prerender": true,
|
||||
"polyfills": ["src/polyfills.ts", "zone.js"],
|
||||
"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"],
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/robots.txt",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": ["@angular/docs/styles/global-styles.scss"],
|
||||
"scripts": [],
|
||||
"webWorkerTsConfig": "tsconfig.worker.json",
|
||||
"optimization": {
|
||||
@@ -84,10 +85,10 @@
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": ["zone.js", "zone.js/testing"],
|
||||
"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"],
|
||||
@@ -99,11 +100,6 @@
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
"analytics": "dca119a9-da31-47f7-a6cb-b60541037021"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"ignore": ["**/.*"],
|
||||
"headers": [
|
||||
{
|
||||
"source": "assets/images/tutorials/common/*.jpg",
|
||||
"source": "assets/tutorials/common/*.jpg",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cross-Origin-Resource-Policy",
|
||||
|
||||
+8
-12
@@ -1,7 +1,7 @@
|
||||
// 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');
|
||||
const {getAdjustedChromeBinPathForWindows} = require('../aio/tools/windows-chromium-path');
|
||||
|
||||
process.env.CHROME_BIN = getAdjustedChromeBinPathForWindows();
|
||||
|
||||
@@ -21,7 +21,7 @@ module.exports = function (config) {
|
||||
'/dummy/image': 'src/assets/images/logos/angular/angular.png',
|
||||
},
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
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
|
||||
@@ -32,12 +32,15 @@ module.exports = function (config) {
|
||||
},
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true, // removes the duplicated traces
|
||||
suppressAll: true // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/site'),
|
||||
subdir: '.',
|
||||
reporters: [{type: 'html'}, {type: 'text-summary'}],
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
],
|
||||
},
|
||||
reporters: ['progress', 'kjhtml', 'jasmine-seed'],
|
||||
port: 9876,
|
||||
@@ -48,14 +51,7 @@ module.exports = function (config) {
|
||||
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',
|
||||
],
|
||||
flags: ['--no-sandbox', '--headless', '--disable-gpu', '--disable-dev-shm-usage', '--hide-scrollbars', '--mute-audio'],
|
||||
},
|
||||
},
|
||||
browsers: ['ChromeHeadlessNoSandbox'],
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*!
|
||||
* @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 {input, confirm} from '@inquirer/prompts';
|
||||
import {existsSync} from 'fs';
|
||||
import {copyFile, mkdir, writeFile} from 'fs/promises';
|
||||
import {dirname, join} from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
import {copyFolder} from './utils/fs.mjs';
|
||||
|
||||
const EXAMPLES_BASE = join(
|
||||
dirname(fileURLToPath(import.meta.url)),
|
||||
'../../src/content/examples',
|
||||
);
|
||||
const STACKBLITZ_TEMPLATE = join(
|
||||
dirname(fileURLToPath(import.meta.url)),
|
||||
'../../src/content/stackblitz-template',
|
||||
);
|
||||
|
||||
const MAIN_TS_FILENAME = 'main.ts';
|
||||
const STACKBLITZ_CONFIG_FILENAME = 'stackblitz.json';
|
||||
|
||||
createExample();
|
||||
|
||||
async function createExample(): Promise<void> {
|
||||
console.info('Create example');
|
||||
const name = await input({message: 'What is the example name?'});
|
||||
const description = await input({message: 'Could you provide the description of the example?'});
|
||||
const tags: string[] = [];
|
||||
let addMoreTags = true;
|
||||
|
||||
while (addMoreTags) {
|
||||
const tag = await input({message: 'Could you provide the tag of the example?'});
|
||||
|
||||
if (!!tag) {
|
||||
tags.push(tag);
|
||||
}
|
||||
|
||||
console.info();
|
||||
|
||||
addMoreTags = await confirm({message: 'Would you like to add another tag?', default: true});
|
||||
}
|
||||
|
||||
const shouldCopySrcAppFolderFromTemplate = await confirm({
|
||||
message: 'Would you like to copy /src/app/**.* from template?',
|
||||
default: true,
|
||||
});
|
||||
const shouldCopyMainTsFromTemplate = await confirm({
|
||||
message: 'Would you like to copy /src/main.ts from template?',
|
||||
default: false,
|
||||
});
|
||||
|
||||
const examplePath = join(EXAMPLES_BASE, name);
|
||||
|
||||
await createEmptyExample(examplePath, name, description, tags);
|
||||
await copyFilesFromTemplate(
|
||||
examplePath,
|
||||
shouldCopySrcAppFolderFromTemplate,
|
||||
shouldCopyMainTsFromTemplate,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the directory and marker files for the new example.
|
||||
*/
|
||||
async function createEmptyExample(
|
||||
examplePath: string,
|
||||
exampleName: string,
|
||||
description: string,
|
||||
tags: string[],
|
||||
): Promise<void> {
|
||||
validateExampleName(exampleName);
|
||||
|
||||
await ensureExamplePath(examplePath);
|
||||
await writeStackBlitzFile(examplePath, description, tags);
|
||||
}
|
||||
|
||||
function validateExampleName(exampleName: string): void {
|
||||
if (/\s/.test(exampleName)) {
|
||||
throw new Error(`Unable to create example. The example name contains spaces: '${exampleName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the new example directory exists.
|
||||
*/
|
||||
async function ensureExamplePath(examplePath: string): Promise<void> {
|
||||
if (existsSync(examplePath)) {
|
||||
throw new Error(
|
||||
`Unable to create example. The path to the new example already exists: ${examplePath}`,
|
||||
);
|
||||
}
|
||||
await mkdir(examplePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the `stackblitz.json` file into the new example.
|
||||
*/
|
||||
async function writeStackBlitzFile(
|
||||
examplePath: string,
|
||||
description: string,
|
||||
tags: string[],
|
||||
): Promise<void> {
|
||||
const config = {
|
||||
description,
|
||||
ignore: ['**/*.d.ts', '**/*.js', '**/*.[1,2].*'],
|
||||
tags,
|
||||
};
|
||||
await writeFile(
|
||||
join(examplePath, STACKBLITZ_CONFIG_FILENAME),
|
||||
JSON.stringify(config, null, 2) + '\n',
|
||||
);
|
||||
}
|
||||
|
||||
async function copyFilesFromTemplate(
|
||||
examplePath: string,
|
||||
shouldCopySrcAppFolderFromTemplate: boolean,
|
||||
shouldCopyMainTsFromTemplate: boolean,
|
||||
): Promise<void> {
|
||||
if (shouldCopySrcAppFolderFromTemplate) {
|
||||
const appTemplateFolderPath = join(STACKBLITZ_TEMPLATE, 'src/app');
|
||||
const exampleAppFolderPath = join(examplePath, 'src/app');
|
||||
await copyFolder(appTemplateFolderPath, exampleAppFolderPath);
|
||||
}
|
||||
if (shouldCopyMainTsFromTemplate) {
|
||||
const mainTsTemplatePath = join(STACKBLITZ_TEMPLATE, 'src', MAIN_TS_FILENAME);
|
||||
const exampleMainTsPath = join(examplePath, 'src', MAIN_TS_FILENAME);
|
||||
await copyFile(mainTsTemplatePath, exampleMainTsPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*!
|
||||
* @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 ts from 'typescript';
|
||||
import * as fs from 'fs';
|
||||
import {dirname, join, relative} from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
import {readFile, writeFile} from 'fs/promises';
|
||||
|
||||
const TYPESCRIPT_EXTENSION = '.ts';
|
||||
const SKIP_FILES_WITH_EXTENSIONS = ['.e2e-spec.ts', '.spec.ts', '.po.ts'];
|
||||
const EXAMPLES_PATH = `../../content/examples`;
|
||||
|
||||
interface File {
|
||||
path: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface AnalyzedFiles {
|
||||
path: string;
|
||||
componentNames: string[];
|
||||
}
|
||||
|
||||
/** Absolute disk path to the project directory. */
|
||||
const examplesDir = join(
|
||||
dirname(fileURLToPath(import.meta.url)),
|
||||
'../../src/content/examples',
|
||||
);
|
||||
const projectDir = join(dirname(fileURLToPath(import.meta.url)), '../../src');
|
||||
const previewsComponentMapFileName = 'previews.ts';
|
||||
|
||||
main();
|
||||
|
||||
async function main() {
|
||||
const files = await retrieveAllTypescriptFiles(
|
||||
examplesDir,
|
||||
(path) => !SKIP_FILES_WITH_EXTENSIONS.some((extensionToSkip) => path.endsWith(extensionToSkip)),
|
||||
);
|
||||
|
||||
const filesWithComponent = files
|
||||
.map((file) => ({
|
||||
componentNames: analyzeFile(file),
|
||||
path: file.path,
|
||||
}))
|
||||
.filter((result) => result.componentNames.length > 0);
|
||||
|
||||
const previewsComponentMap = generatePreviewsComponentMap(filesWithComponent);
|
||||
|
||||
fs.mkdirSync(join(projectDir, 'assets/previews'), {recursive: true});
|
||||
|
||||
await writeFile(
|
||||
join(projectDir, 'assets/previews', previewsComponentMapFileName),
|
||||
previewsComponentMap,
|
||||
);
|
||||
}
|
||||
|
||||
/** Recursively search the provided directory for all typescript files and asynchronously load them. */
|
||||
function retrieveAllTypescriptFiles(
|
||||
baseDir: string,
|
||||
predicateFn: (path: string) => boolean,
|
||||
): Promise<File[]> {
|
||||
const typescriptFiles: Promise<File>[] = [];
|
||||
|
||||
const checkFilesInDirectory = (dir: string) => {
|
||||
const files = fs.readdirSync(dir, {withFileTypes: true});
|
||||
for (const file of files) {
|
||||
const fullPathToFile = join(dir, file.name);
|
||||
const relativeFilePath = relative(baseDir, fullPathToFile);
|
||||
|
||||
if (
|
||||
file.isFile() &&
|
||||
file.name.endsWith(TYPESCRIPT_EXTENSION) &&
|
||||
predicateFn(relativeFilePath)
|
||||
) {
|
||||
typescriptFiles.push(
|
||||
readFile(fullPathToFile, {encoding: 'utf-8'}).then((fileContent) => {
|
||||
return {
|
||||
path: relativeFilePath,
|
||||
content: fileContent,
|
||||
};
|
||||
}),
|
||||
);
|
||||
} else if (file.isDirectory()) {
|
||||
checkFilesInDirectory(fullPathToFile);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
checkFilesInDirectory(baseDir);
|
||||
|
||||
return Promise.all(typescriptFiles);
|
||||
}
|
||||
|
||||
/** Returns list of the `Standalone` @Component class names for given file */
|
||||
function analyzeFile(file: File): string[] {
|
||||
const componentClassNames: string[] = [];
|
||||
const sourceFile = ts.createSourceFile(file.path, file.content, ts.ScriptTarget.Latest, false);
|
||||
|
||||
const visitNode = (node: ts.Node): void => {
|
||||
if (ts.isClassDeclaration(node)) {
|
||||
const decorators = ts.getDecorators(node);
|
||||
const componentName = node.name ? node.name.text : null;
|
||||
|
||||
if (decorators && decorators.length) {
|
||||
for (const decorator of decorators) {
|
||||
const call = decorator.expression;
|
||||
|
||||
if (
|
||||
ts.isCallExpression(call) &&
|
||||
ts.isIdentifier(call.expression) &&
|
||||
call.expression.text === 'Component' &&
|
||||
call.arguments.length > 0 &&
|
||||
ts.isObjectLiteralExpression(call.arguments[0])
|
||||
) {
|
||||
const hasStandaloneProperty = call.arguments[0].properties.some(
|
||||
(property) =>
|
||||
property.name &&
|
||||
ts.isIdentifier(property.name) &&
|
||||
property.name.text === 'standalone',
|
||||
);
|
||||
|
||||
if (hasStandaloneProperty && componentName) {
|
||||
componentClassNames.push(componentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ts.forEachChild(node, visitNode);
|
||||
};
|
||||
|
||||
visitNode(sourceFile);
|
||||
|
||||
return componentClassNames;
|
||||
}
|
||||
|
||||
function generatePreviewsComponentMap(data: AnalyzedFiles[]): string {
|
||||
let result = '';
|
||||
for (const fileData of data) {
|
||||
for (const componentName of fileData.componentNames) {
|
||||
const key = `${fileData.path}${
|
||||
fileData.componentNames.length > 1 ? '_' + componentName : ''
|
||||
}`.replace(/\\/g, '/');
|
||||
result += `['${key}']: () => import('${EXAMPLES_PATH}/${fileData.path
|
||||
.replace(/\\/g, '/')
|
||||
.replace('.ts', '')}').then(c => c.${componentName}),\n`;
|
||||
}
|
||||
}
|
||||
return fs
|
||||
.readFileSync('scripts/examples/previews-components.template', 'utf8')
|
||||
.replace(/\${previewsComponents}/g, result);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*!
|
||||
* @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
|
||||
*/
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* DO NOT MANUALLY EDIT THIS FILE. THIS FILE IS AUTOMATICALLY GENERATED.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
import {Type} from '@angular/core';
|
||||
|
||||
/**
|
||||
* Map of the previews components, values are functions which returns the promise of the component type, which will be displayed as preview in the ExampleViewer component.
|
||||
* Keys has to be equal to paths written down in the docs markdown files.
|
||||
*/
|
||||
export const PREVIEWS_COMPONENTS_MAP: Record<string, () => Promise<Type<unknown>>> = {
|
||||
${previewsComponents}
|
||||
};
|
||||
@@ -0,0 +1,221 @@
|
||||
/*!
|
||||
* @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 {dirname, join} from 'path';
|
||||
import {readFile, writeFile} from 'fs/promises';
|
||||
import {
|
||||
ASSETS_EXAMPLE_PATH,
|
||||
CSS_TS_COPYRIGHT,
|
||||
EXAMPLES_PATH,
|
||||
HTML_COPYRIGHT,
|
||||
STACKBLITZ_TEMPLATE_PATH,
|
||||
STACKBLITZ_CONFIG_FILENAME,
|
||||
TEMPORARY_EXAMPLES_PATH,
|
||||
EXCLUDE_FILES_FOR_STACKBLITZ,
|
||||
} from './utils/examples-constants.mjs';
|
||||
import {copyFolder, createFolder, removeFolder} from './utils/fs.mjs';
|
||||
import jsdom from 'jsdom';
|
||||
import {glob} from 'glob';
|
||||
import {regionParser} from './../../prerender/markdown-pipeline/regions/region-parser.mjs';
|
||||
|
||||
interface StackblitzConfig {
|
||||
ignore: string[];
|
||||
file: string;
|
||||
tags: string[];
|
||||
description: string;
|
||||
}
|
||||
|
||||
export async function generateStackblitzExample(
|
||||
exampleFolderName: string,
|
||||
primaryFilePath: string,
|
||||
title: string,
|
||||
) {
|
||||
const exampleDir = join(EXAMPLES_PATH, exampleFolderName);
|
||||
const temporaryExampleDir = join(TEMPORARY_EXAMPLES_PATH, exampleFolderName);
|
||||
const config = await readFile(join(exampleDir, STACKBLITZ_CONFIG_FILENAME), 'utf-8');
|
||||
const stackblitzConfig: StackblitzConfig = JSON.parse(config);
|
||||
primaryFilePath = join(...primaryFilePath.split('/'));
|
||||
|
||||
await createFolder(temporaryExampleDir);
|
||||
await combineTemplateWithExample(exampleDir, temporaryExampleDir);
|
||||
await generateStackblitzHtml(
|
||||
temporaryExampleDir,
|
||||
stackblitzConfig,
|
||||
exampleFolderName,
|
||||
primaryFilePath,
|
||||
title,
|
||||
);
|
||||
await removeFolder(temporaryExampleDir);
|
||||
}
|
||||
|
||||
async function combineTemplateWithExample(
|
||||
exampleDir: string,
|
||||
temporaryExampleDir: string,
|
||||
): Promise<void> {
|
||||
// Copy template files to TEMP folder
|
||||
await copyFolder(STACKBLITZ_TEMPLATE_PATH, temporaryExampleDir);
|
||||
|
||||
// Copy example files to TEMP folder
|
||||
await copyFolder(exampleDir, temporaryExampleDir);
|
||||
}
|
||||
|
||||
async function generateStackblitzHtml(
|
||||
temporaryExampleDir: string,
|
||||
stackBlitzConfig: StackblitzConfig,
|
||||
exampleFolderName: string,
|
||||
primaryFilePath: string,
|
||||
title: string,
|
||||
): Promise<void> {
|
||||
const defaultIncludes = [
|
||||
'**/*.ts',
|
||||
'**/*.js',
|
||||
'**/*.css',
|
||||
'**/*.html',
|
||||
'**/*.md',
|
||||
'**/*.json',
|
||||
'**/*.svg',
|
||||
];
|
||||
const exampleFilePaths = await glob(defaultIncludes, {
|
||||
cwd: temporaryExampleDir,
|
||||
nodir: true,
|
||||
dot: true,
|
||||
ignore: stackBlitzConfig.ignore,
|
||||
});
|
||||
|
||||
const postData = await createPostData(
|
||||
temporaryExampleDir,
|
||||
stackBlitzConfig,
|
||||
exampleFilePaths,
|
||||
title,
|
||||
);
|
||||
const primaryFile = getPrimaryFile(primaryFilePath ?? stackBlitzConfig.file, exampleFilePaths);
|
||||
const html = createStackblitzHtml(postData, primaryFile);
|
||||
|
||||
const stackblitzHtmlPath = join(
|
||||
join(ASSETS_EXAMPLE_PATH, exampleFolderName),
|
||||
`${primaryFile}.html`,
|
||||
);
|
||||
await createFolder(dirname(stackblitzHtmlPath));
|
||||
await writeFile(stackblitzHtmlPath, html, 'utf-8');
|
||||
}
|
||||
|
||||
function getPrimaryFile(primaryFilePath: string, exampleFilePaths: string[]): string {
|
||||
if (primaryFilePath) {
|
||||
if (!exampleFilePaths.some((filePath) => filePath === primaryFilePath)) {
|
||||
throw new Error(`The specified primary file (${primaryFilePath}) does not exist!`);
|
||||
}
|
||||
return primaryFilePath;
|
||||
} else {
|
||||
const defaultPrimaryFilePaths = [
|
||||
'src/app/app.component.html',
|
||||
'src/app/app.component.ts',
|
||||
'src/app/main.ts',
|
||||
];
|
||||
const primaryFile = defaultPrimaryFilePaths.find((path) =>
|
||||
exampleFilePaths.some((filePath) => filePath === path),
|
||||
);
|
||||
|
||||
if (!primaryFile) {
|
||||
throw new Error(
|
||||
`None of the default primary files (${defaultPrimaryFilePaths.join(', ')}) exists.`,
|
||||
);
|
||||
}
|
||||
|
||||
return primaryFile;
|
||||
}
|
||||
}
|
||||
|
||||
async function createPostData(
|
||||
exampleDir: string,
|
||||
config: StackblitzConfig,
|
||||
exampleFilePaths: string[],
|
||||
title: string,
|
||||
): Promise<Record<string, string>> {
|
||||
const postData: Record<string, string> = {};
|
||||
|
||||
for (const filePath of exampleFilePaths) {
|
||||
if (EXCLUDE_FILES_FOR_STACKBLITZ.some((excludedFile) => filePath.endsWith(excludedFile))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let content = await readFile(join(exampleDir, filePath), 'utf-8');
|
||||
content = appendCopyright(filePath, content);
|
||||
content = extractRegions(filePath, content);
|
||||
|
||||
postData[`project[files][${filePath}]`] = content;
|
||||
}
|
||||
|
||||
const tags = ['angular', 'example', ...(config.tags || [])];
|
||||
tags.forEach((tag, index) => (postData[`project[tags][${index}]`] = tag));
|
||||
|
||||
postData['project[description]'] = `Angular Example - ${config.description}`;
|
||||
postData['project[template]'] = 'node';
|
||||
postData['project[title]'] = title ?? 'Angular Example';
|
||||
|
||||
return postData;
|
||||
}
|
||||
|
||||
function createStackblitzHtml(postData: Record<string, string>, primaryFile: string): string {
|
||||
const baseHtml = createBaseStackblitzHtml(primaryFile);
|
||||
const doc = new jsdom.JSDOM(baseHtml).window.document;
|
||||
const form = doc.querySelector('form');
|
||||
|
||||
for (const [key, value] of Object.entries(postData)) {
|
||||
const element = htmlToElement(doc, `<input type="hidden" name="${key}">`);
|
||||
if (element && form) {
|
||||
element.setAttribute('value', value as string);
|
||||
form.appendChild(element);
|
||||
}
|
||||
}
|
||||
|
||||
return doc.documentElement.outerHTML;
|
||||
}
|
||||
|
||||
function createBaseStackblitzHtml(primaryFile: string) {
|
||||
const file = `?file=${primaryFile}`;
|
||||
const action = `https://stackblitz.com/run${file}`;
|
||||
|
||||
return `
|
||||
<!DOCTYPE html><html lang="en"><body>
|
||||
<form id="mainForm" method="post" action="${action}" target="_self"></form>
|
||||
<script>
|
||||
var embedded = 'ctl=1';
|
||||
var isEmbedded = window.location.search.indexOf(embedded) > -1;
|
||||
|
||||
if (isEmbedded) {
|
||||
var form = document.getElementById('mainForm');
|
||||
var action = form.action;
|
||||
var actionHasParams = action.indexOf('?') > -1;
|
||||
var symbol = actionHasParams ? '&' : '?'
|
||||
form.action = form.action + symbol + embedded;
|
||||
}
|
||||
document.getElementById("mainForm").submit();
|
||||
</script>
|
||||
</body></html>
|
||||
`.trim();
|
||||
}
|
||||
|
||||
function appendCopyright(filename: string, content: string): string {
|
||||
if (filename.endsWith('.html')) {
|
||||
return `${HTML_COPYRIGHT}${content}`;
|
||||
} else if (filename.endsWith('.ts') || filename.endsWith('.css')) {
|
||||
return `${CSS_TS_COPYRIGHT}${content}`;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
function htmlToElement(document: Document, html: string) {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = html;
|
||||
return div.firstElementChild;
|
||||
}
|
||||
|
||||
function extractRegions(path: string, contents: string): string {
|
||||
const regionParserResult = regionParser(contents, path);
|
||||
return regionParserResult.contents;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"ts-node": {
|
||||
"compilerOptions": {
|
||||
"module": "es2020"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*!
|
||||
* @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 {dirname, join} from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
const BASE = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
// Directory paths
|
||||
export const ASSETS_EXAMPLE_PATH = join(
|
||||
BASE,
|
||||
'../../../src/assets/content/examples',
|
||||
);
|
||||
export const EXAMPLES_PATH = join(BASE, '../../../src/content/examples');
|
||||
export const STACKBLITZ_TEMPLATE_PATH = join(
|
||||
BASE,
|
||||
'../../../src/content/stackblitz-template',
|
||||
);
|
||||
|
||||
export const TEMPORARY_EXAMPLES_PATH = join(fileURLToPath(import.meta.url), '../../../../TEMP');
|
||||
|
||||
// Extensions
|
||||
export const TEST_FILES_EXTENSION_SUFFIX = '.spec.ts';
|
||||
export const TEST_FILES_E2E_EXTENSION_SUFFIX = '.e2e-spec.ts';
|
||||
|
||||
// Filename
|
||||
// TODO: BUILD.bazel and example-config will be deprecated when migration to standalone examples will be done.
|
||||
export const BUILD_BAZEL_FILENAME = 'BUILD.bazel';
|
||||
export const EXAMPLE_CONFIG_FILENAME = 'example-config.json';
|
||||
export const STACKBLITZ_CONFIG_FILENAME = 'stackblitz.json';
|
||||
|
||||
// Copyright
|
||||
const PAD = '\n\n';
|
||||
const COPYRIGHT =
|
||||
'@license\n' +
|
||||
'Copyright Google LLC All Rights Reserved.\n' +
|
||||
'\n' +
|
||||
'Use of this source code is governed by an MIT-style license that can be\n' +
|
||||
'found in the LICENSE file at https://angular.dev/license\n';
|
||||
export const CSS_TS_COPYRIGHT = `/*\n${COPYRIGHT}\n*/${PAD}`;
|
||||
export const HTML_COPYRIGHT = `<!-- \n${COPYRIGHT}\n-->${PAD}`;
|
||||
|
||||
// Exclude
|
||||
export const EXCLUDE_FILES_FOR_STACKBLITZ = [
|
||||
STACKBLITZ_CONFIG_FILENAME,
|
||||
BUILD_BAZEL_FILENAME,
|
||||
EXAMPLE_CONFIG_FILENAME,
|
||||
TEST_FILES_EXTENSION_SUFFIX,
|
||||
TEST_FILES_E2E_EXTENSION_SUFFIX,
|
||||
];
|
||||
@@ -0,0 +1,77 @@
|
||||
/*!
|
||||
* @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 {Dirent, existsSync, readdirSync} from 'fs';
|
||||
import {copyFile, mkdir, readFile, readdir, rm, stat} from 'fs/promises';
|
||||
import {join, relative} from 'path';
|
||||
|
||||
export async function copyFolder(source: string, destination: string) {
|
||||
if (!existsSync(destination)) {
|
||||
await mkdir(destination, {recursive: true});
|
||||
}
|
||||
|
||||
const files = await readdir(source);
|
||||
|
||||
for (const file of files) {
|
||||
const sourcePath = join(source, file);
|
||||
const destPath = join(destination, file);
|
||||
|
||||
const stats = await stat(sourcePath);
|
||||
const isDirectory = await stats.isDirectory();
|
||||
|
||||
if (isDirectory) {
|
||||
await copyFolder(sourcePath, destPath);
|
||||
} else {
|
||||
await copyFile(sourcePath, destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Recursively search the provided directory for all files which satisfy predicate and asynchronously load them. */
|
||||
export function retrieveFiles(
|
||||
baseDir: string,
|
||||
predicate?: (file: Dirent) => boolean,
|
||||
): Promise<{path: string; content: string}[]> {
|
||||
const filesWithContent: Promise<{path: string; content: string}>[] = [];
|
||||
|
||||
const checkFilesInDirectory = (dir: string) => {
|
||||
const files = readdirSync(dir, {withFileTypes: true});
|
||||
for (const file of files) {
|
||||
const fullPathToFile = join(dir, file.name);
|
||||
|
||||
if (file.isFile() && (predicate ? predicate(file) : true)) {
|
||||
filesWithContent.push(
|
||||
readFile(fullPathToFile, {encoding: 'utf-8'}).then((fileContent) => {
|
||||
return {
|
||||
path: relative(baseDir, fullPathToFile),
|
||||
content: fileContent,
|
||||
};
|
||||
}),
|
||||
);
|
||||
} else if (file.isDirectory()) {
|
||||
checkFilesInDirectory(fullPathToFile);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
checkFilesInDirectory(baseDir);
|
||||
|
||||
return Promise.all(filesWithContent);
|
||||
}
|
||||
|
||||
export async function createFolder(path: string): Promise<void> {
|
||||
if (!existsSync(path)) {
|
||||
await mkdir(path, {recursive: true});
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeFolder(path: string): Promise<void> {
|
||||
if (existsSync(path)) {
|
||||
await rm(path, {recursive: true});
|
||||
}
|
||||
}
|
||||
@@ -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,49 +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 {RouterLink} from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-breadcrumb',
|
||||
standalone: true,
|
||||
imports: [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();
|
||||
}
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user