Compare commits
80 Commits
Author | SHA1 | Date | |
---|---|---|---|
5db7b4c354 | |||
e08d02145e | |||
dae3a77c43 | |||
02e75df3e7 | |||
f752ab9367 | |||
9c875b30dc | |||
8fa78d10ab | |||
26988f0d62 | |||
6acf117386 | |||
8b731e374d | |||
5378f78e79 | |||
495c40e31c | |||
9963c5d8f7 | |||
13c4a7b1da | |||
70e85d226c | |||
dfb129dbfa | |||
1a1407aef6 | |||
da71f76a6a | |||
0c9b76e9e7 | |||
db34b23ab5 | |||
df0941554b | |||
5221df8e92 | |||
bc35c6a8ed | |||
23fc2b43ac | |||
c16995eb59 | |||
3487d5a13a | |||
1efc75cd72 | |||
c4190e3142 | |||
5d98834585 | |||
529ff73200 | |||
791205005c | |||
2d37e47e95 | |||
27c8066641 | |||
952fd8662c | |||
42be9047d8 | |||
52a0c6b36e | |||
8913aee527 | |||
7628c36f49 | |||
b417dd7b9c | |||
8cf16b4815 | |||
806aed63f4 | |||
eb34037cd7 | |||
ba0df5250f | |||
c4553bbed9 | |||
cc13b37446 | |||
166df5d2ca | |||
a5b474580c | |||
9f132d0d93 | |||
8dee378b3e | |||
0845d1148f | |||
7cfa57a5f7 | |||
f80c22002b | |||
7aa12412f3 | |||
072b707b38 | |||
223b80cb7d | |||
416403fc63 | |||
878e2f0deb | |||
4c30f5135b | |||
6791cd79af | |||
f50313f54d | |||
30433a0710 | |||
86ab9f92b4 | |||
42f9679376 | |||
bee10574d8 | |||
afce0f5038 | |||
bb19e61848 | |||
50e83e2566 | |||
d80c4890be | |||
4f8b716c13 | |||
cb85d69450 | |||
4a446878fa | |||
cb80f46c64 | |||
5199d55d45 | |||
bb11fd9058 | |||
771f7318f0 | |||
5d584b7728 | |||
1b5f6ee7a6 | |||
669e07580c | |||
965249d1da | |||
3a01856e7c |
4
.bazelrc
4
.bazelrc
@ -74,8 +74,8 @@ test --test_output=errors
|
||||
# Trick bazel into treating BUILD files under integration/bazel as being regular files
|
||||
# This lets us glob() up all the files inside this integration test to make them inputs to tests
|
||||
# (Note, we cannot use common --deleted_packages because the bazel version command doesn't support it)
|
||||
build --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/test/e2e
|
||||
query --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/test/e2e
|
||||
build --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/tools,integration/bazel/test/e2e
|
||||
query --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/tools,integration/bazel/test/e2e
|
||||
|
||||
################################
|
||||
# Temporary Settings for Ivy #
|
||||
|
@ -1,3 +1,3 @@
|
||||
3.2.0
|
||||
3.5.1
|
||||
# [NB: this comment has to be after the first line, see https://github.com/bazelbuild/bazelisk/issues/117]
|
||||
# When updating the Bazel version you also need to update the RBE toolchains version in package.bzl
|
||||
|
@ -14,8 +14,8 @@ build --repository_cache=/home/circleci/bazel_repository_cache
|
||||
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
||||
# Limit Bazel to consuming resources that fit in CircleCI "xlarge" class
|
||||
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
|
||||
build --local_cpu_resources=8
|
||||
build --local_ram_resources=14336
|
||||
build --local_cpu_resources=20
|
||||
build --local_ram_resources=32768
|
||||
|
||||
# All build executed remotely should be done using our RBE configuration.
|
||||
build:remote --google_default_credentials
|
||||
|
@ -11,8 +11,8 @@ try-import %workspace%/.circleci/bazel.common.rc
|
||||
build --repository_cache=C:/Users/circleci/bazel_repository_cache
|
||||
|
||||
# Manually set the local resources used in windows CI runs
|
||||
build --local_ram_resources=13500
|
||||
build --local_cpu_resources=4
|
||||
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
|
||||
|
@ -80,7 +80,7 @@ executors:
|
||||
|
||||
windows-executor:
|
||||
working_directory: ~/ng
|
||||
resource_class: windows.medium
|
||||
resource_class: windows.2xlarge
|
||||
# CircleCI windows VMs do have the GitBash shell available:
|
||||
# https://github.com/CircleCI-Public/windows-preview-docs#shells
|
||||
# But in this specific case we really should not use it because Bazel must not be ran from
|
||||
@ -273,6 +273,7 @@ jobs:
|
||||
- run: yarn -s ng-dev format changed $CI_GIT_BASE_REVISION --check
|
||||
- run: yarn -s ts-circular-deps:check
|
||||
- run: yarn -s ng-dev pullapprove verify
|
||||
- run: yarn -s ng-dev ngbot verify
|
||||
- run: yarn -s ng-dev commit-message validate-range --range $CI_COMMIT_RANGE
|
||||
|
||||
test:
|
||||
@ -857,9 +858,16 @@ workflows:
|
||||
- build-npm-packages
|
||||
- build-ivy-npm-packages
|
||||
- legacy-unit-tests-saucelabs
|
||||
- components-repo-unit-tests:
|
||||
requires:
|
||||
- build-npm-packages
|
||||
# Temporarily disabled components-repo-unit-tests to update rules_nodejs to 2.0.0. Breaking changes in
|
||||
# rules_nodejs create a dependency sandwich between angular/angular & angular/components that are very
|
||||
# difficult and time consuming to resolve and involve patching @angular/bazel in components repo such
|
||||
# as https://github.com/angular/components/commit/9e7ba251207df77164d73d66620e619bcbc4d2ad. It is simpler to
|
||||
# 1) land angular/angular upgrade to rule_nodejs 2.0.0 which has breaking changes
|
||||
# 2) land angular/components upgrade to rules_nodejs 2.0.0 using the @angular/bazel builds snapshot
|
||||
# 3) update angular/angular to the landed components commit and re-enable these tests
|
||||
# - components-repo-unit-tests:
|
||||
# requires:
|
||||
# - build-npm-packages
|
||||
- test_zonejs:
|
||||
requires:
|
||||
- setup
|
||||
|
@ -41,7 +41,8 @@ copy .circleci\bazel.windows.rc ${Env:USERPROFILE}\.bazelrc
|
||||
####################################################################################################
|
||||
# Install specific version of node.
|
||||
####################################################################################################
|
||||
choco install nodejs --version 12.14.1 --no-progress
|
||||
nvm install 12.14.1
|
||||
nvm use 12.14.1
|
||||
|
||||
# These Bazel prereqs aren't needed because the CircleCI image already includes them.
|
||||
# choco install yarn --version 1.16.0 --no-progress
|
||||
|
27
.github/angular-robot.yml
vendored
27
.github/angular-robot.yml
vendored
@ -38,6 +38,7 @@ merge:
|
||||
- "modules/benchmarks/**"
|
||||
- "modules/system.d.ts"
|
||||
- "packages/**"
|
||||
- "dev-infra/benchmark/driver-utilities/**"
|
||||
# list of patterns to ignore for the files changed by the PR
|
||||
exclude:
|
||||
- "packages/*"
|
||||
@ -47,8 +48,10 @@ merge:
|
||||
- "packages/bazel/src/ng_package/**"
|
||||
- "packages/bazel/src/protractor/**"
|
||||
- "packages/bazel/src/schematics/**"
|
||||
- "packages/compiler-cli/src/ngcc/**"
|
||||
- "packages/compiler-cli/linker/**"
|
||||
- "packages/compiler-cli/ngcc/**"
|
||||
- "packages/compiler-cli/src/ngtsc/sourcemaps/**",
|
||||
- "packages/compiler-cli/src/ngtsc/sourcemaps/**"
|
||||
- "packages/docs/**"
|
||||
- "packages/elements/schematics/**"
|
||||
- "packages/examples/**"
|
||||
@ -56,6 +59,8 @@ merge:
|
||||
- "packages/localize/**"
|
||||
- "packages/private/**"
|
||||
- "packages/service-worker/**"
|
||||
- "packages/common/locales/**"
|
||||
- "packages/http/**"
|
||||
- "**/.gitignore"
|
||||
- "**/.gitkeep"
|
||||
- "**/yarn.lock"
|
||||
@ -137,24 +142,28 @@ triage:
|
||||
# arrays of labels that determine if an issue has been fully triaged
|
||||
l2TriageLabels:
|
||||
-
|
||||
- "type: bug/fix"
|
||||
- "severity*"
|
||||
- "freq*"
|
||||
- "P0"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: feature"
|
||||
- "P1"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: refactor"
|
||||
- "P2"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: RFC / Discussion / question"
|
||||
- "P3"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: confusing"
|
||||
- "P4"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: use-case"
|
||||
- "P5"
|
||||
- "comp: *"
|
||||
-
|
||||
- "feature"
|
||||
- "comp: *"
|
||||
-
|
||||
- "discussion"
|
||||
- "comp: *"
|
||||
|
||||
# options for the triage PR plugin
|
||||
|
@ -9,11 +9,11 @@ export const caretaker: CaretakerConfig = {
|
||||
},
|
||||
{
|
||||
name: 'Merge Assistance Queue',
|
||||
query: `is:pr is:open status:success label:"action: merge-assistance"`,
|
||||
query: `is:pr is:open label:"action: merge-assistance"`,
|
||||
},
|
||||
{
|
||||
name: 'Primary Triage Queue',
|
||||
query: `is:open is:issue no:milestone`,
|
||||
name: 'Initial Triage Queue',
|
||||
query: `is:open no:milestone`,
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ export const release: ReleaseConfig = {
|
||||
],
|
||||
// TODO: Implement release package building here.
|
||||
buildPackages: async () => [],
|
||||
// TODO: This can be removed once there is a org-wide tool for changelog generation.
|
||||
// TODO: This can be removed once there is an org-wide tool for changelog generation.
|
||||
generateReleaseNotesForHead: async () => {
|
||||
exec('yarn -s gulp changelog', {cwd: join(__dirname, '../')});
|
||||
},
|
||||
|
@ -326,6 +326,7 @@ groups:
|
||||
'aio/content/examples/component-interaction/**',
|
||||
'aio/content/images/guide/component-interaction/**',
|
||||
'aio/content/guide/component-styles.md',
|
||||
'aio/content/guide/view-encapsulation.md',
|
||||
'aio/content/examples/component-styles/**',
|
||||
'aio/content/guide/dependency-injection.md',
|
||||
'aio/content/examples/dependency-injection/**',
|
||||
@ -1115,6 +1116,7 @@ groups:
|
||||
'docs/DEBUG.md',
|
||||
'docs/DEBUG_COMPONENTS_REPO_IVY.md',
|
||||
'docs/DEVELOPER.md',
|
||||
'docs/FIXUP_COMMITS.md',
|
||||
'docs/GITHUB_PROCESS.md',
|
||||
'docs/PR_REVIEW.md',
|
||||
'docs/SAVED_REPLIES.md',
|
||||
|
@ -47,3 +47,9 @@ filegroup(
|
||||
"@npm//:node_modules/angular-mocks-1.6/angular-mocks.js",
|
||||
],
|
||||
)
|
||||
|
||||
# Detect if the build is running under --stamp
|
||||
config_setting(
|
||||
name = "stamp",
|
||||
values = {"stamp": "true"},
|
||||
)
|
||||
|
36
CHANGELOG.md
36
CHANGELOG.md
@ -1,3 +1,39 @@
|
||||
<a name="10.1.6"></a>
|
||||
## 10.1.6 (2020-10-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler:** incorrectly encapsulating [@import](https://github.com/import) containing colons and semicolons ([#38716](https://github.com/angular/angular/issues/38716)) ([52a0c6b](https://github.com/angular/angular/commit/52a0c6b)), closes [#38587](https://github.com/angular/angular/issues/38587)
|
||||
* **compiler-cli:** support namespaced query types in directives ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([f752ab9](https://github.com/angular/angular/commit/f752ab9))
|
||||
* **elements:** detect matchesSelector prototype without IIFE ([#37799](https://github.com/angular/angular/issues/37799)) ([952fd86](https://github.com/angular/angular/commit/952fd86)), closes [#24551](https://github.com/angular/angular/issues/24551)
|
||||
* **ngcc:** ensure that "inline exports" can be interpreted correctly ([#39272](https://github.com/angular/angular/issues/39272)) ([e08d021](https://github.com/angular/angular/commit/e08d021))
|
||||
* **ngcc:** handle aliases in UMD export declarations ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([9963c5d](https://github.com/angular/angular/commit/9963c5d)), closes [#38947](https://github.com/angular/angular/issues/38947)
|
||||
* **ngcc:** map `exports` to the current module in UMD files ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([13c4a7b](https://github.com/angular/angular/commit/13c4a7b))
|
||||
* **ngcc:** support inline export declarations in UMD files ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([9c875b3](https://github.com/angular/angular/commit/9c875b3)), closes [#38947](https://github.com/angular/angular/issues/38947)
|
||||
|
||||
|
||||
### build
|
||||
|
||||
* upgrade angular build, integration/bazel and [@angular](https://github.com/angular)/bazel package to rule_nodejs 2.2.0 ([#39182](https://github.com/angular/angular/issues/39182)) ([7628c36](https://github.com/angular/angular/commit/7628c36))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **ngcc:** do not rescan program source files when referenced from multiple root files ([#39254](https://github.com/angular/angular/issues/39254)) ([5221df8](https://github.com/angular/angular/commit/5221df8)), closes [#39240](https://github.com/angular/angular/issues/39240)
|
||||
|
||||
|
||||
<a name="10.1.5"></a>
|
||||
## 10.1.5 (2020-10-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **router:** update getRouteGuards to check if the context outlet is activated ([#39049](https://github.com/angular/angular/issues/39049)) ([771f731](https://github.com/angular/angular/commit/771f731)), closes [#39030](https://github.com/angular/angular/issues/39030)
|
||||
* **compiler:** Recover on malformed keyed reads and keyed writes ([#39004](https://github.com/angular/angular/issues/39004)) ([f50313f](https://github.com/angular/angular/commit/f50313f)), closes [#38596](https://github.com/angular/angular/issues/38596)
|
||||
|
||||
|
||||
|
||||
<a name="10.1.4"></a>
|
||||
## 10.1.4 (2020-09-30)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
As contributors and maintainers of the Angular project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
|
||||
|
||||
Communication through any of Angular's channels (GitHub, Gitter, IRC, mailing lists, Google+, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
||||
Communication through any of Angular's channels (GitHub, Discord, Gitter, IRC, mailing lists, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
||||
|
||||
We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Angular project to do the same.
|
||||
|
||||
|
@ -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 [our gitter channel][gitter].
|
||||
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?
|
||||
@ -107,7 +107,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
|
||||
|
||||
```shell
|
||||
git commit -a
|
||||
git commit --all
|
||||
```
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
|
||||
@ -119,20 +119,55 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
|
||||
11. In GitHub, send a pull request to `angular:master`.
|
||||
|
||||
If we ask for changes via code reviews then:
|
||||
|
||||
* Make the required updates.
|
||||
* Re-run the Angular test suites to ensure tests are still passing.
|
||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
#### Addressing review feedback
|
||||
|
||||
```shell
|
||||
git rebase master -i
|
||||
git push -f
|
||||
```
|
||||
If we ask for changes via code reviews then:
|
||||
|
||||
1. Make the required updates to the code.
|
||||
|
||||
2. Re-run the Angular test suites to ensure tests are still passing.
|
||||
|
||||
3. Create a fixup commit and push to your GitHub repository (this will update your Pull Request):
|
||||
|
||||
```shell
|
||||
git commit --all --fixup HEAD
|
||||
git push
|
||||
```
|
||||
|
||||
For more info on working with fixup commits see [here](docs/FIXUP_COMMITS.md).
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
|
||||
##### Updating the commit message
|
||||
|
||||
A reviewer might often suggest changes to a commit message (for example, to add more context for a change or adhere to our [commit message guidelines](#commit)).
|
||||
In order to update the commit message of the last commit on your branch:
|
||||
|
||||
1. Check out your branch:
|
||||
|
||||
```shell
|
||||
git checkout my-fix-branch
|
||||
```
|
||||
|
||||
2. Amend the last commit and modify the commit message:
|
||||
|
||||
```shell
|
||||
git commit --amend
|
||||
```
|
||||
|
||||
3. Push to your GitHub repository:
|
||||
|
||||
```shell
|
||||
git push --force-with-lease
|
||||
```
|
||||
|
||||
> NOTE:<br />
|
||||
> If you need to update the commit message of an earlier commit, you can use `git rebase` in interactive mode.
|
||||
> See the [git docs](https://git-scm.com/docs/git-rebase#_interactive_mode) for more details.
|
||||
|
||||
|
||||
#### After your pull request is merged
|
||||
|
||||
After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:
|
||||
@ -349,7 +384,7 @@ The following documents can help you sort out issues with GitHub accounts and mu
|
||||
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
[dev-doc]: https://github.com/angular/angular/blob/master/docs/DEVELOPER.md
|
||||
[github]: https://github.com/angular/angular
|
||||
[gitter]: https://gitter.im/angular/angular
|
||||
[discord]: https://discord.gg/angular
|
||||
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
|
||||
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
|
||||
[jsfiddle]: http://jsfiddle.net
|
||||
|
@ -1,4 +1,5 @@
|
||||
[](https://circleci.com/gh/angular/workflows/angular/tree/master)
|
||||
[](https://discord.gg/angular)
|
||||
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://www.npmjs.com/@angular/core)
|
||||
|
||||
|
24
WORKSPACE
24
WORKSPACE
@ -8,8 +8,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
# Fetch rules_nodejs so we can install our npm dependencies
|
||||
http_archive(
|
||||
name = "build_bazel_rules_nodejs",
|
||||
sha256 = "84abf7ac4234a70924628baa9a73a5a5cbad944c4358cf9abdb4aab29c9a5b77",
|
||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.7.0/rules_nodejs-1.7.0.tar.gz"],
|
||||
sha256 = "4952ef879704ab4ad6729a29007e7094aef213ea79e9f2e94cbe1c9a753e63ef",
|
||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/2.2.0/rules_nodejs-2.2.0.tar.gz"],
|
||||
)
|
||||
|
||||
# Check the rules_nodejs version and download npm dependencies
|
||||
@ -17,7 +17,7 @@ http_archive(
|
||||
# assert on that.
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install")
|
||||
|
||||
check_rules_nodejs_version(minimum_version_string = "1.7.0")
|
||||
check_rules_nodejs_version(minimum_version_string = "2.2.0")
|
||||
|
||||
# Setup the Node.js toolchain
|
||||
node_repositories(
|
||||
@ -39,23 +39,18 @@ yarn_install(
|
||||
yarn_lock = "//:yarn.lock",
|
||||
)
|
||||
|
||||
# Install all bazel dependencies of the @npm npm packages
|
||||
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
|
||||
|
||||
install_bazel_dependencies()
|
||||
|
||||
# Load angular dependencies
|
||||
load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies")
|
||||
|
||||
rules_angular_dev_dependencies()
|
||||
|
||||
# Load protractor dependencies
|
||||
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
|
||||
load("@npm//@bazel/protractor:package.bzl", "npm_bazel_protractor_dependencies")
|
||||
|
||||
npm_bazel_protractor_dependencies()
|
||||
|
||||
# Load karma dependencies
|
||||
load("@npm_bazel_karma//:package.bzl", "npm_bazel_karma_dependencies")
|
||||
load("@npm//@bazel/karma:package.bzl", "npm_bazel_karma_dependencies")
|
||||
|
||||
npm_bazel_karma_dependencies()
|
||||
|
||||
@ -68,11 +63,6 @@ load("//dev-infra/browsers:browser_repositories.bzl", "browser_repositories")
|
||||
|
||||
browser_repositories()
|
||||
|
||||
# Setup the rules_typescript tooolchain
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
|
||||
|
||||
ts_setup_workspace()
|
||||
|
||||
# Setup the rules_sass toolchain
|
||||
load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
|
||||
|
||||
@ -91,8 +81,8 @@ rbe_autoconfig(
|
||||
# Need to specify a base container digest in order to ensure that we can use the checked-in
|
||||
# platform configurations for the "ubuntu16_04" image. Otherwise the autoconfig rule would
|
||||
# need to pull the image and run it in order determine the toolchain configuration. See:
|
||||
# https://github.com/bazelbuild/bazel-toolchains/blob/3.2.0/configs/ubuntu16_04_clang/versions.bzl
|
||||
base_container_digest = "sha256:5e750dd878df9fcf4e185c6f52b9826090f6e532b097f286913a428290622332",
|
||||
# https://github.com/bazelbuild/bazel-toolchains/blob/3.5.1/configs/ubuntu16_04_clang/versions.bzl
|
||||
base_container_digest = "sha256:f6568d8168b14aafd1b707019927a63c2d37113a03bcee188218f99bd0327ea1",
|
||||
# Note that if you change the `digest`, you might also need to update the
|
||||
# `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest:<digest>
|
||||
# and marketplace.gcr.io/google/rbe-ubuntu16-04:<base_container_digest> have
|
||||
|
@ -119,7 +119,7 @@ The `/deep/` combinator also has the aliases `>>>`, and `::ng-deep`.
|
||||
|
||||
Use `/deep/`, `>>>` and `::ng-deep` only with *emulated* view encapsulation.
|
||||
Emulated is the default and most commonly used view encapsulation. For more information, see the
|
||||
[Controlling view encapsulation](guide/component-styles#view-encapsulation) section.
|
||||
[View Encapsulation](guide/view-encapsulation) section.
|
||||
|
||||
</div>
|
||||
|
||||
@ -267,89 +267,3 @@ as explained in the [CLI wiki](https://github.com/angular/angular-cli/wiki/stori
|
||||
Style strings added to the `@Component.styles` array _must be written in CSS_ because the CLI cannot apply a preprocessor to inline styles.
|
||||
|
||||
</div>
|
||||
|
||||
{@a view-encapsulation}
|
||||
|
||||
## View encapsulation
|
||||
|
||||
As discussed earlier, component CSS styles are encapsulated into the component's view and don't
|
||||
affect the rest of the application.
|
||||
|
||||
To control how this encapsulation happens on a *per
|
||||
component* basis, you can set the *view encapsulation mode* in the component metadata.
|
||||
Choose from the following modes:
|
||||
|
||||
* `ShadowDom` view encapsulation uses the browser's native shadow DOM implementation (see
|
||||
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
||||
on the [MDN](https://developer.mozilla.org) site)
|
||||
to attach a shadow DOM to the component's host element, and then puts the component
|
||||
view inside that shadow DOM. The component's styles are included within the shadow DOM.
|
||||
|
||||
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
|
||||
|
||||
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
|
||||
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
||||
For details, see [Inspecting generated CSS](guide/component-styles#inspect-generated-css) below.
|
||||
|
||||
* `None` means that Angular does no view encapsulation.
|
||||
Angular adds the CSS to the global styles.
|
||||
The scoping rules, isolations, and protections discussed earlier don't apply.
|
||||
This is essentially the same as pasting the component's styles into the HTML.
|
||||
|
||||
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
|
||||
|
||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
|
||||
|
||||
`ShadowDom` view encapsulation only works on browsers that have native support
|
||||
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
||||
[Can I use](http://caniuse.com) site). The support is still limited,
|
||||
which is why `Emulated` view encapsulation is the default mode and recommended
|
||||
in most cases.
|
||||
|
||||
{@a inspect-generated-css}
|
||||
|
||||
## Inspecting generated CSS
|
||||
|
||||
When using emulated view encapsulation, Angular preprocesses
|
||||
all component styles so that they approximate the standard shadow CSS scoping rules.
|
||||
|
||||
In the DOM of a running Angular application with emulated view
|
||||
encapsulation enabled, each DOM element has some extra attributes
|
||||
attached to it:
|
||||
|
||||
<code-example format="">
|
||||
<hero-details _nghost-pmm-5>
|
||||
<h2 _ngcontent-pmm-5>Mister Fantastic</h2>
|
||||
<hero-team _ngcontent-pmm-5 _nghost-pmm-6>
|
||||
<h3 _ngcontent-pmm-6>Team</h3>
|
||||
</hero-team>
|
||||
</hero-detail>
|
||||
|
||||
</code-example>
|
||||
|
||||
There are two kinds of generated attributes:
|
||||
|
||||
* An element that would be a shadow DOM host in native encapsulation has a
|
||||
generated `_nghost` attribute. This is typically the case for component host elements.
|
||||
* An element within a component's view has a `_ngcontent` attribute
|
||||
that identifies to which host's emulated shadow DOM this element belongs.
|
||||
|
||||
The exact values of these attributes aren't important. They are automatically
|
||||
generated and you never refer to them in application code. But they are targeted
|
||||
by the generated component styles, which are in the `<head>` section of the DOM:
|
||||
|
||||
<code-example format="">
|
||||
[_nghost-pmm-5] {
|
||||
display: block;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
h3[_ngcontent-pmm-6] {
|
||||
background-color: white;
|
||||
border: 1px solid #777;
|
||||
}
|
||||
</code-example>
|
||||
|
||||
These styles are post-processed so that each selector is augmented
|
||||
with `_nghost` or `_ngcontent` attribute selectors.
|
||||
These extra selectors enable the scoping rules described in this page.
|
||||
|
@ -156,7 +156,7 @@ The library must be rebuilt on every change.
|
||||
When linking a library, make sure that the build step runs in watch mode, and that the library's `package.json` configuration points at the correct entry points.
|
||||
For example, `main` should point at a JavaScript file, not a TypeScript file.
|
||||
|
||||
## Use TypeScript path mapping for peer dependencies
|
||||
### Use TypeScript path mapping for peer dependencies
|
||||
|
||||
Angular libraries should list all `@angular/*` dependencies as peer dependencies.
|
||||
This ensures that when modules ask for Angular, they all get the exact same module.
|
||||
|
@ -397,7 +397,7 @@ The following code example binds an observable of message strings
|
||||
## Caching HTTP requests
|
||||
|
||||
To [communicate with backend services using HTTP](/guide/http "Communicating with backend services using HTTP"), the `HttpClient` service uses observables and offers the `HTTPClient.get()` method to fetch data from a server.
|
||||
The aynchronous method sends an HTTP request, and returns an observable that emits the requested data for the response.
|
||||
The asynchronous method sends an HTTP request, and returns an observable that emits the requested data for the response.
|
||||
|
||||
As shown in the previous section, you can use the impure `AsyncPipe` to accept an observable as input and subscribe to the input automatically.
|
||||
You can also create an impure pipe to make and cache an HTTP request.
|
||||
|
@ -180,7 +180,7 @@ A form group tracks the status and changes for each of its controls, so if one o
|
||||
|
||||
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroup" header="src/app/profile-editor/profile-editor.component.html (template form group)"></code-example>
|
||||
|
||||
Note that just as a form group contains a group of controls, the *profile form* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value.
|
||||
Note that just as a form group contains a group of controls, the *profileForm* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value.
|
||||
|
||||
**Save form data**
|
||||
|
||||
|
@ -479,6 +479,15 @@ using the `downgradeComponent()` method. The result is an AngularJS
|
||||
<code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="downgradecomponent" header="app.module.ts">
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
By default, Angular change detection will also run on the component for every
|
||||
AngularJS `$digest` cycle. If you wish to only have change detection run when
|
||||
the inputs change, you can set `propagateDigest` to `false` when calling
|
||||
`downgradeComponent()`.
|
||||
|
||||
</div>
|
||||
|
||||
Because `HeroDetailComponent` is an Angular component, you must also add it to the
|
||||
`declarations` in the `AppModule`.
|
||||
|
||||
|
83
aio/content/guide/view-encapsulation.md
Normal file
83
aio/content/guide/view-encapsulation.md
Normal file
@ -0,0 +1,83 @@
|
||||
# View encapsulation
|
||||
|
||||
In Angular, component CSS styles are encapsulated into the component's view and don't
|
||||
affect the rest of the application.
|
||||
|
||||
To control how this encapsulation happens on a *per
|
||||
component* basis, you can set the *view encapsulation mode* in the component metadata.
|
||||
Choose from the following modes:
|
||||
|
||||
* `ShadowDom` view encapsulation uses the browser's native shadow DOM implementation (see
|
||||
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
||||
on the [MDN](https://developer.mozilla.org) site)
|
||||
to attach a shadow DOM to the component's host element, and then puts the component
|
||||
view inside that shadow DOM. The component's styles are included within the shadow DOM.
|
||||
|
||||
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
|
||||
|
||||
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
|
||||
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
||||
For details, see [Inspecting generated CSS](guide/view-encapsulation#inspect-generated-css) below.
|
||||
|
||||
* `None` means that Angular does no view encapsulation.
|
||||
Angular adds the CSS to the global styles.
|
||||
The scoping rules, isolations, and protections discussed earlier don't apply.
|
||||
This is essentially the same as pasting the component's styles into the HTML.
|
||||
|
||||
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
|
||||
|
||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
|
||||
|
||||
`ShadowDom` view encapsulation only works on browsers that have native support
|
||||
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
||||
[Can I use](http://caniuse.com) site). The support is still limited,
|
||||
which is why `Emulated` view encapsulation is the default mode and recommended
|
||||
in most cases.
|
||||
|
||||
{@a inspect-generated-css}
|
||||
|
||||
## Inspecting generated CSS
|
||||
|
||||
When using emulated view encapsulation, Angular preprocesses
|
||||
all component styles so that they approximate the standard shadow CSS scoping rules.
|
||||
|
||||
In the DOM of a running Angular application with emulated view
|
||||
encapsulation enabled, each DOM element has some extra attributes
|
||||
attached to it:
|
||||
|
||||
<code-example format="">
|
||||
<hero-details _nghost-pmm-5>
|
||||
<h2 _ngcontent-pmm-5>Mister Fantastic</h2>
|
||||
<hero-team _ngcontent-pmm-5 _nghost-pmm-6>
|
||||
<h3 _ngcontent-pmm-6>Team</h3>
|
||||
</hero-team>
|
||||
</hero-detail>
|
||||
|
||||
</code-example>
|
||||
|
||||
There are two kinds of generated attributes:
|
||||
|
||||
* An element that would be a shadow DOM host in native encapsulation has a
|
||||
generated `_nghost` attribute. This is typically the case for component host elements.
|
||||
* An element within a component's view has a `_ngcontent` attribute
|
||||
that identifies to which host's emulated shadow DOM this element belongs.
|
||||
|
||||
The exact values of these attributes aren't important. They are automatically
|
||||
generated and you never refer to them in application code. But they are targeted
|
||||
by the generated component styles, which are in the `<head>` section of the DOM:
|
||||
|
||||
<code-example format="">
|
||||
[_nghost-pmm-5] {
|
||||
display: block;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
h3[_ngcontent-pmm-6] {
|
||||
background-color: white;
|
||||
border: 1px solid #777;
|
||||
}
|
||||
</code-example>
|
||||
|
||||
These styles are post-processed so that each selector is augmented
|
||||
with `_nghost` or `_ngcontent` attribute selectors.
|
||||
These extra selectors enable the scoping rules described in this page.
|
Binary file not shown.
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 56 KiB |
@ -458,8 +458,8 @@
|
||||
"name": "Sajeetharan Sinnathurai",
|
||||
"picture": "sajee.jpg",
|
||||
"twitter": "kokkisajee",
|
||||
"website": "https://sajeetharan.herokuapp.com/",
|
||||
"bio": "Sajeetharan is a Developer, Top contributor on stackoverflow for #Angular, ng-SriLanka organizer. He makes use of his extensive knowledge over the past years to contribute to community to make the world a better place.",
|
||||
"website": "https://sajeetharan.com/",
|
||||
"bio": "Sajeetharan is a Cloud Architect, Top contributor on stackoverflow for #Angular, ng-SriLanka organizer. He makes use of his extensive knowledge over the past years to contribute to community to make the world a better place.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"lacolaco": {
|
||||
|
@ -46,7 +46,7 @@ Most Angular code can be written with just the latest JavaScript, using [types](
|
||||
|
||||
<h3>You can sit with us!</h3>
|
||||
|
||||
We want to hear from you. [Report problems or submit suggestions for future docs.](https://github.com/angular/angular/issues/new/choose "Angular GitHub repository new issue form")
|
||||
We want to hear from you. [Report problems or submit suggestions for future docs](https://github.com/angular/angular/issues/new/choose "Angular GitHub repository new issue form").
|
||||
|
||||
Contribute to Angular docs by creating
|
||||
[pull requests](https://github.com/angular/angular/pulls "Angular Github pull requests")
|
||||
|
@ -116,6 +116,11 @@
|
||||
"title": "Component Lifecycle",
|
||||
"tooltip": "Angular calls lifecycle hook methods on directives and components as it creates, changes, and destroys them."
|
||||
},
|
||||
{
|
||||
"url": "guide/view-encapsulation",
|
||||
"title": "View Encapsulation",
|
||||
"tooltip": "Describes how component CSS styles are encapsulated into a component's view."
|
||||
},
|
||||
{
|
||||
"url": "guide/component-interaction",
|
||||
"title": "Component Interaction",
|
||||
@ -126,6 +131,11 @@
|
||||
"title": "Component Styles",
|
||||
"tooltip": "Add CSS styles that are specific to a component."
|
||||
},
|
||||
{
|
||||
"url": "guide/inputs-outputs",
|
||||
"title": "Inputs and Outputs",
|
||||
"tooltip": "Introductory guide to sharing data between parent and child directives or components."
|
||||
},
|
||||
{
|
||||
"url": "guide/dynamic-component-loader",
|
||||
"title": "Dynamic Components",
|
||||
@ -187,11 +197,6 @@
|
||||
"title": "Template reference variables",
|
||||
"tooltip": "Introductory guide to referring to DOM elements within a template."
|
||||
},
|
||||
{
|
||||
"url": "guide/inputs-outputs",
|
||||
"title": "Inputs and Outputs",
|
||||
"tooltip": "Introductory guide to sharing data between parent and child directives or components."
|
||||
},
|
||||
{
|
||||
"url": "guide/template-expression-operators",
|
||||
"title": "Template expression operators",
|
||||
@ -1004,6 +1009,11 @@
|
||||
"title": "Stack Overflow",
|
||||
"tooltip": "Stack Overflow: where the community answers your technical Angular questions."
|
||||
},
|
||||
{
|
||||
"url": "https://discord.gg/angular",
|
||||
"title": "Join Discord",
|
||||
"tooltip": "Join the discussions at Angular Community Discord server."
|
||||
},
|
||||
{
|
||||
"url": "https://gitter.im/angular/angular",
|
||||
"title": "Gitter",
|
||||
|
@ -128,7 +128,8 @@
|
||||
// The below paths are referenced in users projects generated by the CLI
|
||||
{"type": 301, "source": "/config/tsconfig", "destination": "/guide/typescript-configuration"},
|
||||
{"type": 301, "source": "/config/solution-tsconfig", "destination": "https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#solution-style-tsconfig"},
|
||||
{"type": 301, "source": "/config/app-package-json", "destination": "/guide/strict-mode#non-local-side-effects-in-applications"}
|
||||
{"type": 301, "source": "/config/app-package-json", "destination": "/guide/strict-mode#non-local-side-effects-in-applications"},
|
||||
{"type": 301, "source": "/strict", "destination": "/guide/strict-mode"}
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
|
@ -148,6 +148,7 @@
|
||||
"!/styleguide/**",
|
||||
"!/testing",
|
||||
"!/testing/**",
|
||||
"!/config/**"
|
||||
"!/config/**",
|
||||
"!/strict"
|
||||
]
|
||||
}
|
||||
|
@ -64,7 +64,7 @@
|
||||
"tools-lint": "tslint --config \"tools/tslint.json\" --project \"tools/firebase-test-utils\"",
|
||||
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js && yarn firebase-utils-test",
|
||||
"preserve-and-sync": "yarn docs",
|
||||
"serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"",
|
||||
"serve-and-sync": "run-p \"docs-watch --watch-only\" \"start {@}\" --",
|
||||
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
|
||||
"boilerplate:add:viewengine": "yarn boilerplate:add --viewengine",
|
||||
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
|
||||
@ -153,7 +153,7 @@
|
||||
"lunr": "^2.1.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"protractor": "~5.4.4",
|
||||
"puppeteer": "3.3.0",
|
||||
"puppeteer": "5.1.0",
|
||||
"rehype": "^6.0.0",
|
||||
"rehype-slug": "^2.0.0",
|
||||
"remark": "^9.0.0",
|
||||
|
@ -782,7 +782,7 @@ describe('AppComponent', () => {
|
||||
it('should grab focus when the / key is pressed', () => {
|
||||
const searchBox: SearchBoxComponent = fixture.debugElement.query(By.directive(SearchBoxComponent)).componentInstance;
|
||||
spyOn(searchBox, 'focus');
|
||||
window.document.dispatchEvent(new KeyboardEvent('keyup', { 'key': '/' }));
|
||||
window.document.dispatchEvent(new KeyboardEvent('keyup', { key: '/' }));
|
||||
fixture.detectChanges();
|
||||
expect(searchBox.focus).toHaveBeenCalled();
|
||||
});
|
||||
@ -791,7 +791,7 @@ describe('AppComponent', () => {
|
||||
const searchBox: SearchBoxComponent = fixture.debugElement.query(By.directive(SearchBoxComponent)).componentInstance;
|
||||
spyOn(searchBox, 'focus');
|
||||
component.showSearchResults = true;
|
||||
window.document.dispatchEvent(new KeyboardEvent('keyup', { 'key': 'Escape' }));
|
||||
window.document.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));
|
||||
fixture.detectChanges();
|
||||
expect(searchBox.focus).toHaveBeenCalled();
|
||||
});
|
||||
@ -968,23 +968,23 @@ describe('AppComponent', () => {
|
||||
|
||||
// Initially, `isTransitoning` is true.
|
||||
expect(component.isTransitioning).toBe(true);
|
||||
expect(toolbar.classes['transitioning']).toBe(true);
|
||||
expect(toolbar.classes.transitioning).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docRendered');
|
||||
fixture.detectChanges();
|
||||
expect(component.isTransitioning).toBe(false);
|
||||
expect(toolbar.classes['transitioning']).toBeFalsy();
|
||||
expect(toolbar.classes.transitioning).toBeFalsy();
|
||||
|
||||
// While a document is being rendered, `isTransitoning` is set to true.
|
||||
triggerDocViewerEvent('docReady');
|
||||
fixture.detectChanges();
|
||||
expect(component.isTransitioning).toBe(true);
|
||||
expect(toolbar.classes['transitioning']).toBe(true);
|
||||
expect(toolbar.classes.transitioning).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docRendered');
|
||||
fixture.detectChanges();
|
||||
expect(component.isTransitioning).toBe(false);
|
||||
expect(toolbar.classes['transitioning']).toBeFalsy();
|
||||
expect(toolbar.classes.transitioning).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should update the sidenav state as soon as a new document is inserted (but not before)', () => {
|
||||
@ -1031,15 +1031,15 @@ describe('AppComponent', () => {
|
||||
|
||||
navigateTo('guide/pipes');
|
||||
expect(component.pageId).toEqual('guide-pipes');
|
||||
expect(container.properties['id']).toEqual('guide-pipes');
|
||||
expect(container.properties.id).toEqual('guide-pipes');
|
||||
|
||||
navigateTo('news');
|
||||
expect(component.pageId).toEqual('news');
|
||||
expect(container.properties['id']).toEqual('news');
|
||||
expect(container.properties.id).toEqual('news');
|
||||
|
||||
navigateTo('');
|
||||
expect(component.pageId).toEqual('home');
|
||||
expect(container.properties['id']).toEqual('home');
|
||||
expect(container.properties.id).toEqual('home');
|
||||
});
|
||||
|
||||
it('should not be affected by changes to the query', () => {
|
||||
@ -1050,7 +1050,7 @@ describe('AppComponent', () => {
|
||||
navigateTo('guide/other?search=http');
|
||||
|
||||
expect(component.pageId).toEqual('guide-other');
|
||||
expect(container.properties['id']).toEqual('guide-other');
|
||||
expect(container.properties.id).toEqual('guide-other');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1125,7 +1125,7 @@ describe('AppComponent', () => {
|
||||
|
||||
function checkHostClass(type: string, value: string) {
|
||||
const host = fixture.debugElement;
|
||||
const classes: string = host.properties['className'];
|
||||
const classes: string = host.properties.className;
|
||||
const classArray = classes.split(' ').filter(c => c.indexOf(`${type}-`) === 0);
|
||||
expect(classArray.length).toBeLessThanOrEqual(1, `"${classes}" should have only one class matching ${type}-*`);
|
||||
expect(classArray).toEqual([`${type}-${value}`], `"${classes}" should contain ${type}-${value}`);
|
||||
@ -1311,42 +1311,42 @@ class TestHttpClient {
|
||||
|
||||
// tslint:disable:quotemark
|
||||
navJson = {
|
||||
"TopBar": [
|
||||
TopBar: [
|
||||
{
|
||||
"url": "features",
|
||||
"title": "Features"
|
||||
url: 'features',
|
||||
title: 'Features',
|
||||
},
|
||||
{
|
||||
"url": "no-title",
|
||||
"title": "No Title"
|
||||
url: 'no-title',
|
||||
title: 'No Title',
|
||||
},
|
||||
],
|
||||
"SideNav": [
|
||||
SideNav: [
|
||||
{
|
||||
"title": "Core",
|
||||
"tooltip": "Learn the core capabilities of Angular",
|
||||
"children": [
|
||||
title: 'Core',
|
||||
tooltip: 'Learn the core capabilities of Angular',
|
||||
children: [
|
||||
{
|
||||
"url": "guide/pipes",
|
||||
"title": "Pipes",
|
||||
"tooltip": "Pipes transform displayed values within a template."
|
||||
url: 'guide/pipes',
|
||||
title: 'Pipes',
|
||||
tooltip: 'Pipes transform displayed values within a template.',
|
||||
},
|
||||
{
|
||||
"url": "guide/bags",
|
||||
"title": "Bags",
|
||||
"tooltip": "Pack your bags for a code adventure."
|
||||
}
|
||||
]
|
||||
url: 'guide/bags',
|
||||
title: 'Bags',
|
||||
tooltip: 'Pack your bags for a code adventure.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"url": "api",
|
||||
"title": "API",
|
||||
"tooltip": "Details of the Angular classes and values."
|
||||
}
|
||||
url: 'api',
|
||||
title: 'API',
|
||||
tooltip: 'Details of the Angular classes and values.',
|
||||
},
|
||||
],
|
||||
"docVersions": TestHttpClient.docVersions,
|
||||
docVersions: TestHttpClient.docVersions,
|
||||
|
||||
"__versionInfo": TestHttpClient.versionInfo,
|
||||
__versionInfo: TestHttpClient.versionInfo,
|
||||
};
|
||||
|
||||
get(url: string) {
|
||||
|
@ -147,7 +147,7 @@ export class AppComponent implements OnInit {
|
||||
// Compute the version picker list from the current version and the versions in the navigation map
|
||||
combineLatest([
|
||||
this.navigationService.versionInfo,
|
||||
this.navigationService.navigationViews.pipe(map(views => views['docVersions'])),
|
||||
this.navigationService.navigationViews.pipe(map(views => views.docVersions)),
|
||||
]).subscribe(([versionInfo, versions]) => {
|
||||
// TODO(pbd): consider whether we can lookup the stable and next versions from the internet
|
||||
const computedVersions: NavigationNode[] = [
|
||||
@ -167,10 +167,10 @@ export class AppComponent implements OnInit {
|
||||
});
|
||||
|
||||
this.navigationService.navigationViews.subscribe(views => {
|
||||
this.footerNodes = views['Footer'] || [];
|
||||
this.sideNavNodes = views['SideNav'] || [];
|
||||
this.topMenuNodes = views['TopBar'] || [];
|
||||
this.topMenuNarrowNodes = views['TopBarNarrow'] || this.topMenuNodes;
|
||||
this.footerNodes = views.Footer || [];
|
||||
this.sideNavNodes = views.SideNav || [];
|
||||
this.topMenuNodes = views.TopBar || [];
|
||||
this.topMenuNarrowNodes = views.TopBarNarrow || this.topMenuNodes;
|
||||
});
|
||||
|
||||
this.navigationService.versionInfo.subscribe(vi => this.versionInfo = vi);
|
||||
|
@ -223,77 +223,77 @@ class TestApiService {
|
||||
// tslint:disable:quotemark
|
||||
const apiSections: ApiSection[] = [
|
||||
{
|
||||
"name": "common",
|
||||
"title": "common",
|
||||
"path": "api/common",
|
||||
"deprecated": false,
|
||||
"items": [
|
||||
name: 'common',
|
||||
title: 'common',
|
||||
path: 'api/common',
|
||||
deprecated: false,
|
||||
items: [
|
||||
{
|
||||
"name": "class_1",
|
||||
"title": "Class 1",
|
||||
"path": "api/common/class_1",
|
||||
"docType": "class",
|
||||
"stability": "experimental",
|
||||
"securityRisk": false,
|
||||
name: 'class_1',
|
||||
title: 'Class 1',
|
||||
path: 'api/common/class_1',
|
||||
docType: 'class',
|
||||
stability: 'experimental',
|
||||
securityRisk: false,
|
||||
},
|
||||
{
|
||||
"name": "class_2",
|
||||
"title": "Class 2",
|
||||
"path": "api/common/class_2",
|
||||
"docType": "class",
|
||||
"stability": "stable",
|
||||
"securityRisk": false,
|
||||
name: 'class_2',
|
||||
title: 'Class 2',
|
||||
path: 'api/common/class_2',
|
||||
docType: 'class',
|
||||
stability: 'stable',
|
||||
securityRisk: false,
|
||||
},
|
||||
{
|
||||
"name": "directive_1",
|
||||
"title": "Directive 1",
|
||||
"path": "api/common/directive_1",
|
||||
"docType": "directive",
|
||||
"stability": "stable",
|
||||
"securityRisk": true,
|
||||
name: 'directive_1',
|
||||
title: 'Directive 1',
|
||||
path: 'api/common/directive_1',
|
||||
docType: 'directive',
|
||||
stability: 'stable',
|
||||
securityRisk: true,
|
||||
},
|
||||
{
|
||||
"name": "pipe_1",
|
||||
"title": "Pipe 1",
|
||||
"path": "api/common/pipe_1",
|
||||
"docType": "pipe",
|
||||
"stability": "stable",
|
||||
"securityRisk": true,
|
||||
name: 'pipe_1',
|
||||
title: 'Pipe 1',
|
||||
path: 'api/common/pipe_1',
|
||||
docType: 'pipe',
|
||||
stability: 'stable',
|
||||
securityRisk: true,
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "core",
|
||||
"title": "core",
|
||||
"path": "api/core",
|
||||
"deprecated": false,
|
||||
"items": [
|
||||
name: 'core',
|
||||
title: 'core',
|
||||
path: 'api/core',
|
||||
deprecated: false,
|
||||
items: [
|
||||
{
|
||||
"name": "class_3",
|
||||
"title": "Class 3",
|
||||
"path": "api/core/class_3",
|
||||
"docType": "class",
|
||||
"stability": "experimental",
|
||||
"securityRisk": false,
|
||||
name: 'class_3',
|
||||
title: 'Class 3',
|
||||
path: 'api/core/class_3',
|
||||
docType: 'class',
|
||||
stability: 'experimental',
|
||||
securityRisk: false,
|
||||
},
|
||||
{
|
||||
"name": "function_1",
|
||||
"title": "Function 1",
|
||||
"path": "api/core/function 1",
|
||||
"docType": "function",
|
||||
"stability": "deprecated",
|
||||
"securityRisk": true,
|
||||
name: 'function_1',
|
||||
title: 'Function 1',
|
||||
path: 'api/core/function 1',
|
||||
docType: 'function',
|
||||
stability: 'deprecated',
|
||||
securityRisk: true,
|
||||
},
|
||||
{
|
||||
"name": "const_1",
|
||||
"title": "Const 1",
|
||||
"path": "api/core/const_1",
|
||||
"docType": "const",
|
||||
"stability": "stable",
|
||||
"securityRisk": false,
|
||||
}
|
||||
]
|
||||
}
|
||||
name: 'const_1',
|
||||
title: 'Const 1',
|
||||
path: 'api/core/const_1',
|
||||
docType: 'const',
|
||||
stability: 'stable',
|
||||
securityRisk: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
function getApiSections() { return apiSections; }
|
||||
|
@ -67,7 +67,7 @@ export class ApiService implements OnDestroy {
|
||||
* API sections is an array of Angular top modules and metadata about their API documents (items).
|
||||
* Updates `sections` observable
|
||||
*
|
||||
* @param {string} [src] - Name of the api list JSON file
|
||||
* @param [src] - Name of the api list JSON file
|
||||
*/
|
||||
fetchSections(src?: string) {
|
||||
// TODO: get URL by configuration?
|
||||
|
@ -20,13 +20,13 @@ export class PrettyPrinter {
|
||||
}
|
||||
|
||||
private getPrettyPrintOne(): Promise<PrettyPrintOne> {
|
||||
const ppo = (window as any)['prettyPrintOne'];
|
||||
const ppo = (window as any).prettyPrintOne;
|
||||
return ppo ? Promise.resolve(ppo) :
|
||||
// `prettyPrintOne` is not on `window`, which means `prettify.js` has not been loaded yet.
|
||||
// Import it; ad a side-effect it will add `prettyPrintOne` on `window`.
|
||||
import('assets/js/prettify.js' as any)
|
||||
.then(
|
||||
() => (window as any)['prettyPrintOne'],
|
||||
() => (window as any).prettyPrintOne,
|
||||
err => {
|
||||
const msg = `Cannot get prettify.js from server: ${err.message}`;
|
||||
this.logger.error(new Error(msg));
|
||||
@ -37,9 +37,9 @@ export class PrettyPrinter {
|
||||
|
||||
/**
|
||||
* Format code snippet as HTML
|
||||
* @param {string} code - the code snippet to format; should already be HTML encoded
|
||||
* @param {string} [language] - The language of the code to render (could be javascript, html, typescript, etc)
|
||||
* @param {string|number} [linenums] - Whether to display line numbers:
|
||||
* @param code - the code snippet to format; should already be HTML encoded
|
||||
* @param [language] - The language of the code to render (could be javascript, html, typescript, etc)
|
||||
* @param [linenums] - Whether to display line numbers:
|
||||
* - false: don't display
|
||||
* - true: do display
|
||||
* - number: do display but start at the given number
|
||||
|
@ -63,7 +63,7 @@ describe('ContributorListComponent', () => {
|
||||
it('should set the query to the "GDE" group when user selects "GDE"', () => {
|
||||
component = getComponent();
|
||||
component.selectGroup('GDE');
|
||||
expect(locationService.searchResult['group']).toBe('GDE');
|
||||
expect(locationService.searchResult.group).toBe('GDE');
|
||||
});
|
||||
|
||||
it('should set the query to the first group when user selects unknown name', () => {
|
||||
@ -71,7 +71,7 @@ describe('ContributorListComponent', () => {
|
||||
component.selectGroup('GDE'); // a legit group that isn't the first
|
||||
|
||||
component.selectGroup('foo'); // not a legit group name
|
||||
expect(locationService.searchResult['group']).toBe('Angular');
|
||||
expect(locationService.searchResult.group).toBe('Angular');
|
||||
});
|
||||
|
||||
//// Test Helpers ////
|
||||
|
@ -29,7 +29,7 @@ export class ContributorListComponent implements OnInit {
|
||||
private locationService: LocationService) { }
|
||||
|
||||
ngOnInit() {
|
||||
const groupName = this.locationService.search()['group'] || '';
|
||||
const groupName = this.locationService.search().group || '';
|
||||
// no need to unsubscribe because `contributors` completes
|
||||
this.contributorService.contributors
|
||||
.subscribe(grps => {
|
||||
|
@ -63,7 +63,7 @@ describe('ResourceListComponent', () => {
|
||||
it('should set the query to the "education" category when user selects "education"', () => {
|
||||
component = getComponent();
|
||||
component.selectCategory('education');
|
||||
expect(locationService.searchResult['category']).toBe('education');
|
||||
expect(locationService.searchResult.category).toBe('education');
|
||||
});
|
||||
|
||||
it('should set the query to the first category when user selects unknown name', () => {
|
||||
@ -71,7 +71,7 @@ describe('ResourceListComponent', () => {
|
||||
component.selectCategory('education'); // a legit group that isn't the first
|
||||
|
||||
component.selectCategory('foo'); // not a legit group name
|
||||
expect(locationService.searchResult['category']).toBe('development');
|
||||
expect(locationService.searchResult.category).toBe('development');
|
||||
});
|
||||
|
||||
//// Test Helpers ////
|
||||
|
@ -20,7 +20,7 @@ export class ResourceListComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const category = this.locationService.search()['category'] || '';
|
||||
const category = this.locationService.search().category || '';
|
||||
// Not using async pipe because cats appear twice in template
|
||||
// No need to unsubscribe because categories observable completes.
|
||||
this.resourceService.categories.subscribe(cats => {
|
||||
|
@ -86,62 +86,61 @@ describe('ResourceService', () => {
|
||||
});
|
||||
|
||||
function getTestResources() {
|
||||
// tslint:disable:quotemark
|
||||
return {
|
||||
"Cat 3": {
|
||||
"order": 3,
|
||||
"subCategories": {
|
||||
"Cat3 SubCat1": {
|
||||
"order": 2,
|
||||
"resources": {
|
||||
"Cat3 SubCat1 Res1": {
|
||||
"desc": "Meetup in Barcelona, Spain. ",
|
||||
"title": "Angular Beers",
|
||||
"url": "http://www.meetup.com/AngularJS-Beers/"
|
||||
'Cat 3': {
|
||||
order: 3,
|
||||
subCategories: {
|
||||
'Cat3 SubCat1': {
|
||||
order: 2,
|
||||
resources: {
|
||||
'Cat3 SubCat1 Res1': {
|
||||
desc: 'Meetup in Barcelona, Spain. ',
|
||||
title: 'Angular Beers',
|
||||
url: 'http://www.meetup.com/AngularJS-Beers/',
|
||||
},
|
||||
"Cat3 SubCat1 Res2": {
|
||||
"desc": "Angular Camps in Barcelona, Spain.",
|
||||
"title": "Angular Camp",
|
||||
"url": "http://angularcamp.org/"
|
||||
}
|
||||
}
|
||||
'Cat3 SubCat1 Res2': {
|
||||
desc: 'Angular Camps in Barcelona, Spain.',
|
||||
title: 'Angular Camp',
|
||||
url: 'http://angularcamp.org/',
|
||||
},
|
||||
},
|
||||
},
|
||||
"Cat3 SubCat2": {
|
||||
"order": 1,
|
||||
"resources": {
|
||||
"Cat3 SubCat2 Res1": {
|
||||
"desc": "A community index of components and libraries",
|
||||
"title": "Catalog of Angular Components & Libraries",
|
||||
"url": "https://a/b/c"
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"Cat 1": {
|
||||
"order": 1,
|
||||
"subCategories": {
|
||||
"Cat1 SubCat1": {
|
||||
"order": 1,
|
||||
"resources": {
|
||||
"S S S": {
|
||||
"desc": "SSS",
|
||||
"title": "Sssss",
|
||||
"url": "http://s/s/s"
|
||||
'Cat3 SubCat2': {
|
||||
order: 1,
|
||||
resources: {
|
||||
'Cat3 SubCat2 Res1': {
|
||||
desc: 'A community index of components and libraries',
|
||||
title: 'Catalog of Angular Components & Libraries',
|
||||
url: 'https://a/b/c',
|
||||
},
|
||||
"A A A": {
|
||||
"desc": "AAA",
|
||||
"title": "Aaaa",
|
||||
"url": "http://a/a/a"
|
||||
},
|
||||
"Z Z Z": {
|
||||
"desc": "ZZZ",
|
||||
"title": "Zzzzz",
|
||||
"url": "http://z/z/z"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
'Cat 1': {
|
||||
order: 1,
|
||||
subCategories: {
|
||||
'Cat1 SubCat1': {
|
||||
order: 1,
|
||||
resources: {
|
||||
'S S S': {
|
||||
desc: 'SSS',
|
||||
title: 'Sssss',
|
||||
url: 'http://s/s/s',
|
||||
},
|
||||
'A A A': {
|
||||
desc: 'AAA',
|
||||
title: 'Aaaa',
|
||||
url: 'http://a/a/a',
|
||||
},
|
||||
'Z Z Z': {
|
||||
desc: 'ZZZ',
|
||||
title: 'Zzzzz',
|
||||
url: 'http://z/z/z',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ describe('NavigationService', () => {
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
navService.navigationViews.subscribe(views => view = views['sideNav']);
|
||||
navService.navigationViews.subscribe(views => view = views.sideNav);
|
||||
httpMock.expectOne({}).flush({sideNav});
|
||||
});
|
||||
|
||||
@ -254,7 +254,7 @@ describe('NavigationService', () => {
|
||||
{...v, ...{ tooltip: v.title + '.'}})
|
||||
);
|
||||
|
||||
navService.navigationViews.subscribe(views => actualDocVersions = views['docVersions']);
|
||||
navService.navigationViews.subscribe(views => actualDocVersions = views.docVersions);
|
||||
});
|
||||
|
||||
it('should extract the docVersions', () => {
|
||||
|
@ -41,7 +41,7 @@ export class SearchBoxComponent implements AfterViewInit {
|
||||
* When we first show this search box we trigger a search if there is a search query in the URL
|
||||
*/
|
||||
ngAfterViewInit() {
|
||||
const query = this.locationService.search()['search'];
|
||||
const query = this.locationService.search().search;
|
||||
if (query) {
|
||||
this.query = this.decodeQuery(query);
|
||||
this.doSearch();
|
||||
|
@ -26,7 +26,7 @@ function createIndex(loadIndexFn: IndexLoader): lunr.Index {
|
||||
// The lunr typings are missing QueryLexer so we have to add them here manually.
|
||||
const queryLexer = (lunr as any as { QueryLexer: { termSeparator: RegExp } }).QueryLexer;
|
||||
queryLexer.termSeparator = lunr.tokenizer.separator = /\s+/;
|
||||
return lunr(/** @this */function() {
|
||||
return lunr(function() {
|
||||
this.ref('path');
|
||||
this.field('topics', { boost: 15 });
|
||||
this.field('titleWords', { boost: 10 });
|
||||
@ -44,7 +44,7 @@ function handleMessage(message: { data: WebWorkerMessage }): void {
|
||||
const payload = message.data.payload;
|
||||
switch (type) {
|
||||
case 'load-index':
|
||||
makeRequest(SEARCH_TERMS_URL, function(searchInfo: PageInfo[]) {
|
||||
makeRequest(SEARCH_TERMS_URL, (searchInfo: PageInfo[]) => {
|
||||
index = createIndex(loadIndex(searchInfo));
|
||||
postMessage({ type, id, payload: true });
|
||||
});
|
||||
@ -94,7 +94,7 @@ function queryIndex(query: string): PageInfo[] {
|
||||
results = index.search(query + ' ' + titleQuery);
|
||||
}
|
||||
// Map the hits into info about each page to be returned as results
|
||||
return results.map(function(hit) { return pages[hit.ref]; });
|
||||
return results.map(hit => pages[hit.ref]);
|
||||
}
|
||||
} catch (e) {
|
||||
// If the search query cannot be parsed the index throws an error
|
||||
|
@ -11,7 +11,7 @@ export class Deployment {
|
||||
* The deployment mode set from the environment provided at build time;
|
||||
* or overridden by the `mode` query parameter: e.g. `...?mode=archive`
|
||||
*/
|
||||
mode: string = this.location.search()['mode'] || environment.mode;
|
||||
mode: string = this.location.search().mode || environment.mode;
|
||||
|
||||
constructor(private location: LocationService) {}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ export class GaService {
|
||||
private previousUrl: string;
|
||||
|
||||
constructor(@Inject(WindowToken) private window: Window) {
|
||||
this.ga('create', environment['gaId'] , 'auto');
|
||||
this.ga('create', environment.gaId , 'auto');
|
||||
}
|
||||
|
||||
locationChanged(url: string) {
|
||||
@ -34,7 +34,7 @@ export class GaService {
|
||||
}
|
||||
|
||||
ga(...args: any[]) {
|
||||
const gaFn = (this.window as any)['ga'];
|
||||
const gaFn = (this.window as any).ga;
|
||||
if (gaFn) {
|
||||
gaFn(...args);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ export class LocationService {
|
||||
/**
|
||||
* Handle user's anchor click
|
||||
*
|
||||
* @param anchor {HTMLAnchorElement} - the anchor element clicked
|
||||
* @param anchor The anchor element clicked
|
||||
* @param button Number of the mouse button held down. 0 means left or none
|
||||
* @param ctrlKey True if control key held down
|
||||
* @param metaKey True if command or window key held down
|
||||
|
@ -13,14 +13,13 @@ import { Logger } from 'app/shared/logger.service';
|
||||
* 1. Checks for available ServiceWorker updates once instantiated.
|
||||
* 2. Re-checks every 6 hours.
|
||||
* 3. Whenever an update is available, it activates the update.
|
||||
*
|
||||
* @property
|
||||
* `updateActivated` {Observable<string>} - Emit the version hash whenever an update is activated.
|
||||
*/
|
||||
@Injectable()
|
||||
export class SwUpdatesService implements OnDestroy {
|
||||
private checkInterval = 1000 * 60 * 60 * 6; // 6 hours
|
||||
private onDestroy = new Subject<void>();
|
||||
|
||||
/** Emit the version hash whenever an update is activated. */
|
||||
updateActivated: Observable<string>;
|
||||
|
||||
constructor(appRef: ApplicationRef, private logger: Logger, private swu: SwUpdate) {
|
||||
|
@ -38,7 +38,11 @@
|
||||
margin: 0;
|
||||
clear: left;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
color: $blue;
|
||||
@include font-size(14);
|
||||
}
|
||||
.show-all {
|
||||
display: initial;
|
||||
}
|
||||
|
@ -105,9 +105,7 @@
|
||||
|
||||
li {
|
||||
box-sizing: border-box;
|
||||
@include font-size(12);
|
||||
@include line-height(16);
|
||||
padding: 3px 0 3px 12px;
|
||||
padding: 7px 0 7px 12px;
|
||||
position: relative;
|
||||
transition: all 0.3s ease-in-out;
|
||||
|
||||
@ -129,6 +127,7 @@
|
||||
color: lighten($darkgray, 10);
|
||||
overflow: visible;
|
||||
@include font-size(12);
|
||||
@include line-height(16);
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
@ -168,11 +167,11 @@
|
||||
}
|
||||
|
||||
&:first-child:before {
|
||||
top: 13px;
|
||||
top: 15px;
|
||||
}
|
||||
|
||||
&:last-child:before {
|
||||
bottom: calc(100% - 14px);
|
||||
bottom: calc(100% - 15px);
|
||||
}
|
||||
|
||||
&:not(.active):hover a:before {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ApiPage } from './api.po';
|
||||
|
||||
describe('Api pages', function() {
|
||||
describe('Api pages', () => {
|
||||
it('should show direct subclasses of a class', () => {
|
||||
const page = new ApiPage('api/forms/AbstractControlDirective');
|
||||
expect(page.getDescendants('class', true)).toEqual(['ControlContainer', 'NgControl']);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { browser, by, element, ElementFinder } from 'protractor';
|
||||
import { SitePage } from './app.po';
|
||||
|
||||
describe('site App', function() {
|
||||
describe('site App', () => {
|
||||
let page: SitePage;
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -3,7 +3,7 @@ import { SitePage } from './app.po';
|
||||
|
||||
/* tslint:disable:max-line-length */
|
||||
|
||||
describe('onerror handler', function() {
|
||||
describe('onerror handler', () => {
|
||||
let page: SitePage;
|
||||
|
||||
beforeAll(() => {
|
||||
@ -186,7 +186,7 @@ createViewNodes@???`);
|
||||
});
|
||||
|
||||
async function callOnError(message: string, url?: string, line?: number, column?: number, error?: Error) {
|
||||
await browser.executeScript(function() {
|
||||
await browser.executeScript(() => {
|
||||
// reset the ga queue
|
||||
(window as any).ga.q.length = 0;
|
||||
// post the error to the handler
|
||||
|
@ -76,7 +76,7 @@
|
||||
"lite-server": "^2.2.2",
|
||||
"lodash": "^4.16.2",
|
||||
"protractor": "~7.0.0",
|
||||
"puppeteer": "3.3.0",
|
||||
"puppeteer": "5.1.0",
|
||||
"rimraf": "^2.5.4",
|
||||
"rollup": "^1.1.0",
|
||||
"rollup-plugin-commonjs": "^9.2.1",
|
||||
|
@ -4336,6 +4336,11 @@ dev-ip@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
|
||||
|
||||
devtools-protocol@0.0.767361:
|
||||
version "0.0.767361"
|
||||
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.767361.tgz#5977f2558b84f9df36f62501bdddb82f3ae7b66b"
|
||||
integrity sha512-ziRTdhEVQ9jEwedaUaXZ7kl9w9TF/7A3SXQ0XuqrJB+hMS62POHZUWTbumDN2ehRTfvWqTPc2Jw4gUl/jggmHA==
|
||||
|
||||
dezalgo@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
|
||||
@ -7704,6 +7709,11 @@ mitt@^1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d"
|
||||
integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==
|
||||
|
||||
mitt@^2.0.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
|
||||
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.0.tgz#47a8732ba97799457c8c1eca28f95132d7e8150a"
|
||||
@ -8759,7 +8769,7 @@ pkg-dir@^3.0.0:
|
||||
dependencies:
|
||||
find-up "^3.0.0"
|
||||
|
||||
pkg-dir@^4.1.0:
|
||||
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
|
||||
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
|
||||
@ -9363,15 +9373,18 @@ punycode@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
puppeteer@3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-3.3.0.tgz#95839af9fdc0aa4de7e5ee073a4c0adeb9e2d3d7"
|
||||
integrity sha512-23zNqRltZ1PPoK28uRefWJ/zKb5Jhnzbbwbpcna2o5+QMn17F0khq5s1bdH3vPlyj+J36pubccR8wiNA/VE0Vw==
|
||||
puppeteer@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.1.0.tgz#e7bae2caa6e3a13a622755e4c27689d9812c38ca"
|
||||
integrity sha512-IZBFG8XcA+oHxYo5rEpJI/HQignUis2XPijPoFpNxla2O+WufonGsUsSqrhRXgBKOME5zNfhRdUY2LvxAiKlhw==
|
||||
dependencies:
|
||||
debug "^4.1.0"
|
||||
devtools-protocol "0.0.767361"
|
||||
extract-zip "^2.0.0"
|
||||
https-proxy-agent "^4.0.0"
|
||||
mime "^2.0.3"
|
||||
mitt "^2.0.1"
|
||||
pkg-dir "^4.2.0"
|
||||
progress "^2.0.1"
|
||||
proxy-from-env "^1.0.0"
|
||||
rimraf "^3.0.2"
|
||||
|
@ -12,12 +12,16 @@
|
||||
{% for option in doc.members %}
|
||||
<a id="{$ option.anchor $}"></a>
|
||||
<table class="is-full-width option-table">
|
||||
<thead><tr><th>
|
||||
<div class="with-github-links">
|
||||
<h3>{$ option.name $}</h3>
|
||||
{$ github.githubLinks(option, versionInfo) $}
|
||||
</div>
|
||||
</th></tr></thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<div class="with-github-links">
|
||||
<h3>{$ option.name $}</h3>
|
||||
{$ github.githubLinks(option, versionInfo) $}
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
@ -26,8 +30,9 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code-example language="ts" hideCopy="true" class="no-box api-heading{% if option.deprecated %} deprecated-api-item{% endif %}">
|
||||
{$ option.name $}: {$ option.type | escape $}
|
||||
<code-example language="ts" hideCopy="true"
|
||||
class="no-box api-heading{% if option.deprecated %} deprecated-api-item{% endif %}">
|
||||
{$ option.name $}{%- if option.isOptional %}?{% endif -%}: {$ option.type | escape $}
|
||||
</code-example>
|
||||
</td>
|
||||
</tr>
|
||||
@ -46,4 +51,4 @@
|
||||
</table>
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
@ -10,7 +10,7 @@
|
||||
<tr class="option">
|
||||
<td>
|
||||
<a class="code-anchor" href="{$ doc.path $}#{$ option.anchor | urlencode $}">
|
||||
<code>{$ option.name $}</code>
|
||||
<code>{$ option.name $}{%- if option.isOptional %}?{% endif -%}</code>
|
||||
</a>
|
||||
</td>
|
||||
<td>{$ option.shortDescription | marked $}</td>
|
||||
|
@ -132,11 +132,11 @@
|
||||
<summary>
|
||||
<div class="icon-action-header">
|
||||
<h4 class="no-anchor">{$ method.overloads.length $} overloads...</h4>
|
||||
<a>
|
||||
<span class="actions">
|
||||
<span class="show-all">Show All</span>
|
||||
<span class="collapse-all">Hide All</span>
|
||||
<i class="material-icons expand">expand_more</i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="detail-contents">
|
||||
|
120
aio/tslint.json
120
aio/tslint.json
@ -11,32 +11,16 @@
|
||||
]
|
||||
},
|
||||
"array-type": false,
|
||||
"arrow-parens": false,
|
||||
"arrow-return-shorthand": true,
|
||||
"ban": [
|
||||
true,
|
||||
{"name": "fdescribe", "message": "Don't keep jasmine focus methods."},
|
||||
{"name": "fit", "message": "Don't keep jasmine focus methods."}
|
||||
],
|
||||
"component-class-suffix": true,
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"aio",
|
||||
"kebab-case"
|
||||
],
|
||||
"contextual-lifecycle": true,
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warn"
|
||||
"severity": "warning"
|
||||
},
|
||||
"directive-class-suffix": true,
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"aio",
|
||||
"camelCase"
|
||||
],
|
||||
"eofline": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
@ -48,13 +32,11 @@
|
||||
"spaces"
|
||||
]
|
||||
},
|
||||
"interface-name": false,
|
||||
"max-classes-per-file": false,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
@ -66,8 +48,8 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-conflicting-lifecycle": true,
|
||||
"no-consecutive-blank-lines": false,
|
||||
// TODO(gkalpak): Fix the code and enable this to align with CLI. (Failures: 114)
|
||||
// "no-any": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
@ -77,24 +59,20 @@
|
||||
"trace"
|
||||
],
|
||||
"no-empty": false,
|
||||
"no-host-metadata-property": true,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-input-rename": true,
|
||||
"no-inputs-metadata-property": true,
|
||||
"no-output-native": true,
|
||||
"no-output-on-prefix": true,
|
||||
"no-output-rename": true,
|
||||
"no-outputs-metadata-property": true,
|
||||
"no-string-literal": false,
|
||||
// TODO(gkalpak): Fix the code and enable this to align with CLI. (Failures: 59)
|
||||
// "no-non-null-assertion": true,
|
||||
"no-redundant-jsdoc": true,
|
||||
// TODO(gkalpak): Fix the code and remove this to align with CLI.
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-key-quotes": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"only-arrow-functions": false,
|
||||
"ordered-imports": false,
|
||||
"object-literal-key-quotes": [
|
||||
true,
|
||||
"as-needed"
|
||||
],
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
@ -113,9 +91,11 @@
|
||||
"named": "never"
|
||||
}
|
||||
},
|
||||
"template-banana-in-box": true,
|
||||
"template-no-negated-async": true,
|
||||
"trailing-comma": false,
|
||||
// TODO(gkalpak): Fix the code and enable this to align with CLI. (Failures: 243)
|
||||
// "typedef": [
|
||||
// true,
|
||||
// "call-signature"
|
||||
// ],
|
||||
"typedef-whitespace": {
|
||||
"options": [
|
||||
{
|
||||
@ -134,26 +114,15 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"use-lifecycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"variable-name": [
|
||||
true,
|
||||
"allow-leading-underscore",
|
||||
"allow-pascal-case",
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"require-const-for-all-caps"
|
||||
],
|
||||
"template-accessibility-alt-text": true,
|
||||
"template-accessibility-elements-content": true,
|
||||
"template-accessibility-label-for": true,
|
||||
"template-accessibility-tabindex-no-positive": true,
|
||||
"template-accessibility-table-scope": true,
|
||||
"template-accessibility-valid-aria": true,
|
||||
"template-click-events-have-key-events": true,
|
||||
"template-mouse-events-have-key-events": true,
|
||||
"template-no-autofocus": true,
|
||||
"template-no-distracting-elements": true,
|
||||
"variable-name": {
|
||||
"options": [
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"allow-leading-underscore",
|
||||
"allow-pascal-case",
|
||||
"require-const-for-all-caps"
|
||||
]
|
||||
},
|
||||
"whitespace": {
|
||||
"options": [
|
||||
"check-branch",
|
||||
@ -163,6 +132,43 @@
|
||||
"check-type",
|
||||
"check-typecast"
|
||||
]
|
||||
}
|
||||
},
|
||||
"component-class-suffix": true,
|
||||
"contextual-lifecycle": true,
|
||||
"directive-class-suffix": true,
|
||||
"no-conflicting-lifecycle": true,
|
||||
"no-host-metadata-property": true,
|
||||
"no-input-rename": true,
|
||||
"no-inputs-metadata-property": true,
|
||||
"no-output-native": true,
|
||||
"no-output-on-prefix": true,
|
||||
"no-output-rename": true,
|
||||
"no-outputs-metadata-property": true,
|
||||
"template-accessibility-alt-text": true,
|
||||
"template-accessibility-elements-content": true,
|
||||
"template-accessibility-label-for": true,
|
||||
"template-accessibility-tabindex-no-positive": true,
|
||||
"template-accessibility-table-scope": true,
|
||||
"template-accessibility-valid-aria": true,
|
||||
"template-banana-in-box": true,
|
||||
"template-click-events-have-key-events": true,
|
||||
"template-mouse-events-have-key-events": true,
|
||||
"template-no-autofocus": true,
|
||||
"template-no-distracting-elements": true,
|
||||
"template-no-negated-async": true,
|
||||
"use-lifecycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"aio",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"aio",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -4509,6 +4509,11 @@ detect-node@^2.0.4:
|
||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
|
||||
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
|
||||
|
||||
devtools-protocol@0.0.767361:
|
||||
version "0.0.767361"
|
||||
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.767361.tgz#5977f2558b84f9df36f62501bdddb82f3ae7b66b"
|
||||
integrity sha512-ziRTdhEVQ9jEwedaUaXZ7kl9w9TF/7A3SXQ0XuqrJB+hMS62POHZUWTbumDN2ehRTfvWqTPc2Jw4gUl/jggmHA==
|
||||
|
||||
dezalgo@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
|
||||
@ -8926,6 +8931,11 @@ mississippi@^3.0.0:
|
||||
stream-each "^1.1.0"
|
||||
through2 "^2.0.0"
|
||||
|
||||
mitt@^2.0.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
|
||||
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||
@ -10040,7 +10050,7 @@ pkg-dir@^3.0.0:
|
||||
dependencies:
|
||||
find-up "^3.0.0"
|
||||
|
||||
pkg-dir@^4.1.0:
|
||||
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
|
||||
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
|
||||
@ -10695,15 +10705,18 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
puppeteer@3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-3.3.0.tgz#95839af9fdc0aa4de7e5ee073a4c0adeb9e2d3d7"
|
||||
integrity sha512-23zNqRltZ1PPoK28uRefWJ/zKb5Jhnzbbwbpcna2o5+QMn17F0khq5s1bdH3vPlyj+J36pubccR8wiNA/VE0Vw==
|
||||
puppeteer@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.1.0.tgz#e7bae2caa6e3a13a622755e4c27689d9812c38ca"
|
||||
integrity sha512-IZBFG8XcA+oHxYo5rEpJI/HQignUis2XPijPoFpNxla2O+WufonGsUsSqrhRXgBKOME5zNfhRdUY2LvxAiKlhw==
|
||||
dependencies:
|
||||
debug "^4.1.0"
|
||||
devtools-protocol "0.0.767361"
|
||||
extract-zip "^2.0.0"
|
||||
https-proxy-agent "^4.0.0"
|
||||
mime "^2.0.3"
|
||||
mitt "^2.0.1"
|
||||
pkg-dir "^4.2.0"
|
||||
progress "^2.0.1"
|
||||
proxy-from-env "^1.0.0"
|
||||
rimraf "^3.0.2"
|
||||
|
@ -1,5 +1,5 @@
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "cli",
|
||||
@ -11,6 +11,7 @@ ts_library(
|
||||
"//dev-infra/caretaker",
|
||||
"//dev-infra/commit-message",
|
||||
"//dev-infra/format",
|
||||
"//dev-infra/ngbot",
|
||||
"//dev-infra/pr",
|
||||
"//dev-infra/pullapprove",
|
||||
"//dev-infra/release",
|
||||
@ -48,7 +49,7 @@ pkg_npm(
|
||||
# substitutions to replace these in the published version of dev-infra.
|
||||
"//dev-infra/": "@npm_angular_dev_infra_private//",
|
||||
"//packages/benchpress": "@npm//@angular/benchpress",
|
||||
"//packages/bazel/": "@npm_angular_bazel//",
|
||||
"//packages/bazel": "@npm//@angular/bazel",
|
||||
"//packages/zone.js/bundles:zone.umd.js": "@npm//:node_modules/zone.js/dist/zone.js",
|
||||
"//packages/core": "@npm//@angular/core",
|
||||
"//packages/platform-browser": "@npm//@angular/platform-browser",
|
||||
@ -56,7 +57,7 @@ pkg_npm(
|
||||
# This substitution is particularly verbose because we need to make sure
|
||||
# that only things available via Angular Bazel are imported from
|
||||
# tools/defaults.bzl.
|
||||
"load\(\"//tools:defaults.bzl\", \"ng_module\"\)": "load(\"@npm_angular_bazel//:index.bzl\", \"ng_module\")",
|
||||
"load\(\"//tools:defaults.bzl\", \"ng_module\"\)": "load(\"@npm//@angular/bazel:index.bzl\", \"ng_module\")",
|
||||
},
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_protractor//:index.bzl", "protractor_web_test_suite")
|
||||
load("@npm//@bazel/protractor:index.bzl", "protractor_web_test_suite")
|
||||
|
||||
"""
|
||||
Macro that can be used to define a benchmark test. This differentiates from
|
||||
|
@ -1,6 +1,6 @@
|
||||
load("//dev-infra/benchmark/ng_rollup_bundle:ng_rollup_bundle.bzl", "ng_rollup_bundle")
|
||||
load("//tools:defaults.bzl", "ng_module")
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_devserver", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_devserver", "ts_library")
|
||||
load(":benchmark_test.bzl", "benchmark_test")
|
||||
|
||||
def copy_default_file(origin, destination):
|
||||
|
@ -1,6 +1,6 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "driver-utilities",
|
||||
|
@ -4,8 +4,8 @@
|
||||
# found in the LICENSE file at https://angular.io/license
|
||||
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "npm_package_bin")
|
||||
load("@npm_bazel_terser//:index.bzl", "terser_minified")
|
||||
load("@npm_bazel_rollup//:index.bzl", "rollup_bundle")
|
||||
load("@npm//@bazel/terser:index.bzl", "terser_minified")
|
||||
load("@npm//@bazel/rollup:index.bzl", "rollup_bundle")
|
||||
load("//dev-infra/bazel:expand_template.bzl", "expand_template")
|
||||
|
||||
def ng_rollup_bundle(
|
||||
|
@ -12,47 +12,47 @@ def define_chromium_repositories():
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromium_amd64",
|
||||
licenses = ["notice"], # BSD 3-clause (maybe more?)
|
||||
sha256 = "2cfd74ee58c79d8b7aada05c899a930967e2fd8bb0186582cde02c7340863f64",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/756066/chrome-linux.zip"],
|
||||
sha256 = "0e303931d9c3e065a160f5d31f1178c647f0748fb0b58b1945b84b04fe1c1165",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/768968/chrome-linux.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromium_macos",
|
||||
licenses = ["notice"], # BSD 3-clause (maybe more?)
|
||||
sha256 = "b841ec5ad03b08422d97593fc719f1c5b038703388ad65e6cd8cc8272d58958c",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/756053/chrome-mac.zip"],
|
||||
sha256 = "39118c96db1b3fdb0129f434912a329c5ca07d3a1c6c6cda673d3383d83e2f9a",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/768968/chrome-mac.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromium_windows",
|
||||
licenses = ["notice"], # BSD 3-clause (maybe more?)
|
||||
sha256 = "4683d7ac88dfec4b98d1da3012ecc8e42cc8c1a560a7b95589ad4cc96bf90fcb",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/756065/chrome-win.zip"],
|
||||
sha256 = "3429746fa80c917c6f4d5d96aba4e58894b905a2b8392e43ddb470c5ba612d60",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/768975/chrome-win.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromedriver_amd64",
|
||||
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
|
||||
sha256 = "95dded16000b82e31445361da7d251ed707e027a4b61e9a3ec5fbd1cc2f62bb1",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/756066/chromedriver_linux64.zip"],
|
||||
sha256 = "f6b9852031d185739a2c1816508fe8158eb92782d13e831b8345957ef2506fe8",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/768968/chromedriver_linux64.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromedriver_macos",
|
||||
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
|
||||
sha256 = "17260e9b2222b0c905a1861285210192baef830f4281778903e7cebb8db683cc",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/756053/chromedriver_mac64.zip"],
|
||||
sha256 = "aa0124085146556d5d32ad172670e5dcef79b7429380112ad02898047ba7a8b7",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/768968/chromedriver_mac64.zip"],
|
||||
)
|
||||
|
||||
platform_http_file(
|
||||
name = "org_chromium_chromedriver_windows",
|
||||
licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT
|
||||
sha256 = "de1423b2d69f96e451e902d686e8d471610d786c345a8de59dd1a5a436e45fc2",
|
||||
# 83.0.4103
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/756065/chromedriver_win32.zip"],
|
||||
sha256 = "c4b04fd263e757d3aa99c596832f2c414f9f00e80d2769590e2b9044072b140e",
|
||||
# 84.0.4147
|
||||
urls = ["https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win/768975/chromedriver_win32.zip"],
|
||||
)
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "caretaker",
|
||||
@ -8,6 +8,7 @@ ts_library(
|
||||
module_name = "@angular/dev-infra-private/caretaker",
|
||||
visibility = ["//dev-infra:__subpackages__"],
|
||||
deps = [
|
||||
"//dev-infra/release/versioning",
|
||||
"//dev-infra/utils",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/node-fetch",
|
||||
|
@ -7,52 +7,55 @@
|
||||
*/
|
||||
|
||||
import fetch from 'node-fetch';
|
||||
import {fetchActiveReleaseTrains} from '../../release/versioning/index';
|
||||
|
||||
import {bold, green, info, red} from '../../utils/console';
|
||||
import {bold, debug, info} from '../../utils/console';
|
||||
import {GitClient} from '../../utils/git';
|
||||
|
||||
|
||||
/** The results of checking the status of CI. */
|
||||
interface StatusCheckResult {
|
||||
status: 'success'|'failed'|'canceled'|'infrastructure_fail'|'timedout'|'failed'|'no_tests';
|
||||
timestamp: Date;
|
||||
buildUrl: string;
|
||||
status: 'success'|'failed';
|
||||
}
|
||||
|
||||
/** Retrieve and log status of CI for the project. */
|
||||
export async function printCiStatus(git: GitClient) {
|
||||
const releaseTrains = await fetchActiveReleaseTrains({api: git.github, ...git.remoteConfig});
|
||||
|
||||
info.group(bold(`CI`));
|
||||
// TODO(josephperrott): Expand list of branches checked to all active branches.
|
||||
await printStatus(git, 'master');
|
||||
for (const [trainName, train] of Object.entries(releaseTrains)) {
|
||||
if (train === null) {
|
||||
debug(`No active release train for ${trainName}`);
|
||||
continue;
|
||||
}
|
||||
const status = await getStatusOfBranch(git, train.branchName);
|
||||
await printStatus(`${trainName.padEnd(6)} (${train.branchName})`, status);
|
||||
}
|
||||
info.groupEnd();
|
||||
info();
|
||||
}
|
||||
|
||||
/** Log the status of CI for a given branch to the console. */
|
||||
async function printStatus(git: GitClient, branch: string) {
|
||||
const result = await getStatusOfBranch(git, branch);
|
||||
const branchName = branch.padEnd(10);
|
||||
if (result === null) {
|
||||
async function printStatus(label: string, status: StatusCheckResult|null) {
|
||||
const branchName = label.padEnd(16);
|
||||
if (status === null) {
|
||||
info(`${branchName} was not found on CircleCI`);
|
||||
} else if (result.status === 'success') {
|
||||
} else if (status.status === 'success') {
|
||||
info(`${branchName} ✅`);
|
||||
} else {
|
||||
info(`${branchName} ❌ (Ran at: ${result.timestamp.toLocaleString()})`);
|
||||
info(`${branchName} ❌`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the CI status of a given branch from CircleCI. */
|
||||
async function getStatusOfBranch(git: GitClient, branch: string): Promise<StatusCheckResult|null> {
|
||||
const {owner, name} = git.remoteConfig;
|
||||
const url = `https://circleci.com/api/v1.1/project/gh/${owner}/${name}/tree/${
|
||||
branch}?limit=1&filter=completed&shallow=true`;
|
||||
const result = (await fetch(url).then(result => result.json()))?.[0];
|
||||
const url = `https://circleci.com/gh/${owner}/${name}/tree/${branch}.svg?style=shield`;
|
||||
const result = await fetch(url).then(result => result.text());
|
||||
|
||||
if (result) {
|
||||
if (result && !result.includes('no builds')) {
|
||||
return {
|
||||
status: result.outcome,
|
||||
timestamp: new Date(result.stop_time),
|
||||
buildUrl: result.build_url
|
||||
status: result.includes('passing') ? 'success' : 'failed',
|
||||
};
|
||||
}
|
||||
return null;
|
||||
|
@ -44,7 +44,8 @@ export async function printG3Comparison(git: GitClient) {
|
||||
/** Url of the ref for fetching master and g3 branches. */
|
||||
const refUrl = `https://github.com/${git.remoteConfig.owner}/${git.remoteConfig.name}.git`;
|
||||
/** The result fo the fetch command. */
|
||||
const fetchResult = git.runGraceful(['fetch', refUrl, `master:${masterRef}`, `g3:${g3Ref}`]);
|
||||
const fetchResult =
|
||||
git.runGraceful(['fetch', '-q', refUrl, `master:${masterRef}`, `g3:${g3Ref}`]);
|
||||
|
||||
// If the upstream repository does not have a g3 branch to compare to, skip the comparison.
|
||||
if (fetchResult.status !== 0) {
|
||||
@ -118,6 +119,6 @@ export async function printG3Comparison(git: GitClient) {
|
||||
/** Determine whether the file name passes both include and exclude checks. */
|
||||
function checkMatchAgainstIncludeAndExclude(
|
||||
file: string, includes: string[], excludes: string[]) {
|
||||
return multimatch(multimatch(file, includes), excludes, {flipNegate: true}).length !== 0;
|
||||
return multimatch(file, includes).length >= 1 && multimatch(file, excludes).length === 0;
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,17 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {alias, params, types} from 'typed-graphqlify';
|
||||
import {alias, onUnion, params, types} from 'typed-graphqlify';
|
||||
|
||||
import {bold, debug, info} from '../../utils/console';
|
||||
import {GitClient} from '../../utils/git';
|
||||
import {CaretakerConfig} from '../config';
|
||||
|
||||
/**
|
||||
* Cap the returned issues in the queries to an arbitrary 100. At that point, caretaker has a lot
|
||||
* of work to do and showing more than that isn't really useful.
|
||||
*/
|
||||
const MAX_RETURNED_ISSUES = 20;
|
||||
|
||||
/** Retrieve the number of matching issues for each github query. */
|
||||
export async function printGithubTasks(git: GitClient, config?: CaretakerConfig) {
|
||||
@ -19,7 +24,7 @@ export async function printGithubTasks(git: GitClient, config?: CaretakerConfig)
|
||||
debug('No github queries defined in the configuration, skipping.');
|
||||
return;
|
||||
}
|
||||
info.group(bold('Github Tasks'));
|
||||
info.group(bold(`Github Tasks`));
|
||||
await getGithubInfo(git, config);
|
||||
info.groupEnd();
|
||||
info();
|
||||
@ -28,7 +33,12 @@ export async function printGithubTasks(git: GitClient, config?: CaretakerConfig)
|
||||
/** Retrieve query match counts and log discovered counts to the console. */
|
||||
async function getGithubInfo(git: GitClient, {githubQueries: queries = []}: CaretakerConfig) {
|
||||
/** The query object for graphql. */
|
||||
const graphQlQuery: {[key: string]: {issueCount: number}} = {};
|
||||
const graphQlQuery: {
|
||||
[key: string]: {
|
||||
issueCount: number,
|
||||
nodes: Array<{url: string}>,
|
||||
}
|
||||
} = {};
|
||||
/** The Github search filter for the configured repository. */
|
||||
const repoFilter = `repo:${git.remoteConfig.owner}/${git.remoteConfig.name}`;
|
||||
queries.forEach(({name, query}) => {
|
||||
@ -37,14 +47,37 @@ async function getGithubInfo(git: GitClient, {githubQueries: queries = []}: Care
|
||||
graphQlQuery[queryKey] = params(
|
||||
{
|
||||
type: 'ISSUE',
|
||||
first: MAX_RETURNED_ISSUES,
|
||||
query: `"${repoFilter} ${query.replace(/"/g, '\\"')}"`,
|
||||
},
|
||||
{issueCount: types.number},
|
||||
{
|
||||
issueCount: types.number,
|
||||
nodes: [{...onUnion({
|
||||
PullRequest: {
|
||||
url: types.string,
|
||||
},
|
||||
Issue: {
|
||||
url: types.string,
|
||||
},
|
||||
})}],
|
||||
},
|
||||
);
|
||||
});
|
||||
/** The results of the generated github query. */
|
||||
const results = await git.github.graphql.query(graphQlQuery);
|
||||
Object.values(results).forEach((result, i) => {
|
||||
info(`${queries[i]?.name.padEnd(25)} ${result.issueCount}`);
|
||||
if (result.issueCount > 0) {
|
||||
const {owner, name: repo} = git.remoteConfig;
|
||||
const url = encodeURI(`https://github.com/${owner}/${repo}/issues?q=${queries[i]?.query}`);
|
||||
info.group(`${url}`);
|
||||
if (result.nodes.length === MAX_RETURNED_ISSUES && result.nodes.length < result.issueCount) {
|
||||
info(`(first ${MAX_RETURNED_ISSUES})`);
|
||||
}
|
||||
for (const node of result.nodes) {
|
||||
info(`- ${node.url}`);
|
||||
}
|
||||
info.groupEnd();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import {buildReleaseParser} from './release/cli';
|
||||
import {buildPrParser} from './pr/cli';
|
||||
import {captureLogOutputForCommand} from './utils/console';
|
||||
import {buildCaretakerParser} from './caretaker/cli';
|
||||
import {buildNgbotParser} from './ngbot/cli';
|
||||
|
||||
yargs.scriptName('ng-dev')
|
||||
.middleware(captureLogOutputForCommand)
|
||||
@ -27,6 +28,7 @@ yargs.scriptName('ng-dev')
|
||||
.command('release <command>', '', buildReleaseParser)
|
||||
.command('ts-circular-deps <command>', '', tsCircularDependenciesBuilder)
|
||||
.command('caretaker <command>', '', buildCaretakerParser)
|
||||
.command('ngbot <command>', false, buildNgbotParser)
|
||||
.wrap(120)
|
||||
.strict()
|
||||
.parse();
|
||||
|
@ -1,5 +1,5 @@
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "commit-message",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "format",
|
||||
|
19
dev-infra/ngbot/BUILD.bazel
Normal file
19
dev-infra/ngbot/BUILD.bazel
Normal file
@ -0,0 +1,19 @@
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "ngbot",
|
||||
srcs = [
|
||||
"cli.ts",
|
||||
"verify.ts",
|
||||
],
|
||||
module_name = "@angular/dev-infra-private/ngbot",
|
||||
visibility = ["//dev-infra:__subpackages__"],
|
||||
deps = [
|
||||
"//dev-infra/utils",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/yaml",
|
||||
"@npm//@types/yargs",
|
||||
"@npm//yaml",
|
||||
"@npm//yargs",
|
||||
],
|
||||
)
|
19
dev-infra/ngbot/cli.ts
Normal file
19
dev-infra/ngbot/cli.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @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.io/license
|
||||
*/
|
||||
import * as yargs from 'yargs';
|
||||
import {verify} from './verify';
|
||||
|
||||
/** Build the parser for the NgBot commands. */
|
||||
export function buildNgbotParser(localYargs: yargs.Argv) {
|
||||
return localYargs.help().strict().demandCommand().command(
|
||||
'verify', 'Verify the NgBot config', {}, () => verify());
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
buildNgbotParser(yargs).parse();
|
||||
}
|
31
dev-infra/ngbot/verify.ts
Normal file
31
dev-infra/ngbot/verify.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @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.io/license
|
||||
*/
|
||||
import {readFileSync} from 'fs';
|
||||
import {resolve} from 'path';
|
||||
import {parse as parseYaml} from 'yaml';
|
||||
|
||||
import {getRepoBaseDir} from '../utils/config';
|
||||
import {error, green, info, red} from '../utils/console';
|
||||
|
||||
export function verify() {
|
||||
/** Full path to NgBot config file */
|
||||
const NGBOT_CONFIG_YAML_PATH = resolve(getRepoBaseDir(), '.github/angular-robot.yml');
|
||||
|
||||
/** The NgBot config file */
|
||||
const ngBotYaml = readFileSync(NGBOT_CONFIG_YAML_PATH, 'utf8');
|
||||
|
||||
try {
|
||||
// Try parsing the config file to verify that the syntax is correct.
|
||||
parseYaml(ngBotYaml);
|
||||
info(`${green('√')} Valid NgBot YAML config`);
|
||||
} catch (e) {
|
||||
error(`${red('!')} Invalid NgBot YAML config`);
|
||||
error(e);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "pr",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "checkout",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "common",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "discover-new-conflicts",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
ts_library(
|
||||
|
@ -41,8 +41,8 @@ export async function getDefaultTargetLabelConfiguration(
|
||||
// allow merging of PRs with `target: major`.
|
||||
if (!next.isMajor) {
|
||||
throw new InvalidTargetLabelError(
|
||||
`Unable to merge pull request. The "${nextBranchName}" branch will be ` +
|
||||
`released as a minor version.`);
|
||||
`Unable to merge pull request. The "${nextBranchName}" branch will be released as ` +
|
||||
'a minor version.');
|
||||
}
|
||||
return [nextBranchName];
|
||||
},
|
||||
|
@ -30,8 +30,8 @@ export async function assertActiveLtsBranch(
|
||||
const ltsNpmTag = getLtsNpmDistTagOfMajor(version.major);
|
||||
const ltsVersion = semver.parse(distTags[ltsNpmTag]);
|
||||
|
||||
// Ensure that there is a LTS version tagged for the given version-branch major. e.g.
|
||||
// if the version branch is `9.2.x` then we want to make sure that there is a LTS
|
||||
// Ensure that there is an LTS version tagged for the given version-branch major. e.g.
|
||||
// if the version branch is `9.2.x` then we want to make sure that there is an LTS
|
||||
// version tagged in NPM for `v9`, following the `v{major}-lts` tag convention.
|
||||
if (ltsVersion === null) {
|
||||
throw new InvalidTargetBranchError(`No LTS version tagged for v${version.major} in NPM.`);
|
||||
|
@ -33,7 +33,7 @@ export async function mergePullRequest(
|
||||
prNumber: number, githubToken: string, projectRoot: string = getRepoBaseDir(),
|
||||
config?: MergeConfigWithRemote) {
|
||||
// Set the environment variable to skip all git commit hooks triggered by husky. We are unable to
|
||||
// rely on `---no-verify` as some hooks still run, notably the `prepare-commit-msg` hook.
|
||||
// rely on `--no-verify` as some hooks still run, notably the `prepare-commit-msg` hook.
|
||||
process.env['HUSKY_SKIP_HOOKS'] = '1';
|
||||
|
||||
const api = await createPullRequestMergeTask(githubToken, projectRoot, config);
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "rebase",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
ts_library(
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "release",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
ts_library(
|
||||
|
@ -60,7 +60,7 @@ describe('ng-dev release build', () => {
|
||||
});
|
||||
|
||||
it('should error if package has not been built', async () => {
|
||||
// Set up a NPM package that is not built.
|
||||
// Set up an NPM package that is not built.
|
||||
npmPackages.push('@angular/non-existent');
|
||||
|
||||
spyOn(console, 'error');
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "config",
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "publish",
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {promises as fs} from 'fs';
|
||||
import * as Ora from 'ora';
|
||||
import * as ora from 'ora';
|
||||
import {join} from 'path';
|
||||
import * as semver from 'semver';
|
||||
|
||||
@ -44,7 +44,7 @@ export interface PullRequest {
|
||||
forkBranch: string;
|
||||
}
|
||||
|
||||
/** Constructor type for a instantiating a release action */
|
||||
/** Constructor type for instantiating a release action */
|
||||
export interface ReleaseActionConstructor<T extends ReleaseAction = ReleaseAction> {
|
||||
/** Whether the release action is currently active. */
|
||||
isActive(active: ActiveReleaseTrains): Promise<boolean>;
|
||||
@ -107,25 +107,22 @@ export abstract class ReleaseAction {
|
||||
if (state === 'failure') {
|
||||
error(
|
||||
red(` ✘ Cannot stage release. Commit "${commitSha}" does not pass all github ` +
|
||||
`status checks. Please make sure this commit passes all checks before re-running.`));
|
||||
'status checks. Please make sure this commit passes all checks before re-running.'));
|
||||
error(` Please have a look at: ${branchCommitsUrl}`);
|
||||
|
||||
if (await promptConfirm('Do you want to ignore the Github status and proceed?')) {
|
||||
info(yellow(
|
||||
` ⚠ Upstream commit is failing CI checks, but status has been ` +
|
||||
`forcibly ignored.`));
|
||||
' ⚠ Upstream commit is failing CI checks, but status has been forcibly ignored.'));
|
||||
return;
|
||||
}
|
||||
throw new UserAbortedReleaseActionError();
|
||||
} else if (state === 'pending') {
|
||||
error(
|
||||
red(` ✘ Commit "${commitSha}" still has pending github statuses that ` +
|
||||
`need to succeed before staging a release.`));
|
||||
'need to succeed before staging a release.'));
|
||||
error(red(` Please have a look at: ${branchCommitsUrl}`));
|
||||
if (await promptConfirm('Do you want to ignore the Github status and proceed?')) {
|
||||
info(yellow(
|
||||
` ⚠ Upstream commit is pending CI, but status has been ` +
|
||||
`forcibly ignored.`));
|
||||
info(yellow(' ⚠ Upstream commit is pending CI, but status has been forcibly ignored.'));
|
||||
return;
|
||||
}
|
||||
throw new UserAbortedReleaseActionError();
|
||||
@ -157,9 +154,9 @@ export abstract class ReleaseAction {
|
||||
*/
|
||||
protected async waitForEditsAndCreateReleaseCommit(newVersion: semver.SemVer) {
|
||||
info(yellow(
|
||||
` ⚠ Please review the changelog and ensure that the log contains only changes ` +
|
||||
`that apply to the public API surface. Manual changes can be made. When done, please ` +
|
||||
`proceed with the prompt below.`));
|
||||
' ⚠ Please review the changelog and ensure that the log contains only changes ' +
|
||||
'that apply to the public API surface. Manual changes can be made. When done, please ' +
|
||||
'proceed with the prompt below.'));
|
||||
|
||||
if (!await promptConfirm('Do you want to proceed and commit the changes?')) {
|
||||
throw new UserAbortedReleaseActionError();
|
||||
@ -188,7 +185,7 @@ export abstract class ReleaseAction {
|
||||
const forks = result.repository.forks.nodes;
|
||||
|
||||
if (forks.length === 0) {
|
||||
error(red(` ✘ Unable to find fork for currently authenticated user.`));
|
||||
error(red(' ✘ Unable to find fork for currently authenticated user.'));
|
||||
error(red(` Please ensure you created a fork of: ${owner}/${name}.`));
|
||||
throw new FatalReleaseActionError();
|
||||
}
|
||||
@ -304,7 +301,7 @@ export abstract class ReleaseAction {
|
||||
return new Promise((resolve, reject) => {
|
||||
debug(`Waiting for pull request #${id} to be merged.`);
|
||||
|
||||
const spinner = Ora().start(`Waiting for pull request #${id} to be merged.`);
|
||||
const spinner = ora().start(`Waiting for pull request #${id} to be merged.`);
|
||||
const intervalId = setInterval(async () => {
|
||||
const prState = await getPullRequestState(this.git, id);
|
||||
if (prState === 'merged') {
|
||||
@ -451,7 +448,7 @@ export abstract class ReleaseAction {
|
||||
|
||||
info(green(
|
||||
` ✓ Pull request for cherry-picking the changelog into "${nextBranch}" ` +
|
||||
`has been created.`));
|
||||
'has been created.'));
|
||||
info(yellow(` Please ask team members to review: ${url}.`));
|
||||
return true;
|
||||
}
|
||||
@ -490,7 +487,7 @@ export abstract class ReleaseAction {
|
||||
|
||||
if (!await this._isCommitForVersionStaging(newVersion, versionBumpCommitSha)) {
|
||||
error(red(` ✘ Latest commit in "${publishBranch}" branch is not a staging commit.`));
|
||||
error(red(` Please make sure the staging pull request has been merged.`));
|
||||
error(red(' Please make sure the staging pull request has been merged.'));
|
||||
throw new FatalReleaseActionError();
|
||||
}
|
||||
|
||||
@ -514,13 +511,13 @@ export abstract class ReleaseAction {
|
||||
await this._publishBuiltPackageToNpm(builtPackage, npmDistTag);
|
||||
}
|
||||
|
||||
info(green(` ✓ Published all packages successfully`));
|
||||
info(green(' ✓ Published all packages successfully'));
|
||||
}
|
||||
|
||||
/** Publishes the given built package to NPM with the specified NPM dist tag. */
|
||||
private async _publishBuiltPackageToNpm(pkg: BuiltPackage, npmDistTag: string) {
|
||||
debug(`Starting publish of "${pkg.name}".`);
|
||||
const spinner = Ora().start(`Publishing "${pkg.name}"`);
|
||||
const spinner = ora().start(`Publishing "${pkg.name}"`);
|
||||
|
||||
try {
|
||||
await runNpmPublish(pkg.outputPath, npmDistTag, this.config.publishRegistry);
|
||||
|
@ -65,14 +65,14 @@ export class CutLongTermSupportPatchAction extends ReleaseAction {
|
||||
{
|
||||
name: 'activeLtsBranch',
|
||||
type: 'list',
|
||||
message: 'Please select a version for which you want to cut a LTS patch',
|
||||
message: 'Please select a version for which you want to cut an LTS patch',
|
||||
choices: activeBranchChoices,
|
||||
},
|
||||
{
|
||||
name: 'inactiveLtsBranch',
|
||||
type: 'list',
|
||||
when: o => o.activeLtsBranch === null,
|
||||
message: 'Please select an inactive LTS version for which you want to cut a LTS patch',
|
||||
message: 'Please select an inactive LTS version for which you want to cut an LTS patch',
|
||||
choices: inactive.map(branch => this._getChoiceForLtsBranch(branch)),
|
||||
}
|
||||
]);
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import * as Ora from 'ora';
|
||||
import * as ora from 'ora';
|
||||
import * as semver from 'semver';
|
||||
|
||||
import {spawnWithDebugOutput} from '../../utils/child-process';
|
||||
@ -19,11 +19,11 @@ import {FatalReleaseActionError} from './actions-error';
|
||||
* ###############################################################
|
||||
*
|
||||
* This file contains helpers for invoking external `ng-dev` commands. A subset of actions,
|
||||
* like building release output or setting a NPM dist tag for release packages, cannot be
|
||||
* like building release output or setting aν NPM dist tag for release packages, cannot be
|
||||
* performed directly as part of the release tool and need to be delegated to external `ng-dev`
|
||||
* commands that exist across arbitrary version branches.
|
||||
*
|
||||
* In an concrete example: Consider a new patch version is released and that a new release
|
||||
* In a concrete example: Consider a new patch version is released and that a new release
|
||||
* package has been added to the `next` branch. The patch branch will not contain the new
|
||||
* release package, so we could not build the release output for it. To work around this, we
|
||||
* call the ng-dev build command for the patch version branch and expect it to return a list
|
||||
@ -44,7 +44,7 @@ export async function invokeSetNpmDistCommand(npmDistTag: string, version: semve
|
||||
info(green(` ✓ Set "${npmDistTag}" NPM dist tag for all packages to v${version}.`));
|
||||
} catch (e) {
|
||||
error(e);
|
||||
error(red(` ✘ An error occurred while setting the NPM dist tag for ${npmDistTag}.`));
|
||||
error(red(` ✘ An error occurred while setting the NPM dist tag for "${npmDistTag}".`));
|
||||
throw new FatalReleaseActionError();
|
||||
}
|
||||
}
|
||||
@ -54,21 +54,21 @@ export async function invokeSetNpmDistCommand(npmDistTag: string, version: semve
|
||||
* packages for the currently checked out branch.
|
||||
*/
|
||||
export async function invokeReleaseBuildCommand(): Promise<BuiltPackage[]> {
|
||||
const spinner = Ora().start('Building release output.');
|
||||
const spinner = ora().start('Building release output.');
|
||||
try {
|
||||
// Since we expect JSON to be printed from the `ng-dev release build` command,
|
||||
// we spawn the process in silent mode. We have set up an Ora progress spinner.
|
||||
const {stdout} = await spawnWithDebugOutput(
|
||||
'yarn', ['--silent', 'ng-dev', 'release', 'build', '--json'], {mode: 'silent'});
|
||||
spinner.stop();
|
||||
info(green(` ✓ Built release output for all packages.`));
|
||||
info(green(' ✓ Built release output for all packages.'));
|
||||
// The `ng-dev release build` command prints a JSON array to stdout
|
||||
// that represents the built release packages and their output paths.
|
||||
return JSON.parse(stdout.trim());
|
||||
} catch (e) {
|
||||
spinner.stop();
|
||||
error(e);
|
||||
error(red(` ✘ An error occurred while building the release packages.`));
|
||||
error(red(' ✘ An error occurred while building the release packages.'));
|
||||
throw new FatalReleaseActionError();
|
||||
}
|
||||
}
|
||||
@ -83,10 +83,10 @@ export async function invokeYarnInstallCommand(projectDir: string): Promise<void
|
||||
// TODO: Consider using an Ora spinner instead to ensure minimal console output.
|
||||
await spawnWithDebugOutput(
|
||||
'yarn', ['install', '--frozen-lockfile', '--non-interactive'], {cwd: projectDir});
|
||||
info(green(` ✓ Installed project dependencies.`));
|
||||
info(green(' ✓ Installed project dependencies.'));
|
||||
} catch (e) {
|
||||
error(e);
|
||||
error(red(` ✘ An error occurred while installing dependencies.`));
|
||||
error(red(' ✘ An error occurred while installing dependencies.'));
|
||||
throw new FatalReleaseActionError();
|
||||
}
|
||||
}
|
||||
|
@ -66,8 +66,7 @@ export class ReleaseTool {
|
||||
// Only print the error message and stack if the error is not a known fatal release
|
||||
// action error (for which we print the error gracefully to the console with colors).
|
||||
if (!(e instanceof FatalReleaseActionError) && e instanceof Error) {
|
||||
console.error(e.message);
|
||||
console.error(e.stack);
|
||||
console.error(e);
|
||||
}
|
||||
return CompletionState.FATAL_ERROR;
|
||||
} finally {
|
||||
@ -90,7 +89,7 @@ export class ReleaseTool {
|
||||
}
|
||||
}
|
||||
|
||||
info(`Please select the type of release you want to perform.`);
|
||||
info('Please select the type of release you want to perform.');
|
||||
|
||||
const {releaseAction} = await prompt<{releaseAction: ReleaseAction}>({
|
||||
name: 'releaseAction',
|
||||
@ -108,9 +107,7 @@ export class ReleaseTool {
|
||||
*/
|
||||
private async _verifyNoUncommittedChanges(): Promise<boolean> {
|
||||
if (this._git.hasUncommittedChanges()) {
|
||||
error(
|
||||
red(` ✘ There are changes which are not committed and should be ` +
|
||||
`discarded.`));
|
||||
error(red(' ✘ There are changes which are not committed and should be discarded.'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -126,7 +123,7 @@ export class ReleaseTool {
|
||||
await this._git.github.repos.getBranch({...this._git.remoteParams, branch: nextBranchName});
|
||||
|
||||
if (headSha !== data.commit.sha) {
|
||||
error(red(` ✘ Running release tool from an outdated local branch.`));
|
||||
error(red(' ✘ Running release tool from an outdated local branch.'));
|
||||
error(red(` Please make sure you are running from the "${nextBranchName}" branch.`));
|
||||
return false;
|
||||
}
|
||||
|
@ -68,5 +68,6 @@ async function isCommitClosingPullRequest(api: GitClient, sha: string, id: numbe
|
||||
const {data} = await api.github.repos.getCommit({...api.remoteParams, ref: sha});
|
||||
// Matches the closing keyword supported in commit messages. See:
|
||||
// https://docs.github.com/en/enterprise/2.16/user/github/managing-your-work-on-github/closing-issues-using-keywords.
|
||||
return data.commit.message.match(new RegExp(`close[sd]? #${id}[^0-9]?`, 'i'));
|
||||
return data.commit.message.match(
|
||||
new RegExp(`(?:close[sd]?|fix(?:e[sd]?)|resolve[sd]?):? #${id}(?!\\d)`, 'i'));
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
ts_library(
|
||||
|
@ -13,7 +13,7 @@ import {CutLongTermSupportPatchAction} from '../actions/cut-lts-patch';
|
||||
|
||||
import {expectStagingAndPublishWithCherryPick, fakeNpmPackageQueryRequest, getTestingMocksForReleaseAction, parse, setupReleaseActionForTesting, testTmpDir} from './test-utils';
|
||||
|
||||
describe('cut a LTS patch action', () => {
|
||||
describe('cut an LTS patch action', () => {
|
||||
it('should be active', async () => {
|
||||
expect(await CutLongTermSupportPatchAction.isActive({
|
||||
releaseCandidate: null,
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
load("//tools:defaults.bzl", "jasmine_node_test")
|
||||
|
||||
ts_library(
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import * as Ora from 'ora';
|
||||
import * as ora from 'ora';
|
||||
import * as semver from 'semver';
|
||||
import {Arguments, Argv, CommandModule} from 'yargs';
|
||||
|
||||
@ -15,7 +15,7 @@ import {getReleaseConfig} from '../config/index';
|
||||
import {setNpmTagForPackage} from '../versioning/npm-publish';
|
||||
|
||||
|
||||
/** Command line options for setting a NPM dist tag. */
|
||||
/** Command line options for setting an NPM dist tag. */
|
||||
export interface ReleaseSetDistTagOptions {
|
||||
tagName: string;
|
||||
targetVersion: string;
|
||||
@ -42,11 +42,11 @@ async function handler(args: Arguments<ReleaseSetDistTagOptions>) {
|
||||
const version = semver.parse(rawVersion);
|
||||
|
||||
if (version === null) {
|
||||
error(red(`Invalid version specified. Unable to set NPM dist tag.`));
|
||||
error(red(`Invalid version specified (${rawVersion}). Unable to set NPM dist tag.`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const spinner = Ora().start();
|
||||
const spinner = ora().start();
|
||||
debug(`Setting "${tagName}" NPM dist tag for release packages to v${version}.`);
|
||||
|
||||
for (const pkgName of npmPackages) {
|
||||
@ -69,7 +69,7 @@ async function handler(args: Arguments<ReleaseSetDistTagOptions>) {
|
||||
info(green(` ${bold(tagName)} will now point to ${bold(`v${version}`)}.`));
|
||||
}
|
||||
|
||||
/** CLI command module for setting a NPM dist tag. */
|
||||
/** CLI command module for setting an NPM dist tag. */
|
||||
export const ReleaseSetDistTagCommand: CommandModule<{}, ReleaseSetDistTagOptions> = {
|
||||
builder,
|
||||
handler,
|
||||
|
@ -66,7 +66,7 @@ describe('ng-dev release set-dist-tag', () => {
|
||||
await invokeCommand('latest', '10.0');
|
||||
|
||||
expect(console.error)
|
||||
.toHaveBeenCalledWith('Invalid version specified. Unable to set NPM dist tag.');
|
||||
.toHaveBeenCalledWith('Invalid version specified (10.0). Unable to set NPM dist tag.');
|
||||
expect(process.exit).toHaveBeenCalledWith(1);
|
||||
expect(process.exit).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
||||
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "versioning",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user