Compare commits

..

34 Commits

Author SHA1 Message Date
62a8618536 docs: add changelog for 4.1.2 2017-05-10 15:44:28 -07:00
419fe0ca0d release: cut the 4.1.2 release 2017-05-10 15:42:11 -07:00
e46a65f8fd build: update key for pushing to PACKAGE-builds repos (#16667) 2017-05-09 17:34:35 -07:00
f0e1043a1d docs(*) fix dangling links in API docs (#16632)
* docs(animations): fix links to `Component` animations

* docs(core): fix links to `ReflectiveInjector` methods

The `resolve` and other methods were moved from the
`Injector` to the `ReflectiveInjector`.

* docs(core): fix links to `Renderer`

The local links were assuming that that methods were on the
current document (e.g. `RootRenderer`), but they are actually
on the `Renderer` class.

* docs(router): fix links to methods

* docs(forms): fix links to methods

* docs(core): fix links to methods

* docs(router): fix API page links and an internal link
2017-05-09 17:34:35 -07:00
c1938f5af1 docs(core): remove link to non-existent class in InjectableDecorator (#16653)
Closes #16640
2017-05-09 17:34:34 -07:00
915eae50b4 fix(router): fix redirect to a URL with a param having multiple values (#16376)
fixes #16310

PR Close #16376
2017-05-09 17:34:33 -07:00
68675e625a test(router): simplify redirect tests (#16376) 2017-05-09 17:34:32 -07:00
d0e1688514 fix(compiler): avoid a ...null spread in extraction (#16547)
This code only runs in ES5 mode in the test suite, so this is difficult to test.
However `updateFromTemplate` is being called with a spread operator, as
`...updateFromTemplate(...)`. The spread operator should fail on `null` values.
This change avoids the problem by always returning a (possibly empty) array.

PR Close #16547
2017-05-09 17:34:31 -07:00
ee6705af49 fix(core): detach projected views when a parent view is destroyed (#16592)
This also clarifies via a test 
that we only update projected views when the view is created or destroyed,
but not when it is attached/detached/moved.

Fixes #15578

PR Close #16592
2017-05-09 17:34:31 -07:00
9218812011 fix(core): projected views should be dirty checked when the declaring component is dirty checked. (#16592)
Previously a projected view was only dirty checked when the
component in which it was inserted was dirty checked.

This fix changes the behavior so that a view is also dirty checked if
the declaring component is dirty checked.

Note: This does not change the order of change detection,
only the fact whether a projected view is dirty checked or not.

Fixes #14321
2017-05-09 17:34:30 -07:00
ec77bf9fb0 docs(core): EventEmitter docs for isAsync defaults (#15780)
- solves #15758
2017-05-09 17:34:29 -07:00
fee5b2ad56 docs(animations): remove duplicate word (#16508) 2017-05-09 17:34:24 -07:00
9c70a3cfb1 fix(http): flatten metadata for @angular/http/testing
@angular/http/testing used to publish a metadata structure which paralleled
the .d.ts structure. This causes ngc to write incorrect imports for this
bundle when compiling providers using MockBackend and other http testing
classes.

This change restructures the @angular/http/testing build a bit, modeling it
after @angular/platform-browser-animations, and produces a FESM structure
that has flat metadata.

Fixes #15521.
2017-05-09 17:33:59 -07:00
ec3b6e9603 fix(http): introduce encodingHint for text() for better ArrayBuffer support
Currently, if a Response has an ArrayBuffer body and text() is called, Angular
attempts to convert the ArrayBuffer to a string. Doing this requires knowing
the encoding of the bytes in the buffer, which is context that we don't have.

Instead, we assume that the buffer is encoded in UTF-16, and attempt to process
it that way. Unfortunately the approach chosen (interpret buffer as Uint16Array and
create a Javascript string from each entry using String.fromCharCode) is incorrect
as it does not handle UTF-16 surrogate pairs. What Angular actually implements, then,
is UCS-2 decoding, which is equivalent to UTF-16 with characters restricted to the
base plane.

No standard way of decoding UTF-8 or UTF-16 exists in the browser today. APIs like
TextDecoder are only supported in a few browsers, and although hacks like using the
FileReader API with a Blob to force browsers to do content encoding detection and
decoding exist, they're slow and not compatible with the synchronous text() API.

Thus, this bug is fixed by introducing an encodingHint parameter to text(). The
default value of this parameter is 'legacy', indicating that the existing broken
behavior should be used - this prevents breaking existing apps. The only other
possible value of the hint is 'iso-8859' which interprets each byte of the buffer
with String.fromCharCode. UTF-8 and UTF-16 are not supported - it is up to the
consumer to get the ArrayBuffer and decode it themselves.

The parameter is a hint, as it's not always used (for example, if the conversion
to text doesn't involve an ArrayBuffer source). Additionally, this leaves the door
open for future implementations to perform more sophisticated encoding detection
and ignore the user-provided value if it can be proven to be incorrect.

Fixes #15932.

PR Close #16420
2017-05-09 17:33:59 -07:00
63066f7697 fix(http): honor RequestArgs.search and RequestArgs.params map type
Currently `new Request({search: ...})` is not honored, and
`new Request({params: {'x': 'y'}) doesn't work either, as this object would have
toString() called. This change allows both of these cases to work, as proved by
the 2 new tests.

Fixes #15761

PR Close #16392
2017-05-09 17:33:58 -07:00
5f6d0f2340 revert: fix: public API golden files (#16414)
This reverts commit dcaa11a88b.
2017-05-04 15:00:09 -07:00
4a0e93b03b revert: test(compiler-cli): add test for missingTranslation parameter
This reverts commit 109229246c.
2017-05-04 14:51:30 -07:00
1f5dce2128 docs: add changelog for 4.1.1 2017-05-04 14:22:43 -07:00
14e7e43ad8 release: cut the 4.1.1 release 2017-05-04 14:18:24 -07:00
54d4b893fd test(compiler-cli): add test for missingTranslation parameter 2017-05-04 14:05:17 -07:00
4670cf51cc test: cleanup rxjs custom build
The latest rxjs release works with closure compiler out of the box.
We no longer need to compile our own.

Also put closure options into a file rather than using a shell script.
2017-05-04 14:05:16 -07:00
dd4e501999 fix(upgrade): initialize all inputs in time for ngOnChanges()
Previously, non-bracketed inputs (e.g. `xyz="foo"`) on downgraded components
were initialized using `attrs.$observe()` (which uses `$evalAsync()` under the
hood), while bracketed inputs (e.g. `[xyz]="'foo'"`) were initialized using
`$watch()`. If the downgraded component was created during a `$digest` (e.g. by
an `ng-if` watcher), the non-bracketed inputs were not initialized in time for
the initial call to `ngOnChanges()` and `ngOnInit()`.

This commit fixes it by using `$watch()` to initialize all inputs. `$observe()`
is still used for subsequent updates on non-bracketed inputs, because it is more
performant.

Fixes #16212
2017-05-04 14:05:16 -07:00
9124994849 build: update concurrently to latest version
The regression in `concurrently` v3.2.0 (which made us roll back to v3.1.0
in #14378) has been fixed in v3.3.0 (see kimmobrunfeldt/concurrently#89).
2017-05-04 14:05:16 -07:00
4fbc61469f docs: fix links in api docs 2017-05-04 14:05:16 -07:00
8a883f24f6 refactor(compiler): simplify AOT tests 2017-05-04 14:05:15 -07:00
07cef367ac fix(core): don’t stop change detection because of errors
- prevents unsubscribing from the zone on error
- prevents unsubscribing from directive `EventEmitter`s on error
- prevents detaching views in dev mode if there on error
- ensures that `ngOnInit` is only called 1x (also in prod mode)

Fixes #9531
Fixes #2413
Fixes #15925
2017-05-04 14:05:15 -07:00
c060110695 fix(language-service): remove asserts for non-null expressions (#16422)
Reworked some of the code so asserts are no longer necessary.
Added additional and potentially redundant checks
Added checks where the null checker found real problems.

PR Close #16422
2017-05-04 14:05:15 -07:00
93ff3166ab docs(common): fix API docs for NgComponentOutlet (#16411)
fixes #16373

PR Close #16411
2017-05-04 14:05:14 -07:00
85a1b54c6e fix(core): don’t set ng-version for dynamically created components (#16394)
Angular uses the `ng-version` attribute to indicate which elements
were used to bootstrap an application. However, after 4.0 we also
added this attribute for all dynamically created components.

Fixes #15880

PR Close #16394
2017-05-04 14:05:14 -07:00
acf83b90bc fix(core): allow to detach OnPush components (#16394)
Fixes #9720
2017-05-04 14:05:14 -07:00
f66e59ebe4 fix(core): allow directives to inject the component’s ChangeDetectorRef. (#16394)
When a directive lives on the same element as a component
(e.g. `<my-comp myDir>`), the directive was not able to get hold
of the `ChangeDetectorRef` of the component on that element. However,
as directives are supposed to decorate components, this is incorrect.

This commit enables this use case.

Closes #12816
2017-05-04 14:05:14 -07:00
d932e724ab ci(language-service): update ci tests to official 2.3 build (#16415)
PR Close #16415
2017-05-04 14:05:13 -07:00
dcaa11a88b fix: public API golden files (#16414) 2017-05-04 14:05:13 -07:00
427d63a422 fix: strictNullCheck support. (#16389) (#16389)
Fix #16357

Workaround for https://github.com/Microsoft/TypeScript/issues/10078

Closes #16389

PR Close #16389
2017-05-04 14:05:13 -07:00
1172 changed files with 27371 additions and 32513 deletions

View File

@ -136,7 +136,6 @@ groups:
users:
- alexeagle
- chuckjaz
- vicb
- tbosch
- IgorMinar #fallback
- mhevery #fallback

View File

@ -34,9 +34,9 @@ env:
# This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery.
- secure: "aCdHveZuY8AT4Jr1JoJB4LxZsnGWRe/KseZh1YXYe5UtufFCtTVHvUcLn0j2aLBF0KpdyS+hWf0i4np9jthKu2xPKriefoPgCMpisYeC0MFkwbmv+XlgkUbgkgVZMGiVyX7DCYXVahxIoOUjVMEDCbNiHTIrfEuyq24U3ok2tHc="
# FIREBASE_TOKEN
# This is needed for publishing builds to the "aio-staging" and "angular-io" firebase projects.
# This token was generated using the aio-deploy@angular.io account using `firebase login:ci` and password from valentine
- secure: "L5CyQmpwWtoR4Qi4xlWQh/cL1M6ZeJL4W4QAr4HdKFMgYt9h+Whqkymyh2NxwmCbPvWa7yUd+OiLQUDCY7L2VIg16hTwoe2CgYDyQA0BEwLzxtRrJXl93TfwMlrUx5JSIzAccD6D4sjtz8kSFMomK2Nls33xOXOukwyhVMjd0Cg="
# This is needed for publishing builds to the "aio-staging" firebase site.
# TODO(i): the token was generated using the iminar@google account, we should switch to a shared/role-base account.
- secure: "MPx3UM77o5IlhT75PKHL0FXoB5tSXDc3vnCXCd1sRy4XUTZ9vjcV6nNuyqEf+SOw659bGbC1FI4mACGx1Q+z7MQDR85b1mcA9uSgHDkh+IR82CnCVdaX9d1RXafdJIArahxfmorbiiPPLyPIKggo7ituRm+2c+iraoCkE/pXxYg="
matrix:
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
- CI_MODE=e2e

View File

@ -1,84 +1,3 @@
<a name="4.2.0-rc.1"></a>
# [4.2.0-rc.1](https://github.com/angular/angular/compare/4.2.0-rc.0...4.2.0-rc.1) (2017-05-26)
### Bug Fixes
* **animations:** repair flicker issues with WA polyfill ([#16937](https://github.com/angular/angular/issues/16937)) ([e7d9fd8](https://github.com/angular/angular/commit/e7d9fd8)), closes [#16919](https://github.com/angular/angular/issues/16919) [#16918](https://github.com/angular/angular/issues/16918)
* **animations:** use a lightweight renderer for non-animation components ([#17003](https://github.com/angular/angular/issues/17003)) ([3ab86bd](https://github.com/angular/angular/commit/3ab86bd))
* **compiler:** compile `.ngfactory.ts` files even if nobody references them. ([#16899](https://github.com/angular/angular/issues/16899)) ([573b861](https://github.com/angular/angular/commit/573b861)), closes [#16741](https://github.com/angular/angular/issues/16741)
* **compiler:** do not report type errors for arguments with `@Inject` ([#16222](https://github.com/angular/angular/issues/16222)) ([27761b4](https://github.com/angular/angular/commit/27761b4)), closes [#15424](https://github.com/angular/angular/issues/15424)
* **core:** make decorators closure safe ([#16905](https://github.com/angular/angular/issues/16905)) ([a80ac0a](https://github.com/angular/angular/commit/a80ac0a)), closes [#16889](https://github.com/angular/angular/issues/16889)
* **tsc-wrapped:** ignore `|null` and `|undefined` when collecting types ([#16222](https://github.com/angular/angular/issues/16222)) ([1651a8f](https://github.com/angular/angular/commit/1651a8f))
* **tsc-wrapped:** resolve short-hand literal values to locals ([#16873](https://github.com/angular/angular/issues/16873)) ([11c10b2](https://github.com/angular/angular/commit/11c10b2))
### Features
* **compiler:** add location note to extracted xliff2 files ([#16791](https://github.com/angular/angular/issues/16791)) ([08dfe91](https://github.com/angular/angular/commit/08dfe91)), closes [#16531](https://github.com/angular/angular/issues/16531)
* **core:** update zone.js to 0.8.10 and expose the flush method ([#16860](https://github.com/angular/angular/issues/16860)) ([85d4c4b](https://github.com/angular/angular/commit/85d4c4b))
* **tsc-wrapped:** support template literals in metadata collection ([#16880](https://github.com/angular/angular/issues/16880)) ([6e41add](https://github.com/angular/angular/commit/6e41add))
<a name="4.2.0-rc.0"></a>
# [4.2.0-rc.0](https://github.com/angular/angular/compare/4.2.0-beta.0...4.2.0-rc.0) (2017-05-19)
### Bug Fixes
* **animations:** make sure reuseable animation subtitutions work without default params ([#16875](https://github.com/angular/angular/issues/16875)) ([7d9f96a](https://github.com/angular/angular/commit/7d9f96a))
* **animations:** only require one flushMicrotasks call when testing animations ([6cb93c1](https://github.com/angular/angular/commit/6cb93c1))
* **compiler:** avoid a `...null` spread in extraction ([#16547](https://github.com/angular/angular/issues/16547)) ([e0a8376](https://github.com/angular/angular/commit/e0a8376))
* **compiler-cli:** allow '==' to compare nullable types ([#16731](https://github.com/angular/angular/issues/16731)) ([d761059](https://github.com/angular/angular/commit/d761059))
* **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([f0f6544](https://github.com/angular/angular/commit/f0f6544)), closes [#15578](https://github.com/angular/angular/issues/15578)
* **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([fcc91d8](https://github.com/angular/angular/commit/fcc91d8)), closes [#14321](https://github.com/angular/angular/issues/14321)
* **http:** flatten metadata for [@angular](https://github.com/angular)/http/testing ([9da6340](https://github.com/angular/angular/commit/9da6340)), closes [#15521](https://github.com/angular/angular/issues/15521)
* **http:** honor RequestArgs.search and RequestArgs.params map type ([aef5245](https://github.com/angular/angular/commit/aef5245)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392)
* **http:** introduce encodingHint for text() for better ArrayBuffer support ([7ae7a84](https://github.com/angular/angular/commit/7ae7a84)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420)
* **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([5d4b36f](https://github.com/angular/angular/commit/5d4b36f)), closes [#16310](https://github.com/angular/angular/issues/16310)
### Features
* **animations:** introduce a wave of new animation features ([16c8167](https://github.com/angular/angular/commit/16c8167))
* **animations:** introduce routeable animation support ([f1a9e3c](https://github.com/angular/angular/commit/f1a9e3c))
* add .ngsummary.ts files to support AOT unit tests ([547c363](https://github.com/angular/angular/commit/547c363))
* introduce `TestBed.overrideProvider` ([#16725](https://github.com/angular/angular/issues/16725)) ([39b92f7](https://github.com/angular/angular/commit/39b92f7))
* **compiler:** support a non-null postfix assert ([#16672](https://github.com/angular/angular/issues/16672)) ([b9521b5](https://github.com/angular/angular/commit/b9521b5))
* **core:** introduce fixture.whenRenderingDone for testing ([#16732](https://github.com/angular/angular/issues/16732)) ([38c524d](https://github.com/angular/angular/commit/38c524d))
### Performance Improvements
* **animations:** reduce size of animations bundle ([712630c](https://github.com/angular/angular/commit/712630c))
<a name="4.1.3"></a>
## [4.1.3](https://github.com/angular/angular/compare/4.1.2...4.1.3) (2017-05-17)
### Bug Fixes
* add typescript 2.3.2 typings test ([#16738](https://github.com/angular/angular/issues/16738)) ([a5bdbed](https://github.com/angular/angular/commit/a5bdbed)), closes [#16663](https://github.com/angular/angular/issues/16663)
* **compiler-cli:** import routing module with forRoot ([#16438](https://github.com/angular/angular/issues/16438)) ([b7f8581](https://github.com/angular/angular/commit/b7f8581))
* **platform-server:** wait for async app initializers to complete before removing server side styles ([#16712](https://github.com/angular/angular/issues/16712)) ([0a82f7d](https://github.com/angular/angular/commit/0a82f7d)), closes [#15716](https://github.com/angular/angular/issues/15716)
* **router:** Wrap Promise-like instances in native Promises ([#16759](https://github.com/angular/angular/issues/16759)) ([883ca28](https://github.com/angular/angular/commit/883ca28))
* **upgrade:** Prevent renaming of $inject property ([#16706](https://github.com/angular/angular/issues/16706)) ([afb7540](https://github.com/angular/angular/commit/afb7540))
* **upgrade:** use quote to prevent ClossureCompiler obfuscating $event. ([#16724](https://github.com/angular/angular/issues/16724)) ([47df3d6](https://github.com/angular/angular/commit/47df3d6))
<a name="4.2.0-beta.1"></a>
# [4.2.0-beta.1](https://github.com/angular/angular/compare/4.2.0-beta.0...4.2.0-beta.1) (2017-05-10)
### Features
* add .ngsummary.ts files to support AOT unit tests ([547c363](https://github.com/angular/angular/commit/547c363))
<a name="4.1.2"></a>
## [4.1.2](https://github.com/angular/angular/compare/4.1.1...4.1.2) (2017-05-10)
@ -95,32 +14,6 @@
<a name="4.2.0-beta.0"></a>
# [4.2.0-beta.0](https://github.com/angular/angular/compare/4.1.0...4.2.0-beta.0) (2017-05-04)
### Bug Fixes
* **core**: strictNullCheck support. ([#16389](https://github.com/angular/angular/issues/16389)) ([#16389](https://github.com/angular/angular/issues/16389)) ([8c09d10](https://github.com/angular/angular/commit/8c09d10)), closes [#16357](https://github.com/angular/angular/issues/16357)
* **core:** allow directives to inject the components `ChangeDetectorRef`. ([#16394](https://github.com/angular/angular/issues/16394)) ([392d584](https://github.com/angular/angular/commit/392d584)), closes [#12816](https://github.com/angular/angular/issues/12816)
* **core:** allow to detach `OnPush` components ([#16394](https://github.com/angular/angular/issues/16394)) ([aa8bba4](https://github.com/angular/angular/commit/aa8bba4)), closes [#9720](https://github.com/angular/angular/issues/9720)
* **core:** dont set `ng-version` for dynamically created components ([#16394](https://github.com/angular/angular/issues/16394)) ([a4de214](https://github.com/angular/angular/commit/a4de214)), closes [#15880](https://github.com/angular/angular/issues/15880)
* **core:** dont stop change detection because of errors ([e263e19](https://github.com/angular/angular/commit/e263e19)), closes [#9531](https://github.com/angular/angular/issues/9531) [#2413](https://github.com/angular/angular/issues/2413) [#15925](https://github.com/angular/angular/issues/15925)
* **language-service:** remove asserts for non-null expressions ([#16422](https://github.com/angular/angular/issues/16422)) ([253345c](https://github.com/angular/angular/commit/253345c))
* **upgrade:** initialize all inputs in time for `ngOnChanges()` ([b3e63c0](https://github.com/angular/angular/commit/b3e63c0)), closes [#16212](https://github.com/angular/angular/issues/16212)
### Features
* **compiler-cli:** add param to set MissingTranslationStrategy on ngc ([#15987](https://github.com/angular/angular/issues/15987)) ([6e2abcd](https://github.com/angular/angular/commit/6e2abcd)), closes [#15808](https://github.com/angular/angular/issues/15808)
* **core:** add `begin` and `end` renderer methods to track change detection ([7f9c589](https://github.com/angular/angular/commit/7f9c589))
* **core:** allow custom selector when bootstrapping components ([#15668](https://github.com/angular/angular/issues/15668)) ([900a88b](https://github.com/angular/angular/commit/900a88b)), closes [#7136](https://github.com/angular/angular/issues/7136)
* **core:** upgrade dep on zone.js to 0.8.9 ([#16401](https://github.com/angular/angular/issues/16401)) ([065b76d](https://github.com/angular/angular/commit/065b76d))
* **forms:** introduce min and max validators ([#15813](https://github.com/angular/angular/issues/15813)) ([81925fa](https://github.com/angular/angular/commit/81925fa))
* **language-service:** provide external file list to TypeScript ([#16417](https://github.com/angular/angular/issues/16417)) ([f4b771a](https://github.com/angular/angular/commit/f4b771a))
<a name="4.1.1"></a>
## [4.1.1](https://github.com/angular/angular/compare/4.1.0...4.1.1) (2017-05-04)
@ -143,10 +36,35 @@
### Bug Fixes
* **aio:** AppComponent should scroll only once when location changes ([ac5e6ba](https://github.com/angular/angular/commit/ac5e6ba))
* **aio:** copy button placement fix ([23e6502](https://github.com/angular/angular/commit/23e6502))
* **aio:** fix URL redirection for API pages ([54e587a](https://github.com/angular/angular/commit/54e587a))
* **aio:** header anchor placement ([b0c5d21](https://github.com/angular/angular/commit/b0c5d21))
* **aio:** resource nav ([35a2dfc](https://github.com/angular/angular/commit/35a2dfc))
* **aio:** strip leading slashes from path (and improve DRY-ness) ([#16238](https://github.com/angular/angular/issues/16238)) ([9c1318d](https://github.com/angular/angular/commit/9c1318d)), closes [#16230](https://github.com/angular/angular/issues/16230)
* **aio:** use SVG icons for page load sensitive UI ([c3fa880](https://github.com/angular/angular/commit/c3fa880)), closes [#16100](https://github.com/angular/angular/issues/16100)
* **router:** forward the query parameters in the ng1 -> ng2 url sync ([#16249](https://github.com/angular/angular/issues/16249)) ([2f97731](https://github.com/angular/angular/commit/2f97731)), closes [#16067](https://github.com/angular/angular/issues/16067)
* **upgrade:** use correct attribute name for upgraded component's bindings ([#16128](https://github.com/angular/angular/issues/16128)) ([d1fb066](https://github.com/angular/angular/commit/d1fb066)), closes [#8856](https://github.com/angular/angular/issues/8856)
### Features
* **aio:** api page column layout ([64ef69f](https://github.com/angular/angular/commit/64ef69f))
* **aio:** api page styles ([cf034f7](https://github.com/angular/angular/commit/cf034f7))
* **aio:** api pages styling ([bb52e22](https://github.com/angular/angular/commit/bb52e22))
* **aio:** boilerplate:add cleans (removes) before adding ([d8e2829](https://github.com/angular/angular/commit/d8e2829))
* **aio:** copy code snackbar and design updates ([e7c37d7](https://github.com/angular/angular/commit/e7c37d7))
* **aio:** don't animate sidenav on launch. ([11b2f62](https://github.com/angular/angular/commit/11b2f62))
* **aio:** dont set query params during search [#16125](https://github.com/angular/angular/issues/16125) ([#16217](https://github.com/angular/angular/issues/16217)) ([7520ddc](https://github.com/angular/angular/commit/7520ddc))
* **aio:** layout max width and design cleanup ([710b4a3](https://github.com/angular/angular/commit/710b4a3))
### Performance Improvements
* **aio:** improve unit test rebuild time ([d7719aa](https://github.com/angular/angular/commit/d7719aa))
<a name="4.1.0-rc.0"></a>
# [4.1.0-rc.0](https://github.com/angular/angular/compare/4.1.0-beta.0...4.1.0-rc.0) (2017-04-21)

View File

@ -9,11 +9,10 @@
"outDir": "dist",
"assets": [
"assets",
"generated",
"content",
"app/search/search-worker.js",
"favicon.ico",
"pwa-manifest.json",
"google385281288605d160.html"
"pwa-manifest.json"
],
"index": "index.html",
"main": "main.ts",
@ -22,11 +21,12 @@
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "aio",
"serviceWorker": false,
"serviceWorker": true,
"styles": [
"styles.scss"
],
"scripts": [
],
"environmentSource": "environments/environment.ts",
"environments": {

2
aio/.gitignore vendored
View File

@ -3,7 +3,7 @@
# compiled output
/dist
/out-tsc
/src/generated
/src/content
/tmp
# dependencies

View File

@ -30,19 +30,6 @@ Here are the most important tasks you might need to use:
* `yarn generate-plunkers` - generate the plunker files that are used by the `live-example` tags in the docs.
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
* `yarn build-ie-polyfills` - generates a js file of polyfills that can be loaded in Internet Explorer.
## Using ServiceWorker locally
Since abb36e3cb, running `yarn start -- --prod` will no longer set up the ServiceWorker, which
would require manually running `yarn sw-manifest` and `yarn sw-copy` (something that is not possible
with webpack serving the files from memory).
If you want to test ServiceWorker locally, you can use `yarn build` and serve the files in `dist/`
with `yarn http-server -- dist -p 4200`.
For more details see #16745.
## Guide to authoring
@ -69,7 +56,7 @@ extracting the documentation and generating JSON files that can be consumed by t
Full doc generation can take up to one minute. That's too slow for efficient document creation and editing.
You can make small changes in a smart editor that displays formatted markdown:
You can make small changes in a smart editor that displays formatted markdown:
>In VS Code, _Cmd-K, V_ opens markdown preview in side pane; _Cmd-B_ toggles left sidebar
You also want to see those changes displayed properly in the doc viewer

View File

@ -51,7 +51,6 @@ ENV AIO_BUILDS_DIR=$AIO_BUILDS_DIR TEST_AIO_BUILDS_DIR=$TEST
AIO_UPLOAD_HOSTNAME=$AIO_UPLOAD_HOSTNAME TEST_AIO_UPLOAD_HOSTNAME=$TEST_AIO_UPLOAD_HOSTNAME \
AIO_UPLOAD_MAX_SIZE=$AIO_UPLOAD_MAX_SIZE TEST_AIO_UPLOAD_MAX_SIZE=$TEST_AIO_UPLOAD_MAX_SIZE \
AIO_UPLOAD_PORT=$AIO_UPLOAD_PORT TEST_AIO_UPLOAD_PORT=$TEST_AIO_UPLOAD_PORT \
AIO_WWW_USER=www-data \
NODE_ENV=production
@ -64,7 +63,6 @@ RUN apt-get update -y && apt-get install -y curl
RUN curl --silent --show-error --location https://deb.nodesource.com/setup_6.x | bash -
RUN curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/backports.list
# Install packages
@ -73,11 +71,11 @@ RUN apt-get update -y && apt-get install -y \
cron \
dnsmasq \
nano \
nginx \
nodejs \
openssl \
rsyslog \
yarn
RUN apt-get install -t jessie-backports -y nginx
RUN yarn global add pm2@2
@ -111,31 +109,31 @@ RUN update-ca-certificates
# Set up nginx (for production and testing)
RUN sed -i -E "s|^user\s+\S+;|user $AIO_WWW_USER;|" /etc/nginx/nginx.conf
RUN rm -f /etc/nginx/conf.d/*
RUN rm -f /etc/nginx/sites-enabled/*
RUN rm /etc/nginx/sites-enabled/*
COPY nginx/aio-builds.conf /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_BUILDS_DIR}}|$AIO_BUILDS_DIR|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_DOMAIN_NAME}}|$AIO_DOMAIN_NAME|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_LOCALCERTS_DIR}}|$AIO_LOCALCERTS_DIR|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_LOGS_DIR}}|$AIO_NGINX_LOGS_DIR|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTP}}|$AIO_NGINX_PORT_HTTP|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTPS}}|$AIO_NGINX_PORT_HTTPS|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$AIO_UPLOAD_HOSTNAME|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_MAX_SIZE}}|$AIO_UPLOAD_MAX_SIZE|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$AIO_UPLOAD_PORT|g" /etc/nginx/conf.d/aio-builds-prod.conf
COPY nginx/aio-builds.conf /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_BUILDS_DIR}}|$AIO_BUILDS_DIR|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_DOMAIN_NAME}}|$AIO_DOMAIN_NAME|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_LOCALCERTS_DIR}}|$AIO_LOCALCERTS_DIR|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_LOGS_DIR}}|$AIO_NGINX_LOGS_DIR|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTP}}|$AIO_NGINX_PORT_HTTP|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTPS}}|$AIO_NGINX_PORT_HTTPS|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$AIO_UPLOAD_HOSTNAME|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_MAX_SIZE}}|$AIO_UPLOAD_MAX_SIZE|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$AIO_UPLOAD_PORT|g" /etc/nginx/sites-available/aio-builds-prod.conf
RUN ln -s /etc/nginx/sites-available/aio-builds-prod.conf /etc/nginx/sites-enabled/aio-builds-prod.conf
COPY nginx/aio-builds.conf /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_BUILDS_DIR}}|$TEST_AIO_BUILDS_DIR|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_DOMAIN_NAME}}|$TEST_AIO_DOMAIN_NAME|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_LOCALCERTS_DIR}}|$TEST_AIO_LOCALCERTS_DIR|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_LOGS_DIR}}|$TEST_AIO_NGINX_LOGS_DIR|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTP}}|$TEST_AIO_NGINX_PORT_HTTP|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTPS}}|$TEST_AIO_NGINX_PORT_HTTPS|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$TEST_AIO_UPLOAD_HOSTNAME|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_MAX_SIZE}}|$TEST_AIO_UPLOAD_MAX_SIZE|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$TEST_AIO_UPLOAD_PORT|g" /etc/nginx/conf.d/aio-builds-test.conf
COPY nginx/aio-builds.conf /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_BUILDS_DIR}}|$TEST_AIO_BUILDS_DIR|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_DOMAIN_NAME}}|$TEST_AIO_DOMAIN_NAME|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_LOCALCERTS_DIR}}|$TEST_AIO_LOCALCERTS_DIR|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_LOGS_DIR}}|$TEST_AIO_NGINX_LOGS_DIR|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTP}}|$TEST_AIO_NGINX_PORT_HTTP|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTPS}}|$TEST_AIO_NGINX_PORT_HTTPS|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$TEST_AIO_UPLOAD_HOSTNAME|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_MAX_SIZE}}|$TEST_AIO_UPLOAD_MAX_SIZE|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$TEST_AIO_UPLOAD_PORT|g" /etc/nginx/sites-available/aio-builds-test.conf
RUN ln -s /etc/nginx/sites-available/aio-builds-test.conf /etc/nginx/sites-enabled/aio-builds-test.conf
# Set up pm2

View File

@ -17,22 +17,16 @@ server {
server {
server_name "~^pr(?<pr>[1-9][0-9]*)-(?<sha>[0-9a-f]{40})\.";
listen {{$AIO_NGINX_PORT_HTTPS}} ssl http2;
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl http2;
listen {{$AIO_NGINX_PORT_HTTPS}} ssl;
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl;
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
ssl_certificate_key {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.key;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
ssl_certificate_key {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.key;
root {{$AIO_BUILDS_DIR}}/$pr/$sha;
disable_symlinks on from=$document_root;
index index.html;
gzip on;
gzip_comp_level 7;
gzip_types *;
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
@ -49,13 +43,11 @@ server {
server {
server_name _;
listen {{$AIO_NGINX_PORT_HTTPS}} ssl http2 default_server;
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl http2;
listen {{$AIO_NGINX_PORT_HTTPS}} ssl default_server;
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl;
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
ssl_certificate_key {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.key;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
ssl_certificate_key {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.key;
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;

View File

@ -18,8 +18,8 @@ function _main() {
// Exit codes:
// - 0: The PR author is a member.
// - 1: An error occurred.
// - 2: The PR author is not a member.
// - 1: The PR author is not a member.
// - 2: An error occurred.
buildVerifier.getPrAuthorTeamMembership(pr).
then(({author, isMember}) => {
if (isMember) {
@ -27,10 +27,10 @@ function _main() {
} else {
const errorMessage = `User '${author}' is not an active member of any of the following teams: ` +
`${allowedTeamSlugs.join(', ')}`;
onError(errorMessage, 2);
onError(errorMessage, 1);
}
}).
catch(err => onError(err, 1));
catch(err => onError(err, 2));
}
function onError(err: string, exitCode: number) {

View File

@ -1,3 +1,6 @@
// TODO(gkalpak): Find more suitable way to run as `www-data`.
process.setuid('www-data');
// Imports
import {getEnvVar} from '../common/utils';
import {uploadServerFactory} from './upload-server-factory';
@ -12,10 +15,8 @@ const AIO_PREVIEW_DEPLOYMENT_TOKEN = getEnvVar('AIO_PREVIEW_DEPLOYMENT_TOKEN');
const AIO_REPO_SLUG = getEnvVar('AIO_REPO_SLUG');
const AIO_UPLOAD_HOSTNAME = getEnvVar('AIO_UPLOAD_HOSTNAME');
const AIO_UPLOAD_PORT = +getEnvVar('AIO_UPLOAD_PORT');
const AIO_WWW_USER = getEnvVar('AIO_WWW_USER');
// Run
process.setuid(AIO_WWW_USER); // TODO(gkalpak): Find more suitable way to run as `www-data`.
_main();
// Functions

View File

@ -7,6 +7,7 @@ import * as shell from 'shelljs';
import {getEnvVar} from '../common/utils';
// Constans
const SERVER_USER = 'www-data';
const TEST_AIO_BUILDS_DIR = getEnvVar('TEST_AIO_BUILDS_DIR');
const TEST_AIO_NGINX_HOSTNAME = getEnvVar('TEST_AIO_NGINX_HOSTNAME');
const TEST_AIO_NGINX_PORT_HTTP = +getEnvVar('TEST_AIO_NGINX_PORT_HTTP');
@ -14,7 +15,6 @@ const TEST_AIO_NGINX_PORT_HTTPS = +getEnvVar('TEST_AIO_NGINX_PORT_HTTPS');
const TEST_AIO_UPLOAD_HOSTNAME = getEnvVar('TEST_AIO_UPLOAD_HOSTNAME');
const TEST_AIO_UPLOAD_MAX_SIZE = +getEnvVar('TEST_AIO_UPLOAD_MAX_SIZE');
const TEST_AIO_UPLOAD_PORT = +getEnvVar('TEST_AIO_UPLOAD_PORT');
const WWW_USER = getEnvVar('AIO_WWW_USER');
// Interfaces - Types
export interface CmdResult { success: boolean; err: Error; stdout: string; stderr: string; }
@ -31,7 +31,7 @@ class Helper {
public get nginxHostname() { return TEST_AIO_NGINX_HOSTNAME; }
public get nginxPortHttp() { return TEST_AIO_NGINX_PORT_HTTP; }
public get nginxPortHttps() { return TEST_AIO_NGINX_PORT_HTTPS; }
public get wwwUser() { return WWW_USER; }
public get serverUser() { return SERVER_USER; }
public get uploadHostname() { return TEST_AIO_UPLOAD_HOSTNAME; }
public get uploadPort() { return TEST_AIO_UPLOAD_PORT; }
public get uploadMaxSize() { return TEST_AIO_UPLOAD_MAX_SIZE; }
@ -46,7 +46,7 @@ class Helper {
// Constructor
constructor() {
shell.mkdir('-p', this.buildsDir);
shell.exec(`chown -R ${this.wwwUser} ${this.buildsDir}`);
shell.exec(`chown -R ${this.serverUser} ${this.buildsDir}`);
}
// Methods - Public
@ -64,7 +64,7 @@ class Helper {
public createDummyArchive(pr: string, sha: string, archivePath: string): CleanUpFn {
const inputDir = path.join(this.buildsDir, 'uploaded', pr, sha);
const cmd1 = `tar --create --gzip --directory "${inputDir}" --file "${archivePath}" .`;
const cmd2 = `chown ${this.wwwUser} ${archivePath}`;
const cmd2 = `chown ${this.serverUser} ${archivePath}`;
const cleanUpTemp = this.createDummyBuild(`uploaded/${pr}`, sha, true);
shell.exec(cmd1);
@ -82,7 +82,7 @@ class Helper {
this.writeFile(idxPath, {content: `PR: ${pr} | SHA: ${sha} | File: /index.html`}, force);
this.writeFile(barPath, {content: `PR: ${pr} | SHA: ${sha} | File: /foo/bar.js`}, force);
shell.exec(`chown -R ${this.wwwUser} ${prDir}`);
shell.exec(`chown -R ${this.serverUser} ${prDir}`);
return this.createCleanUpFn(() => shell.rm('-rf', prDir));
}
@ -166,7 +166,7 @@ class Helper {
// Create a file with the specified content.
fs.writeFileSync(filePath, content || '');
}
shell.exec(`chown ${this.wwwUser} ${filePath}`);
shell.exec(`chown ${this.serverUser} ${filePath}`);
return this.createCleanUpFn(() => shell.rm('-rf', cleanUpTarget));
}

View File

@ -159,7 +159,7 @@ describe('upload-server (on HTTP)', () => {
});
it(`should create files/directories owned by '${h.wwwUser}'`, done => {
it(`should create files/directories owned by '${h.serverUser}'`, done => {
const shaDir = path.join(h.buildsDir, pr, sha9);
const idxPath = path.join(shaDir, 'index.html');
const barPath = path.join(shaDir, 'foo', 'bar.js');
@ -167,7 +167,7 @@ describe('upload-server (on HTTP)', () => {
uploadPromise.
then(() => Promise.all([
h.runCmd(`find ${shaDir}`),
h.runCmd(`find ${shaDir} -user ${h.wwwUser}`),
h.runCmd(`find ${shaDir} -user ${h.serverUser}`),
])).
then(([{stdout: allFiles}, {stdout: userFiles}]) => {
expect(userFiles).toBe(allFiles);

View File

@ -6,18 +6,18 @@
"author": "Angular",
"license": "MIT",
"scripts": {
"prebuild": "yarn clean-dist",
"prebuild": "yarn run clean",
"build": "tsc",
"build-watch": "yarn tsc -- --watch",
"clean-dist": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
"dev": "concurrently --kill-others --raw --success first \"yarn build-watch\" \"yarn test-watch\"",
"build-watch": "yarn run tsc -- --watch",
"clean": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
"dev": "concurrently --kill-others --raw --success first \"yarn run build-watch\" \"yarn run test-watch\"",
"lint": "tslint --project tsconfig.json",
"pre~~test-only": "yarn lint",
"pre~~test-only": "yarn run lint",
"~~test-only": "node dist/test",
"pretest": "yarn build",
"test": "yarn ~~test-only",
"pretest-watch": "yarn build",
"test-watch": "nodemon --exec \"yarn ~~test-only\" --watch dist"
"pretest": "yarn run build",
"test": "yarn run ~~test-only",
"pretest-watch": "yarn run build",
"test-watch": "nodemon --exec \"yarn run ~~test-only\" --watch dist"
},
"dependencies": {
"express": "^4.14.1",

View File

@ -20,11 +20,7 @@
## Starting the docker container
- [Start docker container](vm-setup--start-docker-container.md)
## Updating the docker container
- [Update docker container](vm-setup--update-docker-container.md)
- [Create docker image](vm-setup--start-docker-container.md)
## Miscellaneous

View File

@ -8,7 +8,7 @@ This is an overview of the available scripts and commands.
The scripts are located inside `<aio-builds-setup-dir>/scripts/`. The following scripts are
available:
- `create-image.sh`:
- `build.sh`:
Can be used for creating a preconfigured docker image.
See [here](vm-setup--create-docker-image.md) for more info.
@ -18,13 +18,10 @@ available:
- `travis-preverify-pr.sh`
Can be used for "preverifying" a PR before uploading the artifacts to the server. It checks that
the author of the PR is a member of one of the specified GitHub teams and therefore allowed to
upload build artifacts. This is useful for CI integration. See [here](misc--integrate-with-ci.md)
for more info.
the author of the PR a member of one of the specified GitHub teams and therefore allowed to upload
build artifacts. This is useful for CI integration. See [here](misc--integrate-with-ci.md) for
more info.
- `update-preview-server.sh`
Can be used for updating the docker container (and image) based on the latest changes checked out
from a git repository. See [here](vm-setup--update-docker-container.md) for more info.
## Commands
The following commands are available globally from inside the docker container. They are either used

View File

@ -6,11 +6,11 @@
## Build docker image
- `<aio-builds-setup-dir>/scripts/create-image.sh [<name>[:<tag>] [--build-arg <NAME>=<value> ...]]`
- `<aio-builds-setup-dir>/scripts/build.sh [<name>[:<tag>] [--build-arg <NAME>=<value> ...]]`
- You can overwrite the default environment variables inside the image, by passing new values using
`--build-arg`.
**Note:** The script has to execute docker commands with `sudo`.
**Note:** The build script has to execute docker commands with `sudo`.
## Example

View File

@ -7,16 +7,16 @@ command:
```
sudo docker run \
--detach \
-d \
--dns 127.0.0.1 \
--name <instance-name> \
--publish 80:80 \
--publish 443:443 \
-p 80:80 \
-p 443:443 \
--restart unless-stopped \
[--volume <host-cert-dir>:/etc/ssl/localcerts:ro] \
--volume <host-secrets-dir>:/aio-secrets:ro \
--volume <host-builds-dir>:/var/www/aio-builds \
[--volume <host-logs-dir>:/var/log/aio] \
[-v <host-cert-dir>:/etc/ssl/localcerts:ro] \
-v <host-secrets-dir>:/aio-secrets:ro \
-v <host-builds-dir>:/var/www/aio-builds \
[-v <host-logs-dir>:/var/log/aio] \
<name>[:<tag>]
```
@ -27,7 +27,7 @@ can be found [here](https://docs.docker.com/engine/reference/run/).
sudo docker run \
# Start as a daemon.
--detach \
-d \
# Use the local DNS server.
# (This is necessary for mapping internal URLs, e.g. for the Node.js upload-server.)
@ -37,9 +37,9 @@ sudo docker run \
# Useful for running `docker` commands, e.g.: `docker stop <instance-name>`
--name <instance-name> \
# Map ports of the host VM (left) to ports of the docker container (right)
--publish 80:80 \
--publish 443:443 \
# Map ports of the hosr VM (left) to ports of the docker container (right)
-p 80:80 \
-p 443:443 \
# Automatically restart the container (unless it was explicitly stopped by the user).
# (This ensures that the container will be automatically started on boot.)
@ -48,22 +48,22 @@ sudo docker run \
# The directory the contains the SSL certificates.
# (See [here](vm-setup--create-host-dirs-and-files.md) for more info.)
# If not provided, the container will use self-signed certificates.
[--volume <host-cert-dir>:/etc/ssl/localcerts:ro] \
[-v <host-cert-dir>:/etc/ssl/localcerts:ro] \
# The directory the contains the secrets (e.g. GitHub token, JWT secret, etc).
# (See [here](vm-setup--set-up-secrets.md) for more info.)
--volume <host-secrets-dir>:/aio-secrets:ro \
-v <host-secrets-dir>:/aio-secrets:ro \
# The uploaded build artifacts will stored to and served from this directory.
# (If you are using a persistent disk - as described [here](vm-setup--attach-persistent-disk.md) -
# this will be a directory inside the disk.)
--volume <host-builds-dir>:/var/www/aio-builds \
-v <host-builds-dir>:/var/www/aio-builds \
# The directory where the logs are being kept.
# (See [here](vm-setup--create-host-dirs-and-files.md) for more info.)
# If not provided, the logs will be kept inside the container, which means they will be lost
# whenever a new container is created.
[--volume <host-logs-dir>:/var/log/aio] \
[-v <host-logs-dir>:/var/log/aio] \
# The name of the docker image to use (and an optional tag; defaults to `latest`).
# (See [here](vm-setup--create-docker-image.md) for instructions on how to create the iamge.)
@ -78,15 +78,15 @@ by the container for accesing secrets and SSL certificates and keeping the build
```
sudo docker run \
--detach \
-d \
--dns 127.0.0.1 \
--name foobar-builds-1 \
--publish 80:80 \
--publish 443:443 \
-p 80:80 \
-p 443:443 \
--restart unless-stopped \
--volume /etc/ssl/localcerts:/etc/ssl/localcerts:ro \
--volume /foobar-secrets:/aio-secrets:ro \
--volume /mnt/disks/foobar-builds:/var/www/aio-builds \
--volume /foobar-logs:/var/log/aio \
-v /etc/ssl/localcerts:/etc/ssl/localcerts:ro \
-v /foobar-secrets:/aio-secrets:ro \
-v /mnt/disks/foobar-builds:/var/www/aio-builds \
-v /foobar-logs:/var/log/aio \
foobar-builds
```

View File

@ -1,52 +0,0 @@
# VM setup - Update docker container
## Overview
Assuming you have cloned the repository containing the preview server code (as described
[here](vm-setup--create-docker-image.md)), you can use the `update-preview-server.sh` script on the
VM host to update the preview server based on changes in the source code.
The script will pull the latest changes from the origin's master branch and examine if there have
been any changes in files inside the preview server source code directory (see below). If there are,
it will create a new image and verify that is works as expected. Finally, it will stop and remove
the old docker container and image, create and new container based on the new image and start it.
The script assumes that the preview server source code is in the repository's
`aio/aio-builds-setup/` directory and expects the following inputs:
- **$1**: `HOST_REPO_DIR`
- **$2**: `HOST_LOCALCERTS_DIR`
- **$3**: `HOST_SECRETS_DIR`
- **$4**: `HOST_BUILDS_DIR`
- **$5**: `HOST_LOGS_DIR`
See [here](vm-setup--create-host-dirs-and-files.md) for more info on what each input directory is
used for.
**Note 1:** The script has to execute docker commands with `sudo`.
**Note 2:** Make sure the user that executes the script has access to update the repository
## Run the script manually
You may choose to manually run the script, when necessary. Example:
```
update-preview-server.sh \
/path/to/repo \
/path/to/localcerts \
/path/to/secrets \
/path/to/builds \
/path/to/logs
```
## Run the script automatically
You may choose to automatically trigger the script, e.g. using a cronjob. For example, the following
cronjob entry would run the script every hour and update the preview server (assuming the user has
the necessary permissions):
```
# Periodically check for changes and update the preview server (if necessary)
*/30 * * * * /path/to/update-preview-server.sh /path/to/repo /path/to/localcerts /path/to/secrets /path/to/builds /path/to/logs
```

View File

@ -2,9 +2,15 @@
set -eux -o pipefail
# Set up env
source "`dirname $0`/_env.sh"
source "`dirname $0`/env.sh"
readonly defaultImageNameAndTag="aio-builds:latest"
# Build `scripts-js/`
cd "$SCRIPTS_JS_DIR"
yarn install
yarn run build
cd -
# Create docker image
readonly nameAndOptionalTag=${1:-$defaultImageNameAndTag}
sudo docker build --tag $nameAndOptionalTag ${@:2} $DOCKERBUILD_DIR

View File

@ -2,11 +2,10 @@
set -eux -o pipefail
# Set up env
source "`dirname $0`/_env.sh"
source "`dirname $0`/env.sh"
# Test `scripts-js/`
(
cd "$SCRIPTS_JS_DIR"
yarn install
yarn test
)
cd "$SCRIPTS_JS_DIR"
yarn install
yarn test
cd -

View File

@ -2,14 +2,7 @@
set -eux -o pipefail
# Set up env
source "`dirname $0`/_env.sh"
# Build `scripts-js/`
(
cd "$SCRIPTS_JS_DIR"
yarn install
yarn build
)
source "`dirname $0`/env.sh"
# Preverify PR
AIO_GITHUB_ORGANIZATION="angular" \

View File

@ -1,70 +0,0 @@
#!/usr/bin/env bash
set -eux -o pipefail
exec 3>&1
echo "[`date`] - Updating the preview server..."
# Input
readonly HOST_REPO_DIR=$1
readonly HOST_LOCALCERTS_DIR=$2
readonly HOST_SECRETS_DIR=$3
readonly HOST_BUILDS_DIR=$4
readonly HOST_LOGS_DIR=$5
# Constants
readonly PROVISIONAL_IMAGE_NAME=aio-builds:provisional
readonly LATEST_IMAGE_NAME=aio-builds:latest
readonly CONTAINER_NAME=aio
# Run
(
cd "$HOST_REPO_DIR"
readonly lastDeployedCommit=$(git rev-parse HEAD)
echo "Currently at commit $lastDeployedCommit."
# Pull latest master from origin.
git pull origin master
# Do not update the server unless files inside `aio-builds-setup/` have changed
# or the last attempt failed (identified by the provisional image still being around).
readonly relevantChangedFilesCount=$(git diff --name-only $lastDeployedCommit...HEAD | grep -P "^aio/aio-builds-setup/" | wc -l)
readonly lastAttemptFailed=$(sudo docker rmi "$PROVISIONAL_IMAGE_NAME" >> /dev/fd/3 && echo "true" || echo "false")
if [[ $relevantChangedFilesCount -eq 0 ]] && [[ "$lastAttemptFailed" != "true" ]]; then
echo "Skipping update because no relevant files have been touched."
exit 0
fi
# Create and verify a new docker image.
aio/aio-builds-setup/scripts/create-image.sh "$PROVISIONAL_IMAGE_NAME"
readonly imageVerified=$(sudo docker run --dns 127.0.0.1 --rm --volume $HOST_SECRETS_DIR:/aio-secrets:ro "$PROVISIONAL_IMAGE_NAME" /bin/bash -c "aio-init && aio-health-check && aio-verify-setup" >> /dev/fd/3 && echo "true" || echo "false")
if [[ "$imageVerified" != "true" ]]; then
echo "Failed to verify new docker image. Aborting update!"
exit 1
fi
# Remove the old container and replace the docker image.
sudo docker stop "$CONTAINER_NAME" || true
sudo docker rm "$CONTAINER_NAME" || true
sudo docker rmi "$LATEST_IMAGE_NAME" || true
sudo docker tag "$PROVISIONAL_IMAGE_NAME" "$LATEST_IMAGE_NAME"
sudo docker rmi "$PROVISIONAL_IMAGE_NAME"
# Create and start a docker container based on the new image.
sudo docker run \
--detach \
--dns 127.0.0.1 \
--name "$CONTAINER_NAME" \
--publish 80:80 \
--publish 443:443 \
--restart unless-stopped \
--volume $HOST_LOCALCERTS_DIR:/etc/ssl/localcerts:ro \
--volume $HOST_SECRETS_DIR:/aio-secrets:ro \
--volume $HOST_BUILDS_DIR:/var/www/aio-builds \
--volume $HOST_LOGS_DIR:/var/log/aio \
"$LATEST_IMAGE_NAME"
echo "The new docker image has been successfully deployed."
)

View File

@ -19,7 +19,7 @@ export class AppComponent {
movie: IMovie = null;
movies: IMovie[] = [];
showImage = true;
title = 'AngularJS to Angular Quick Ref Cookbook';
title: string = 'AngularJS to Angular Quick Ref Cookbook';
toggleImage(event: UIEvent) {
this.showImage = !this.showImage;
this.eventType = (event && event.type) || 'not provided';

View File

@ -19,7 +19,7 @@ import { MovieService } from './movie.service';
export class MovieListComponent {
// #enddocregion class
favoriteHero: string;
showImage = false;
showImage: boolean = false;
movies: IMovie[];
// #docregion di

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { protractor, browser, element, by, ElementFinder } from 'protractor';

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';

View File

@ -28,7 +28,7 @@ export class HighlightDirective {
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
// #enddocregion mouse-methods,
// #enddocregion mouse-methods,
// #docregion color
@Input() highlightColor: string;

View File

@ -1,5 +1,5 @@
/* tslint:disable:member-ordering */
// #docregion imports,
// #docregion imports,
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
// #enddocregion imports

View File

@ -15,6 +15,6 @@ import { HEROES } from './hero';
})
export class HeroParentComponent {
heroes = HEROES;
master = 'Master';
master: string = 'Master';
}
// #enddocregion

View File

@ -11,8 +11,8 @@ import { Component } from '@angular/core';
`
})
export class VersionParentComponent {
major = 1;
minor = 23;
major: number = 1;
minor: number = 23;
newMinor() {
this.minor++;

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';

View File

@ -16,7 +16,7 @@ import { UserService } from './user.service';
export class AppComponent {
// #enddocregion import-services
private userId = 1;
private userId: number = 1;
// #docregion ctor
constructor(logger: LoggerService, public userContext: UserContextService) {

View File

@ -1,4 +1,4 @@
/* tslint:disable:one-line*/
/* tslint:disable:one-line:check-open-brace*/
// #docregion
import { Injectable } from '@angular/core';

View File

@ -1,4 +1,4 @@
/* tslint:disable:one-line*/
/* tslint:disable:one-line:check-open-brace*/
// #docplaster
// #docregion injection-token
import { InjectionToken } from '@angular/core';

View File

@ -1,7 +1,7 @@
// #docregion
import { Hero } from './hero';
export const HEROES: Hero[] = [
export var HEROES: Hero[] = [
{ id: 11, isSecret: false, name: 'Mr. Nice' },
{ id: 12, isSecret: false, name: 'Narco' },
{ id: 13, isSecret: false, name: 'Bombasto' },

View File

@ -117,7 +117,7 @@ class OldLogger {
export class Provider6aComponent {
log: string;
constructor(newLogger: NewLogger, oldLogger: OldLogger) {
if (newLogger === oldLogger) {
if (newLogger === oldLogger){
throw new Error('expected the two loggers to be different instances');
}
oldLogger.log('Hello OldLogger (but we want NewLogger)');
@ -140,7 +140,7 @@ export class Provider6aComponent {
export class Provider6bComponent {
log: string;
constructor(newLogger: NewLogger, oldLogger: OldLogger) {
if (newLogger !== oldLogger) {
if (newLogger !== oldLogger){
throw new Error('expected the two loggers to be the same instance');
}
oldLogger.log('Hello from NewLogger (via aliased OldLogger)');

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';

View File

@ -8,7 +8,7 @@ import 'rxjs/add/operator/delay';
@Injectable()
export class AuthService {
isLoggedIn = false;
isLoggedIn: boolean = false;
// store the URL so we can redirect after logging in
redirectUrl: string;

View File

@ -15,7 +15,7 @@ export class ComposeMessageComponent {
@HostBinding('style.position') position = 'absolute';
details: string;
sending = false;
sending: boolean = false;
constructor(private router: Router) {}

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, By } from 'protractor';

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';

View File

@ -1,4 +1,4 @@
/* tslint:disable use-output-property-decorator directive-class-suffix */
/* tslint:disable use-output-property-decorator */
// #docplaster
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';

View File

@ -3,7 +3,7 @@ import { DependentService, FancyService } from './bag';
///////// Fakes /////////
export class FakeFancyService extends FancyService {
value = 'faked value';
value: string = 'faked value';
}
////////////////////////
// #docregion FancyService

View File

@ -677,5 +677,5 @@ class FakeGrandchildComponent { }
@Injectable()
class FakeFancyService extends FancyService {
value = 'faked value';
value: string = 'faked value';
}

View File

@ -20,7 +20,7 @@ export class Hero {
// #docregion FancyService
@Injectable()
export class FancyService {
protected value = 'real value';
protected value: string = 'real value';
getValue() { return this.value; }
setValue(value: string) { this.value = value; }

View File

@ -1,7 +1,7 @@
// #docregion
import { Hero } from './hero';
export const HEROES: Hero[] = [
export var HEROES: Hero[] = [
new Hero(11, 'Mr. Nice'),
new Hero(12, 'Narco'),
new Hero(13, 'Bombasto'),

View File

@ -5,7 +5,7 @@ export { HeroService } from '../hero.service';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
export const HEROES: Hero[] = [
export var HEROES: Hero[] = [
new Hero(41, 'Bob'),
new Hero(42, 'Carol'),
new Hero(43, 'Ted'),

View File

@ -0,0 +1,37 @@
// #docregion show-hero
template: '<h1>{{title}}</h1><h2>{{hero}} details!</h2>'
// #enddocregion show-hero
// #docregion show-hero-2
template: '<h1>{{title}}</h1><h2>{{hero.name}} details!</h2>'
// #enddocregion show-hero-2
// #docregion show-hero-properties
template: '<h1>{{title}}</h1><h2>{{hero.name}} details!</h2><div><label>id: </label>{{hero.id}}</div><div><label>name: </label>{{hero.name}}</div>'
// #enddocregion show-hero-properties
// #docregion multi-line-strings
template: '''
<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div><label>name: </label>{{hero.name}}</div>'''
// #enddocregion multi-line-strings
// #docregion editing-Hero
template: '''
<h1>{{title}}</h1>
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<input value="{{hero.name}}" placeholder="name">
</div>'''
// #enddocregion editing-Hero
// #docregion app-component-1
class AppComponent {
String title = 'Tour of Heroes';
var hero = 'Windstorm';
}
// #enddocregion app-component-1

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by, ElementFinder } from 'protractor';
import { promise } from 'selenium-webdriver';

View File

@ -0,0 +1,69 @@
// #docregion ng-for
<li *ngFor="let hero of heroes">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
// #enddocregion ng-for
// #docregion heroes-styled
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
// #enddocregion heroes-styled
// #docregion selectedHero-click
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
// #enddocregion selectedHero-click
// #docregion selectedHero-details
<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="selectedHero.name" placeholder="name">
</div>
// #enddocregion selectedHero-details
// #docregion ng-if
<div *ngIf="selectedHero != null">
<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="selectedHero.name" placeholder="name">
</div>
</div>
// #enddocregion ng-if
// #docregion hero-array-1
final List<Hero> heroes = mockHeroes;
// #enddocregion hero-array-1
// #docregion heroes-template-1
<h2>My Heroes</h2>
<ul class="heroes">
<li>
<!-- each hero goes here -->
</li>
</ul>
// #enddocregion heroes-template-1
// #docregion heroes-ngfor-1
<li *ngFor="let hero of heroes">
// #enddocregion heroes-ngfor-1
// #docregion class-selected-1
[class.selected]="hero == selectedHero"
// #enddocregion class-selected-1
// #docregion class-selected-2
<li *ngFor="let hero of heroes"
[class.selected]="hero == selectedHero"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
// #enddocregion class-selected-2

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by, ElementFinder } from 'protractor';
import { promise } from 'selenium-webdriver';

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by, ElementFinder } from 'protractor';
import { promise } from 'selenium-webdriver';

View File

@ -1,4 +1,4 @@
'use strict'; // necessary for es6 output in node
'use strict'; // necessary for es6 output in node
import { browser, element, by, ElementFinder } from 'protractor';
import { promise } from 'selenium-webdriver';

View File

@ -2,14 +2,14 @@
import { Hero } from './hero';
export const HEROES: Hero[] = [
{ id: 11, name: 'Mr. Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' }
{id: 11, name: 'Mr. Nice'},
{id: 12, name: 'Narco'},
{id: 13, name: 'Bombasto'},
{id: 14, name: 'Celeritas'},
{id: 15, name: 'Magneta'},
{id: 16, name: 'RubberMan'},
{id: 17, name: 'Dynama'},
{id: 18, name: 'Dr IQ'},
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'}
];

View File

@ -1,15 +1,15 @@
// #docregion
import { Hero } from './hero';
export const HEROES: Hero[] = [
{ id: 11, name: 'Mr. Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' }
export var HEROES: Hero[] = [
{id: 11, name: 'Mr. Nice'},
{id: 12, name: 'Narco'},
{id: 13, name: 'Bombasto'},
{id: 14, name: 'Celeritas'},
{id: 15, name: 'Magneta'},
{id: 16, name: 'RubberMan'},
{id: 17, name: 'Dynama'},
{id: 18, name: 'Dr IQ'},
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'}
];

View File

@ -5,7 +5,7 @@ import { promise } from 'selenium-webdriver';
const expectedH1 = 'Tour of Heroes';
const expectedTitle = `Angular ${expectedH1}`;
const targetHero = { id: 14, name: 'Celeritas' };
const targetHero = { id: 15, name: 'Magneta' };
const targetHeroDashboardIndex = 3;
const nameSuffix = 'X';
const newHeroName = targetHero.name + nameSuffix;
@ -136,7 +136,7 @@ describe('Tutorial part 6', () => {
getPageElts().myHeroesHref.click();
let page = getPageElts();
expect(page.myHeroes.isPresent()).toBeTruthy();
expect(page.allHeroes.count()).toEqual(11, 'number of heroes');
expect(page.allHeroes.count()).toEqual(10, 'number of heroes');
});
it(`selects and shows ${targetHero.name} as selected in list`, () => {
@ -176,7 +176,7 @@ describe('Tutorial part 6', () => {
const page = getPageElts();
expect(page.myHeroes.isPresent()).toBeTruthy();
expect(page.allHeroes.count()).toEqual(10, 'number of heroes');
expect(page.allHeroes.count()).toEqual(9, 'number of heroes');
const heroesAfter = await toHeroArray(page.allHeroes);
const expectedHeroes = heroesBefore.filter(h => h.name !== newHeroName);
expect(heroesAfter).toEqual(expectedHeroes);
@ -206,20 +206,20 @@ describe('Tutorial part 6', () => {
beforeAll(() => browser.get(''));
it(`searches for 'Ce'`, async () => {
getPageElts().searchBox.sendKeys('Ce');
it(`searches for 'Ma'`, async () => {
getPageElts().searchBox.sendKeys('Ma');
browser.sleep(1000);
expect(getPageElts().searchResults.count()).toBe(4);
});
it(`continues search with 'g'`, async () => {
getPageElts().searchBox.sendKeys('g');
browser.sleep(1000);
expect(getPageElts().searchResults.count()).toBe(2);
});
it(`continues search with 'l'`, async () => {
getPageElts().searchBox.sendKeys('l');
browser.sleep(1000);
expect(getPageElts().searchResults.count()).toBe(1);
});
it(`continues search with 'e' and gets ${targetHero.name}`, async () => {
getPageElts().searchBox.sendKeys('e');
it(`continues search with 'n' and gets ${targetHero.name}`, async () => {
getPageElts().searchBox.sendKeys('n');
browser.sleep(1000);
let page = getPageElts();
expect(page.searchResults.count()).toBe(1);

View File

@ -2,18 +2,17 @@
import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
const heroes = [
{ id: 0, name: 'Zero' },
{ id: 11, name: 'Mr. Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' }
let heroes = [
{id: 11, name: 'Mr. Nice'},
{id: 12, name: 'Narco'},
{id: 13, name: 'Bombasto'},
{id: 14, name: 'Celeritas'},
{id: 15, name: 'Magneta'},
{id: 16, name: 'RubberMan'},
{id: 17, name: 'Dynama'},
{id: 18, name: 'Dr IQ'},
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'}
];
return {heroes};
}

View File

@ -8,7 +8,7 @@ import { Attribute, Component, Inject, Optional } from '@angular/core';
})
// #enddocregion templateUrl
export class HeroTitleComponent {
msg = '';
msg: string = '';
constructor(
@Inject('titlePrefix') @Optional() private titlePrefix: string,
@Attribute('title') private title: string

View File

@ -1,94 +0,0 @@
{
"rulesDirectory": [
"../../node_modules/codelyzer"
],
"rules": {
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"indent": [
true,
"spaces"
],
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": false,
"no-eval": true,
"no-inferrable-types": true,
"no-string-literal": false,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"import-destructuring-spacing": true
}
}

View File

@ -162,4 +162,22 @@ describe('Upgrade Tests', function () {
});
describe('Dividing routes', function() {
beforeAll(function () {
browser.get('/index-divide-routes.html');
});
it('allows ng1 routes', function () {
browser.get('/index-divide-routes.html#/villain');
expect(element(by.css('h2')).getText()).toBe('Mr. Nice - No More Mr. Nice Guy');
});
it('allows ng2 routes', function () {
browser.get('/index-divide-routes.html#/hero');
expect(element(by.css('h2')).getText()).toBe('Windstorm - Specific powers of controlling winds');
});
});
});

View File

@ -6,9 +6,8 @@ import { UpgradeModule } from '@angular/upgrade/static';
import { heroDetailComponent } from './hero-detail.component';
// #docregion ngmodule, register
// #docregion ngmodule
import { Heroes } from './heroes';
// #enddocregion register
@NgModule({
imports: [
@ -18,10 +17,7 @@ import { Heroes } from './heroes';
providers: [ Heroes ]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
}
ngDoBootstrap() {}
}
// #enddocregion ngmodule
// #docregion register
@ -32,4 +28,7 @@ angular.module('heroApp', [])
.component('heroDetail', heroDetailComponent);
// #enddocregion register
platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});

View File

@ -22,10 +22,7 @@ import { ContainerComponent } from './container.component';
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
}
ngDoBootstrap() {}
}
// #enddocregion heroupgrade
@ -36,4 +33,7 @@ angular.module('heroApp', [])
downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory
);
platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});

View File

@ -8,8 +8,7 @@ export const heroDetail = {
<div>
<ng-transclude></ng-transclude>
</div>
`,
transclude: true
`
};
// #enddocregion

View File

@ -11,10 +11,7 @@ import { UpgradeModule } from '@angular/upgrade/static';
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
}
ngDoBootstrap() {}
}
// #enddocregion ngmodule
angular.module('heroApp', [])
@ -25,5 +22,8 @@ angular.module('heroApp', [])
// #docregion bootstrap
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});
// #enddocregion bootstrap

View File

@ -1,12 +1,10 @@
// #docregion ng1module
angular.module('heroApp', [])
.controller('MainCtrl', function() {
this.message = 'Hello world';
});
// #enddocregion ng1module
document.addEventListener('DOMContentLoaded', function() {
// #docregion bootstrap
angular.bootstrap(document.body, ['heroApp'], { strictDi: true });
angular.bootstrap(document.body, ['heroApp'], {strictDi: true});
// #enddocregion bootstrap
});

View File

@ -20,10 +20,7 @@ import { HeroDetailComponent } from './hero-detail.component';
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
}
ngDoBootstrap() {}
}
angular.module('heroApp', [])
@ -33,4 +30,7 @@ angular.module('heroApp', [])
inputs: ['hero']
}) as angular.IDirectiveFactory);
platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});

View File

@ -27,10 +27,7 @@ import { heroesServiceProvider } from './ajs-upgraded-providers';
// #docregion register
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
}
ngDoBootstrap() {}
}
// #enddocregion register
@ -41,4 +38,7 @@ angular.module('heroApp', [])
downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory
);
platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});

View File

@ -0,0 +1,11 @@
// #docregion
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<router-outlet></router-outlet>
<div ng-view></div>
`,
})
export class AppComponent { }

View File

@ -0,0 +1,62 @@
// #docregion
declare var angular: angular.IAngularStatic;
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UpgradeModule } from '@angular/upgrade/static';
import { HeroModule } from './hero.module';
// #docregion router-config
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
import { RouterModule, UrlHandlingStrategy, UrlTree } from '@angular/router';
import { AppComponent } from './app.component';
class HybridUrlHandlingStrategy implements UrlHandlingStrategy {
// use only process the `/hero` url
shouldProcessUrl(url: UrlTree) { return url.toString().startsWith('/hero'); }
extract(url: UrlTree) { return url; }
merge(url: UrlTree, whole: UrlTree) { return url; }
}
@NgModule({
imports: [
BrowserModule,
UpgradeModule,
HeroModule,
RouterModule.forRoot([])
],
providers: [
// use hash location strategy
{ provide: LocationStrategy, useClass: HashLocationStrategy },
// use custom url handling strategy
{ provide: UrlHandlingStrategy, useClass: HybridUrlHandlingStrategy }
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
// #enddocregion router-config
import { Villain } from '../villain';
export const villainDetail = {
template: `
<h1>Villain detail</h1>
<h2>{{$ctrl.villain.name}} - {{$ctrl.villain.description}}</h2>
`,
controller: function() {
this.villain = new Villain(1, 'Mr. Nice', 'No More Mr. Nice Guy');
}
};
angular.module('heroApp', ['ngRoute'])
.component('villainDetail', villainDetail)
.config(['$locationProvider', '$routeProvider',
function config($locationProvider: angular.ILocationProvider,
$routeProvider: angular.route.IRouteProvider) {
// #docregion ajs-route
$routeProvider
.when('/villain', { template: '<villain-detail></villain-detail>' });
// #enddocregion ajs-route
}
]);

View File

@ -0,0 +1,32 @@
// #docregion
import { Component } from '@angular/core';
import { Hero } from '../hero';
@Component({
template: `
<h1>Hero detail</h1>
<h2>{{hero.name}} - {{hero.description}}</h2>
`
})
export class HeroDetailComponent {
hero = new Hero(1, 'Windstorm', 'Specific powers of controlling winds');
}
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
@NgModule({
imports: [
CommonModule,
// #docregion a-route
RouterModule.forChild([
{ path: 'hero', children: [
{ path: '', component: HeroDetailComponent },
] },
])
// #enddocregion a-route
],
declarations: [ HeroDetailComponent ]
})
export class HeroModule {}

View File

@ -0,0 +1,10 @@
// #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { UpgradeModule } from '@angular/upgrade/static';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});

View File

@ -23,17 +23,21 @@ import { HeroDetailComponent } from './hero-detail.component';
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
}
ngDoBootstrap() {}
}
// #docregion downgradecomponent
angular.module('heroApp', [])
.controller('MainController', MainController)
.directive('heroDetail', downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory);
.directive('heroDetail', downgradeComponent({
component: HeroDetailComponent,
inputs: ['hero'],
outputs: ['deleted']
}) as angular.IDirectiveFactory);
// #enddocregion downgradecomponent
platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});

View File

@ -21,10 +21,7 @@ import { HeroDetailComponent } from './hero-detail.component';
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
}
ngDoBootstrap() {}
}
// #enddocregion ngmodule
// #docregion downgradecomponent
@ -34,9 +31,12 @@ import { downgradeComponent } from '@angular/upgrade/static';
angular.module('heroApp', [])
.directive(
'heroDetail',
downgradeComponent({ component: HeroDetailComponent }) as angular.IDirectiveFactory
downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory
);
// #enddocregion downgradecomponent
platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});

View File

@ -8,15 +8,15 @@ export function heroDetailDirective() {
deleted: '&'
},
template: `
<h2>{{$ctrl.hero.name}} details!</h2>
<div><label>id: </label>{{$ctrl.hero.id}}</div>
<button ng-click="$ctrl.onDelete()">Delete</button>
<h2>{{ctrl.hero.name}} details!</h2>
<div><label>id: </label>{{ctrl.hero.id}}</div>
<button ng-click="ctrl.onDelete()">Delete</button>
`,
controller: function() {
this.onDelete = () => {
this.deleted({hero: this.hero});
};
},
controllerAs: '$ctrl'
controllerAs: 'ctrl'
};
}

View File

@ -22,10 +22,7 @@ import { ContainerComponent } from './container.component';
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
}
ngDoBootstrap() {}
}
// #enddocregion heroupgrade
@ -36,4 +33,7 @@ angular.module('heroApp', [])
downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory
);
platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
});

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