Compare commits
243 Commits
4.1.1
...
4.2.0-rc.0
Author | SHA1 | Date | |
---|---|---|---|
3d382dc750 | |||
9081f84543 | |||
f1a9e3c1bb | |||
b10029c18b | |||
5d4f5434fd | |||
81ca51a8f0 | |||
6cb93c1fac | |||
eed67ddafb | |||
be9e8b99ff | |||
8a0e5659c0 | |||
2842b0cc3d | |||
a42322da0c | |||
4ccb2269a5 | |||
b836aca999 | |||
7d9f96abf0 | |||
86b7bd9c8e | |||
a0a6029915 | |||
6531806996 | |||
3a604ba0bf | |||
39f2977fa8 | |||
faacbe4dac | |||
47c72e4627 | |||
59136fdbe4 | |||
35d1922006 | |||
b40aae54b7 | |||
baa3fbab46 | |||
3361a7b834 | |||
0e13a5956c | |||
9466908c22 | |||
93d27d283a | |||
6f59a4a5b2 | |||
71c3103312 | |||
198edb3109 | |||
44d48d9d7a | |||
712630ca65 | |||
6416e79933 | |||
238c5238a5 | |||
593fe5ed25 | |||
54a6e4ff9e | |||
8a6eb1ac78 | |||
16c8167886 | |||
d761059e4d | |||
c805082648 | |||
9a7f5d580f | |||
af99cf2a41 | |||
221f85af3f | |||
a68ad6d58d | |||
7ae0440cca | |||
2ee7662737 | |||
44195858e6 | |||
39b92f7e54 | |||
1eba623d12 | |||
ea2b24fb4e | |||
a9d9aa18a0 | |||
ecc356ecea | |||
98e31290a7 | |||
7a759df49e | |||
38c524d655 | |||
06264645fd | |||
21d213dfc7 | |||
3065fc6cca | |||
bcefc61da4 | |||
569b1e0eb7 | |||
b83fe6f2a4 | |||
b016984c04 | |||
90bc5b221b | |||
37f1fcbfc8 | |||
4a599eec45 | |||
fdfeaaf1f3 | |||
decb4cc4a3 | |||
44c7ac0fe9 | |||
abb36e3cba | |||
84c30be164 | |||
5afaa39e68 | |||
ce1d7c4a6e | |||
b9521b568f | |||
2eca6e67e1 | |||
c757e5794f | |||
67dc970ce4 | |||
56ccd5e6a1 | |||
bcbee13e26 | |||
d28a3f7878 | |||
162dffb7e8 | |||
0f0b9896b7 | |||
e242e20ca3 | |||
f148ebe99e | |||
f795f649cf | |||
063db641f8 | |||
b44f5c69e1 | |||
56833a6171 | |||
efa2928547 | |||
f5335d17ec | |||
dc7d24267d | |||
412ab3f20c | |||
954c08e97c | |||
a2dcb7b476 | |||
bb0902c592 | |||
9e661e58d1 | |||
d0e72a8f8f | |||
b44eb328e0 | |||
7b4a8d53a7 | |||
73505e2ff0 | |||
e11f5294ab | |||
0190df9cf3 | |||
1af42aedfa | |||
215611aa9e | |||
98d83b2e2d | |||
cf7689ea7b | |||
2848f0499f | |||
5d4b36f80f | |||
415a0f8047 | |||
e0a8376237 | |||
f0f65443c6 | |||
fcc91d862f | |||
3887d8a429 | |||
041f57cb7d | |||
c5ce0408a1 | |||
98dd609f89 | |||
6dc67772b0 | |||
5cf64266f8 | |||
03513e9d70 | |||
b9ed97c0d9 | |||
799be9c98a | |||
566dab1140 | |||
42dc2c19ee | |||
518eb540aa | |||
309ada5df5 | |||
9da63408b0 | |||
7ae7a8440c | |||
aef524506b | |||
547c363473 | |||
2714644528 | |||
d27588b5fb | |||
a8379a46cf | |||
b7caa3e024 | |||
3e33482386 | |||
5057e16874 | |||
9449eff6fd | |||
03610526e5 | |||
cd28df627c | |||
59d62bc5aa | |||
8f46db3701 | |||
109229246c | |||
5856298798 | |||
7f9c589ba3 | |||
8931e71c5c | |||
5bc435eba3 | |||
4dabec6a48 | |||
978376a46e | |||
895f47a9c2 | |||
aec65dee71 | |||
2f66932bd1 | |||
919ff12377 | |||
6748aeabb6 | |||
b3e63c09ab | |||
77b8a76f2e | |||
55b8de9fdd | |||
eb56ab38dc | |||
f29c6bbc6f | |||
464701a899 | |||
5b96fb9320 | |||
1cfb263ee3 | |||
9ca2b4c967 | |||
673d8ae583 | |||
8760bf7be4 | |||
ea02073c84 | |||
b051d7ff48 | |||
cade722e48 | |||
58817f55e1 | |||
3f1d7f7a76 | |||
c8dc116951 | |||
9684d78cae | |||
71f5b73296 | |||
5ba8c14893 | |||
ea9d8a6bc7 | |||
9650ff0824 | |||
00dce1698a | |||
c946a929b7 | |||
21c96a5af1 | |||
a0b9c23100 | |||
cb5bc76766 | |||
1c8772a879 | |||
79ed0e7121 | |||
0c69903123 | |||
04dc24820d | |||
e263e19a2a | |||
ac220fc2bb | |||
3b80472bad | |||
ca17d4f639 | |||
64335d3521 | |||
9945ce2259 | |||
6d9da73090 | |||
c889fb1ef5 | |||
d32bc5df3e | |||
efaf502e95 | |||
ff32c53099 | |||
235eb17cca | |||
aaa562898f | |||
c8fd904c32 | |||
65a8f7f6c9 | |||
f32bfcdbe5 | |||
24b9067047 | |||
de8de84cea | |||
8d300ffbfc | |||
f74dafcb07 | |||
065b76d14c | |||
253345c0c0 | |||
270d694ed2 | |||
f4b771a0c6 | |||
a4de214e2b | |||
aa8bba4865 | |||
392d584572 | |||
900a88b15d | |||
cb384e8ed3 | |||
a2b2afb21c | |||
b70b9606eb | |||
938406122e | |||
951a575db3 | |||
8c50457385 | |||
8c09d10ba9 | |||
c04e51cb15 | |||
7b94f493b9 | |||
f1f04fa782 | |||
4be1966a21 | |||
de25cfc0cb | |||
de36a9b718 | |||
883a3250e4 | |||
1ceb2f9c79 | |||
fbde2a8010 | |||
81925fa66d | |||
6e2abcd5fc | |||
3f46645f5f | |||
2a7f63650c | |||
cd5b1f306a | |||
749bcf3d9c | |||
a9027a2570 | |||
72e32b1f17 | |||
96648ba98a | |||
6561d46349 | |||
2e5e37ac58 | |||
6bac4e65ce | |||
a28f5eeed3 | |||
c0c50133e3 |
@ -32,7 +32,7 @@ env:
|
|||||||
global:
|
global:
|
||||||
# GITHUB_TOKEN_ANGULAR=<github token, a personal access token of the angular-builds account, account access in valentine>
|
# GITHUB_TOKEN_ANGULAR=<github token, a personal access token of the angular-builds account, account access in valentine>
|
||||||
# This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery.
|
# This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery.
|
||||||
- secure: "rNqXoy2gqjbF5tBXlRBy+oiYntO3BtzcxZuEtlLMzNaTNzC4dyMOFub0GkzIPWwOzkARoEU9Kv+bC97fDVbCBUKeyzzEqxqddUKhzRxeaYjsefJ6XeTvBvDxwo7wDwyxZSuWdBeGAe4eARVHm7ypsd+AlvqxtzjyS27TK2BzdL4="
|
- secure: "aCdHveZuY8AT4Jr1JoJB4LxZsnGWRe/KseZh1YXYe5UtufFCtTVHvUcLn0j2aLBF0KpdyS+hWf0i4np9jthKu2xPKriefoPgCMpisYeC0MFkwbmv+XlgkUbgkgVZMGiVyX7DCYXVahxIoOUjVMEDCbNiHTIrfEuyq24U3ok2tHc="
|
||||||
# FIREBASE_TOKEN
|
# FIREBASE_TOKEN
|
||||||
# This is needed for publishing builds to the "aio-staging" firebase site.
|
# 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.
|
# TODO(i): the token was generated using the iminar@google account, we should switch to a shared/role-base account.
|
||||||
|
126
CHANGELOG.md
126
CHANGELOG.md
@ -1,3 +1,104 @@
|
|||||||
|
<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)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** avoid a `...null` spread in extraction ([#16547](https://github.com/angular/angular/issues/16547)) ([d0e1688](https://github.com/angular/angular/commit/d0e1688))
|
||||||
|
* **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([ee6705a](https://github.com/angular/angular/commit/ee6705a)), 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)) ([9218812](https://github.com/angular/angular/commit/9218812)), closes [#14321](https://github.com/angular/angular/issues/14321)
|
||||||
|
* **http:** flatten metadata for [@angular](https://github.com/angular)/http/testing ([9c70a3c](https://github.com/angular/angular/commit/9c70a3c)), closes [#15521](https://github.com/angular/angular/issues/15521)
|
||||||
|
* **http:** honor RequestArgs.search and RequestArgs.params map type ([63066f7](https://github.com/angular/angular/commit/63066f7)), 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 ([ec3b6e9](https://github.com/angular/angular/commit/ec3b6e9)), 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)) ([915eae5](https://github.com/angular/angular/commit/915eae5)), closes [#16310](https://github.com/angular/angular/issues/16310)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<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 component’s `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:** don’t 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:** don’t 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>
|
<a name="4.1.1"></a>
|
||||||
## [4.1.1](https://github.com/angular/angular/compare/4.1.0...4.1.1) (2017-05-04)
|
## [4.1.1](https://github.com/angular/angular/compare/4.1.0...4.1.1) (2017-05-04)
|
||||||
|
|
||||||
@ -20,35 +121,10 @@
|
|||||||
|
|
||||||
### Bug Fixes
|
### 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)
|
* **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)
|
* **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>
|
<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)
|
# [4.1.0-rc.0](https://github.com/angular/angular/compare/4.1.0-beta.0...4.1.0-rc.0) (2017-04-21)
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"assets": [
|
"assets": [
|
||||||
"assets",
|
"assets",
|
||||||
"content",
|
"generated",
|
||||||
"app/search/search-worker.js",
|
"app/search/search-worker.js",
|
||||||
"favicon.ico",
|
"favicon.ico",
|
||||||
"pwa-manifest.json"
|
"pwa-manifest.json"
|
||||||
@ -21,12 +21,12 @@
|
|||||||
"tsconfig": "tsconfig.app.json",
|
"tsconfig": "tsconfig.app.json",
|
||||||
"testTsconfig": "tsconfig.spec.json",
|
"testTsconfig": "tsconfig.spec.json",
|
||||||
"prefix": "aio",
|
"prefix": "aio",
|
||||||
"serviceWorker": true,
|
"serviceWorker": false,
|
||||||
"styles": [
|
"styles": [
|
||||||
"styles.scss"
|
"styles.scss"
|
||||||
],
|
],
|
||||||
"scripts": [
|
"scripts": [
|
||||||
|
"../node_modules/tslib/tslib.js"
|
||||||
],
|
],
|
||||||
"environmentSource": "environments/environment.ts",
|
"environmentSource": "environments/environment.ts",
|
||||||
"environments": {
|
"environments": {
|
||||||
|
2
aio/.gitignore
vendored
2
aio/.gitignore
vendored
@ -3,7 +3,7 @@
|
|||||||
# compiled output
|
# compiled output
|
||||||
/dist
|
/dist
|
||||||
/out-tsc
|
/out-tsc
|
||||||
/src/content
|
/src/generated
|
||||||
/tmp
|
/tmp
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
|
@ -30,6 +30,19 @@ 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-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 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
|
## Guide to authoring
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ 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_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_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_UPLOAD_PORT=$AIO_UPLOAD_PORT TEST_AIO_UPLOAD_PORT=$TEST_AIO_UPLOAD_PORT \
|
||||||
|
AIO_WWW_USER=www-data \
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ 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 --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 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 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
|
# Install packages
|
||||||
@ -71,11 +73,11 @@ RUN apt-get update -y && apt-get install -y \
|
|||||||
cron \
|
cron \
|
||||||
dnsmasq \
|
dnsmasq \
|
||||||
nano \
|
nano \
|
||||||
nginx \
|
|
||||||
nodejs \
|
nodejs \
|
||||||
openssl \
|
openssl \
|
||||||
rsyslog \
|
rsyslog \
|
||||||
yarn
|
yarn
|
||||||
|
RUN apt-get install -t jessie-backports -y nginx
|
||||||
RUN yarn global add pm2@2
|
RUN yarn global add pm2@2
|
||||||
|
|
||||||
|
|
||||||
@ -109,31 +111,31 @@ RUN update-ca-certificates
|
|||||||
|
|
||||||
|
|
||||||
# Set up nginx (for production and testing)
|
# Set up nginx (for production and testing)
|
||||||
RUN rm /etc/nginx/sites-enabled/*
|
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/*
|
||||||
|
|
||||||
COPY nginx/aio-builds.conf /etc/nginx/sites-available/aio-builds-prod.conf
|
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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/aio-builds-prod.conf
|
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$AIO_UPLOAD_PORT|g" /etc/nginx/conf.d/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/sites-available/aio-builds-test.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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/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/sites-available/aio-builds-test.conf
|
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$TEST_AIO_UPLOAD_PORT|g" /etc/nginx/conf.d/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
|
# Set up pm2
|
||||||
|
@ -17,16 +17,22 @@ server {
|
|||||||
server {
|
server {
|
||||||
server_name "~^pr(?<pr>[1-9][0-9]*)-(?<sha>[0-9a-f]{40})\.";
|
server_name "~^pr(?<pr>[1-9][0-9]*)-(?<sha>[0-9a-f]{40})\.";
|
||||||
|
|
||||||
listen {{$AIO_NGINX_PORT_HTTPS}} ssl;
|
listen {{$AIO_NGINX_PORT_HTTPS}} ssl http2;
|
||||||
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl;
|
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl http2;
|
||||||
|
|
||||||
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
|
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
|
||||||
ssl_certificate_key {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.key;
|
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;
|
||||||
|
|
||||||
root {{$AIO_BUILDS_DIR}}/$pr/$sha;
|
root {{$AIO_BUILDS_DIR}}/$pr/$sha;
|
||||||
disable_symlinks on from=$document_root;
|
disable_symlinks on from=$document_root;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_comp_level 7;
|
||||||
|
gzip_types *;
|
||||||
|
|
||||||
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
|
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
|
||||||
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
|
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
|
||||||
|
|
||||||
@ -43,11 +49,13 @@ server {
|
|||||||
server {
|
server {
|
||||||
server_name _;
|
server_name _;
|
||||||
|
|
||||||
listen {{$AIO_NGINX_PORT_HTTPS}} ssl default_server;
|
listen {{$AIO_NGINX_PORT_HTTPS}} ssl http2 default_server;
|
||||||
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl;
|
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl http2;
|
||||||
|
|
||||||
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
|
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
|
||||||
ssl_certificate_key {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.key;
|
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;
|
||||||
|
|
||||||
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
|
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
|
||||||
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
|
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
|
||||||
|
@ -18,8 +18,8 @@ function _main() {
|
|||||||
|
|
||||||
// Exit codes:
|
// Exit codes:
|
||||||
// - 0: The PR author is a member.
|
// - 0: The PR author is a member.
|
||||||
// - 1: The PR author is not a member.
|
// - 1: An error occurred.
|
||||||
// - 2: An error occurred.
|
// - 2: The PR author is not a member.
|
||||||
buildVerifier.getPrAuthorTeamMembership(pr).
|
buildVerifier.getPrAuthorTeamMembership(pr).
|
||||||
then(({author, isMember}) => {
|
then(({author, isMember}) => {
|
||||||
if (isMember) {
|
if (isMember) {
|
||||||
@ -27,10 +27,10 @@ function _main() {
|
|||||||
} else {
|
} else {
|
||||||
const errorMessage = `User '${author}' is not an active member of any of the following teams: ` +
|
const errorMessage = `User '${author}' is not an active member of any of the following teams: ` +
|
||||||
`${allowedTeamSlugs.join(', ')}`;
|
`${allowedTeamSlugs.join(', ')}`;
|
||||||
onError(errorMessage, 1);
|
onError(errorMessage, 2);
|
||||||
}
|
}
|
||||||
}).
|
}).
|
||||||
catch(err => onError(err, 2));
|
catch(err => onError(err, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onError(err: string, exitCode: number) {
|
function onError(err: string, exitCode: number) {
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
// TODO(gkalpak): Find more suitable way to run as `www-data`.
|
|
||||||
process.setuid('www-data');
|
|
||||||
|
|
||||||
// Imports
|
// Imports
|
||||||
import {getEnvVar} from '../common/utils';
|
import {getEnvVar} from '../common/utils';
|
||||||
import {uploadServerFactory} from './upload-server-factory';
|
import {uploadServerFactory} from './upload-server-factory';
|
||||||
@ -15,8 +12,10 @@ const AIO_PREVIEW_DEPLOYMENT_TOKEN = getEnvVar('AIO_PREVIEW_DEPLOYMENT_TOKEN');
|
|||||||
const AIO_REPO_SLUG = getEnvVar('AIO_REPO_SLUG');
|
const AIO_REPO_SLUG = getEnvVar('AIO_REPO_SLUG');
|
||||||
const AIO_UPLOAD_HOSTNAME = getEnvVar('AIO_UPLOAD_HOSTNAME');
|
const AIO_UPLOAD_HOSTNAME = getEnvVar('AIO_UPLOAD_HOSTNAME');
|
||||||
const AIO_UPLOAD_PORT = +getEnvVar('AIO_UPLOAD_PORT');
|
const AIO_UPLOAD_PORT = +getEnvVar('AIO_UPLOAD_PORT');
|
||||||
|
const AIO_WWW_USER = getEnvVar('AIO_WWW_USER');
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
|
process.setuid(AIO_WWW_USER); // TODO(gkalpak): Find more suitable way to run as `www-data`.
|
||||||
_main();
|
_main();
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
@ -7,7 +7,6 @@ import * as shell from 'shelljs';
|
|||||||
import {getEnvVar} from '../common/utils';
|
import {getEnvVar} from '../common/utils';
|
||||||
|
|
||||||
// Constans
|
// Constans
|
||||||
const SERVER_USER = 'www-data';
|
|
||||||
const TEST_AIO_BUILDS_DIR = getEnvVar('TEST_AIO_BUILDS_DIR');
|
const TEST_AIO_BUILDS_DIR = getEnvVar('TEST_AIO_BUILDS_DIR');
|
||||||
const TEST_AIO_NGINX_HOSTNAME = getEnvVar('TEST_AIO_NGINX_HOSTNAME');
|
const TEST_AIO_NGINX_HOSTNAME = getEnvVar('TEST_AIO_NGINX_HOSTNAME');
|
||||||
const TEST_AIO_NGINX_PORT_HTTP = +getEnvVar('TEST_AIO_NGINX_PORT_HTTP');
|
const TEST_AIO_NGINX_PORT_HTTP = +getEnvVar('TEST_AIO_NGINX_PORT_HTTP');
|
||||||
@ -15,6 +14,7 @@ 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_HOSTNAME = getEnvVar('TEST_AIO_UPLOAD_HOSTNAME');
|
||||||
const TEST_AIO_UPLOAD_MAX_SIZE = +getEnvVar('TEST_AIO_UPLOAD_MAX_SIZE');
|
const TEST_AIO_UPLOAD_MAX_SIZE = +getEnvVar('TEST_AIO_UPLOAD_MAX_SIZE');
|
||||||
const TEST_AIO_UPLOAD_PORT = +getEnvVar('TEST_AIO_UPLOAD_PORT');
|
const TEST_AIO_UPLOAD_PORT = +getEnvVar('TEST_AIO_UPLOAD_PORT');
|
||||||
|
const WWW_USER = getEnvVar('AIO_WWW_USER');
|
||||||
|
|
||||||
// Interfaces - Types
|
// Interfaces - Types
|
||||||
export interface CmdResult { success: boolean; err: Error; stdout: string; stderr: string; }
|
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 nginxHostname() { return TEST_AIO_NGINX_HOSTNAME; }
|
||||||
public get nginxPortHttp() { return TEST_AIO_NGINX_PORT_HTTP; }
|
public get nginxPortHttp() { return TEST_AIO_NGINX_PORT_HTTP; }
|
||||||
public get nginxPortHttps() { return TEST_AIO_NGINX_PORT_HTTPS; }
|
public get nginxPortHttps() { return TEST_AIO_NGINX_PORT_HTTPS; }
|
||||||
public get serverUser() { return SERVER_USER; }
|
public get wwwUser() { return WWW_USER; }
|
||||||
public get uploadHostname() { return TEST_AIO_UPLOAD_HOSTNAME; }
|
public get uploadHostname() { return TEST_AIO_UPLOAD_HOSTNAME; }
|
||||||
public get uploadPort() { return TEST_AIO_UPLOAD_PORT; }
|
public get uploadPort() { return TEST_AIO_UPLOAD_PORT; }
|
||||||
public get uploadMaxSize() { return TEST_AIO_UPLOAD_MAX_SIZE; }
|
public get uploadMaxSize() { return TEST_AIO_UPLOAD_MAX_SIZE; }
|
||||||
@ -46,7 +46,7 @@ class Helper {
|
|||||||
// Constructor
|
// Constructor
|
||||||
constructor() {
|
constructor() {
|
||||||
shell.mkdir('-p', this.buildsDir);
|
shell.mkdir('-p', this.buildsDir);
|
||||||
shell.exec(`chown -R ${this.serverUser} ${this.buildsDir}`);
|
shell.exec(`chown -R ${this.wwwUser} ${this.buildsDir}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods - Public
|
// Methods - Public
|
||||||
@ -64,7 +64,7 @@ class Helper {
|
|||||||
public createDummyArchive(pr: string, sha: string, archivePath: string): CleanUpFn {
|
public createDummyArchive(pr: string, sha: string, archivePath: string): CleanUpFn {
|
||||||
const inputDir = path.join(this.buildsDir, 'uploaded', pr, sha);
|
const inputDir = path.join(this.buildsDir, 'uploaded', pr, sha);
|
||||||
const cmd1 = `tar --create --gzip --directory "${inputDir}" --file "${archivePath}" .`;
|
const cmd1 = `tar --create --gzip --directory "${inputDir}" --file "${archivePath}" .`;
|
||||||
const cmd2 = `chown ${this.serverUser} ${archivePath}`;
|
const cmd2 = `chown ${this.wwwUser} ${archivePath}`;
|
||||||
|
|
||||||
const cleanUpTemp = this.createDummyBuild(`uploaded/${pr}`, sha, true);
|
const cleanUpTemp = this.createDummyBuild(`uploaded/${pr}`, sha, true);
|
||||||
shell.exec(cmd1);
|
shell.exec(cmd1);
|
||||||
@ -82,7 +82,7 @@ class Helper {
|
|||||||
|
|
||||||
this.writeFile(idxPath, {content: `PR: ${pr} | SHA: ${sha} | File: /index.html`}, force);
|
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);
|
this.writeFile(barPath, {content: `PR: ${pr} | SHA: ${sha} | File: /foo/bar.js`}, force);
|
||||||
shell.exec(`chown -R ${this.serverUser} ${prDir}`);
|
shell.exec(`chown -R ${this.wwwUser} ${prDir}`);
|
||||||
|
|
||||||
return this.createCleanUpFn(() => shell.rm('-rf', prDir));
|
return this.createCleanUpFn(() => shell.rm('-rf', prDir));
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ class Helper {
|
|||||||
// Create a file with the specified content.
|
// Create a file with the specified content.
|
||||||
fs.writeFileSync(filePath, content || '');
|
fs.writeFileSync(filePath, content || '');
|
||||||
}
|
}
|
||||||
shell.exec(`chown ${this.serverUser} ${filePath}`);
|
shell.exec(`chown ${this.wwwUser} ${filePath}`);
|
||||||
|
|
||||||
return this.createCleanUpFn(() => shell.rm('-rf', cleanUpTarget));
|
return this.createCleanUpFn(() => shell.rm('-rf', cleanUpTarget));
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ describe('upload-server (on HTTP)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it(`should create files/directories owned by '${h.serverUser}'`, done => {
|
it(`should create files/directories owned by '${h.wwwUser}'`, done => {
|
||||||
const shaDir = path.join(h.buildsDir, pr, sha9);
|
const shaDir = path.join(h.buildsDir, pr, sha9);
|
||||||
const idxPath = path.join(shaDir, 'index.html');
|
const idxPath = path.join(shaDir, 'index.html');
|
||||||
const barPath = path.join(shaDir, 'foo', 'bar.js');
|
const barPath = path.join(shaDir, 'foo', 'bar.js');
|
||||||
@ -167,7 +167,7 @@ describe('upload-server (on HTTP)', () => {
|
|||||||
uploadPromise.
|
uploadPromise.
|
||||||
then(() => Promise.all([
|
then(() => Promise.all([
|
||||||
h.runCmd(`find ${shaDir}`),
|
h.runCmd(`find ${shaDir}`),
|
||||||
h.runCmd(`find ${shaDir} -user ${h.serverUser}`),
|
h.runCmd(`find ${shaDir} -user ${h.wwwUser}`),
|
||||||
])).
|
])).
|
||||||
then(([{stdout: allFiles}, {stdout: userFiles}]) => {
|
then(([{stdout: allFiles}, {stdout: userFiles}]) => {
|
||||||
expect(userFiles).toBe(allFiles);
|
expect(userFiles).toBe(allFiles);
|
||||||
|
@ -6,18 +6,18 @@
|
|||||||
"author": "Angular",
|
"author": "Angular",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "yarn run clean",
|
"prebuild": "yarn clean-dist",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"build-watch": "yarn run tsc -- --watch",
|
"build-watch": "yarn tsc -- --watch",
|
||||||
"clean": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
|
"clean-dist": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
|
||||||
"dev": "concurrently --kill-others --raw --success first \"yarn run build-watch\" \"yarn run test-watch\"",
|
"dev": "concurrently --kill-others --raw --success first \"yarn build-watch\" \"yarn test-watch\"",
|
||||||
"lint": "tslint --project tsconfig.json",
|
"lint": "tslint --project tsconfig.json",
|
||||||
"pre~~test-only": "yarn run lint",
|
"pre~~test-only": "yarn lint",
|
||||||
"~~test-only": "node dist/test",
|
"~~test-only": "node dist/test",
|
||||||
"pretest": "yarn run build",
|
"pretest": "yarn build",
|
||||||
"test": "yarn run ~~test-only",
|
"test": "yarn ~~test-only",
|
||||||
"pretest-watch": "yarn run build",
|
"pretest-watch": "yarn build",
|
||||||
"test-watch": "nodemon --exec \"yarn run ~~test-only\" --watch dist"
|
"test-watch": "nodemon --exec \"yarn ~~test-only\" --watch dist"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.14.1",
|
"express": "^4.14.1",
|
||||||
|
@ -20,7 +20,11 @@
|
|||||||
|
|
||||||
|
|
||||||
## Starting the docker container
|
## Starting the docker container
|
||||||
- [Create docker image](vm-setup--start-docker-container.md)
|
- [Start docker container](vm-setup--start-docker-container.md)
|
||||||
|
|
||||||
|
|
||||||
|
## Updating the docker container
|
||||||
|
- [Update docker container](vm-setup--update-docker-container.md)
|
||||||
|
|
||||||
|
|
||||||
## Miscellaneous
|
## Miscellaneous
|
||||||
|
@ -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
|
The scripts are located inside `<aio-builds-setup-dir>/scripts/`. The following scripts are
|
||||||
available:
|
available:
|
||||||
|
|
||||||
- `build.sh`:
|
- `create-image.sh`:
|
||||||
Can be used for creating a preconfigured docker image.
|
Can be used for creating a preconfigured docker image.
|
||||||
See [here](vm-setup--create-docker-image.md) for more info.
|
See [here](vm-setup--create-docker-image.md) for more info.
|
||||||
|
|
||||||
@ -18,10 +18,13 @@ available:
|
|||||||
|
|
||||||
- `travis-preverify-pr.sh`
|
- `travis-preverify-pr.sh`
|
||||||
Can be used for "preverifying" a PR before uploading the artifacts to the server. It checks that
|
Can be used for "preverifying" a PR before uploading the artifacts to the server. It checks that
|
||||||
the author of the PR a member of one of the specified GitHub teams and therefore allowed to upload
|
the author of the PR is a member of one of the specified GitHub teams and therefore allowed to
|
||||||
build artifacts. This is useful for CI integration. See [here](misc--integrate-with-ci.md) for
|
upload build artifacts. This is useful for CI integration. See [here](misc--integrate-with-ci.md)
|
||||||
more info.
|
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
|
## Commands
|
||||||
The following commands are available globally from inside the docker container. They are either used
|
The following commands are available globally from inside the docker container. They are either used
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
|
|
||||||
## Build docker image
|
## Build docker image
|
||||||
- `<aio-builds-setup-dir>/scripts/build.sh [<name>[:<tag>] [--build-arg <NAME>=<value> ...]]`
|
- `<aio-builds-setup-dir>/scripts/create-image.sh [<name>[:<tag>] [--build-arg <NAME>=<value> ...]]`
|
||||||
- You can overwrite the default environment variables inside the image, by passing new values using
|
- You can overwrite the default environment variables inside the image, by passing new values using
|
||||||
`--build-arg`.
|
`--build-arg`.
|
||||||
|
|
||||||
**Note:** The build script has to execute docker commands with `sudo`.
|
**Note:** The script has to execute docker commands with `sudo`.
|
||||||
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
@ -7,16 +7,16 @@ command:
|
|||||||
|
|
||||||
```
|
```
|
||||||
sudo docker run \
|
sudo docker run \
|
||||||
-d \
|
--detach \
|
||||||
--dns 127.0.0.1 \
|
--dns 127.0.0.1 \
|
||||||
--name <instance-name> \
|
--name <instance-name> \
|
||||||
-p 80:80 \
|
--publish 80:80 \
|
||||||
-p 443:443 \
|
--publish 443:443 \
|
||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
[-v <host-cert-dir>:/etc/ssl/localcerts:ro] \
|
[--volume <host-cert-dir>:/etc/ssl/localcerts:ro] \
|
||||||
-v <host-secrets-dir>:/aio-secrets:ro \
|
--volume <host-secrets-dir>:/aio-secrets:ro \
|
||||||
-v <host-builds-dir>:/var/www/aio-builds \
|
--volume <host-builds-dir>:/var/www/aio-builds \
|
||||||
[-v <host-logs-dir>:/var/log/aio] \
|
[--volume <host-logs-dir>:/var/log/aio] \
|
||||||
<name>[:<tag>]
|
<name>[:<tag>]
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ can be found [here](https://docs.docker.com/engine/reference/run/).
|
|||||||
sudo docker run \
|
sudo docker run \
|
||||||
|
|
||||||
# Start as a daemon.
|
# Start as a daemon.
|
||||||
-d \
|
--detach \
|
||||||
|
|
||||||
# Use the local DNS server.
|
# Use the local DNS server.
|
||||||
# (This is necessary for mapping internal URLs, e.g. for the Node.js upload-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>`
|
# Useful for running `docker` commands, e.g.: `docker stop <instance-name>`
|
||||||
--name <instance-name> \
|
--name <instance-name> \
|
||||||
|
|
||||||
# Map ports of the hosr VM (left) to ports of the docker container (right)
|
# Map ports of the host VM (left) to ports of the docker container (right)
|
||||||
-p 80:80 \
|
--publish 80:80 \
|
||||||
-p 443:443 \
|
--publish 443:443 \
|
||||||
|
|
||||||
# Automatically restart the container (unless it was explicitly stopped by the user).
|
# Automatically restart the container (unless it was explicitly stopped by the user).
|
||||||
# (This ensures that the container will be automatically started on boot.)
|
# (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.
|
# The directory the contains the SSL certificates.
|
||||||
# (See [here](vm-setup--create-host-dirs-and-files.md) for more info.)
|
# (See [here](vm-setup--create-host-dirs-and-files.md) for more info.)
|
||||||
# If not provided, the container will use self-signed certificates.
|
# If not provided, the container will use self-signed certificates.
|
||||||
[-v <host-cert-dir>:/etc/ssl/localcerts:ro] \
|
[--volume <host-cert-dir>:/etc/ssl/localcerts:ro] \
|
||||||
|
|
||||||
# The directory the contains the secrets (e.g. GitHub token, JWT secret, etc).
|
# The directory the contains the secrets (e.g. GitHub token, JWT secret, etc).
|
||||||
# (See [here](vm-setup--set-up-secrets.md) for more info.)
|
# (See [here](vm-setup--set-up-secrets.md) for more info.)
|
||||||
-v <host-secrets-dir>:/aio-secrets:ro \
|
--volume <host-secrets-dir>:/aio-secrets:ro \
|
||||||
|
|
||||||
# The uploaded build artifacts will stored to and served from this directory.
|
# 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) -
|
# (If you are using a persistent disk - as described [here](vm-setup--attach-persistent-disk.md) -
|
||||||
# this will be a directory inside the disk.)
|
# this will be a directory inside the disk.)
|
||||||
-v <host-builds-dir>:/var/www/aio-builds \
|
--volume <host-builds-dir>:/var/www/aio-builds \
|
||||||
|
|
||||||
# The directory where the logs are being kept.
|
# The directory where the logs are being kept.
|
||||||
# (See [here](vm-setup--create-host-dirs-and-files.md) for more info.)
|
# (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
|
# If not provided, the logs will be kept inside the container, which means they will be lost
|
||||||
# whenever a new container is created.
|
# whenever a new container is created.
|
||||||
[-v <host-logs-dir>:/var/log/aio] \
|
[--volume <host-logs-dir>:/var/log/aio] \
|
||||||
|
|
||||||
# The name of the docker image to use (and an optional tag; defaults to `latest`).
|
# 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.)
|
# (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 \
|
sudo docker run \
|
||||||
-d \
|
--detach \
|
||||||
--dns 127.0.0.1 \
|
--dns 127.0.0.1 \
|
||||||
--name foobar-builds-1 \
|
--name foobar-builds-1 \
|
||||||
-p 80:80 \
|
--publish 80:80 \
|
||||||
-p 443:443 \
|
--publish 443:443 \
|
||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
-v /etc/ssl/localcerts:/etc/ssl/localcerts:ro \
|
--volume /etc/ssl/localcerts:/etc/ssl/localcerts:ro \
|
||||||
-v /foobar-secrets:/aio-secrets:ro \
|
--volume /foobar-secrets:/aio-secrets:ro \
|
||||||
-v /mnt/disks/foobar-builds:/var/www/aio-builds \
|
--volume /mnt/disks/foobar-builds:/var/www/aio-builds \
|
||||||
-v /foobar-logs:/var/log/aio \
|
--volume /foobar-logs:/var/log/aio \
|
||||||
foobar-builds
|
foobar-builds
|
||||||
```
|
```
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
# 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
|
||||||
|
```
|
@ -2,15 +2,9 @@
|
|||||||
set -eux -o pipefail
|
set -eux -o pipefail
|
||||||
|
|
||||||
# Set up env
|
# Set up env
|
||||||
source "`dirname $0`/env.sh"
|
source "`dirname $0`/_env.sh"
|
||||||
readonly defaultImageNameAndTag="aio-builds:latest"
|
readonly defaultImageNameAndTag="aio-builds:latest"
|
||||||
|
|
||||||
# Build `scripts-js/`
|
|
||||||
cd "$SCRIPTS_JS_DIR"
|
|
||||||
yarn install
|
|
||||||
yarn run build
|
|
||||||
cd -
|
|
||||||
|
|
||||||
# Create docker image
|
# Create docker image
|
||||||
readonly nameAndOptionalTag=${1:-$defaultImageNameAndTag}
|
readonly nameAndOptionalTag=${1:-$defaultImageNameAndTag}
|
||||||
sudo docker build --tag $nameAndOptionalTag ${@:2} $DOCKERBUILD_DIR
|
sudo docker build --tag $nameAndOptionalTag ${@:2} $DOCKERBUILD_DIR
|
@ -2,10 +2,11 @@
|
|||||||
set -eux -o pipefail
|
set -eux -o pipefail
|
||||||
|
|
||||||
# Set up env
|
# Set up env
|
||||||
source "`dirname $0`/env.sh"
|
source "`dirname $0`/_env.sh"
|
||||||
|
|
||||||
# Test `scripts-js/`
|
# Test `scripts-js/`
|
||||||
cd "$SCRIPTS_JS_DIR"
|
(
|
||||||
yarn install
|
cd "$SCRIPTS_JS_DIR"
|
||||||
yarn test
|
yarn install
|
||||||
cd -
|
yarn test
|
||||||
|
)
|
||||||
|
@ -2,7 +2,14 @@
|
|||||||
set -eux -o pipefail
|
set -eux -o pipefail
|
||||||
|
|
||||||
# Set up env
|
# Set up env
|
||||||
source "`dirname $0`/env.sh"
|
source "`dirname $0`/_env.sh"
|
||||||
|
|
||||||
|
# Build `scripts-js/`
|
||||||
|
(
|
||||||
|
cd "$SCRIPTS_JS_DIR"
|
||||||
|
yarn install
|
||||||
|
yarn build
|
||||||
|
)
|
||||||
|
|
||||||
# Preverify PR
|
# Preverify PR
|
||||||
AIO_GITHUB_ORGANIZATION="angular" \
|
AIO_GITHUB_ORGANIZATION="angular" \
|
||||||
|
70
aio/aio-builds-setup/scripts/update-preview-server.sh
Executable file
70
aio/aio-builds-setup/scripts/update-preview-server.sh
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
#!/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."
|
||||||
|
)
|
@ -19,7 +19,7 @@ export class AppComponent {
|
|||||||
movie: IMovie = null;
|
movie: IMovie = null;
|
||||||
movies: IMovie[] = [];
|
movies: IMovie[] = [];
|
||||||
showImage = true;
|
showImage = true;
|
||||||
title: string = 'AngularJS to Angular Quick Ref Cookbook';
|
title = 'AngularJS to Angular Quick Ref Cookbook';
|
||||||
toggleImage(event: UIEvent) {
|
toggleImage(event: UIEvent) {
|
||||||
this.showImage = !this.showImage;
|
this.showImage = !this.showImage;
|
||||||
this.eventType = (event && event.type) || 'not provided';
|
this.eventType = (event && event.type) || 'not provided';
|
||||||
|
@ -19,7 +19,7 @@ import { MovieService } from './movie.service';
|
|||||||
export class MovieListComponent {
|
export class MovieListComponent {
|
||||||
// #enddocregion class
|
// #enddocregion class
|
||||||
favoriteHero: string;
|
favoriteHero: string;
|
||||||
showImage: boolean = false;
|
showImage = false;
|
||||||
movies: IMovie[];
|
movies: IMovie[];
|
||||||
|
|
||||||
// #docregion di
|
// #docregion di
|
||||||
|
@ -15,6 +15,6 @@ import { HEROES } from './hero';
|
|||||||
})
|
})
|
||||||
export class HeroParentComponent {
|
export class HeroParentComponent {
|
||||||
heroes = HEROES;
|
heroes = HEROES;
|
||||||
master: string = 'Master';
|
master = 'Master';
|
||||||
}
|
}
|
||||||
// #enddocregion
|
// #enddocregion
|
@ -11,8 +11,8 @@ import { Component } from '@angular/core';
|
|||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class VersionParentComponent {
|
export class VersionParentComponent {
|
||||||
major: number = 1;
|
major = 1;
|
||||||
minor: number = 23;
|
minor = 23;
|
||||||
|
|
||||||
newMinor() {
|
newMinor() {
|
||||||
this.minor++;
|
this.minor++;
|
@ -16,7 +16,7 @@ import { UserService } from './user.service';
|
|||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
// #enddocregion import-services
|
// #enddocregion import-services
|
||||||
|
|
||||||
private userId: number = 1;
|
private userId = 1;
|
||||||
|
|
||||||
// #docregion ctor
|
// #docregion ctor
|
||||||
constructor(logger: LoggerService, public userContext: UserContextService) {
|
constructor(logger: LoggerService, public userContext: UserContextService) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* tslint:disable:one-line:check-open-brace*/
|
/* tslint:disable:one-line*/
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* tslint:disable:one-line:check-open-brace*/
|
/* tslint:disable:one-line*/
|
||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion injection-token
|
// #docregion injection-token
|
||||||
import { InjectionToken } from '@angular/core';
|
import { InjectionToken } from '@angular/core';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
export var HEROES: Hero[] = [
|
export const HEROES: Hero[] = [
|
||||||
{ id: 11, isSecret: false, name: 'Mr. Nice' },
|
{ id: 11, isSecret: false, name: 'Mr. Nice' },
|
||||||
{ id: 12, isSecret: false, name: 'Narco' },
|
{ id: 12, isSecret: false, name: 'Narco' },
|
||||||
{ id: 13, isSecret: false, name: 'Bombasto' },
|
{ id: 13, isSecret: false, name: 'Bombasto' },
|
||||||
|
@ -117,7 +117,7 @@ class OldLogger {
|
|||||||
export class Provider6aComponent {
|
export class Provider6aComponent {
|
||||||
log: string;
|
log: string;
|
||||||
constructor(newLogger: NewLogger, oldLogger: OldLogger) {
|
constructor(newLogger: NewLogger, oldLogger: OldLogger) {
|
||||||
if (newLogger === oldLogger){
|
if (newLogger === oldLogger) {
|
||||||
throw new Error('expected the two loggers to be different instances');
|
throw new Error('expected the two loggers to be different instances');
|
||||||
}
|
}
|
||||||
oldLogger.log('Hello OldLogger (but we want NewLogger)');
|
oldLogger.log('Hello OldLogger (but we want NewLogger)');
|
||||||
@ -140,7 +140,7 @@ export class Provider6aComponent {
|
|||||||
export class Provider6bComponent {
|
export class Provider6bComponent {
|
||||||
log: string;
|
log: string;
|
||||||
constructor(newLogger: NewLogger, oldLogger: OldLogger) {
|
constructor(newLogger: NewLogger, oldLogger: OldLogger) {
|
||||||
if (newLogger !== oldLogger){
|
if (newLogger !== oldLogger) {
|
||||||
throw new Error('expected the two loggers to be the same instance');
|
throw new Error('expected the two loggers to be the same instance');
|
||||||
}
|
}
|
||||||
oldLogger.log('Hello from NewLogger (via aliased OldLogger)');
|
oldLogger.log('Hello from NewLogger (via aliased OldLogger)');
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'my-app',
|
|
||||||
template: '<hero-form></hero-form>'
|
|
||||||
})
|
|
||||||
export class AppComponent { }
|
|
@ -1,31 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<!-- #docregion -->
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Hero Form</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="styles.css">
|
|
||||||
<!-- #docregion bootstrap -->
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css">
|
|
||||||
<!-- #enddocregion bootstrap -->
|
|
||||||
|
|
||||||
<!-- Polyfills for older browsers -->
|
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
|
||||||
|
|
||||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
|
||||||
<script src="node_modules/reflect-metadata/Reflect.js"></script>
|
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
|
||||||
|
|
||||||
<script src="systemjs.config.js"></script>
|
|
||||||
<script>
|
|
||||||
System.import('main.js').catch(function(err){ console.error(err); });
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<my-app>Loading...</my-app>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -8,7 +8,7 @@ import 'rxjs/add/operator/delay';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
isLoggedIn: boolean = false;
|
isLoggedIn = false;
|
||||||
|
|
||||||
// store the URL so we can redirect after logging in
|
// store the URL so we can redirect after logging in
|
||||||
redirectUrl: string;
|
redirectUrl: string;
|
||||||
|
@ -15,7 +15,7 @@ export class ComposeMessageComponent {
|
|||||||
@HostBinding('style.position') position = 'absolute';
|
@HostBinding('style.position') position = 'absolute';
|
||||||
|
|
||||||
details: string;
|
details: string;
|
||||||
sending: boolean = false;
|
sending = false;
|
||||||
|
|
||||||
constructor(private router: Router) {}
|
constructor(private router: Router) {}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* tslint:disable use-output-property-decorator */
|
/* tslint:disable use-output-property-decorator directive-class-suffix */
|
||||||
// #docplaster
|
// #docplaster
|
||||||
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';
|
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { DependentService, FancyService } from './bag';
|
|||||||
|
|
||||||
///////// Fakes /////////
|
///////// Fakes /////////
|
||||||
export class FakeFancyService extends FancyService {
|
export class FakeFancyService extends FancyService {
|
||||||
value: string = 'faked value';
|
value = 'faked value';
|
||||||
}
|
}
|
||||||
////////////////////////
|
////////////////////////
|
||||||
// #docregion FancyService
|
// #docregion FancyService
|
||||||
|
@ -677,5 +677,5 @@ class FakeGrandchildComponent { }
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class FakeFancyService extends FancyService {
|
class FakeFancyService extends FancyService {
|
||||||
value: string = 'faked value';
|
value = 'faked value';
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ export class Hero {
|
|||||||
// #docregion FancyService
|
// #docregion FancyService
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FancyService {
|
export class FancyService {
|
||||||
protected value: string = 'real value';
|
protected value = 'real value';
|
||||||
|
|
||||||
getValue() { return this.value; }
|
getValue() { return this.value; }
|
||||||
setValue(value: string) { this.value = value; }
|
setValue(value: string) { this.value = value; }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
export var HEROES: Hero[] = [
|
export const HEROES: Hero[] = [
|
||||||
new Hero(11, 'Mr. Nice'),
|
new Hero(11, 'Mr. Nice'),
|
||||||
new Hero(12, 'Narco'),
|
new Hero(12, 'Narco'),
|
||||||
new Hero(13, 'Bombasto'),
|
new Hero(13, 'Bombasto'),
|
||||||
|
@ -5,7 +5,7 @@ export { HeroService } from '../hero.service';
|
|||||||
import { Hero } from '../hero';
|
import { Hero } from '../hero';
|
||||||
import { HeroService } from '../hero.service';
|
import { HeroService } from '../hero.service';
|
||||||
|
|
||||||
export var HEROES: Hero[] = [
|
export const HEROES: Hero[] = [
|
||||||
new Hero(41, 'Bob'),
|
new Hero(41, 'Bob'),
|
||||||
new Hero(42, 'Carol'),
|
new Hero(42, 'Carol'),
|
||||||
new Hero(43, 'Ted'),
|
new Hero(43, 'Ted'),
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
// #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
|
|
@ -1,69 +0,0 @@
|
|||||||
// #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
|
|
@ -2,14 +2,14 @@
|
|||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
export const HEROES: Hero[] = [
|
export const HEROES: Hero[] = [
|
||||||
{id: 11, name: 'Mr. Nice'},
|
{ id: 11, name: 'Mr. Nice' },
|
||||||
{id: 12, name: 'Narco'},
|
{ id: 12, name: 'Narco' },
|
||||||
{id: 13, name: 'Bombasto'},
|
{ id: 13, name: 'Bombasto' },
|
||||||
{id: 14, name: 'Celeritas'},
|
{ id: 14, name: 'Celeritas' },
|
||||||
{id: 15, name: 'Magneta'},
|
{ id: 15, name: 'Magneta' },
|
||||||
{id: 16, name: 'RubberMan'},
|
{ id: 16, name: 'RubberMan' },
|
||||||
{id: 17, name: 'Dynama'},
|
{ id: 17, name: 'Dynama' },
|
||||||
{id: 18, name: 'Dr IQ'},
|
{ id: 18, name: 'Dr IQ' },
|
||||||
{id: 19, name: 'Magma'},
|
{ id: 19, name: 'Magma' },
|
||||||
{id: 20, name: 'Tornado'}
|
{ id: 20, name: 'Tornado' }
|
||||||
];
|
];
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
export var HEROES: Hero[] = [
|
export const HEROES: Hero[] = [
|
||||||
{id: 11, name: 'Mr. Nice'},
|
{ id: 11, name: 'Mr. Nice' },
|
||||||
{id: 12, name: 'Narco'},
|
{ id: 12, name: 'Narco' },
|
||||||
{id: 13, name: 'Bombasto'},
|
{ id: 13, name: 'Bombasto' },
|
||||||
{id: 14, name: 'Celeritas'},
|
{ id: 14, name: 'Celeritas' },
|
||||||
{id: 15, name: 'Magneta'},
|
{ id: 15, name: 'Magneta' },
|
||||||
{id: 16, name: 'RubberMan'},
|
{ id: 16, name: 'RubberMan' },
|
||||||
{id: 17, name: 'Dynama'},
|
{ id: 17, name: 'Dynama' },
|
||||||
{id: 18, name: 'Dr IQ'},
|
{ id: 18, name: 'Dr IQ' },
|
||||||
{id: 19, name: 'Magma'},
|
{ id: 19, name: 'Magma' },
|
||||||
{id: 20, name: 'Tornado'}
|
{ id: 20, name: 'Tornado' }
|
||||||
];
|
];
|
||||||
|
@ -5,7 +5,7 @@ import { promise } from 'selenium-webdriver';
|
|||||||
|
|
||||||
const expectedH1 = 'Tour of Heroes';
|
const expectedH1 = 'Tour of Heroes';
|
||||||
const expectedTitle = `Angular ${expectedH1}`;
|
const expectedTitle = `Angular ${expectedH1}`;
|
||||||
const targetHero = { id: 15, name: 'Magneta' };
|
const targetHero = { id: 14, name: 'Celeritas' };
|
||||||
const targetHeroDashboardIndex = 3;
|
const targetHeroDashboardIndex = 3;
|
||||||
const nameSuffix = 'X';
|
const nameSuffix = 'X';
|
||||||
const newHeroName = targetHero.name + nameSuffix;
|
const newHeroName = targetHero.name + nameSuffix;
|
||||||
@ -136,7 +136,7 @@ describe('Tutorial part 6', () => {
|
|||||||
getPageElts().myHeroesHref.click();
|
getPageElts().myHeroesHref.click();
|
||||||
let page = getPageElts();
|
let page = getPageElts();
|
||||||
expect(page.myHeroes.isPresent()).toBeTruthy();
|
expect(page.myHeroes.isPresent()).toBeTruthy();
|
||||||
expect(page.allHeroes.count()).toEqual(10, 'number of heroes');
|
expect(page.allHeroes.count()).toEqual(11, 'number of heroes');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`selects and shows ${targetHero.name} as selected in list`, () => {
|
it(`selects and shows ${targetHero.name} as selected in list`, () => {
|
||||||
@ -176,7 +176,7 @@ describe('Tutorial part 6', () => {
|
|||||||
|
|
||||||
const page = getPageElts();
|
const page = getPageElts();
|
||||||
expect(page.myHeroes.isPresent()).toBeTruthy();
|
expect(page.myHeroes.isPresent()).toBeTruthy();
|
||||||
expect(page.allHeroes.count()).toEqual(9, 'number of heroes');
|
expect(page.allHeroes.count()).toEqual(10, 'number of heroes');
|
||||||
const heroesAfter = await toHeroArray(page.allHeroes);
|
const heroesAfter = await toHeroArray(page.allHeroes);
|
||||||
const expectedHeroes = heroesBefore.filter(h => h.name !== newHeroName);
|
const expectedHeroes = heroesBefore.filter(h => h.name !== newHeroName);
|
||||||
expect(heroesAfter).toEqual(expectedHeroes);
|
expect(heroesAfter).toEqual(expectedHeroes);
|
||||||
@ -206,20 +206,20 @@ describe('Tutorial part 6', () => {
|
|||||||
|
|
||||||
beforeAll(() => browser.get(''));
|
beforeAll(() => browser.get(''));
|
||||||
|
|
||||||
it(`searches for 'Ma'`, async () => {
|
it(`searches for 'Ce'`, async () => {
|
||||||
getPageElts().searchBox.sendKeys('Ma');
|
getPageElts().searchBox.sendKeys('Ce');
|
||||||
browser.sleep(1000);
|
|
||||||
expect(getPageElts().searchResults.count()).toBe(4);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`continues search with 'g'`, async () => {
|
|
||||||
getPageElts().searchBox.sendKeys('g');
|
|
||||||
browser.sleep(1000);
|
browser.sleep(1000);
|
||||||
expect(getPageElts().searchResults.count()).toBe(2);
|
expect(getPageElts().searchResults.count()).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`continues search with 'n' and gets ${targetHero.name}`, async () => {
|
it(`continues search with 'l'`, async () => {
|
||||||
getPageElts().searchBox.sendKeys('n');
|
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');
|
||||||
browser.sleep(1000);
|
browser.sleep(1000);
|
||||||
let page = getPageElts();
|
let page = getPageElts();
|
||||||
expect(page.searchResults.count()).toBe(1);
|
expect(page.searchResults.count()).toBe(1);
|
||||||
|
@ -2,17 +2,18 @@
|
|||||||
import { InMemoryDbService } from 'angular-in-memory-web-api';
|
import { InMemoryDbService } from 'angular-in-memory-web-api';
|
||||||
export class InMemoryDataService implements InMemoryDbService {
|
export class InMemoryDataService implements InMemoryDbService {
|
||||||
createDb() {
|
createDb() {
|
||||||
let heroes = [
|
const heroes = [
|
||||||
{id: 11, name: 'Mr. Nice'},
|
{ id: 0, name: 'Zero' },
|
||||||
{id: 12, name: 'Narco'},
|
{ id: 11, name: 'Mr. Nice' },
|
||||||
{id: 13, name: 'Bombasto'},
|
{ id: 12, name: 'Narco' },
|
||||||
{id: 14, name: 'Celeritas'},
|
{ id: 13, name: 'Bombasto' },
|
||||||
{id: 15, name: 'Magneta'},
|
{ id: 14, name: 'Celeritas' },
|
||||||
{id: 16, name: 'RubberMan'},
|
{ id: 15, name: 'Magneta' },
|
||||||
{id: 17, name: 'Dynama'},
|
{ id: 16, name: 'RubberMan' },
|
||||||
{id: 18, name: 'Dr IQ'},
|
{ id: 17, name: 'Dynama' },
|
||||||
{id: 19, name: 'Magma'},
|
{ id: 18, name: 'Dr IQ' },
|
||||||
{id: 20, name: 'Tornado'}
|
{ id: 19, name: 'Magma' },
|
||||||
|
{ id: 20, name: 'Tornado' }
|
||||||
];
|
];
|
||||||
return {heroes};
|
return {heroes};
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { Attribute, Component, Inject, Optional } from '@angular/core';
|
|||||||
})
|
})
|
||||||
// #enddocregion templateUrl
|
// #enddocregion templateUrl
|
||||||
export class HeroTitleComponent {
|
export class HeroTitleComponent {
|
||||||
msg: string = '';
|
msg = '';
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('titlePrefix') @Optional() private titlePrefix: string,
|
@Inject('titlePrefix') @Optional() private titlePrefix: string,
|
||||||
@Attribute('title') private title: string
|
@Attribute('title') private title: string
|
||||||
|
94
aio/content/examples/tslint.json
Normal file
94
aio/content/examples/tslint.json
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
@ -162,22 +162,4 @@ 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');
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -6,8 +6,9 @@ import { UpgradeModule } from '@angular/upgrade/static';
|
|||||||
|
|
||||||
import { heroDetailComponent } from './hero-detail.component';
|
import { heroDetailComponent } from './hero-detail.component';
|
||||||
|
|
||||||
// #docregion ngmodule
|
// #docregion ngmodule, register
|
||||||
import { Heroes } from './heroes';
|
import { Heroes } from './heroes';
|
||||||
|
// #enddocregion register
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -17,7 +18,10 @@ import { Heroes } from './heroes';
|
|||||||
providers: [ Heroes ]
|
providers: [ Heroes ]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion ngmodule
|
// #enddocregion ngmodule
|
||||||
// #docregion register
|
// #docregion register
|
||||||
@ -28,7 +32,4 @@ angular.module('heroApp', [])
|
|||||||
.component('heroDetail', heroDetailComponent);
|
.component('heroDetail', heroDetailComponent);
|
||||||
// #enddocregion register
|
// #enddocregion register
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
|
@ -22,7 +22,10 @@ import { ContainerComponent } from './container.component';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion heroupgrade
|
// #enddocregion heroupgrade
|
||||||
|
|
||||||
@ -33,7 +36,4 @@ angular.module('heroApp', [])
|
|||||||
downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory
|
downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory
|
||||||
);
|
);
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
|
@ -8,7 +8,8 @@ export const heroDetail = {
|
|||||||
<div>
|
<div>
|
||||||
<ng-transclude></ng-transclude>
|
<ng-transclude></ng-transclude>
|
||||||
</div>
|
</div>
|
||||||
`
|
`,
|
||||||
|
transclude: true
|
||||||
};
|
};
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
||||||
|
@ -11,7 +11,10 @@ import { UpgradeModule } from '@angular/upgrade/static';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion ngmodule
|
// #enddocregion ngmodule
|
||||||
angular.module('heroApp', [])
|
angular.module('heroApp', [])
|
||||||
@ -22,8 +25,5 @@ angular.module('heroApp', [])
|
|||||||
// #docregion bootstrap
|
// #docregion bootstrap
|
||||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
// #enddocregion bootstrap
|
// #enddocregion bootstrap
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
// #docregion ng1module
|
||||||
angular.module('heroApp', [])
|
angular.module('heroApp', [])
|
||||||
.controller('MainCtrl', function() {
|
.controller('MainCtrl', function() {
|
||||||
this.message = 'Hello world';
|
this.message = 'Hello world';
|
||||||
});
|
});
|
||||||
|
// #enddocregion ng1module
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// #docregion bootstrap
|
// #docregion bootstrap
|
||||||
angular.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
angular.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
// #enddocregion bootstrap
|
// #enddocregion bootstrap
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,10 @@ import { HeroDetailComponent } from './hero-detail.component';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
angular.module('heroApp', [])
|
angular.module('heroApp', [])
|
||||||
@ -30,7 +33,4 @@ angular.module('heroApp', [])
|
|||||||
inputs: ['hero']
|
inputs: ['hero']
|
||||||
}) as angular.IDirectiveFactory);
|
}) as angular.IDirectiveFactory);
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
|
@ -27,7 +27,10 @@ import { heroesServiceProvider } from './ajs-upgraded-providers';
|
|||||||
// #docregion register
|
// #docregion register
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion register
|
// #enddocregion register
|
||||||
|
|
||||||
@ -38,7 +41,4 @@ angular.module('heroApp', [])
|
|||||||
downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory
|
downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory
|
||||||
);
|
);
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'my-app',
|
|
||||||
template: `
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
<div ng-view></div>
|
|
||||||
`,
|
|
||||||
})
|
|
||||||
export class AppComponent { }
|
|
@ -1,62 +0,0 @@
|
|||||||
// #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
|
|
||||||
}
|
|
||||||
]);
|
|
@ -1,32 +0,0 @@
|
|||||||
// #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 {}
|
|
@ -1,10 +0,0 @@
|
|||||||
// #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});
|
|
||||||
});
|
|
@ -23,21 +23,17 @@ import { HeroDetailComponent } from './hero-detail.component';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #docregion downgradecomponent
|
// #docregion downgradecomponent
|
||||||
|
|
||||||
angular.module('heroApp', [])
|
angular.module('heroApp', [])
|
||||||
.controller('MainController', MainController)
|
.controller('MainController', MainController)
|
||||||
.directive('heroDetail', downgradeComponent({
|
.directive('heroDetail', downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory);
|
||||||
component: HeroDetailComponent,
|
|
||||||
inputs: ['hero'],
|
|
||||||
outputs: ['deleted']
|
|
||||||
}) as angular.IDirectiveFactory);
|
|
||||||
|
|
||||||
// #enddocregion downgradecomponent
|
// #enddocregion downgradecomponent
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
|
@ -21,7 +21,10 @@ import { HeroDetailComponent } from './hero-detail.component';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion ngmodule
|
// #enddocregion ngmodule
|
||||||
// #docregion downgradecomponent
|
// #docregion downgradecomponent
|
||||||
@ -31,12 +34,9 @@ import { downgradeComponent } from '@angular/upgrade/static';
|
|||||||
angular.module('heroApp', [])
|
angular.module('heroApp', [])
|
||||||
.directive(
|
.directive(
|
||||||
'heroDetail',
|
'heroDetail',
|
||||||
downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory
|
downgradeComponent({ component: HeroDetailComponent }) as angular.IDirectiveFactory
|
||||||
);
|
);
|
||||||
|
|
||||||
// #enddocregion downgradecomponent
|
// #enddocregion downgradecomponent
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
|
@ -8,15 +8,15 @@ export function heroDetailDirective() {
|
|||||||
deleted: '&'
|
deleted: '&'
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<h2>{{ctrl.hero.name}} details!</h2>
|
<h2>{{$ctrl.hero.name}} details!</h2>
|
||||||
<div><label>id: </label>{{ctrl.hero.id}}</div>
|
<div><label>id: </label>{{$ctrl.hero.id}}</div>
|
||||||
<button ng-click="ctrl.onDelete()">Delete</button>
|
<button ng-click="$ctrl.onDelete()">Delete</button>
|
||||||
`,
|
`,
|
||||||
controller: function() {
|
controller: function() {
|
||||||
this.onDelete = () => {
|
this.onDelete = () => {
|
||||||
this.deleted({hero: this.hero});
|
this.deleted({hero: this.hero});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
controllerAs: 'ctrl'
|
controllerAs: '$ctrl'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,10 @@ import { ContainerComponent } from './container.component';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion heroupgrade
|
// #enddocregion heroupgrade
|
||||||
|
|
||||||
@ -33,7 +36,4 @@ angular.module('heroApp', [])
|
|||||||
downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory
|
downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory
|
||||||
);
|
);
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
|
@ -24,7 +24,10 @@ import { ContainerComponent } from './container.component';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion hero-detail-upgrade
|
// #enddocregion hero-detail-upgrade
|
||||||
|
|
||||||
@ -35,7 +38,4 @@ angular.module('heroApp', [])
|
|||||||
downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory
|
downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory
|
||||||
);
|
);
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true});
|
|
||||||
});
|
|
||||||
|
@ -11,7 +11,7 @@ export const heroDetail = {
|
|||||||
// #enddocregion hero-detail
|
// #enddocregion hero-detail
|
||||||
|
|
||||||
// #docregion hero-detail-upgrade
|
// #docregion hero-detail-upgrade
|
||||||
import { Directive, ElementRef, Injector } from '@angular/core';
|
import { Directive, ElementRef, Injector, SimpleChanges } from '@angular/core';
|
||||||
import { UpgradeComponent } from '@angular/upgrade/static';
|
import { UpgradeComponent } from '@angular/upgrade/static';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
<!DOCTYPE HTML>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Angular 2 Upgrade</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="stylesheet" href="styles.css">
|
|
||||||
|
|
||||||
<script src="https://code.angularjs.org/1.5.5/angular.js"></script>
|
|
||||||
<script src="https://code.angularjs.org/1.5.5/angular-route.js"></script>
|
|
||||||
|
|
||||||
<!-- Polyfills for older browsers -->
|
|
||||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
|
||||||
|
|
||||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
|
||||||
<script src="node_modules/reflect-metadata/Reflect.js"></script>
|
|
||||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
|
||||||
|
|
||||||
<script src="systemjs.config.1.js"></script>
|
|
||||||
<script>
|
|
||||||
System.import('app/divide-routes/main')
|
|
||||||
.then(null, console.error.bind(console));
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<!--#docregion body-->
|
|
||||||
<body>
|
|
||||||
<my-app>Loading...</my-app>
|
|
||||||
</body>
|
|
||||||
<!--#enddocregion body-->
|
|
||||||
</html>
|
|
@ -67,7 +67,10 @@ import { PhoneDetailComponent } from './phone-detail/phone-detail.component';
|
|||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
// #enddocregion bare
|
// #enddocregion bare
|
||||||
ngDoBootstrap() {}
|
constructor(private upgrade: UpgradeModule) { }
|
||||||
|
ngDoBootstrap() {
|
||||||
|
this.upgrade.bootstrap(document.documentElement, ['phonecatApp']);
|
||||||
|
}
|
||||||
// #docregion bare
|
// #docregion bare
|
||||||
}
|
}
|
||||||
// #enddocregion bare, upgrademodule, httpmodule, phone, phonelist, phonedetail, checkmarkpipe
|
// #enddocregion bare, upgrademodule, httpmodule, phone, phonelist, phonedetail, checkmarkpipe
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { platformBrowser } from '@angular/platform-browser';
|
import { platformBrowser } from '@angular/platform-browser';
|
||||||
import { UpgradeModule } from '@angular/upgrade/static';
|
|
||||||
|
|
||||||
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
|
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
|
||||||
|
|
||||||
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then(platformRef => {
|
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
||||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
|
||||||
upgrade.bootstrap(document.documentElement, ['phonecatApp']);
|
|
||||||
});
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
// #docregion bootstrap
|
|
||||||
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.documentElement, ['phonecatApp']);
|
|
||||||
});
|
|
||||||
// #enddocregion bootstrap
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user