mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
docs: update and reorganize contributor docs (#56141)
* Move from `docs/` to `contributing-docs/` * Updated file names to better communicate their content * Consolidated content into fewer docs * Updated and/or deleted obsolete info PR Close #56141
This commit is contained in:
committed by
Andrew Kushnir
parent
567c2f6d90
commit
f0fbced1c5
@@ -0,0 +1,19 @@
|
||||
<a name="conversation-locking"></a>
|
||||
|
||||
# Automatic conversation locking
|
||||
|
||||
Closed issues and pull requests are locked automatically after 30 days of inactivity.
|
||||
|
||||
## I want to comment on a locked conversation, what should I do?
|
||||
|
||||
When an issue has been closed and inactive for over 30 days, the original context is likely
|
||||
outdated.
|
||||
If you encounter a similar or related issue in the current version, please open a new issue and
|
||||
provide up-to-date reproduction instructions.
|
||||
|
||||
## Why lock conversations?
|
||||
|
||||
Automatically locking closed, inactive issues guides people towards filing new issues with updated
|
||||
context rather than commenting on a "resolved" issue that contains out-of-date or unrelated
|
||||
information. As an example, someone may comment "I'm still having this issue", but without
|
||||
providing any of the additional information the team needs to investigate.
|
||||
@@ -0,0 +1,108 @@
|
||||
# Angular Branching and Versioning: A Practical Guide
|
||||
|
||||
This guide explains how the Angular team manages branches and how those branches relate to
|
||||
merging PRs and publishing releases. Before reading, you should understand
|
||||
[Semantic Versioning](https://semver.org/#semantic-versioning-200).
|
||||
|
||||
## Distribution tags on npm
|
||||
|
||||
Angular's branching relates directly to versions published on npm. We will reference these [npm
|
||||
distribution tags](https://docs.npmjs.com/cli/v6/commands/npm-dist-tag#purpose) throughout:
|
||||
|
||||
| Tag | Description |
|
||||
|--------|-----------------------------------------------------------------------------------|
|
||||
| latest | The most recent stable version. |
|
||||
| next | The most recent pre-release version of Angular for testing. May not always exist. |
|
||||
| v*-lts | The most recent LTS release for the specified version, such as `v9-lts`. |
|
||||
|
||||
## Branch naming
|
||||
|
||||
Angular's main branch is `main`. This branch always represents the absolute latest changes. The
|
||||
code on `main` always represents a pre-release version, often published with the `next` tag on npm.
|
||||
|
||||
For each minor and major version increment, a new branch is created. These branches use a naming
|
||||
scheme matching `\d+\.\d+\.x` and receive subsequent patch changes for that version range. For
|
||||
example, the `10.2.x` branch represents the latest patch changes for subsequent releases starting
|
||||
with `10.2.`. The version tagged on npm as `latest` will always correspond to such a branch,
|
||||
referred to as the **active patch branch**.
|
||||
|
||||
## Major releases lifecycle
|
||||
|
||||
Angular releases a major version roughly every six months. Following a major release, we move
|
||||
through a consistent lifecycle to the next major release, and repeat. At a high level, this
|
||||
process proceeds as follows:
|
||||
|
||||
* A major release occurs. The `main` branch now represents the next minor version.
|
||||
* Six weeks later, a minor release occurs. The `main` branch now represents the next minor
|
||||
version.
|
||||
* Six weeks later, a second minor release occurs. The `main` branch now represents the next major
|
||||
version.
|
||||
* Three months later, a major release occurs and the process repeats.
|
||||
|
||||
### Example
|
||||
* Angular publishes `11.0.0`. At this point in time, the `main` branch represents `11.1.0`.
|
||||
* Six weeks later, we publish `11.1.0` and `main` represents `11.2.0`.
|
||||
* Six weeks later, we publish `11.2.0` and `main` represents `12.0.0`.
|
||||
* Three months later, this cycle repeats with the publication of `12.0.0`.
|
||||
|
||||
### Feature freeze and release candidates
|
||||
|
||||
Before publishing minor and major versions as `latest` on npm, they go through a feature freeze and
|
||||
a release candidate (RC) phase.
|
||||
|
||||
**Feature freeze** means that `main` is forked into a branch for a specific version, with no
|
||||
additional features permitted before releasing as `latest` to npm. This branch becomes the **active
|
||||
RC branch**. Upon branching, the `main` branch increments to the next minor or major pre-release
|
||||
version. One week after feature freeze, the first RC is published with the `next` tag on npm from
|
||||
the active RC branch. Patch bug fixes continue to merge into `main`, the active RC branch, and
|
||||
the active patch branch during this entire period.
|
||||
|
||||
One to three weeks after publishing the first RC, the active RC branch is published as `latest` on
|
||||
npm and the branch becomes the active patch branch. At this point there is no active RC branch until
|
||||
the next minor or major release.
|
||||
|
||||
## Targeting pull requests
|
||||
|
||||
Every pull request has a **base branch**:
|
||||
|
||||

|
||||
|
||||
This base branch represents the latest branch that will receive the change. Most pull requests
|
||||
should specify `main`. However, some changes will explicitly use an earlier branch, such as
|
||||
`11.1.x`, in order to patch an older version. Specific GitHub labels, described below, control the
|
||||
additional branches into which a pull request will be cherry-picked.
|
||||
|
||||
### Labelling pull requests
|
||||
|
||||
There are five labels that target PRs to versions:
|
||||
|
||||
| Label | Description |
|
||||
|---------------|-----------------------------------------------------------------------------|
|
||||
| target: major | A change that includes a backwards-incompatible behavior or API change. |
|
||||
| target: minor | A change that introduces a new, backwards-compatible functionality. |
|
||||
| target: patch | A backwards-compatible bug fix. |
|
||||
| target: rc | A change that should be explicitly included in an active release candidate. |
|
||||
| target: lts | A critical security or browser compatibility fix for LTS releases. |
|
||||
|
||||
Every PR must have exactly one `target: *` label. Angular's dev tooling will merge the pull request
|
||||
into its base branch and then cherry-pick the commits to the appropriate branches based on the
|
||||
specified target label.
|
||||
|
||||
The vast majority of pull requests will target `major`, `minor`, or `patch` based on the contents of
|
||||
the code change. In rare cases, a pull request will specify `target: rc` or `target: lts` to
|
||||
explicitly target a special branch.
|
||||
|
||||
Breaking changes, marked with `target: major`, can only be merged when `main` represents the next
|
||||
major version.
|
||||
|
||||
### Pull request examples
|
||||
|
||||
| I want to... | Target branch | Target label | Your change will land in... |
|
||||
| ----------------------------------------------------------- | ----------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Make a non-breaking bug fix | `main` | `patch` | `main`, the active patch branch, and the active RC branch if there is one |
|
||||
| Introduce a new feature | `main` | `minor` | `main` (any time) |
|
||||
| Make a breaking change | `main` | `major` | `main` (only when `main` represents the next major version) |
|
||||
| Make a critical security fix | `main` | `lts` | `main`, the active patch branch, the active RC branch if there is one, and all branches for versions within the LTS window |
|
||||
| Bump the version of an RC | the active RC branch | `rc` | The active RC branch |
|
||||
| Fix an RC bug for a major release feature | `main` | `rc` | `main` and the active RC branch |
|
||||
| Backport a bug fix to the `latest` npm version during an RC | the active patch branch | `patch` | the active patch branch only |
|
||||
@@ -0,0 +1,216 @@
|
||||
# Building and Testing Angular
|
||||
|
||||
This document describes how to set up your development environment to build and test Angular.
|
||||
It also explains the basic mechanics of using `git`, `node`, and `yarn`.
|
||||
|
||||
* [Prerequisite Software](#prerequisite-software)
|
||||
* [Getting the Sources](#getting-the-sources)
|
||||
* [Installing NPM Modules](#installing-npm-modules)
|
||||
* [Building](#building)
|
||||
* [Running Tests Locally](#running-tests-locally)
|
||||
* [Formatting your Source Code](#formatting-your-source-code)
|
||||
* [Linting/verifying your Source Code](#lintingverifying-your-source-code)
|
||||
* [Publishing Snapshot Builds](#publishing-snapshot-builds)
|
||||
* [Bazel Support](#bazel-support)
|
||||
|
||||
See the [contribution guidelines](https://github.com/angular/angular/blob/main/CONTRIBUTING.md)
|
||||
if you'd like to contribute to Angular.
|
||||
|
||||
## Prerequisite Software
|
||||
|
||||
Before you can build and test Angular, you must install and configure the
|
||||
following on your development machine:
|
||||
|
||||
* [Git](https://git-scm.com/) and/or the [**GitHub app**](https://desktop.github.com/) (for Mac and
|
||||
Windows);
|
||||
[GitHub's Guide to Installing Git](https://help.github.com/articles/set-up-git) is a good source
|
||||
of information.\
|
||||
**Windows Users**: Git Bash or an equivalent shell is required\
|
||||
*Windows Powershell and cmd shells are not
|
||||
supported [#46780](https://github.com/angular/angular/issues/46780) so some commands might fail*
|
||||
|
||||
* [Node.js](https://nodejs.org), (version specified in [`.nvmrc`](../.nvmrc)) which is used to run a
|
||||
development web server,
|
||||
run tests, and generate distributable files.
|
||||
`.nvmrc` is read by [nvm](https://github.com/nvm-sh/nvm) commands like `nvm install`
|
||||
and `nvm use`.
|
||||
|
||||
* [Yarn](https://yarnpkg.com) (version specified in the engines field
|
||||
of [`package.json`](../package.json)) which is used to install dependencies.
|
||||
|
||||
* On Windows: [MSYS2](https://www.msys2.org/) which is used by Bazel. Follow
|
||||
the [instructions](https://bazel.build/install/windows#installing-compilers-and-language-runtimes)
|
||||
|
||||
## Getting the Sources
|
||||
|
||||
Fork and clone the Angular repository:
|
||||
|
||||
1. Login to your GitHub account or create one by following the instructions given
|
||||
[here](https://github.com/signup/free).
|
||||
2. [Fork](https://help.github.com/forking) the [main Angular
|
||||
repository](https://github.com/angular/angular).
|
||||
3. Clone your fork of the Angular repository and define an `upstream` remote pointing back to
|
||||
the Angular repository that you forked in the first place.
|
||||
|
||||
```shell
|
||||
# Clone your GitHub repository:
|
||||
git clone git@github.com:<github username>/angular.git
|
||||
|
||||
# Go to the Angular directory:
|
||||
cd angular
|
||||
|
||||
# Add the main Angular repository as an upstream remote to your repository:
|
||||
git remote add upstream https://github.com/angular/angular.git
|
||||
```
|
||||
|
||||
## Installing NPM Modules
|
||||
|
||||
Next, install the JavaScript modules needed to build and test Angular:
|
||||
|
||||
```shell
|
||||
# Install Angular project dependencies (package.json)
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To build Angular run:
|
||||
|
||||
```shell
|
||||
yarn build
|
||||
```
|
||||
|
||||
* Results are put in the `dist/packages-dist` folder.
|
||||
|
||||
## Running Tests Locally
|
||||
|
||||
Bazel is used as the primary tool for building and testing Angular.
|
||||
|
||||
To see how to run and debug Angular tests locally please refer to the
|
||||
Bazel [Testing Angular](./BAZEL.md#testing-angular) section.
|
||||
|
||||
Note that you should execute all test suites before submitting a PR to
|
||||
GitHub (`yarn test //packages/...`).
|
||||
|
||||
However, affected tests will be executed on our CI infrastructure. So if you forgot to run some
|
||||
affected tests which would fail, GitHub will indicate the error state and present you the failures.
|
||||
|
||||
PRs can only be merged if the code is formatted properly and all tests are passing.
|
||||
|
||||
<a name="formatting-your-source-code"></a>
|
||||
<a name="clang-format"></a>
|
||||
<a name="prettier"></a>
|
||||
|
||||
### Testing changes against a local library/project
|
||||
|
||||
Often for developers the best way to ensure the changes they have made work as expected is to run
|
||||
use changes in another library or project. To do this developers can build Angular locally, and
|
||||
using `yarn link` build a local project with the created artifacts.
|
||||
|
||||
This can be done by running:
|
||||
|
||||
```sh
|
||||
yarn ng-dev misc build-and-link <path-to-local-project-root>
|
||||
```
|
||||
|
||||
### Building and serving a project
|
||||
|
||||
#### Cache
|
||||
|
||||
When making changes to Angular packages and testing in a local library/project you need to
|
||||
run `ng cache disable` to disable the Angular CLI disk cache. If you are making changes that are not
|
||||
reflected in your locally served library/project, verify if you
|
||||
have [CLI Cache](https://angular.io/guide/workspace-config#cache-options) disabled.
|
||||
|
||||
#### Invoking the Angular CLI
|
||||
|
||||
The Angular CLI needs to be invoked using
|
||||
Node.js [`--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks) flag. Otherwise
|
||||
the symbolic links will be resolved using their real path which causes node module resolution to
|
||||
fail.
|
||||
|
||||
```sh
|
||||
node --preserve-symlinks --preserve-symlinks-main node_modules/@angular/cli/lib/init.js serve
|
||||
```
|
||||
|
||||
## Formatting your source code
|
||||
|
||||
Angular uses [prettier](https://clang.llvm.org/docs/ClangFormat.html) to format the source code.
|
||||
If the source code is not properly formatted, the CI will fail and the PR cannot be merged.
|
||||
|
||||
You can automatically format your code by running:
|
||||
|
||||
- `yarn ng-dev format changed [shaOrRef]`: format only files changed since the provided
|
||||
sha/ref. `shaOrRef` defaults to `main`.
|
||||
- `yarn ng-dev format all`: format _all_ source code
|
||||
- `yarn ng-dev format files <files..>`: format only provided files
|
||||
|
||||
## Linting/verifying your Source Code
|
||||
|
||||
You can check that your code is properly formatted and adheres to coding style by running:
|
||||
|
||||
``` shell
|
||||
$ yarn lint
|
||||
```
|
||||
|
||||
## Publishing Snapshot Builds
|
||||
|
||||
When a build of any branch on the upstream fork angular/angular is green on CI, it
|
||||
automatically publishes build artifacts to repositories in the Angular org. For example,
|
||||
the `@angular/core` package is published to https://github.com/angular/core-builds.
|
||||
|
||||
You may find that your un-merged change needs some validation from external participants.
|
||||
Rather than requiring them to pull your Pull Request and build Angular locally, they can depend on
|
||||
snapshots of the Angular packages created based on the code in the Pull Request.
|
||||
|
||||
### Publishing to GitHub Repos
|
||||
|
||||
You can also manually publish `*-builds` snapshots just like our CI build does for upstream
|
||||
builds. Before being able to publish the packages, you need to build them locally by running the
|
||||
`yarn build` command.
|
||||
|
||||
First time, you need to create the GitHub repositories:
|
||||
|
||||
``` shell
|
||||
$ export TOKEN=[get one from https://github.com/settings/tokens]
|
||||
$ CREATE_REPOS=1 ./scripts/ci/publish-build-artifacts.sh [GitHub username]
|
||||
```
|
||||
|
||||
For subsequent snapshots, just run:
|
||||
|
||||
``` shell
|
||||
$ ./scripts/ci/publish-build-artifacts.sh [GitHub username]
|
||||
```
|
||||
|
||||
The script will publish the build snapshot to a branch with the same name as your current branch,
|
||||
and create it if it doesn't exist.
|
||||
|
||||
## Bazel Support
|
||||
|
||||
### IDEs
|
||||
|
||||
#### VS Code
|
||||
|
||||
1. Install [Bazel](https://marketplace.visualstudio.com/items?itemName=BazelBuild.vscode-bazel)
|
||||
extension for VS Code.
|
||||
|
||||
#### WebStorm / IntelliJ
|
||||
|
||||
1. Install the [Bazel](https://plugins.jetbrains.com/plugin/8609-bazel) plugin
|
||||
2. You can find the settings under `Preferences->Other Settings->Bazel Settings`
|
||||
|
||||
It will automatically recognize `*.bazel` and `*.bzl` files.
|
||||
|
||||
### Remote Build Execution and Remote Caching
|
||||
|
||||
Bazel builds in the Angular repository use a shared cache. When a build occurs, a hash of the inputs
|
||||
is computed
|
||||
and checked against available outputs in the shared cache. If an output is found, it is used as the
|
||||
output for the
|
||||
build action rather than performing the build locally.
|
||||
|
||||
> Remote Build Execution requires authentication as a google.com account.
|
||||
|
||||
#### --config=remote flag
|
||||
|
||||
The `--config=remote` flag can be added to enable remote execution of builds.
|
||||
@@ -0,0 +1,346 @@
|
||||
# Building Angular with Bazel
|
||||
|
||||
Note: This doc is for developing Angular. It is _not_ public
|
||||
documentation for building an Angular application with Bazel.
|
||||
|
||||
The Bazel build tool (https://bazel.build) provides fast, reliable
|
||||
incremental builds. The majority of Angular's code is built with Bazel.
|
||||
|
||||
## Installation and running
|
||||
|
||||
Angular installs Bazel from npm rather than having contributors install Bazel
|
||||
directly. This ensures that everyone uses the same version of Bazel.
|
||||
|
||||
The binaries for Bazel are provided by
|
||||
the [`@bazel/bazelisk`](https://github.com/bazelbuild/bazelisk)
|
||||
npm package and its platform-specific dependencies.
|
||||
|
||||
You can run Bazel with the `yarn bazel` command.
|
||||
|
||||
## Configuration
|
||||
|
||||
The `WORKSPACE` file indicates that our root directory is a
|
||||
Bazel project. It contains the version of the Bazel rules we
|
||||
use to execute build steps, from `npm_bazel_typescript`.
|
||||
The sources on [GitHub] are published from Google's internal
|
||||
repository (google3).
|
||||
|
||||
Bazel accepts a lot of options. We check in some options in the
|
||||
`.bazelrc` file. See the [bazelrc doc]. For example, if you don't
|
||||
want Bazel to create several symlinks in your project directory
|
||||
(`bazel-*`) you can add the line `build --symlink_prefix=/` to your
|
||||
`.bazelrc` file.
|
||||
|
||||
[GitHub]: https://github.com/bazelbuild/rules_typescript
|
||||
[bazelrc doc]: https://bazel.build/run/bazelrc
|
||||
|
||||
## Building Angular
|
||||
|
||||
- Build a package: `yarn bazel build packages/core`
|
||||
- Build all packages: `yarn bazel build packages/...`
|
||||
|
||||
You can use [ibazel] to run in a "watch mode" that continuously
|
||||
keeps the outputs up-to-date as you save sources.
|
||||
|
||||
[ibazel]: https://github.com/bazelbuild/bazel-watcher
|
||||
|
||||
## Testing Angular
|
||||
|
||||
- Test package in node: `yarn test packages/core/test:test`
|
||||
- Test package in karma: `yarn test packages/core/test:test_web`
|
||||
- Test all packages: `yarn test packages/...`
|
||||
- Test angular.io app locally: `yarn test //aio/... --config=aio_local_deps`
|
||||
|
||||
The ellipsis in the examples above are not meant to be substituted by a package name, but
|
||||
are used by Bazel as a wildcard to execute all tests in the specified path. To execute all the tests for a
|
||||
single package, the commands are (exemplary):
|
||||
- `yarn test //packages/core/...` for all tests, or
|
||||
- `yarn test //packages/core/test:test` for a particular test suite.
|
||||
|
||||
Bazel very effectively caches build results, so it's common for your first time building a target
|
||||
to be much slower than subsequent builds.
|
||||
|
||||
You can use [ibazel] to run in a "watch mode" that continuously
|
||||
keeps the outputs up-to-date as you save sources.
|
||||
|
||||
### Testing with flags
|
||||
|
||||
If you're experiencing problems with seemingly unrelated tests failing, it may be because you're not
|
||||
using the proper flags with your Bazel test runs in Angular.
|
||||
|
||||
- `--config=debug`: build and launch in debug mode (see [debugging](#debugging) instructions below)
|
||||
- `--test_arg=--node_options=--inspect=9228`: change the inspector port.
|
||||
- `--test_tag_filters=<tag>`: filter tests down to tags defined in the `tag` config of your rules in
|
||||
any given `BUILD.bazel`.
|
||||
|
||||
### Debugging a Node Test in Chrome DevTools
|
||||
<a id="debugging"></a>
|
||||
|
||||
- Open Chrome at: [chrome://inspect](chrome://inspect)
|
||||
- Click on `Open dedicated DevTools for Node` to launch a debugger.
|
||||
- Run your test with the debug configuration,
|
||||
e.g. `yarn bazel test packages/core/test:test --config=debug`
|
||||
|
||||
The process should automatically connect to the debugger.
|
||||
For more, see the [rules_nodejs Debugging documentation](https://bazelbuild.github.io/rules_nodejs/index.html#debugging).
|
||||
|
||||
For additional info and testing options, see the
|
||||
[nodejs_test documentation](https://bazelbuild.github.io/rules_nodejs/Built-ins.html#nodejs_test).
|
||||
|
||||
- Click on "Resume script execution" to let the code run until the first `debugger` statement or a
|
||||
previously set breakpoint.
|
||||
- If you want to inspect generated template instructions while debugging, find the
|
||||
template of your component in the call stack and click on `(source mapped from [CompName].js)` at
|
||||
the bottom of the code. You can also disable sourcemaps in Chrome DevTools' options or go to
|
||||
sources and look into ng:// namespace to see all the generated code.
|
||||
|
||||
### Debugging a Node Test in VSCode
|
||||
|
||||
First time setup:
|
||||
- Go to Debug > Add configuration (in the menu bar) to open `launch.json`
|
||||
- Add the following to the `configurations` array:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"name": "Attach to Remote",
|
||||
"port": 9229
|
||||
}
|
||||
```
|
||||
|
||||
**Setting breakpoints directly in your code files may not work in VSCode**. This is because the
|
||||
files you're actually debugging are built files that exist in a `./private/...` folder.
|
||||
The easiest way to debug a test for now is to add a `debugger` statement in the code
|
||||
and launch the bazel corresponding test (`yarn bazel test <target> --config=debug`).
|
||||
|
||||
Bazel will wait on a connection. Go to the debug view (by clicking on the sidebar or
|
||||
Apple+Shift+D on Mac) and click on the green play icon next to the configuration name
|
||||
(ie `Attach to Remote`).
|
||||
|
||||
### Debugging a Karma Test
|
||||
|
||||
- Run test with `_debug` appended to the target name,
|
||||
e.g. `yarn bazel run packages/core/test:test_web_debug`.
|
||||
Every `karma_web_test_suite` target has an additional `_debug` target.
|
||||
- Open any browser at: [http://localhost:9876/debug.html](http://localhost:9876/debug.html)
|
||||
- Open the browser's DevTools to debug the tests (after, for example, having focused on specific
|
||||
tests via `fit` and/or `fdescribe` or having added `debugger` statements in them)
|
||||
|
||||
### Debugging Bazel rules
|
||||
|
||||
Open `external` directory which contains everything that bazel downloaded while executing the
|
||||
workspace file:
|
||||
```sh
|
||||
open $(yarn -s bazel info output_base)/external
|
||||
```
|
||||
|
||||
See subcommands that bazel executes (helpful for debugging):
|
||||
```sh
|
||||
yarn bazel build //packages/core:package -s
|
||||
```
|
||||
|
||||
To debug nodejs_binary executable paths uncomment `find . -name rollup 1>&2` (~ line 96) in
|
||||
```sh
|
||||
open $(yarn -s bazel info output_base)/external/build_bazel_rules_nodejs/internal/node_launcher.sh
|
||||
```
|
||||
|
||||
## Stamping
|
||||
|
||||
Bazel supports the ability to include non-hermetic information from the version control system in
|
||||
built artifacts. This is called stamping.
|
||||
You can see an overview at https://www.kchodorow.com/blog/2017/03/27/stamping-your-builds/
|
||||
|
||||
Angular configures stamping as follows:
|
||||
|
||||
1. In `tools/bazel_stamp_vars.js` we run the `git` commands to generate our versioning info.
|
||||
2. In `.bazelrc` we register this script as the value for the `workspace_status_command` flag. Bazel
|
||||
will run the script when it needs to stamp a binary.
|
||||
|
||||
## Remote cache
|
||||
|
||||
Bazel supports fetching action results from a cache, allowing a clean build to reuse artifacts
|
||||
from prior builds. This makes builds incremental, even on CI.
|
||||
|
||||
Bazel assigns a content-based hash to all action inputs, which is used as the cache
|
||||
key for the action outputs. Because Bazel builds are hermetic, it can skip executing an action if
|
||||
the inputs hash is already present in the cache.
|
||||
|
||||
When using this caching feature, non-hermetic actions cause problems. At worst, you can fetch a
|
||||
broken artifact from the cache, making your build non-reproducible. For this reason, we are careful
|
||||
to implement our Bazel rules to depend _exclusively_ on their inputs, never reading from the
|
||||
filesystem or the underlying environment directly.
|
||||
|
||||
Currently, we only use remote caching on CI. Angular core developers can enable remote
|
||||
caching to speed up their builds.
|
||||
|
||||
### Remote cache in development
|
||||
|
||||
Note: this is only available to Googlers
|
||||
|
||||
To enable remote caching for your build:
|
||||
|
||||
1. Go to the service accounts for the ["internal" project](https://console.cloud.google.com/iam-admin/serviceaccounts?project=internal-200822)
|
||||
2. Select "Angular local dev", click on "Edit", scroll to the bottom, and click "Create key"
|
||||
3. When the pop-up shows, select "JSON" for "Key type" and click "Create"
|
||||
4. Save the key in a secure location
|
||||
5. Create a file called `.bazelrc.user` in the root directory of the workspace, and add the following content:
|
||||
|
||||
```
|
||||
build --config=angular-team --google_credentials=[ABSOLUTE_PATH_TO_SERVICE_KEY]
|
||||
```
|
||||
|
||||
## Diagnosing slow builds
|
||||
|
||||
If a build seems slow you can use Bazel to diagnose where time is spent.
|
||||
|
||||
The first step is to generate a profile of the build using the `--profile filename_name.profile`
|
||||
flag.
|
||||
|
||||
```sh
|
||||
yarn bazel build //packages/compiler --profile filename_name.profile
|
||||
```
|
||||
|
||||
This generates a `filename_name.profile` that you can then analyse
|
||||
using chrome://tracing or
|
||||
Bazel's [analyze-profile](https://docs.bazel.build/versions/master/user-manual.html#analyze-profile)
|
||||
command.
|
||||
|
||||
## Using the console profile report
|
||||
|
||||
You can obtain a simple report directly in the console by running:
|
||||
|
||||
```sh
|
||||
yarn bazel analyze-profile filename_name.profile
|
||||
```
|
||||
|
||||
This will show the phase summary, individual phase information and critical path.
|
||||
|
||||
You can also list all individual tasks and the time they took using `--task_tree`.
|
||||
```sh
|
||||
yarn bazel analyze-profile filename_name.profile --task_tree ".*"
|
||||
```
|
||||
|
||||
To show all tasks that take longer than a certain threshold, use the `--task_tree_threshold` flag.
|
||||
The default behavior is to use a 50ms threshold.
|
||||
```sh
|
||||
yarn bazel analyze-profile filename_name.profile --task_tree ".*" --task_tree_threshold 5000
|
||||
```
|
||||
|
||||
`--task_tree` takes a regexp as argument that filters by the text shown after the time taken.
|
||||
|
||||
Compiling TypeScript shows as:
|
||||
```
|
||||
70569 ACTION_EXECUTE (10974.826 ms) Compiling TypeScript (devmode) //packages/compiler:compiler []
|
||||
```
|
||||
|
||||
To filter all tasks by TypeScript compilations that took more than 5 seconds, use:
|
||||
|
||||
```sh
|
||||
yarn bazel analyze-profile filename_name.profile --task_tree "Compiling TypeScript" --task_tree_threshold 5000
|
||||
```
|
||||
|
||||
### Using the HTML profile report
|
||||
|
||||
A more comprehensive way to visualize the profile information is through the HTML report:
|
||||
|
||||
```sh
|
||||
yarn bazel analyze-profile filename_name.profile --html --html_details --html_histograms
|
||||
```
|
||||
|
||||
This generates a `filename_name.profile.html` file that you can open in your browser.
|
||||
|
||||
In the upper right corner that is a small table of contents with links to three areas: Tasks,
|
||||
Legend, and Statistics.
|
||||
|
||||
In the Tasks section you will find a graph of where time is spent. Legend shows what the colors in
|
||||
the Tasks graph mean.
|
||||
Hovering over the background will show what phase that is, while hovering over bars will show more
|
||||
details about that specific action.
|
||||
|
||||
The Statistics section shows how long each phase took and how time was spent in that phase.
|
||||
Usually the longest one is the execution phase, which also includes critical path information.
|
||||
|
||||
Also in the Statistics section are the Skylark statistic, split in User-Defined and Builtin function
|
||||
execution time.
|
||||
You can click the "self" header twice to order the table by functions where the most time (in ms) is
|
||||
spent.
|
||||
|
||||
When diagnosing slow builds you should focus on the top time spenders across all phases and
|
||||
functions.
|
||||
Usually there is a single item (or multiple items of the same kind) where the overwhelming majority
|
||||
of time is spent.
|
||||
|
||||
## Known issues
|
||||
|
||||
### Windows
|
||||
|
||||
#### bazel run
|
||||
If you see the following error:
|
||||
|
||||
```
|
||||
Error: Cannot find module 'C:\users\xxxx\_bazel_xxxx\7lxopdvs\execroot\angular\bazel-out\x64_windows-fastbuild\bin\packages\core\test\bundling\hello_world\symbol_test.bat.runfiles\angular\c;C:\msys64\users\xxxx\_bazel_xxxx\7lxopdvs\execroot\angular\bazel-out\x64_windows-fastbuild\bin\packages\core\test\bundling\hello_world\symbol_test.bat.runfiles\angular\packages\core\test\bundling\hello_world\symbol_test_require_patch.js'
|
||||
Require stack:
|
||||
- internal/preload
|
||||
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:793:17)
|
||||
at Function.Module._load (internal/modules/cjs/loader.js:686:27)
|
||||
at Module.require (internal/modules/cjs/loader.js:848:19)
|
||||
at Module._preloadModules (internal/modules/cjs/loader.js:1133:12)
|
||||
at loadPreloadModules (internal/bootstrap/pre_execution.js:443:5)
|
||||
at prepareMainThreadExecution (internal/bootstrap/pre_execution.js:62:3)
|
||||
at internal/main/run_main_module.js:7:1 {
|
||||
code: 'MODULE_NOT_FOUND',
|
||||
requireStack: [ 'internal/preload' ]
|
||||
```
|
||||
|
||||
`bazel run` only works in Bazel Windows with non-test targets. Ensure that you are using `bazel test` instead.
|
||||
|
||||
e.g: `yarn bazel test packages/core/test/bundling/forms:symbol_test`
|
||||
|
||||
#### mkdir missing
|
||||
If you see the following error::
|
||||
```
|
||||
ERROR: An error occurred during the fetch of repository 'npm':
|
||||
Traceback (most recent call last):
|
||||
File "C:/users/anusername/_bazel_anusername/idexbm2i/external/build_bazel_rules_nodejs/internal/npm_install/npm_install.bzl", line 618, column 15, in _yarn_install_impl
|
||||
_copy_file(repository_ctx, repository_ctx.attr.package_json)
|
||||
File "C:/users/anusername/_bazel_anusername/idexbm2i/external/build_bazel_rules_nodejs/internal/npm_install/npm_install.bzl", line 345, column 17, in _copy_file
|
||||
fail("mkdir -p %s failed: \nSTDOUT:\n%s\nSTDERR:\n%s" % (dirname, result.stdout, result.stderr))
|
||||
Error in fail: mkdir -p _ failed:
|
||||
```
|
||||
The `msys64` library and associated tools (like `mkdir`) are required to build Angular.
|
||||
|
||||
Make sure you have `C:\msys64\usr\bin` in the "system" `PATH` rather than the "user" `PATH`.
|
||||
|
||||
After that, a `git clean -xfd`, `yarn`, and `yarn build` should resolve this issue.
|
||||
|
||||
### Xcode
|
||||
|
||||
If running `yarn bazel build packages/...` returns the following error:
|
||||
|
||||
```
|
||||
ERROR: /private/var/tmp/[...]/external/local_config_cc/BUILD:50:5: in apple_cc_toolchain rule @local_config_cc//:cc-compiler-darwin_x86_64: Xcode version must be specified to use an Apple CROSSTOOL
|
||||
ERROR: Analysis of target '//packages/core/test/render3:render3' failed; build aborted: Analysis of target '@local_config_cc//:cc-compiler-darwin_x86_64' failed; build aborted
|
||||
```
|
||||
|
||||
It might be linked to an interaction with VSCode.
|
||||
If closing VSCode fixes the issue, you can add the following line to your VSCode configuration:
|
||||
|
||||
```json
|
||||
"files.exclude": {"bazel-*": true}
|
||||
```
|
||||
|
||||
source: https://github.com/bazelbuild/bazel/issues/4603
|
||||
|
||||
If VSCode is not the root cause, you might try:
|
||||
|
||||
- Quit VSCode (make sure no VSCode is running).
|
||||
|
||||
```sh
|
||||
bazel clean --expunge
|
||||
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
|
||||
sudo xcodebuild -license
|
||||
yarn bazel build //packages/core # Run a build outside VSCode to pre-build the xcode; then safe to run VSCode
|
||||
```
|
||||
|
||||
Source: https://stackoverflow.com/questions/45276830/xcode-version-must-be-specified-to-use-an-apple-crosstool
|
||||
@@ -0,0 +1,49 @@
|
||||
# Caretaker
|
||||
|
||||
The *caretaker* is a role responsible for merging PRs and syncing into Google's
|
||||
internal code repository. The caretaker role rotates weekly.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
- Merging PR (PRs with [`action: merge`](https://github.com/angular/angular/pulls?q=is%3Aopen+is%3Apr+label%3A%22action%3A+merge%22) label)
|
||||
- Light issue triage [new issues](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Alabel).
|
||||
|
||||
## Merging the PR
|
||||
|
||||
A PR requires the `action: merge` and a `target: *` label to be merged.
|
||||
|
||||
The tooling automatically verifies the given PR is ready for merge. If the PR passes the tests, the
|
||||
tool will automatically merge it based on the applied target label.
|
||||
|
||||
To merge a PR run:
|
||||
|
||||
```sh
|
||||
$ yarn ng-dev pr merge <pr number>
|
||||
```
|
||||
|
||||
## Primitives and blocked merges
|
||||
|
||||
Some directories in the Angular codebase have additional protections or rules. For example, code
|
||||
under `//packages/core/primitives` must be merged and synced into Google separately from other
|
||||
changes. Attempting to combine changes in `primitives` with other changes results in an error. This
|
||||
practices makes it significantly easier to rollback or revert changes in the event of a breakage or
|
||||
outage.
|
||||
|
||||
## PRs that require global presubmits
|
||||
|
||||
Most PRs are tested against a curated subset of Angular application tests inside Google. However,
|
||||
if a change is deemed risky or otherwise requires more thorough testing, add the `requires: TGP`
|
||||
label to the PR. For such PRs, the merge tooling enforces that _all_ affected tests inside Google
|
||||
have been run (a "global presubmit"). A Googler can alternatively satisfy the merge tooling check by
|
||||
adding a review comment that starts with `TESTED=` and then put a reason why the PR is sufficiently
|
||||
tested. The `requires: TGP` label is automatically added to PRs that affect files
|
||||
matching `separateFilePatterns` in [`.ng-dev/google-sync-config.json`](https://github.com/angular/angular/blob/main/.ng-dev/google-sync-config.json).
|
||||
|
||||
An example of specfying a `TESTED=` comment:
|
||||
```
|
||||
TESTED=docs only update and does not need a TGP
|
||||
```
|
||||
|
||||
### Recovering from failed `merge-pr` due to conflicts
|
||||
|
||||
The `ng-dev pr merge` tool will automatically restore to the previous git state when a merge fails.
|
||||
@@ -0,0 +1,268 @@
|
||||
# Angular Framework Coding Standards
|
||||
|
||||
The coding practices in this doc apply only to development on Angular itself, not applications
|
||||
built _with_ Angular. (Though you can follow them too if you really want).
|
||||
|
||||
## Code style
|
||||
|
||||
The [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html) is the
|
||||
basis for Angular's coding style, with additional guidance here pertaining to TypeScript. The team
|
||||
uses `prettier` to automatically format code; automatic formatting is enforced by CI.
|
||||
|
||||
## Code practices
|
||||
|
||||
### Write useful comments
|
||||
|
||||
Comments that explain what some block of code does are nice; they can tell you something in less
|
||||
time than it would take to follow through the code itself.
|
||||
|
||||
Comments that explain why some block of code exists at all, or does something the way it does,
|
||||
are _invaluable_. The "why" is difficult, or sometimes impossible, to track down without seeking out
|
||||
the original author. When collaborators are in the same room, this hurts productivity.
|
||||
When collaborators are in different timezones, this can be devastating to productivity.
|
||||
|
||||
For example, this is a not-very-useful comment:
|
||||
```typescript
|
||||
// Set default tabindex.
|
||||
if (!attributes['tabindex']) {
|
||||
element.setAttribute('tabindex', '-1');
|
||||
}
|
||||
```
|
||||
|
||||
While this is much more useful:
|
||||
```typescript
|
||||
// Unless the user specifies otherwise, the calendar should not be a tab stop.
|
||||
// This prevents ngAria from overzealously adding a tabindex to anything with an ng-model.
|
||||
if (!attributes['tabindex']) {
|
||||
element.setAttribute('tabindex', '-1');
|
||||
}
|
||||
```
|
||||
|
||||
In TypeScript code, use JsDoc-style comments for descriptions (on classes, members, etc.) and
|
||||
use `//` style comments for everything else (explanations, background info, etc.).
|
||||
|
||||
### API Design
|
||||
|
||||
#### Boolean arguments
|
||||
|
||||
Generally avoid adding boolean arguments to a method in cases where that argument means
|
||||
"do something extra". In these cases, prefer breaking the behavior up into different functions.
|
||||
|
||||
```typescript
|
||||
// AVOID
|
||||
function getTargetElement(createIfNotFound = false) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
// PREFER
|
||||
function getExistingTargetElement() {
|
||||
// ...
|
||||
}
|
||||
|
||||
function createTargetElement() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
You can ignore this guidance when necessary for performance reasons in framework code.
|
||||
|
||||
#### Optional arguments
|
||||
|
||||
Use optional function arguments only when such an argument makes sense for an API or when required
|
||||
for performance. Don't use optional arguments merely for convenience in implementation.
|
||||
|
||||
### TypeScript
|
||||
|
||||
#### Typing
|
||||
|
||||
Avoid `any` where possible. If you find yourself using `any`, consider whether a generic or
|
||||
`unknown` may be appropriate in your case.
|
||||
|
||||
#### Getters and Setters
|
||||
|
||||
Getters and setters introduce openings for side effects, add more complexity for code readers,
|
||||
and generate additional code when targeting older browsers.
|
||||
|
||||
* Only use getters and setters for `@Input` properties or when otherwise required for API
|
||||
compatibility.
|
||||
* Avoid long or complex getters and setters. If the logic of an accessor would take more than
|
||||
three lines, introduce a new method to contain the logic.
|
||||
* A getter should immediately precede its corresponding setter.
|
||||
* Decorators such as `@Input` should be applied to the getter and not the setter.
|
||||
* Always use a `readonly` property instead of a getter (with no setter) when possible.
|
||||
|
||||
```typescript
|
||||
/** YES */
|
||||
readonly active: boolean;
|
||||
|
||||
/** NO */
|
||||
get active(): boolean {
|
||||
// Using a getter solely to make the property read-only.
|
||||
return this._active;
|
||||
}
|
||||
```
|
||||
|
||||
#### Iteration
|
||||
|
||||
Prefer `for` or `for of` to `Array.prototype.forEach`. The `forEach` API makes debugging harder
|
||||
and may increase overhead from unnecessary function invocations (though modern browsers do usually
|
||||
optimize this well).
|
||||
|
||||
#### JsDoc comments
|
||||
|
||||
All public APIs must have user-facing comments. These are extracted for API documentation and shown
|
||||
in IDEs.
|
||||
|
||||
Private and internal APIs should have JsDoc when they are not obvious. Ultimately it is the purview
|
||||
of the code reviewer as to what is "obvious", but the rule of thumb is that *most* classes,
|
||||
properties, and methods should have a JsDoc description.
|
||||
|
||||
Properties should have a concise description of what the property means:
|
||||
```typescript
|
||||
/** The label position relative to the checkbox. Defaults to 'after' */
|
||||
@Input() labelPosition: 'before' | 'after' = 'after';
|
||||
```
|
||||
|
||||
Methods blocks should describe what the function does and provide a description for each parameter
|
||||
and the return value:
|
||||
```typescript
|
||||
/**
|
||||
* Opens a modal dialog containing the given component.
|
||||
* @param component Type of the component to load into the dialog.
|
||||
* @param config Dialog configuration options.
|
||||
* @returns Reference to the newly-opened dialog.
|
||||
*/
|
||||
open<T>(component: ComponentType<T>, config?: MatDialogConfig): MatDialogRef<T> { ... }
|
||||
```
|
||||
|
||||
Boolean properties and return values should use "Whether..." as opposed to "True if...":
|
||||
```ts
|
||||
/** Whether the button is disabled. */
|
||||
disabled: boolean = false;
|
||||
```
|
||||
|
||||
#### Try-Catch
|
||||
|
||||
Only use `try-catch` blocks when dealing with legitimately unexpected errors. Don't use `try` to
|
||||
avoid checking for expected error conditions such as null dereference or out-of-bound array access.
|
||||
|
||||
Each `try-catch` block **must** include a comment that explains the
|
||||
specific error being caught and why it cannot be prevented.
|
||||
|
||||
##### Variable declarations
|
||||
|
||||
Prefer `const` wherever possible, only using `let` when a value must change. Avoid `var` unless
|
||||
absolutely necessary.
|
||||
|
||||
##### `readonly`
|
||||
|
||||
Use `readonly` members wherever possible.
|
||||
|
||||
#### Naming
|
||||
|
||||
##### General
|
||||
|
||||
* Prefer writing out words instead of using abbreviations.
|
||||
* Prefer *exact* names over short names (within reason). For example, `labelPosition` is better than
|
||||
`align` because the former much more exactly communicates what the property means.
|
||||
* Except for `@Input()` properties, use `is` and `has` prefixes for boolean properties / methods.
|
||||
* Name identifiers based on their responsibility. Names should capture what the code *does*,
|
||||
not how it is used:
|
||||
|
||||
```typescript
|
||||
/** NO: */
|
||||
class DefaultRouteReuseStrategy { }
|
||||
|
||||
/** YES: */
|
||||
class NonStoringRouteReuseStrategy { }
|
||||
```
|
||||
|
||||
##### Observables
|
||||
|
||||
Don't suffix observables with `$`.
|
||||
|
||||
##### Classes
|
||||
|
||||
* Use PascalCase (aka UpperCamelCase).
|
||||
* Class names should not end in `Impl`.
|
||||
|
||||
##### Interfaces
|
||||
|
||||
* Do not prefix interfaces with `I`.
|
||||
* Do not suffix interfaces with `Interface`.
|
||||
|
||||
##### Functions and methods
|
||||
|
||||
Use camelCase (aka lowerCamelCase).
|
||||
|
||||
The name of a function should capture the action performed *by* that method rather than
|
||||
describing when the method will be called. For example:
|
||||
|
||||
```typescript
|
||||
/** AVOID: does not describe what the function does. */
|
||||
handleClick() {
|
||||
// ...
|
||||
}
|
||||
|
||||
/** PREFER: describes the action performed by the function. */
|
||||
activateRipple() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
##### Constants and injection tokens
|
||||
|
||||
Use UPPER_SNAKE_CASE.
|
||||
|
||||
##### Test classes and examples
|
||||
|
||||
Give test classes and examples meaningful, descriptive names.
|
||||
|
||||
```ts
|
||||
/** PREFER: describes the scenario under test. */
|
||||
class FormGroupWithCheckboxAndRadios { /* ... */ }
|
||||
class InputWithNgModel { /* ... */ }
|
||||
|
||||
|
||||
/** AVOID: does not fully describe the scenario under test. */
|
||||
class Comp { /* ... */ }
|
||||
class InputComp { /* ... */ }
|
||||
```
|
||||
|
||||
#### RxJS
|
||||
|
||||
When importing the `of` function to create an `Observable` from a value, alias the imported
|
||||
function as `observableOf`.
|
||||
|
||||
```typescript
|
||||
import {of as observableOf} from 'rxjs';
|
||||
```
|
||||
|
||||
#### Testing
|
||||
|
||||
##### Test names
|
||||
|
||||
Use descriptive names for jasmine tests. Ideally, test names should read as a sentence, often of
|
||||
the form "it should...".
|
||||
|
||||
```typescript
|
||||
/** PREFER: describes the scenario under test. */
|
||||
describe('Router', () => {
|
||||
describe('with the default route reuse strategy', () => {
|
||||
it('should not reuse routes upon location change', () => {
|
||||
// ...
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
/** AVOID: does not fully describe the scenario under test. */
|
||||
describe('Router', () => {
|
||||
describe('default strategy', () => {
|
||||
it('should work', () => {
|
||||
// ...
|
||||
});
|
||||
})
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,157 @@
|
||||
# Debugging tips for developing on Angular
|
||||
|
||||
## Debugging tests
|
||||
|
||||
The Angular project has comprehensive unit tests for the core packages and the tools.
|
||||
Packages are tested both in the browser (via Karma) and on the server (via node.js).
|
||||
Angular uses the Jasmine test framework.
|
||||
|
||||
You can focus your debugging on one test at a time by changing that test to be
|
||||
defined using the `fit(...)` function, rather than `it(...)`. Moreover, it can be helpful
|
||||
to place a `debugger` statement in this `fit` clause to cause the debugger to stop when
|
||||
it hits this test.
|
||||
|
||||
For instructions on debugging both Karma and node.js tests, see
|
||||
[Building with bazel](./building-with-bazel.md).
|
||||
|
||||
## Angular debug tools in the dev console
|
||||
|
||||
Angular provides a set of debug tools that are accessible from any browser's
|
||||
developer console. In Chrome the dev console can be accessed by pressing
|
||||
Ctrl + Shift + j.
|
||||
|
||||
### Enabling debug tools
|
||||
|
||||
By default, the debug tools are disabled. You can enable debug tools as follows:
|
||||
|
||||
```typescript
|
||||
import {ApplicationRef} from '@angular/core';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import {enableDebugTools} from '@angular/platform-browser';
|
||||
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.then(moduleRef => {
|
||||
const applicationRef = moduleRef.injector.get(ApplicationRef);
|
||||
const appComponent = applicationRef.components[0];
|
||||
enableDebugTools(appComponent);
|
||||
})
|
||||
```
|
||||
|
||||
### Using debug tools
|
||||
|
||||
In the browser open the developer console (Ctrl + Shift + j in Chrome). The
|
||||
top level object is called `ng` and contains more specific tools inside it.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
### Change detection profiler
|
||||
|
||||
If your application is janky (it misses frames) or is slow according to other
|
||||
metrics, it is important to find the root cause of the issue. Change detection
|
||||
is a phase in Angular's lifecycle that detects changes in values that are
|
||||
bound to UI, and if it finds a change it performs the corresponding UI update.
|
||||
However, sometimes it is hard to tell if the slowness is due to the act of
|
||||
computing the changes being slow, or due to the act of applying those changes
|
||||
to the UI. For your application to be performant it is important that the
|
||||
process of computing changes is very fast. For best results it should be under
|
||||
3 milliseconds in order to leave room for the application logic, the UI updates
|
||||
and browser's rendering pipeline to fit within the 16 millisecond frame
|
||||
(assuming the 60 FPS target frame rate).
|
||||
|
||||
Change detection profiler repeatedly performs change detection without invoking
|
||||
any user actions, such as clicking buttons or entering text in input fields. It
|
||||
then computes the average amount of time it took to perform a single cycle of
|
||||
change detection in milliseconds and prints it to the console. This number
|
||||
depends on the current state of the UI. You will likely see different numbers
|
||||
as you go from one screen in your application to another.
|
||||
|
||||
#### Running the profiler
|
||||
|
||||
Enable debug tools (see above), then in the dev console enter the following:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The results will be printed to the console.
|
||||
|
||||
#### Recording CPU profile
|
||||
|
||||
Pass `{record: true}` an argument:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then open the "Profiles" tab. You will see the recorded profile titled
|
||||
"Change Detection". In Chrome, if you record the profile repeatedly, all the
|
||||
profiles will be nested under "Change Detection".
|
||||
|
||||
#### Interpreting the numbers
|
||||
|
||||
In a properly-designed application repeated attempts to detect changes without
|
||||
any user actions should result in no changes to be applied on the UI. It is
|
||||
also desirable to have the cost of a user action be proportional to the amount
|
||||
of UI changes required. For example, popping up a menu with 5 items should be
|
||||
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
|
||||
change detection with no UI updates should be as fast as possible. Ideally the
|
||||
number printed by the profiler should be well below the length of a single
|
||||
animation frame (16ms). A good rule of thumb is to keep it under 3ms.
|
||||
|
||||
#### Investigating slow change detection
|
||||
|
||||
So you found a screen in your application on which the profiler reports a very
|
||||
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
|
||||
recording while profiling:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then look for hot spots using
|
||||
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
|
||||
|
||||
#### Reducing change detection cost
|
||||
|
||||
There are many reasons for slow change detection. To gain intuition about
|
||||
possible causes it would help to understand how change detection works. Such a
|
||||
discussion is outside the scope of this document (TODO link to docs), but here
|
||||
are some key concepts in brief.
|
||||
|
||||
By default Angular uses "dirty checking" mechanism for finding model changes.
|
||||
This mechanism involves evaluating every bound expression that's active on the
|
||||
UI. These usually include text interpolation via `{{expression}}` and property
|
||||
bindings via `[prop]="expression"`. If any of the evaluated expressions are
|
||||
costly to compute they could contribute to slow change detection. A good way to
|
||||
speed things up is to use plain class fields in your expressions and avoid any
|
||||
kinds of computation. Example:
|
||||
|
||||
```typescript
|
||||
@Component({
|
||||
template: '<button [enabled]="isEnabled">{{title}}</button>'
|
||||
})
|
||||
class FancyButton {
|
||||
// GOOD: no computation, just return the value
|
||||
isEnabled: boolean;
|
||||
|
||||
// BAD: computes the final value upon request
|
||||
_title: String;
|
||||
get title(): String { return this._title.trim().toUpperCase(); }
|
||||
}
|
||||
```
|
||||
|
||||
Most cases like these could be solved by precomputing the value and storing the
|
||||
final value in a field.
|
||||
|
||||
Angular also supports a second type of change detection - the "push" model. In
|
||||
this model Angular does not poll your component for changes. Instead, the
|
||||
component "tells" Angular when it changes and only then does Angular perform
|
||||
the update. This model is suitable in situations when your data model uses
|
||||
observable or immutable objects (also a discussion for another time).
|
||||
@@ -0,0 +1,24 @@
|
||||
## Releasing APIs before they're fully stable
|
||||
|
||||
The Angular team may occasionally seek to release a feature or API without immediately
|
||||
including this API in Angular's normal support and deprecation category. You can use
|
||||
one of two labels on such APIs: Developer Preview and Experimental. APIs tagged this way
|
||||
are not subject to Angular's breaking change and deprecation policy.
|
||||
|
||||
Use the sections below to decide whether a pre-stable tag makes sense.
|
||||
|
||||
### Developer Preview
|
||||
|
||||
Use "Developer Preview" when:
|
||||
* The team has relatively high confidence the API will ship as stable.
|
||||
* The team needs additional community feedback before fully committing to an exact API shape.
|
||||
* The API may undergo only minor, superficial changes. This can include changes like renaming
|
||||
or reordering parameters, but should not include significant conceptual or structural changes.
|
||||
|
||||
### Experimental
|
||||
|
||||
Use "Experimental" when:
|
||||
* The team has low-to-medium confidence that the API should exist at all.
|
||||
* The team needs additional community feedback before deciding to move forward with the API at all.
|
||||
* The API may undergo significant conceptual or structural changes.
|
||||
* The API relies on a not-yet-standardized platform feature.
|
||||
@@ -0,0 +1,47 @@
|
||||
<a name="feature-request"></a>
|
||||
|
||||
# Feature request process
|
||||
|
||||
To manage the requests we receive at scale, we introduced automation in our feature request
|
||||
management process. After we identify an issue as a feature request, it goes through several steps.
|
||||
|
||||
## Manual review
|
||||
|
||||
First, we manually review the issue to see if it aligns with any of the existing roadmap efforts. If
|
||||
it does, we prioritize it accordingly. Alternatively, we keep it open and our feature request bot
|
||||
initiates a voting process.
|
||||
|
||||
## Voting phase
|
||||
|
||||
To include the community in the feature request process, we open voting for a fixed length of time.
|
||||
Anyone can cast a vote for the request with a thumbs-up (👍) reaction on the original issue
|
||||
description.
|
||||
When a feature request reaches 20 or more upvotes, we formally consider the feature request.
|
||||
Alternatively, the bot closes the request.
|
||||
|
||||
**For issues that are 60+ days old**: The voting phase is 20 days
|
||||
|
||||
**For new issues**: The voting phase is 60 days
|
||||
|
||||
## Consideration phase
|
||||
|
||||
If the feature request receives 20 or more thumbs-up (👍) votes on the original issue description
|
||||
(during the voting phase described above), we verify the Angular team can afford to maintain the
|
||||
feature and whether it aligns with the long-term vision of Angular. If the answers to both of these
|
||||
questions are yes, we prioritize the request, alternatively we close it with an explanation of our
|
||||
decision.
|
||||
|
||||
## Diagram
|
||||
|
||||
<p align="center" width="100%">
|
||||
<img src="./images/feature-request-automation.png" alt="Feature Request Automation">
|
||||
</p>
|
||||
|
||||
## What if I want to implement the feature to help the Angular team?
|
||||
|
||||
Often implementing the feature as a separate package is a better option. Building an external
|
||||
package rather than including the functionality in Angular helps with:
|
||||
|
||||
- Keeping the framework's runtime smaller and simpler
|
||||
- Makes the learning journey of developers getting started with Angular smoother
|
||||
- Reduces maintainers burden and the complexity of the source code
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
@@ -0,0 +1,114 @@
|
||||
# Supported public API surface of angular/angular code
|
||||
|
||||
Angular's SemVer, release schedule, and deprecation policy applies to these npm packages:
|
||||
|
||||
- `@angular/animations`
|
||||
- `@angular/common`
|
||||
- `@angular/core`
|
||||
- `@angular/elements`
|
||||
- `@angular/forms`
|
||||
- `@angular/platform-browser-dynamic`
|
||||
- `@angular/platform-browser`
|
||||
- `@angular/platform-server`
|
||||
- `@angular/router`
|
||||
- `@angular/service-worker`
|
||||
- `@angular/upgrade`
|
||||
|
||||
The `@angular/compiler` package is explicitly excluded from this list. The compiler is a generally
|
||||
considered private/internal API and may change at any time. Only very specific use-cases, such as
|
||||
linters or IDE integration, require direct access to the compiler API. If you are
|
||||
working on this kind of integration, please reach out to us first.
|
||||
|
||||
Additionally, only the command line usage (not direct use of APIs) of
|
||||
`@angular/compiler-cli` is covered.
|
||||
|
||||
Within the supported packages, Angular keeps stable:
|
||||
|
||||
- Symbols exported via the main entry point (e.g. `@angular/core`) and testing entry point (
|
||||
e.g. `@angular/core/testing`). This applies to both runtime/JavaScript values and TypeScript
|
||||
types.
|
||||
- Symbols exported via global namespace `ng` (e.g. `ng.core`)
|
||||
|
||||
We explicitly consider the following to be _excluded_ from the public API:
|
||||
|
||||
- Any file/import paths within our package except for the `/`, `/testing` and `/bundles/*` and other
|
||||
documented package entry-points.
|
||||
- Constructors of injectable classes (services and directives). Use dependency injection to obtain
|
||||
instances of these classes
|
||||
- Any class members or symbols marked as `private`, or prefixed with
|
||||
underscore (`_`), [barred latin o](https://en.wikipedia.org/wiki/%C6%9F) (`ɵ`), and double barred latin o (`ɵɵ`).
|
||||
- Extending any of our classes unless the support for this is specifically documented in the API
|
||||
reference.
|
||||
- The contents and API surface of the code generated by Angular's compiler.
|
||||
- The `@angular/core/primitives` package, including its descendant entry-points.
|
||||
|
||||
Our peer dependencies (such as TypeScript, Zone.js, or RxJS) are not considered part of our API
|
||||
surface, but they are included in our SemVer policies. We might update the required version of these
|
||||
dependencies in minor releases if the update doesn't cause breaking changes for Angular
|
||||
applications. Peer dependency updates that result in non-trivial breaking changes must be deferred
|
||||
to major Angular releases.
|
||||
|
||||
<a name="final-classes"></a>
|
||||
|
||||
## Extending Angular classes
|
||||
|
||||
All classes in Angular's public API are considered `final`. They should not be extended unless
|
||||
explicitly stated in the API documentation.
|
||||
|
||||
Extending such classes is not supported, since protected members and internal implementation may
|
||||
change outside major releases.
|
||||
|
||||
<a name="golden-files"></a>
|
||||
|
||||
## Golden files
|
||||
|
||||
Angular tracks the status of the public API in a *golden file*, maintained with a tool called the
|
||||
*public API guard*.
|
||||
If you modify any part of a public API in one of the supported public packages, the PR will fail a
|
||||
test in CI with an error message that instructs you to accept the golden file.
|
||||
|
||||
The public API guard provides a Bazel target that updates the current status of a given package. If
|
||||
you add to or modify the public API in any way, you must use [yarn](https://yarnpkg.com/) to execute
|
||||
the Bazel target in your terminal shell of choice (a recent version of `bash` is recommended).
|
||||
|
||||
```shell
|
||||
yarn bazel run //packages/<modified_package>:<modified_package>_api.accept
|
||||
```
|
||||
|
||||
Here is an example of a CI test failure that resulted from adding a new allowed type to a public
|
||||
property in `core.d.ts`. Error messages from the API guard use [`git-diff` formatting](https://git-scm.com/docs/git-diff#_combined_diff_format).
|
||||
|
||||
```
|
||||
FAIL: //packages/core:core_api (see /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/execroot/angular/bazel-out/k8-fastbuild/testlogs/packages/core/core_api/test_attempts/attempt_1.log)
|
||||
INFO: From Action packages/compiler-cli/ngcc/test/fesm5_angular_core.js:
|
||||
[BABEL] Note: The code generator has deoptimised the styling of /b/f/w/bazel-out/k8-fastbuild/bin/packages/core/npm_package/fesm2015/core.js as it exceeds the max of 500KB.
|
||||
FAIL: //packages/core:core_api (see /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/execroot/angular/bazel-out/k8-fastbuild/testlogs/packages/core/core_api/test.log)
|
||||
|
||||
FAILED: //packages/core:core_api (Summary)
|
||||
/home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/execroot/angular/bazel-out/k8-fastbuild/testlogs/packages/core/core_api/test.log
|
||||
/home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/execroot/angular/bazel-out/k8-fastbuild/testlogs/packages/core/core_api/test_attempts/attempt_1.log
|
||||
INFO: From Testing //packages/core:core_api:
|
||||
==================== Test output for //packages/core:core_api:
|
||||
/b/f/w/bazel-out/k8-fastbuild/bin/packages/core/core_api.sh.runfiles/angular/packages/core/npm_package/core.d.ts(7,1): error: No export declaration found for symbol "ComponentFactory"
|
||||
--- goldens/public-api/core/core.d.ts Golden file
|
||||
+++ goldens/public-api/core/core.d.ts Generated API
|
||||
@@ -563,9 +563,9 @@
|
||||
ngModule: Type<T>;
|
||||
providers?: Provider[];
|
||||
}
|
||||
|
||||
-export declare type NgIterable<T> = Array<T> | Iterable<T>;
|
||||
+export declare type NgIterable<T> = Iterable<T>;
|
||||
|
||||
export declare interface NgModule {
|
||||
bootstrap?: Array<Type<any> | any[]>;
|
||||
declarations?: Array<Type<any> | any[]>;
|
||||
|
||||
|
||||
If you modify a public API, you must accept the new golden file.
|
||||
|
||||
|
||||
To do so, execute the following Bazel target:
|
||||
yarn bazel run //packages/core:core_api.accept
|
||||
|
||||
```
|
||||
@@ -0,0 +1,35 @@
|
||||
## Benchmarks
|
||||
|
||||
- Benchmarks code can be found in: `/modules/benchmarks/src`.
|
||||
- Benchmarks convenience script code in `/scripts/benchmarks`.
|
||||
- Benchpress (the sample runner) in `/packages/benchpress`.
|
||||
|
||||
### Running benchmark
|
||||
|
||||
```
|
||||
yarn benchmarks run
|
||||
```
|
||||
|
||||
### Running a comparison with local changes
|
||||
|
||||
```
|
||||
yarn benchmarks run-compare main
|
||||
yarn benchmarks run-compare <compare-sha> [bazel-target]
|
||||
```
|
||||
|
||||
If no benchmark target is specified, a prompt will allow you to select an available benchmark.
|
||||
|
||||
### Running a comparison in a PR
|
||||
|
||||
You can start a comparison by adding a comment as followed to any PR:
|
||||
|
||||
```
|
||||
/benchmark-compare main //modules/benchmarks/src/expanding_rows:perf_chromium
|
||||
```
|
||||
|
||||
```
|
||||
/benchmark-compare <other-sha> //modules/benchmarks/src/expanding_rows:perf_chromium
|
||||
```
|
||||
|
||||
**Note**: An explicit benchmark target must be provided. You can use the prompt
|
||||
of `yarn benchmarks run` to discover available benchmarks.
|
||||
@@ -0,0 +1,98 @@
|
||||
# Saved Responses for Angular's Issue Tracker
|
||||
|
||||
This doc collects canned responses that the Angular team can use to close issues that fall into the
|
||||
listed resolution categories.
|
||||
|
||||
Since GitHub currently doesn't allow us to have a repository-wide or organization-wide list
|
||||
of [saved replies](https://help.github.com/articles/working-with-saved-replies/), these replies need
|
||||
to be maintained by individual team members. Since the responses can be modified in the future, all
|
||||
responses are versioned to simplify the process of keeping the responses up to date.
|
||||
|
||||
## Angular: Already Fixed (v3)
|
||||
|
||||
```
|
||||
Thanks for reporting this issue. Luckily it has already been fixed in one of the recent releases. Please update to the most recent version to resolve the problem.
|
||||
|
||||
If after upgrade the problem still exists in your application please [open a new issue](https://github.com/angular/angular/issues/new/choose) and follow the instructions in the issue template.
|
||||
```
|
||||
|
||||
## Angular: Don't Understand (v3)
|
||||
|
||||
```
|
||||
I'm sorry but we don't understand the problem you are reporting.
|
||||
|
||||
If the problem still exists in your application, please [open a new issue](https://github.com/angular/angular/issues/new/choose) and follow the instructions in the issue template.
|
||||
```
|
||||
|
||||
## Angular: Can't reproduce (v2)
|
||||
|
||||
```
|
||||
I'm sorry but we can't reproduce the problem you are reporting. We require that reported issues have a minimal reproduction that showcases the problem.
|
||||
|
||||
If the problem still exists in your application, please [open a new issue](https://github.com/angular/angular/issues/new/choose) and follow the instructions in the issue template that include info on how to create a reproduction using our template.
|
||||
```
|
||||
|
||||
## Angular: Duplicate (v2)
|
||||
|
||||
```
|
||||
Thanks for reporting this issue. However this issue is a duplicate of an existing issue #ISSUE_NUMBER. Please subscribe to that issue for future updates.
|
||||
```
|
||||
|
||||
## Angular: Insufficient Information Provided (v2)
|
||||
|
||||
```
|
||||
Thanks for reporting this issue. However, you didn't provide sufficient information for us to understand and reproduce the problem. Please check out [our submission guidelines](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#submit-issue) to understand why we can't act on issues that are lacking important information.
|
||||
|
||||
If the problem still exists in your application, please [open a new issue](https://github.com/angular/angular/issues/new/choose) and follow the instructions in the issue template.
|
||||
|
||||
```
|
||||
|
||||
## Angular: Issue Outside of Angular (v2)
|
||||
|
||||
```
|
||||
I'm sorry but this issue is not caused by Angular. Please contact the author(s) of project PROJECT_NAME or file issue on their issue tracker.
|
||||
```
|
||||
|
||||
## Angular: Behaving as Expected (v1)
|
||||
|
||||
```
|
||||
It appears this behaves as expected. If you still feel there is an issue, please provide further details in a new issue.
|
||||
```
|
||||
|
||||
## Angular: Non-reproducible (v2)
|
||||
|
||||
```
|
||||
I'm sorry but we can't reproduce the problem following the instructions you provided.
|
||||
|
||||
If the problem still exists in your application please [open a new issue](https://github.com/angular/angular/issues/new/choose) and follow the instructions in the issue template.
|
||||
```
|
||||
|
||||
## Angular: Obsolete (v2)
|
||||
|
||||
```
|
||||
Thanks for reporting this issue. This issue is now obsolete due to changes in the recent releases. Please update to the most recent Angular version.
|
||||
|
||||
If the problem still exists in your application, please [open a new issue](https://github.com/angular/angular/issues/new/choose) and follow the instructions in the issue template.
|
||||
```
|
||||
|
||||
## Angular: Support Request (v1)
|
||||
|
||||
```
|
||||
Hello, we reviewed this issue and determined that it doesn't fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on [StackOverflow](https://stackoverflow.com/) using tag `angular`.
|
||||
|
||||
If you are wondering why we don't resolve support issues via the issue tracker, please [check out this explanation](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#question).
|
||||
```
|
||||
|
||||
## Angular: Commit Header
|
||||
|
||||
```
|
||||
It looks like you need to update your commit header to match our requirements. This is different from the PR title. To update the commit header, use the command `git commit --amend` and update the header there.
|
||||
|
||||
Once you've finished that update, you will need to force push using `git push [origin name] [branch name] --force`. That should address this.
|
||||
```
|
||||
|
||||
## Angular: Rebase and Squash
|
||||
|
||||
```
|
||||
Please rebase and squash your commits. To do this, make sure to `git fetch upstream` to get the latest changes from the angular repository. Then in your branch run `git rebase upstream/main -i` to do an interactive rebase. This should allow you to fixup or drop any unnecessary commits. After you finish the rebase, force push using `git push [origin name] [branch name] --force`.
|
||||
```
|
||||
@@ -0,0 +1,225 @@
|
||||
# Triage Process and GitHub Labels for Angular
|
||||
|
||||
This document describes how the Angular team uses labels and milestones to triage issues on GitHub.
|
||||
The basic idea of the process is that caretaker only assigns a component (`area: *`) label.
|
||||
The owner of the component is then responsible for the detailed / component-level triage.
|
||||
|
||||
## Label Types
|
||||
|
||||
### Areas
|
||||
|
||||
The caretaker should be able to determine the _area_ for incoming issues.
|
||||
Most areas generally corresponds to a specific directory or set of directories in this repo. Some
|
||||
areas are more cross-cutting (e.g. for performance or security). Apply all labels that make sense
|
||||
for an issue. Each `area: ` label on GitHub should have a description of what it's for.
|
||||
|
||||
### Community engagement
|
||||
|
||||
* `help wanted` - Indicates an issue whose complexity/scope makes it suitable for a community
|
||||
contributor to pick up.
|
||||
* `good first issue` - Indicates an issue that is suitable for first-time contributors.
|
||||
(This label should be applied _in addition_ to `help wanted` for better discoverability.)
|
||||
|
||||
<sub>`help wanted` and `good first issue` are [default GitHub labels] familiar to many
|
||||
developers.</sub>
|
||||
|
||||
[default GitHub labels]: https://docs.github.com/en/github/managing-your-work-on-github/managing-labels#about-default-labels
|
||||
|
||||
## Caretaker Triage Process (Initial Triage)
|
||||
|
||||
The caretaker assigns `area: *` labels to new issues as they come in.
|
||||
Untriaged issues can be found by selecting the issues with no milestone.
|
||||
|
||||
If an issue or PR obviously relates to a release regression, the caretaker must assign an
|
||||
appropriate priority (`P0` or `P1`) and ensure that someone from the team is actively working to
|
||||
resolve it.
|
||||
|
||||
Initial triage should occur daily so that issues can move into detailed triage.
|
||||
|
||||
Once the initial triage is done, the ng-bot automatically adds the milestone `needsTriage`.
|
||||
|
||||
## Detailed Triage
|
||||
|
||||
Detailed triage can be done by anyone familiar with the issue's area.
|
||||
|
||||
### Step 1: Does the issue have enough information?
|
||||
|
||||
Gauge whether the issue has enough information to act upon. This typically includes a test case
|
||||
via StackBlitz or GitHub and steps to reproduce. If the issue may be legitimate but needs more
|
||||
information, add the "needs clarification" label. These labels can be revisited if the author can
|
||||
provide further clarification. If the issue does have enough information, move on to step 2.
|
||||
|
||||
### Step 2: Bug, feature, or discussion?
|
||||
|
||||
By default, all issues are considered bugs. Bug reports require only a priority label.
|
||||
|
||||
If the issue is a feature request, apply the "feature" label. Use your judgement to determine
|
||||
whether the feature request is reasonable. If it's clear that the issue requests something
|
||||
infeasible, close the issue with a comment explaining why.
|
||||
|
||||
If the issue is an RFC or discussion, apply the "discussion" label. Use your judgement to determine
|
||||
whether this discussion belongs on GitHub. Discussions here should pertain to the technical
|
||||
implementation details of Angular. Redirect requests for debugging help or advice to a more
|
||||
appropriate channel unless they're capturing a legitimate bug.
|
||||
|
||||
### Step 3: Set a Priority
|
||||
|
||||
For bug reports, set a priority label.
|
||||
|
||||
| Label | Description |
|
||||
|-------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| P0 | An issue that causes a full outage, breakage, or major function unavailability for everyone, without any known workaround. The issue must be fixed immediately, taking precedence over all other work. Should receive updates at least once per day. |
|
||||
| P1 | An issue that significantly impacts a large percentage of users; if there is a workaround it is partial or overly painful. The issue should be resolved before the next release. |
|
||||
| P2 | The issue is important to a large percentage of users, with a workaround. Issues that are significantly ugly or painful (especially first-use or install-time issues). Issues with workarounds that would otherwise be P0 or P1. |
|
||||
| P3 | An issue that is relevant to core functions, but does not impede progress. Important, but not urgent. |
|
||||
| P4 | A relatively minor issue that is not relevant to core functions, or relates only to the attractiveness or pleasantness of use of the system. Good to have but not necessary changes/fixes. |
|
||||
| P5 | The team acknowledges the request but (due to any number of reasons) does not plan to work on or accept contributions for this request. The issue remains open for discussion. |
|
||||
|
||||
Issues marked with "feature" or "discussion" don't require a priority.
|
||||
|
||||
### Step 4: Apply additional information labels
|
||||
|
||||
Many optional labels provide additional context for issues. Consider adding any of the following if
|
||||
they apply to the issue:
|
||||
|
||||
* Browser or operating system labels (`windows`, `browser: ie 11`, etc.)
|
||||
* Labels that inform the severity (`regression`, `has workaround`, `no workaround`)
|
||||
* Labels that categorize the bug (`performance`, `refactoring`, `memory leak`)
|
||||
* Community engagement labels (`help wanted`, `good first issue`)
|
||||
|
||||
Once this triage is done, the ng-bot automatically changes the milestone from `needs triage` to
|
||||
`Backlog`.
|
||||
|
||||
## Triaging PRs
|
||||
|
||||
PRs labels signal their state. Every triaged PR must have a `action: *` label assigned to it:
|
||||
|
||||
* `action: discuss`: Discussion is needed, to be led by the author.
|
||||
* _**Who adds it:** Typically the PR author._
|
||||
* _**Who removes it:** Whoever added it._
|
||||
* `action: review` (optional): One or more reviews are pending. The label is optional, since the
|
||||
review status can be derived from GitHub's Reviewers interface.
|
||||
* _**Who adds it:** Any team member. The caretaker can use it to differentiate PRs pending
|
||||
review from merge-ready PRs._
|
||||
* _**Who removes it:** Whoever added it or the reviewer adding the last missing review._
|
||||
* `action: cleanup`: More work is needed from the author.
|
||||
* _**Who adds it:** The reviewer requesting changes to the PR._
|
||||
* _**Who removes it:** Either the author (after implementing the requested changes) or the
|
||||
reviewer (after confirming the requested changes have been implemented)._
|
||||
* `action: merge`: The PR author is ready for the changes to be merged by the caretaker as soon as
|
||||
the PR is green (or merge-assistance label is applied and caretaker has deemed it acceptable
|
||||
manually). In other words, this label indicates to "auto submit when ready".
|
||||
* _**Who adds it:** Typically the PR author._
|
||||
* _**Who removes it:** Whoever added it._
|
||||
|
||||
In addition, PRs can have the following states:
|
||||
|
||||
* `state: WIP`: PR is experimental or rapidly changing. Not ready for review or triage.
|
||||
* _**Who adds it:** The PR author._
|
||||
* _**Who removes it:** Whoever added it._
|
||||
* `state: blocked`: PR is blocked on an issue or other PR. Not ready for merge.
|
||||
* _**Who adds it:** Any team member._
|
||||
* _**Who removes it:** Any team member._
|
||||
|
||||
When a PR is ready for review, a review should be requested using the Reviewers interface in GitHub.
|
||||
|
||||
## PR Target
|
||||
|
||||
See [Branches and versioning](./branches-and-versioning.md) for background on how Angular
|
||||
manages its branches and versioning.
|
||||
|
||||
In our git workflow, we merge changes either to the `main` branch, the active patch branch (
|
||||
e.g. `5.0.x`), or to both.
|
||||
|
||||
The decision about the target must be done by the PR author and/or reviewer.
|
||||
This decision is then honored when the PR is being merged by the caretaker.
|
||||
|
||||
To communicate the target we use GitHub labels and only one target label may be applied to a PR.
|
||||
|
||||
Targeting an active release train:
|
||||
|
||||
* `target: major`: Any breaking change
|
||||
* `target: minor`: Any new feature
|
||||
* `target: patch`: Bug fixes, refactorings, documentation changes, etc. that pose no or very low
|
||||
risk of adversely
|
||||
affecting existing applications.
|
||||
|
||||
Special Cases:
|
||||
|
||||
* `target: rc`: A critical fix for an active release-train while it is in a feature freeze or RC
|
||||
phase
|
||||
* `target: lts`: A critical fix for a specific release-train that is still within the long term
|
||||
support phase
|
||||
|
||||
Notes:
|
||||
|
||||
- To land a change only in a patch/RC branch, without landing it in any other active release-train
|
||||
branch (such
|
||||
as `main`), the patch/RC branch can be targeted in the GitHub UI with the appropriate
|
||||
`target: patch`/`target: rc` label.
|
||||
- `target: lts` PRs must target the specific LTS branch they would need to merge into in the GitHub
|
||||
UI, in
|
||||
cases which a change is desired in multiple LTS branches, individual PRs for each LTS branch must
|
||||
be created
|
||||
|
||||
If a PR is missing the `target:*` label, it will be marked as pending by the angular robot status
|
||||
checks.
|
||||
|
||||
## PR Approvals
|
||||
|
||||
Before a PR can be merged it must be approved by the appropriate reviewer(s).
|
||||
|
||||
To ensure that the right people review each change, we set review requests
|
||||
using [PullApprove](https://docs.pullapprove.com/) (via `.pullapprove`) and require that each PR has
|
||||
at least one approval from an appropriate code owner.
|
||||
|
||||
If the PR author is a code owner themselves, the approval can come from _any_ repo collaborator (
|
||||
person with write access).
|
||||
In any case, the reviewer should actually look through the code and provide feedback if necessary.
|
||||
|
||||
Note that approved state does not mean a PR is ready to be merged.
|
||||
For example, a reviewer might approve the PR but request a minor tweak that doesn't need further
|
||||
review, e.g., a rebase or small uncontroversial change.
|
||||
Only the `action: merge` label means that the PR is ready for merging.
|
||||
|
||||
## Special Labels
|
||||
|
||||
### `cla: yes`, `cla: no`
|
||||
|
||||
* _**Who adds it:** @googlebot, or a Googler manually overriding the status in case the bot got it
|
||||
wrong._
|
||||
* _**Who removes it:** @googlebot._
|
||||
|
||||
Managed by googlebot.
|
||||
Indicates whether a PR has a CLA on file for its author(s).
|
||||
Only issues with `cla:yes` should be merged into main.
|
||||
|
||||
### `adev: preview`
|
||||
|
||||
* _**Who adds it:** Any team member. (Typically the author or a reviewer.)_
|
||||
* _**Who removes it:** Any team member. (Typically, whoever added it.)_
|
||||
|
||||
Applying this label to a PR makes the angular.dev preview available regardless of the
|
||||
author.
|
||||
|
||||
### `action: merge-assistance`
|
||||
|
||||
* _**Who adds it:** Any team member._
|
||||
* _**Who removes it:** Any team member._
|
||||
|
||||
This label can be added to let the caretaker know that the PR needs special attention.
|
||||
There should always be a comment added to the PR to explain why the caretaker's assistance is
|
||||
needed.
|
||||
The comment should be formatted like
|
||||
this: `merge-assistance: <explain what kind of assistance you need, and if not obvious why>`
|
||||
|
||||
For example, the PR owner might not be a Googler and needs help to run g3sync; or one of the checks
|
||||
is failing due to external causes and the PR should still be merged.
|
||||
|
||||
### `action: rerun CI at HEAD`
|
||||
|
||||
* _**Who adds it:** Any team member._
|
||||
* _**Who removes it:** The Angular Bot, once it triggers the CI rerun._
|
||||
|
||||
This label can be added to instruct the Angular Bot to rerun the CI jobs for the PR at latest HEAD
|
||||
of the branch it targets.
|
||||
@@ -0,0 +1,111 @@
|
||||
# Working with fixup commits
|
||||
|
||||
This document provides information and guidelines for working with fixup commits:
|
||||
|
||||
- [What are fixup commits](#about-fixup-commits)
|
||||
- [Why use fixup commits](#why-fixup-commits)
|
||||
- [Creating fixup commits](#create-fixup-commits)
|
||||
- [Squashing fixup commits](#squash-fixup-commits)
|
||||
|
||||
[This blog post](https://thoughtbot.com/blog/autosquashing-git-commits) is also a good resource on
|
||||
the subject.
|
||||
|
||||
## <a name="about-fixup-commits"></a> What are fixup commits
|
||||
|
||||
At their core, fixup commits are just regular commits with a special commit message:
|
||||
The first line of their commit message starts with "fixup! " (notice the space after "!") followed
|
||||
by the first line of the commit message of an earlier commit (it doesn't have to be the immediately
|
||||
preceding one).
|
||||
|
||||
The purpose of a fixup commit is to modify an earlier commit.
|
||||
I.e. it allows adding more changes in a new commit, but "marking" them as belonging to an earlier
|
||||
commit.
|
||||
`Git` provides tools to make it easy to squash fixup commits into the original commit at a later
|
||||
time (see [below](#squash-fixup-commits) for details).
|
||||
|
||||
For example, let's assume you have added the following commits to your branch:
|
||||
|
||||
```
|
||||
feat: first commit
|
||||
fix: second commit
|
||||
```
|
||||
|
||||
If you want to add more changes to the first commit, you can create a new commit with the commit
|
||||
message:
|
||||
`fixup! feat: first commit`:
|
||||
|
||||
```
|
||||
feat: first commit
|
||||
fix: second commit
|
||||
fixup! feat: first commit
|
||||
```
|
||||
|
||||
## <a name="why-fixup-commits"></a> Why use fixup commits
|
||||
|
||||
So, when are fixup commits useful?
|
||||
|
||||
During the life of a Pull Request, a reviewer might request changes.
|
||||
The Pull Request author can make the requested changes and submit them for another review.
|
||||
Normally, these changes should be part of one of the original commits of the Pull Request.
|
||||
However, amending an existing commit with the changes makes it difficult for the reviewer to know
|
||||
exactly what has changed since the last time they reviewed the Pull Request.
|
||||
|
||||
Here is where fixup commits come in handy.
|
||||
By addressing review feedback in fixup commits, you make it very straight forward for the reviewer
|
||||
to see what are the new changes that need to be reviewed and verify that their earlier feedback has
|
||||
been addressed.
|
||||
This can save a lot of effort, especially on larger Pull Requests (where having to re-review _all_
|
||||
the changes is pretty wasteful).
|
||||
|
||||
When the time comes to merge the Pull Request into the repository, the merge script knows how to
|
||||
automatically squash fixup commits with the corresponding regular commits.
|
||||
|
||||
## <a name="create-fixup-commits"></a> Creating fixup commits
|
||||
|
||||
As mentioned [above](#about-fixup-commits), the only thing that differentiates a fixup commit from a
|
||||
regular commit is the commit message.
|
||||
You can create a fixup commit by specifying an appropriate commit message (
|
||||
i.e. `fixup! <original-commit-message-subject>`).
|
||||
|
||||
In addition, the `git` command-line tool provides an easy way to create a fixup commit
|
||||
via [git commit --fixup](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---fixupltcommitgt):
|
||||
|
||||
```sh
|
||||
# Create a fixup commit to fix up the last commit on the branch:
|
||||
git commit --fixup HEAD ...
|
||||
|
||||
# Create a fixup commit to fix up commit with SHA <COMMIT_SHA>:
|
||||
git commit --fixup <COMMIT_SHA> ...
|
||||
```
|
||||
|
||||
## <a name="squash-fixup-commits"></a> Squashing fixup commits
|
||||
|
||||
As mentioned above, the merge script will automatically squash fixup commits.
|
||||
However, sometimes you might want to manually squash a fixup commit.
|
||||
|
||||
### Rebasing to squash fixup commits
|
||||
|
||||
The easiest way to re-order and squash any commit is
|
||||
via [rebasing interactively](https://git-scm.com/docs/git-rebase#_interactive_mode). You move a
|
||||
commit right after the one you want to squash it into in the rebase TODO list and change the
|
||||
corresponding action from `pick` to `fixup`.
|
||||
|
||||
`Git` can do all these automatically for you if you pass the `--autosquash` option to `git rebase`.
|
||||
See the [`git` docs](https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---autosquash)
|
||||
for more details.
|
||||
|
||||
### Additional options
|
||||
|
||||
You may like to consider some optional configurations:
|
||||
|
||||
#### Configuring `git` to auto-squash by default
|
||||
|
||||
By default, `git` will not automatically squash fixup commits when interactively rebasing.
|
||||
If you prefer to not have to pass the `--autosquash` option every time, you can change the default
|
||||
behavior by setting the `rebase.autoSquash` `git` config option to true.
|
||||
See
|
||||
the [`git` docs](https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt-rebaseautoSquash)
|
||||
for more details.
|
||||
|
||||
If you have `rebase.autoSquash` set to true, you can pass the `--no-autosquash` option
|
||||
to `git rebase` to override and disable this setting.
|
||||
Reference in New Issue
Block a user