Compare commits

...

2094 Commits

Author SHA1 Message Date
018750154d test: fix firebase deployment script test
When I fixed the project id in 2c4850dc58,
I didn't realize we had a test that verified the wrong behavior.
2018-05-04 15:10:17 -07:00
b19216d58b fix(aio): correct project id for deployment of archive sites 2018-05-03 15:09:17 -07:00
84fc1a3663 docs: add changelog for the 4.4.7 release 2018-04-16 02:00:31 -06:00
1c40be26c6 release: cut the 4.4.7 release 2018-04-16 02:00:02 -06:00
2c5cf19c6d fix(core): use appropriate inert document strategy for Firefox & Safari (#22077)
Both Firefox and Safari are vulnerable to XSS if we use an inert document
created via `document.implementation.createHTMLDocument()`.

Now we check for those vulnerabilities and then use a DOMParser or XHR
strategy if needed.

Further the platform-server has its own library for parsing HTML, so we
sniff for that (by checking whether DOMParser exists) and fall back to
the standard strategy.

Thanks to @cure53 for the heads up on this issue.
2018-02-13 10:05:14 -08:00
0dacf6d5f1 ci: use sudo: false on Travis (#21641)
Related to #21422.

PR Close #21641
2018-02-11 21:18:03 +02:00
e9f1d44015 ci: downgrade Chromium to a version that does not cause flakes
There seems to be some issue that causes Chrome/ChromeDriver to
unexpectedly reload during the aio e2e tests, causing flakes. It is not
clear what exactly is causing the reloading, but to the best of my
knowledge it is something inside Chrome or ChromeDriver.

Pinning Chrome to r494239 (between 62.0.3185.0 and 62.0.3186.0) fixes
the flakes.

Fixes #20159
2018-02-11 21:18:03 +02:00
1d9024ee9a build: pin ChromeDriver version (#20940)
Since our version of Chromium is also pinned, a new ChromeDriver (that
drops support for our Chromium version) can cause random (and unrelated
to the corresponding changes) errors on CI.
This commit pins the version of ChromeDriver and it should now be
manually upgraded to a vrsion that is compatible with th currently used
Chromium version.

PR Close #20940
2018-02-11 21:18:03 +02:00
6a6164ab4f revert: ci: use chrome stable (#18307)
This reverts commit 8bcb268140.
2018-02-11 19:39:55 +02:00
7231f5e26a docs: add changelog for 4.4.6 2017-10-18 16:14:53 -07:00
86415223cb release: cut the 4.4.6 release 2017-10-18 16:12:10 -07:00
269f5acc54 fix(common): attempt to JSON.parse errors for JSON responses (#19773)
Prior behavior for HttpClient was to parse the body as JSON when
responseType was set to 'json', even if the response was
unsuccessful. This changed due to a recent bugfix, and
unsuccessful responses had their bodies treated as strings.

There is no guarantee that if a service returns JSON in the
successful case that it will do so for errors. However, users
indicate that most APIs in the wild do work this way. Therefore,
this commit changes the error case behavior to attempt a JSON
parsing of the response body, and falls back on returning it as
a string if that fails.

PR Close #19773
2017-10-18 12:58:49 -07:00
6e6c866de9 docs(aio): changed confusing term (#19762)
Controller should be decorator I believe

PR Close #19762
2017-10-18 12:58:40 -07:00
732ed92cb7 test(animations): ensure :enter callbacks fire on container insertion (#19674)
PR Close #19674
2017-10-18 12:58:26 -07:00
53a807ae09 fix(router): RouterLinkActive should update its state right after checking the children
Closes #18983
2017-10-18 12:57:53 -07:00
3342a8253b fix(aio): make tests less flaky (#19784)
PR Close #19784
2017-10-18 10:19:48 -07:00
630c19f52d build: remove required BrowserStack run as it fails with “Access denied” (#19769)
See #19768
PR Close #19769
2017-10-17 15:53:05 -07:00
af8c2fa4be build: don’t make BrowserStack required as it fails with “Access denied”
See #19768
2017-10-17 14:56:41 -07:00
0789601dd6 build: fix broken path for animations in .pullapprove (#19453)
PR Close #19453
2017-10-17 10:44:43 -07:00
ce0ac46e42 style: fix formatting of check-node-modules (#19720)
PR Close #19720
2017-10-17 10:41:18 -07:00
b531d87580 ci: validate commit messages correctly when not on master (#19720)
PR Close #19720
2017-10-17 10:41:18 -07:00
23a2154817 docs(aio): update 2018 events (#19706)
update ac 2017 dates

PR Close #19706
2017-10-17 10:41:09 -07:00
76d2496f24 perf(animations): reduce size of bundle by removing AST classes (#19673)
This CL refactors the animation AST code to make use of interfaces
instead of classes. Given that interfaces are not persisted during
runtime the removal of classes should nicely cut down on size for the
animations-browser bundle.

PR Close #19673
2017-10-17 10:41:01 -07:00
b85cb410f1 docs(aio): change in-mem-web-api version for examples (#19668)
PR Close #19668
2017-10-17 10:40:52 -07:00
1be22df0df ci(aio): raise payload limit to accommodate the new search feature (#19704)
PR Close #19704
2017-10-13 15:20:23 -07:00
a805839d38 feat(aio): add search to 404 page (#19704)
The 404 page will now run a search based on the given URL to offer
suggestions for the page that the user really wanted.

PR Close #19704
2017-10-13 15:20:23 -07:00
3ac61a7550 refactor(aio): move SearchResultsComponent into shared module (#19704)
This will allow it to be used by an embedded component.

PR Close #19704
2017-10-13 15:20:23 -07:00
57ea33bc5c feat(aio): allow SearchService to have multiple clients (#19704)
PR Close #19704
2017-10-13 15:20:23 -07:00
4891649d68 test(aio): tidy up e2e tests that used invalid URLs (#19704)
PR Close #19704
2017-10-13 15:20:23 -07:00
93aba1bb1c build(aio): remove unused imports and local variables (#19704)
PR Close #19704
2017-10-13 15:20:23 -07:00
f983a6c615 fix(animations): properly support boolean-based transitions and state changes (#19672)
Closes #9396
Closes #12337

PR Close #19672
2017-10-13 09:40:29 -07:00
18f1b016e5 build(aio): consider devDependencies when overwriting dependencies of local Angular packages (#19687)
Previously, only `dependencies` were taken into account.

PR Close #19687
2017-10-13 09:30:10 -07:00
591dcc26af docs(animations): add missing bracket to fadeAnimation
Closes #18899
2017-10-13 09:14:29 -07:00
4acd322128 fix(core): don't refer to hydration in docs anymore.
Closes #18458
2017-10-13 09:05:30 -07:00
32a814bdfa docs: removing unnecessary commits from change log 2017-10-12 13:32:23 -07:00
912068e71c docs: add changelog for 4.4.5 2017-10-12 10:26:21 -07:00
df8e57dc5d release: cut the 4.4.5 release 2017-10-12 10:07:33 -07:00
f27f6e498f docs(aio): improve the Angular Connect homepage banner (#19684)
The original logo was too small.
The conference is over two days.

PR Close #19684
2017-10-12 09:49:58 -07:00
01bfbcb84a build(aio): update yarn.lock (#19683)
PR Close #19683
2017-10-12 09:49:48 -07:00
a15abbb324 docs(aio): change Material 2 to Material (#19663)
it is just called Angular Material now
PR Close #19663
2017-10-11 16:54:09 -07:00
28c29d560e build: fix rxjs version for aio (#19585)
PR Close #19585
2017-10-11 15:30:52 -07:00
65ca7fd4aa docs(aio): update banner ad (#19669)
PR Close #19669
2017-10-11 14:45:06 -07:00
3e3f918bb3 ci: freeze yarn lockfile when installing dependencies (#19616)
PR Close #19616
2017-10-11 14:37:38 -07:00
fc1dcffbdd build(aio): freeze lockfile when setting up examples (#19616)
PR Close #19616
2017-10-11 14:37:38 -07:00
ee3c681f98 build(aio): freeze yarn lockfile for aio-builds-setup scripts (#19616)
PR Close #19616
2017-10-11 14:37:37 -07:00
6225fedcb8 build(aio): freeze lockfile when installing example dependencies (#19616)
PR Close #19616
2017-10-11 14:37:37 -07:00
2905069559 ci(aio): freeze the lockfile for CI builds (#19616)
The CI will now fail if the dependencies in the AIO
package.json have been modified without the
lockfile being updated.

PR Close #19616
2017-10-11 14:37:37 -07:00
47202dd747 build(aio): improve accessor rendering (#19637)
Includes an update to `dgeni-packages@0.22.0` which provides more info
about accessors if required.

PR Close #19637
2017-10-11 14:37:28 -07:00
fb130c4eae build(aio): append information about links in and out of docs (#19583)
Closes #19560

PR Close #19583
2017-10-11 14:37:16 -07:00
734378c90b fix(compiler): TestBed.overrideProvider should keep imported NgModules eager (#19624)
Before, as soon as a user called `TestBed.overrideProvider` for a provider
of a `NgModule` that was imported via `TestBed.configureTestingModule`,
that `NgModule` became lazy.

This commit changes this behavior to keep the `NgModule` eager,
with or without a call to `TestBed.overrideProvider`.

PR Close #19624
2017-10-11 14:01:04 -07:00
3959b7ef28 refactor(compiler): introduce TestBed.deprecatedOverrideProvider (#19558)
This allows use to fix `TestBed.overrideProvider` to keep imported `NgModule`s eager,
while allowing our users to still keep the old semantics until they have fixed their
tests.

PR Close #19558
2017-10-11 14:00:32 -07:00
e292548523 fix(compiler): correctly instantiate eager providers that are used via Injector.get (#19558)
Closes #15501

PR Close #19558
2017-10-11 14:00:32 -07:00
c2506a78a1 docs(aio): add copy about ngNoForm to NgForm API doc (#19561)
PR Close #19561
2017-10-11 14:00:12 -07:00
34f70c6de2 build(aio): sort API list alphabetically (#19566)
Closes #19559

PR Close #19566
2017-10-11 13:52:19 -07:00
3d9c2a6352 build: add a Git .mailmap with my new name (#19550)
In this way my past contribution is mapped correctly.

PR Close #19550
2017-10-11 13:52:06 -07:00
3232125650 build(aio): remove unnecessary -- from yarn commands (#19565)
Essentially backports ffceae0a0 and f7199aa8c to 4.4.x.

PR Close #19565
2017-10-11 13:26:07 -07:00
c9f8718d2a fix(tsc-wrapped): don't rewrite imports when annotating for closure (#19579)
Port of f24ea59f74 to 4.4.x

Closure no longer needs to have the imports rewritten so avoid
rewriting as this can cause issues when the source directory
structure differs from what is deployed.

Fixes: #17171

PR Close #19579
2017-10-11 13:25:01 -07:00
f89ac92e5e test(aio): temporarily disable failing examples e2e tests (#19600)
Temporarily disable a couple of failing upgrade example e2e tests
to unblock the 4.4.x branch while investigating and fixing the
issues.
It seems to be some typings-related issues that TypeScript 2.5.3
complains about.

(Note: The same tests are temporarily disabled on master too.)

PR Close #19600
2017-10-10 15:58:45 -07:00
f82efcf942 build(aio): do not fail on first yarn setup (#19600)
PR Close #19600
2017-10-10 15:58:45 -07:00
dc22f4dc69 build(aio): fix overwriting with local Angular packages that depend on other local ones (#19600)
PR Close #19600
2017-10-10 15:58:45 -07:00
173ccf03ab test(aio): fix testing of NgPackagesInstaller (#19600)
PR Close #19600
2017-10-10 15:58:44 -07:00
1d5c3c1c9b build(aio): example-boilerplate is no longer responsible for yarn install (#19600)
The tooling for boilerplate was also running `yarn install` on the examples'
shared folder. But since this is handled by `ng-packages-installer` this
commit refactors the tools so that the boilerplate no longer does this
anymore.

PR Close #19600
2017-10-10 15:58:44 -07:00
e4dac421db build(aio): ignore @angular/mobile-toolkit in dist builds (#19600)
The new v5 version of this toolkit is too incompatible for us to run
AIO against both versions. So for now we will ignore this libary when
running against local Angular distributions and continue to use the
version on npm.

PR Close #19600
2017-10-10 15:58:44 -07:00
c639cdd3b3 build(aio): support ignoring dist packages in "local" mode (#19600)
PR Close #19600
2017-10-10 15:58:44 -07:00
5bcfa7cdfe build(aio): provide cleaner scripts for local build switching (#19600)
PR Close #19600
2017-10-10 15:58:44 -07:00
d8fd892e71 ci(aio): use custom package.json to run with local distributables (#19600)
Closes #19388

PR Close #19600
2017-10-10 15:58:44 -07:00
074a997302 build(aio): add support for using the locally built Angular packages for aio (#19600)
This commit allows building angular.io against the locally built Angular
packages. It adds two new npm scripts:

- `setup-local`: Same as `setup`, but overwrites the Angular packages for both
  angular.io and the examples boilerplate with the locally built ones.
- `build-local`: Same as `build`, but uses `setup-local` instead of `setup`
  under the hood, thus overwriting installed Angular packages with locally built
  ones.

Fixes #18611

PR Close #19600
2017-10-10 15:58:44 -07:00
62616f541a build(aio): ensure webdriver is updated when switching between local and npm deps (#19600)
PR Close #19600
2017-10-10 15:58:44 -07:00
156442f80d docs(aio): fix animations example to work with Angular v5 (#19600)
PR Close #19600
2017-10-10 15:58:44 -07:00
37112f549a build(aio): upgrade ts-node to support newer TypeScript config (#19600)
This was causing `Cannot find type definition file for 'jasmine'. (2688)`
errors when running Protractor.

PR Close #19600
2017-10-10 15:58:44 -07:00
cf4b4d53ba fix(aio): fix SearchService to work with TypeScript 2.4 (#19600)
The call to `race` required a type parameter to disambiguate the return type.

PR Close #19600
2017-10-10 15:58:43 -07:00
d45e3aa433 fix(aio): downgrade yarn to 1.0.2 temporarily (#19600)
PR Close #19600
2017-10-10 15:58:43 -07:00
ccc25ee901 fix: reformat files from previous cherry-picks 2017-10-05 13:54:46 -07:00
3052063c05 refactor(compiler): remove stale metadata classes for animations
These are no longer needed as animations are a purely
runtime concept.
2017-10-05 13:54:46 -07:00
e107322f5c refactor(core): add a checkIndex to the compiler view nodes
Each node now has two index: nodeIndex and checkIndex.

nodeIndex is the index in both the view definition and the view data.
checkIndex is the index in in the update function (update directives and update
renderer).

While nodeIndex and checkIndex have the same value for now, having both of them
will allow changing the structure of view definition after compilation (ie for
runtime translations).
2017-10-05 13:54:46 -07:00
f0774254de refactor(compiler): misc minor refactor / cleanup (#19189)
PR Close #19189
2017-10-05 13:54:46 -07:00
6c66031c4a fix(core): make dynamic & inline code checking behave the same (#19189)
PR Close #19189
2017-10-05 13:54:46 -07:00
8f668807cf Revert "fix(platform-browser): support customEqualityTesters when overriding Jasmine toEqual"
This reverts commit cc8ae32503.

Reason: broke a few existing tests.
2017-10-05 13:25:05 -07:00
f98eb35179 docs(aio): document Custom Async validators
docs(aio): Custom Async validators edits

incorporating suggestions from kapunahelewong
2017-10-04 15:08:00 -07:00
cc8ae32503 fix(platform-browser): support customEqualityTesters when overriding Jasmine toEqual 2017-10-04 15:01:11 -07:00
95f3b1dbe6 fix(compiler): disallow references for select and index evaluation
Also fixes an issue where enum values of 0 or '``' where not treated
correctly.

Fixes: #18170
2017-10-04 14:54:53 -07:00
6b96b069bf docs(aio): fix typo in preview server config file comment 2017-10-04 12:43:37 -07:00
ecfe85b06c docs(aio): document the special treatment of undefined 2017-10-04 12:43:28 -07:00
5439d4cd49 docs(aio): fix broken link in toh-pt5 2017-10-04 12:43:10 -07:00
df91fd032d build: update npm dependencies 2017-10-04 10:22:48 -07:00
2d5ef15e08 build: switch from npm to yarn 2017-10-04 10:22:48 -07:00
544a7ad0a5 docs(aio): Fix incorrect wording 2017-10-03 08:16:16 -07:00
ec2c1bec4a build(aio): fix various API rendering issues
Upgrading to dgeni-packages 0.21.4 gives us
access to more properties on the API docs, which
allows us to fix the following issues:

Closes #19450
Closes #19452
Closes #19456
2017-10-03 08:15:25 -07:00
e064d2607d docs(aio): add ngVikings to the events page 2017-10-03 08:14:30 -07:00
d489ad595d docs: add changelog for 4.4.4 2017-09-28 12:18:14 -07:00
0a3753bcce release: cut the 4.4.4 release 2017-09-28 12:13:13 -07:00
7fc2dceaf5 fix(compiler): do not consider a reference with members as a reference (#19466)
fixes: #18170
ref: #19454
2017-09-28 12:04:20 -07:00
c3b39bac52 fix(compiler): correctly map error message locations (#19424) 2017-09-28 10:55:17 -07:00
2cd88bfb0f docs(animations): document usage of negative limit values for query (#19451) 2017-09-28 09:35:10 -07:00
0cefb0b79b docs(aio): add copy about NgForOf (#18686) 2017-09-27 15:29:23 -07:00
55a7443974 docs(aio): edit summary and next step headers (#16962) 2017-09-27 13:47:03 -07:00
f9ebaf1b90 docs(aio): remove links to top of documents (#16971) 2017-09-27 13:46:50 -07:00
bc81fbdd27 fix(animations): properly support the query limit option value (#19419)
Closes #19232
2017-09-26 13:18:47 -07:00
c7aa8a132d fix(compiler): skip   when trimming / removing whitespaces (#19310)
Fixes #19304
2017-09-25 13:35:32 -07:00
5c99b01512 build(aio): run the upload server as a non-previleged user
closes #19352

Previously, the upload server (for PR previews) was run as root and
"downleveled" to a non-privileged user from inside the node script.

Now, with the latest version of `pm2` (which is used to run the upload server
scripts), we can get rid of that workaround and set the desired UID directly
through `pm2`.
2017-09-25 12:05:00 -07:00
992ba33a28 build(aio): upgrade all preview server dependencies 2017-09-25 12:04:51 -07:00
17e7c58981 build(aio): add metadata aliases for directives, components and pipes (#19317)
This change will enable people to link to the API docs via their selectors
or names, as used in a template.

Since the selectors can be quite complex we are not able to get 100%
accuracy.

Closes #16787
2017-09-25 12:04:41 -07:00
b8f15d2b77 build(aio): render class/interface "descendants" in API docs (#19343)
For classes, the tree of subclasses is rendered, recursively.

For interfaces, the descendants are separated into child interfaces, which
extend the interface, and classes, which implement the interface.

Closes #19306
2017-09-25 12:04:28 -07:00
5f9a10aab9 build(aio): ensure decorators with shared interface types are found (#19361)
Closes #19358
2017-09-25 12:03:31 -07:00
04bc5257a6 docs(aio): tidy up tooling documentation (#18151)
PR Close #18151
2017-09-21 11:27:01 -07:00
5bca58e748 docs(aio): applying some feedback (#18151)
PR Close #18151
2017-09-21 11:27:01 -07:00
526a67f8f4 docs(aio): add zipper documentation (#18151)
PR Close #18151
2017-09-21 11:27:00 -07:00
53a27e07b1 docs(aio): complete the plunker-builder docs (#18151)
PR Close #18151
2017-09-21 11:27:00 -07:00
ba0fb1e055 docs(aio): add boilerplate readme (#18151)
PR Close #18151
2017-09-21 11:27:00 -07:00
ed2c8aa6f8 docs(aio): high-level documentation of the transforms folder (#18151)
PR Close #18151
2017-09-21 11:27:00 -07:00
9226760120 docs(aio): high-level documentation of AIO tooling (#18151)
PR Close #18151
2017-09-21 11:27:00 -07:00
b9ee8b46a0 refactor(core): viewDef related refactoring (#19272)
- optimize the way node flags are propagated in `viewDef()`,
- fix `elementDef()` signature to make `namespaceAndName` nullable,
- move render parent computation with the parent computation

PR Close #19272
2017-09-21 11:26:43 -07:00
e7eb0b8b7c docs: update README and author guide about doc build errors (#19276)
- tells reader about `yarn serve-and-sync`.
- directs reader to look to docs-style-guide if get doc build error.
- update docs-style-guide to warn about ignored code files.

PR Close #19276
2017-09-21 09:56:33 -07:00
ae52851458 fix(tsc-wrapped): add metadata for type declarations (#19040)
PR Close #19040
2017-09-20 17:06:25 -07:00
e63cf3b89e ci(aio): correctly serialize commit messages with "double-quotes" (#19184)
PR Close #19184
2017-09-20 17:05:31 -07:00
9624fda082 build(aio): improve error message for ignored example files (#19265)
Addresses https://github.com/angular/angular/pull/18707#issuecomment-330396771

PR Close #19265
2017-09-20 16:50:36 -07:00
e19b6a8f38 build(aio): remove commented out code (#19265)
PR Close #19265
2017-09-20 16:50:36 -07:00
2aa6b54201 build: pin docker image to a tag for CircleCI (#19295)
Fixes the broken build
PR Close #19295
2017-09-20 16:50:20 -07:00
fe8550d278 docs: animations - replace iterator with simple code style (#18965)
Replaces iterator facade over the HeroService because webpack threw up.
Also this was an obscure distraction for readers with no obvious benefits.

PR Close #18965
2017-09-20 16:50:05 -07:00
e2e8ba6ffa release: cut the 4.4.3 release 2017-09-19 15:22:05 -07:00
60cdf9dc38 docs(CHANGELOG.MD): add release notes for 4.4.2 and 4.4.3 2017-09-19 15:21:51 -07:00
0371538d10 fix(tsc-wrapped): deduplicate metadata only when the module is the same (#19261)
Fixes #19219
PR Close #19261
2017-09-19 14:25:27 -07:00
351331a81b ci: update yarn to 1.0.2 (#19270)
PR Close #19270
2017-09-19 13:53:09 -07:00
0a54713f8a build: automatically version tsc-wrapped just like other packages (#19270)
This removes manual steps from the release list.

I had to modify a few integration tests not to install compiler-cli dirrectly
because it depends on tsc-wrapped which yarn was eager to fetch from npm rather
than from the local build.

PR Close #19270
2017-09-19 13:53:09 -07:00
49d122e560 release: cut the 4.4.2 release 2017-09-18 21:14:03 -07:00
ff8729423e docs(changelog): fix the changelog link for comparing 4.4.1 to 4.3.6 2017-09-15 16:00:56 -07:00
0c72f7d358 docs: update combined changelog for 4.4 stable 2017-09-15 15:53:54 -07:00
818f4a751e release: cut the 4.4.1 release 2017-09-15 15:35:25 -07:00
4e7d2bd5bf docs: add changelog for 4.4.0 2017-09-15 14:58:32 -07:00
395ac510f7 release: cut the 4.4.0 release 2017-09-15 14:51:21 -07:00
b20c5d2c37 fix(upgrade): remove code setting id attribute. (#19182)
The id was leftover from previous iterations of ngUpgrade and is
no longer needed. Moreover, setting it can clash with CSS usage of id.

Fixes #18446

PR Close #19182
2017-09-15 17:19:50 -04:00
ea02b1ccfa fix(upgrade): remove code setting id attribute.
The id was leftover from previous iterations of ngUpgrade and is
no longer needed. Moreover, setting it can clash with CSS usage of id.

Fixes #18446
2017-09-15 17:19:50 -04:00
0bafd03e85 revert: test(packaging): added test for source map correctness
This reverts commit 86f7b4170c.
2017-09-15 11:55:29 -07:00
e8d1858c64 revert: build(platform-browser): fix typo
This reverts commit 991a802a8e.
2017-09-15 13:47:07 -04:00
d1efc5ae90 revert: fix(upgrade): remove code setting id attribute
This reverts commit 1302e54947.
2017-09-13 13:19:19 -07:00
86f7b4170c test(packaging): added test for source map correctness 2017-09-13 13:48:36 -04:00
9d93c859d7 build(aio): auto-link more code items
We now parse all code blocks, after they have been rendered by dgeni
and insert links to API docs that match "words" in the code.
2017-09-12 14:06:26 -04:00
5baa069b16 docs(aio): fix typo 2017-09-12 14:06:14 -04:00
12b7d00747 fix(aio): relax search on titles further
This change will now match `ControlValueAccessor` for the query `accessor`.

Closes #18872
2017-09-12 14:06:02 -04:00
d777d79c61 build(aio): do not render annotations block for directives 2017-09-12 14:05:46 -04:00
062a772e48 build(aio): improve rendering of directive selectors 2017-09-12 14:05:41 -04:00
3618cc6d34 build(aio): do not render comments in decorators
Closes #18873
2017-09-12 14:05:35 -04:00
9413ca8a2e build(aio): update karma & systemjs config for HttpClient
While adding the references to the `HttpClient` packages it also crucially
adds ref to new “tslib” library required by `HttpClient`.
2017-09-12 13:46:12 -04:00
1302e54947 fix(upgrade): remove code setting id attribute.
The id was leftover from previous iterations of ngUpgrade and is
no longer needed. Moreover, setting it can clash with CSS usage of id.

Fixes #18446
2017-09-08 16:30:18 -07:00
edf423af3d build(aio): update package.json for angular-in-mem-web-api 0.4.0 2017-09-08 18:25:20 -04:00
37086748bf docs(aio): provide link text for AbstractControl references in reactive directives for forms
Closes #17484
2017-09-08 18:25:14 -04:00
6c3f1f70ba build(aio): render metadata members from decorator ancestors 2017-09-08 18:25:08 -04:00
8a8c4d37aa build(aio): render ancestor members in directives
See `CheckBoxRequiredValidator` for an example.
2017-09-08 18:25:00 -04:00
f6a7183c52 fix(tsc-wrapped): fix metadata symbol reference 2017-09-08 17:26:28 -04:00
c86e16db5f feat(aio): include more API results in search
By adding a more relaxed search on the title
of docs, we are more likely to catch API docs.

The additional search terms match anything
with a word in the title that starts with the
characters of the first term in the search.

E.g. if the search is "ngCont guide" then
search for "ngCont guide titleWords:ngCont*"
2017-09-08 17:01:39 -04:00
c3907893c1 build(aio): don't show constructor detail if there is none 2017-09-08 17:01:39 -04:00
d61c6f996a build(aio): support rendering of constructor overloads in API docs
Closes #18258
2017-09-08 17:01:39 -04:00
bd04cd61f8 docs(aio): change Stack Overflow link 2017-09-08 16:29:17 -04:00
96dcfafe45 docs(aio): Updated jqwidgets resource desc and url
Updated the description and url of the jqwidgets item in the resources page
2017-09-07 16:07:52 -04:00
991a802a8e build(platform-browser): fix typo
fixes #19033
2017-09-07 16:07:27 -04:00
48ae1a6574 fix(tsc-wrapped): deduplicate metadata for re-exported modules 2017-09-07 16:06:12 -04:00
dd2d1be006 fix(aio): align footer background image repeat (#19035)
Refs #17465
PR Close #19035
2017-09-05 23:25:06 -05:00
5369de80d6 docs(aio): add changelog, as hidden, to navigation (#19028)
This ensures that the changelog page is formatted correctly.

Closes #17604

PR Close #19028
2017-09-05 23:25:06 -05:00
552dbfc2f1 docs(aio): add Nir Kaufman to GDE resources (#19012)
PR Close #19012
2017-09-05 23:25:06 -05:00
0aa4cbdbc8 docs(forms): clarify ControlValueAccessor docs (#19008)
Closes #18174

PR Close #19008
2017-09-05 23:25:06 -05:00
9f16c2620c docs(aio): updating about page for team changes (#19003)
PR Close #19003
2017-09-05 23:25:06 -05:00
9b256a9144 build(aio): render the extends ancestors of classes in API docs (#18927)
PR Close #18927
2017-09-05 23:25:06 -05:00
0f1476be33 build(aio): ensure dgeni can load all angular Typescript modules (#18927)
PR Close #18927
2017-09-05 23:25:06 -05:00
769b2aada2 docs(aio): add new lib to Data Libraries (#18656)
add AngularCommerse, set of components to build e-commerce solutions with Angular + Firebase

PR Close #18656
2017-09-05 23:25:06 -05:00
301236e1a5 docs(aio): Updated usage of Observables in router guide. Added section for advanced redirects (#18197)
PR Close #18197
2017-09-05 23:25:06 -05:00
aeb98dbcdf docs: add changelog for 4.4.0-RC.0 2017-09-01 22:01:41 -07:00
8036d05412 release: cut the 4.4.0-RC.0 release 2017-09-01 23:49:51 -05:00
7d137d7f88 fix(core): complete EventEmitter in QueryList on component destroy (#18902)
Fixes #18741

PR Close #18902
2017-09-01 22:52:03 -05:00
b8b551cf2b perf(core): add option to remove blank text nodes from compiled templates (#18823)
PR Close #18823
2017-09-01 13:30:04 -05:00
7ec28fe9af feat(compiler): allow multiple exportAs names (#18723)
This change allows users to specify multiple exportAs names for a
directive by giving a comma-delimited list inside the string.

The primary motivation for this change is to allow these names to be
changed in a backwards compatible way.

PR Close #18723
2017-09-01 13:26:10 -05:00
1cc3fe21b6 fix(animations): do not leak DOM nodes/styling for host triggered animations (#18853)
Closes #18606

PR Close #18853
2017-09-01 10:24:14 -07:00
ba7d70e5e0 build: fix changelog to remove AIO line items (#18956)
fixes 18740

PR Close #18956
2017-08-30 18:10:56 -07:00
497e0178cc fix(compiler): normalize the locale name (#18963)
PR Close #18963
2017-08-30 17:48:08 -07:00
8821723526 fix(common): fix XSSI prefix stripping by using JSON.parse always (#18466)
Currently HttpClient sends requests for JSON data with the
XMLHttpRequest.responseType set to 'json'. With this flag, the browser
will attempt to parse the response as JSON, but will return 'null' on
any errors. If the JSON response contains an XSSI-prevention prefix,
this will cause the browser's parsing to fail, which is unrecoverable.

The only compelling reason to use the responseType 'json' is for
performance (especially if the browser offloads JSON parsing to a
separate thread). I'm not aware of any browser which does this currently,
nor of any plans to do so. JSON.parse and responseType 'json' both
end up using the same V8 code path in Chrome to implement the parse.

Thus, this change switches all JSON parsing in HttpClient to use
JSON.parse directly.

Fixes #18396, #18453.

PR Close #18466
2017-08-29 17:19:02 -07:00
a203a959ae fix(common): fix improper packaging for @angular/common/http (#18613)
PR Close #18613
2017-08-29 17:16:56 -07:00
dfe2bad663 build: Add GitHub scripts for rebasing PRs (#18359)
PR Close #18359
2017-08-28 18:33:11 -05:00
f09a266e01 docs: add changelog for 4.3.6 2017-08-23 15:01:42 -05:00
3853fff795 release: cut the 4.3.6 release 2017-08-23 14:59:49 -05:00
641be64544 docs(aio): add info about --local option in the readme (#18824)
PR Close #18824
2017-08-23 13:19:23 -05:00
bcf211bdb3 docs(aio): fix "Error handling" section in "HttpClient" (#18821)
Removed additional curly brackets to fix blocks. Also replaced tab with 2 spaces.

PR Close #18821
2017-08-23 13:19:15 -05:00
ee5591d583 fix(core): make sure onStable runs in the right zone (#18706)
Make sure the callbacks to the NgZone callbacks run in the right zone
with or without the rxjs Zone patch -
1ed83d08ac.

PR Close #18706
2017-08-23 13:18:47 -05:00
1f43713506 fix(aio): do not redirect API pages on archive and next deployments (#18791)
PR Close #18791
2017-08-21 18:34:55 -05:00
325b9b4562 docs(aio): add ngAtlanta to the events page (#18649)
PR Close #18649
2017-08-21 18:34:25 -05:00
88abdbd50b docs(aio): update resources to include NinjaCodeGen Angular CRUD generator (#18518)
PR Close #18518
2017-08-21 18:34:17 -05:00
14d34c9bdf style(animations): format integration spec (#18805)
PR Close #18805
2017-08-21 17:09:53 -05:00
e1f45a33b7 fix(animations): restore auto-style support for removed DOM nodes (#18787)
PR Close #18787
2017-08-18 23:32:41 -05:00
9a754f9f0f fix(animations): make sure animation cancellations respect AUTO style values (#18787)
Closes #17450

PR Close #18787
2017-08-18 23:32:34 -05:00
c3dcbf9cb3 fix(animations): make sure @.disabled respects disabled parent/sub animation sequences (#18715)
Prior to this fix if @parent and @child animations ran at the same
time within a disabled region then there was a chance that a @child
sub animation would never complete. This would cause *directives to
never close a removal when a @child trigger was placed on them. This
patch fixes this issue.

PR Close #18715
2017-08-18 23:32:28 -05:00
5d68c830d2 fix(animations): ensure animations are disabled on the element containing the @.disabled flag (#18714)
Prior to fix this fix, @.disabled would only work to disable child
animations. Now it will also disable animations for the element that has
the @.disabled flag (which makes more sense).

PR Close #18714
2017-08-18 23:32:21 -05:00
ac58914b97 feat(animations): allow @.disabled property to work without an expression (#18713)
PR Close #18713
2017-08-18 23:32:13 -05:00
Joe
77ebd2b020 docs(aio): fix card inconsistency (#18726)
PR Close #18726
2017-08-18 23:15:36 -05:00
fec3b1a0e9 fix(core): correct order in ContentChildren query result (#18326)
Fixes #16568

PR Close #18326
2017-08-18 23:15:17 -05:00
3b571a4f3d build(aio): do not auto-link code elements already inside a link (#18776)
Closes #18769

PR Close #18776
2017-08-18 13:38:43 -05:00
Tea
efee81eb57 docs(aio): typo in template-syntax guide (#18765)
PR Close #18765
2017-08-18 13:38:16 -05:00
a7a698c36f docs(aio): update resource for codelyzer (#18742)
PR Close #18742
2017-08-18 13:22:11 -05:00
b5f1dc32d1 test(aio): fix error logged during tests (#18659)
The fixed test expected there to be a doc version without a URL. This used to be
the case but not any more. As a result, an error was logged in the test output
(but no failure).

This commit fixes it by ensuring that a version without a URL exists.

PR Close #18659
2017-08-18 13:20:22 -05:00
eef28144ce docs(aio): move code snippet to appropriate location (#18650)
PR Close #18650
2017-08-18 13:19:15 -05:00
f9b290570e fix(animations): resolve error when using AnimationBuilder with platform-server (#18642)
Use an injected DOCUMENT instead of assuming the global 'document'
exists.

Fixes #18635.

PR Close #18642
2017-08-18 13:15:05 -05:00
4852f55875 build(packaging): increase node memory for tests (#18731)
PR Close #18731
2017-08-18 13:15:05 -05:00
793f31b9b3 feat(common): add an empty DeprecatedI18NPipesModule module
Adding an empty module to ease the migration to the i18n pipes.
2017-08-18 13:15:05 -05:00
7e94405271 docs: add changelog for 4.3.5 2017-08-16 10:51:23 -07:00
6076a8d7bb release: cut the 4.3.5 release 2017-08-16 10:49:38 -07:00
a1624f217c fix(forms): re-assigning options should not clear select
Fixes #18330
2017-08-16 10:34:23 -07:00
b2f4d53bf0 docs(forms): fix reactive-forms guide typo
closes #17943
2017-08-15 16:43:21 -07:00
7662cefe6f docs: remove TypeScript to JavaScript guide & sample 2017-08-15 16:35:01 -07:00
1cb607697a build(aio): switch from @angular/http to @angular/common/http
```
$ ls -l dist/*.js

 14942            dist/0.b19e913fbdd6507d346b.chunk.js
  1535            dist/inline.a1b446562b36eebb766d.bundle.js
524385  (+  682)  dist/main.19fec4390ff7837ee6ef.bundle.js
 37402            dist/polyfills.9f7e0e53bce2a6c8326e.bundle.js
 54001            dist/worker-basic.min.js

632265  (+  682)  total
```
2017-08-15 15:16:10 -07:00
1990c3c722 build(aio): upgrade zone.js to 0.8.16
```
$ ls -l dist/*.js

 14942            dist/0.b19e913fbdd6507d346b.chunk.js
  1535            dist/inline.a1b446562b36eebb766d.bundle.js
523703            dist/main.19fec4390ff7837ee6ef.bundle.js
 37402  (+ 3088)  dist/polyfills.9f7e0e53bce2a6c8326e.bundle.js
 54001            dist/worker-basic.min.js

631583  (+ 3088)  total
```
2017-08-15 15:16:10 -07:00
b589d85d6f build(aio): upgrade @angular/* to 5.0.0-beta.3
```
$ ls -l dist/*.js

 14942            dist/0.b19e913fbdd6507d346b.chunk.js
  1535            dist/inline.7813f9128903f164bc00.bundle.js
523703  (-18484)  dist/main.19fec4390ff7837ee6ef.bundle.js
 34314            dist/polyfills.9b05df3b6c9270ebf575.bundle.js
 54001            dist/worker-basic.min.js

628495  (-18484)  total
```
2017-08-15 15:16:10 -07:00
03ec3a2169 build(aio): upgrade @angular/* to 4.3.4
```
$ ls -l dist/*.js

 14942            dist/0.b19e913fbdd6507d346b.chunk.js
  1535            dist/inline.dd77b84267809087d225.bundle.js
542187  (+ 2191)  dist/main.f3ffdb5bb1a5bcec2163.bundle.js
 34314            dist/polyfills.9b05df3b6c9270ebf575.bundle.js
 54001            dist/worker-basic.min.js

646979  (+ 2191)  total
```
2017-08-15 15:16:10 -07:00
a5baed6b97 build(aio): upgrade @angular/cli to 1.3.0
```
$ ls -l dist/*.js

 14942  (+    4)  dist/0.b19e913fbdd6507d346b.chunk.js
  1535            dist/inline.e07e02e29b7fc93816c6.bundle.js
539996  (-56433)  dist/main.f466098a873c1169a6dc.bundle.js
 34314  (-   33)  dist/polyfills.9b05df3b6c9270ebf575.bundle.js
 54001            dist/worker-basic.min.js

644788  (-56462)  total
```
2017-08-15 15:16:10 -07:00
259fc91305 docs(core): correct code examples for ChangeDetectorRef 2017-08-15 15:12:35 -07:00
a618d6e4ce docs(forms): add api docs for AbstractControlDirective 2017-08-15 15:07:44 -07:00
b315a84ba0 docs(aio): add Metadata guide based on Chuck’s docs
Chuck’s gist
https://gist.github.com/chuckjaz/65dcc2fd5f4f5463e492ed0cb93bca60#file-Angular%20Metadata-md
Also chuck’s doc on metadata-related errors (link needed)
2017-08-15 12:21:23 -07:00
972538be7a fix(core): forbid destroyed views to be inserted or moved in VC
Fixes #18615
2017-08-14 12:09:22 -07:00
d7be4f12b5 perf(aio): update to new version of build-optimizer 2017-08-11 13:29:01 -07:00
b9c1c913c1 fix(aio): skip PWA test when redeploying non-public commit 2017-08-11 13:29:01 -07:00
06e479ff66 docs: add changelog for 4.3.4 2017-08-10 09:40:01 -07:00
0065868f37 release: cut the 4.3.4 release 2017-08-10 09:38:13 -07:00
77fa3c3e48 test(aio): fix tests for example-boilerplate (#18619)
PR #18520 was accidentally merged into 4.3.x, which uses a different
location for building `tsc-wrapped`. This commit reverts the changes
from #18520 that were not compatible with 4.3.x.
2017-08-09 20:28:43 -07:00
f4cb45345d test(aio): fix running docs examples against local builds (#18520)
This commit also updates the version of `@angular/cli` used for docs examples.
The previous (transient) dependency `@ngtools/webpack` was not compatible with
`@angular/compiler-cli@>=5` and was breaking when running against the local
builds (currently at 5.0.0-beta.2). The version of `@ngtools/webpack` used by
the latest `@angular/cli` version is compatible with `@angular/compiler-cli@5`.
2017-08-09 14:21:39 -07:00
9329bfb86a fix(aio): add missing code snippet (#18547)
The snippet got lost some time during the migration from the old version (it is
[present in v2][1]).

[1]: https://v2.angular.io/docs/ts/latest/cookbook/aot-compiler.html#!#running-the-application

Fixes #18544
2017-08-09 14:20:50 -07:00
3efc88fb81 test(aio): fix the deploy-to-firebase tests
This commit also ensures that if the tests fail, the script exits with an error.

closes #18595
2017-08-09 14:18:07 -07:00
954b09022a ci(aio): fix deploying the stable branch to Firebase
The `deploy-to-firebase.sh` always expects there to be a
`src/extra-files/<mode>` directory and breaks if it doesn't exist.
2017-08-09 14:17:47 -07:00
71f5e78bcb test(animations): disable buggy test in Chrome 39 (#18483)
Fixes #15793
2017-08-09 14:16:03 -07:00
f0c3ed0f14 ci(aio): fix deploying to firebase (#18590) 2017-08-08 14:00:59 -07:00
c8fd3f5237 docs(common): fix the DatePipe API docs (#18548) 2017-08-07 11:47:38 -07:00
e0660b1b72 fix(animations): support persisting dynamic styles within animation states (#18468)
Closes #18423
Closes #17505
2017-08-07 11:40:34 -07:00
5a165ebcef fix(animations): revert container/queried animations accordingly during cancel (#18516) 2017-08-07 11:39:04 -07:00
3212f8c826 docs(aio): typo & update the bio (#18559) 2017-08-07 10:20:52 -07:00
c421ccaae9 ci(aio): compute AIO deployment mode
There are now 3 modes for deployment: next, stable, archive.
We compute which mode (and other deployment properties)
from the `TRAVIS_BRANCH` and the `STABLE_BRANCH`.

If the TRAVIS_BRANCH is master we deploy as "next".
If the `TRAVIS_BRANCH` matches the `STABLE_BRANCH` we deploy as "stable".

Otherwise if the branch has a major version lower than the stable version
and its minor version is highest of similar branches we deploy as "archive".

For "archive" deployments we compute the firebase project and deployment
url based on the major version of the `TRAVIS_BRANCH`.

As well as choosing where to deploy the build, we also use this
to select the environment file for the AIO Angular app.
This will enable the app to change its rendering and behaviour
based on its mode.

See #18287
2017-08-04 09:15:38 -07:00
bbec7db7ba feat(aio): add "archive" and "next" color themes 2017-08-04 09:15:38 -07:00
00134ae4e0 feat(aio): redirect marketing pages to docs if deploy mode is archive
See #18287
2017-08-04 09:15:38 -07:00
07bd459baa feat(aio): add deploy mode to version picker
See #18287
2017-08-04 09:15:38 -07:00
302adf1081 feat(aio): enable deployment mode to be set via URL query
The deployment mode set from the environment provided at build time;
or overridden by the `mode` query parameter: e.g. `...?mode=archive`

See #18287
2017-08-04 09:15:38 -07:00
1a6a13425b feat(aio): update UI based on deployment mode
* Add a banner if the mode is "archive"
* Add a `mode-...` class to the `aio-shell` element to enable
mode based theming.

See #18287
2017-08-04 09:15:38 -07:00
072a772ca6 ci(aio): include extra files in AIO deployment based on mode
Any files that are inside the `extra-files/{mode}` folder
will be copied over to the `dist` folder before deployment
to Firebase.

See #18287
2017-08-04 09:15:38 -07:00
5f0e0a46fd ci(aio): compute AIO deployment mode
There are now 3 modes for deployment: next, stable, archive.
We compute which mode (and other deployment properties)
from the `TRAVIS_BRANCH` and the `STABLE_BRANCH`.

If the TRAVIS_BRANCH is master we deploy as "next".
Otherwise if the branch is the highest of its minor versions
we deploy as "stable" if the `TRAVIS_BRANCH` matches the `STABLE_BRANCH` or
else "archive".

For "archive" deployments we compute the firebase project and deployment
url based on the major version of the `TRAVIS_BRANCH`.

As well as choosing where to deploy the build, we also use this
to select the environment file for the AIO Angular app.
This will enable the app to change its rendering and behaviour
based on its mode.

See #18287
2017-08-04 09:15:38 -07:00
c7b72aa575 docs(aio): tech edits to form validation (PR #18495) 2017-08-03 13:58:22 -07:00
732eb61957 docs(forms): update and re-organize validation guide 2017-08-03 13:57:58 -07:00
e7e7622971 fix(compiler): ignore @import in multi-line css (#18452)
Fixes #18038
2017-08-03 11:01:24 -07:00
4176832266 refactor(router): compile router cleanly with TypeScript 2.4 (#18465) 2017-08-02 17:32:27 -07:00
71de92a189 docs(router): fix typo (#18479) 2017-08-02 17:31:33 -07:00
e0021d4cf5 refactor(platform-browser): compiler platform-browser packages cleanly (#18464) 2017-08-02 16:31:14 -07:00
4e44102e31 refactor(forms): compile forms cleanly with TypeScript 2.4 (#18462) 2017-08-02 16:29:57 -07:00
111b70d108 refactor(upgrade): compile upgrade cleanly with TypeScript 2.4 (#18461) 2017-08-02 16:28:38 -07:00
5e4054b8f3 fix(compiler): cleanly compile with TypeScript 2.4 (#18456) 2017-08-02 16:27:14 -07:00
5afc7abcb0 fix(benchpress): compile cleanly with TS 2.4 (#18455) 2017-08-02 16:24:33 -07:00
65d0888708 fix(aio): fix layout of the webpack guide (#18493)
This is possibly a temporary fix for the layout, until we decide whether we want
to remove the guide or properly add it to the SideNav menu.

Fixes #17912
2017-08-02 16:01:02 -07:00
adfd2373b8 ci(aio): Add commit message to payload data (#18137) 2017-08-02 15:59:54 -07:00
3a82af3bde docs(aio): fix missing anchor-open in i18n documentation (#18476)
The Internationalisation documentation, "Translate text nodes" section, has an incomplete
markdown anchor, and leaks markdown into the page. Fix the anchor by adding the opening bracket.
2017-08-02 15:56:25 -07:00
3af62306b4 fix(aio): correctly redirect cookbook/a1-a2-quick-reference.html (#18418)
Fixes #18415
2017-08-02 15:54:49 -07:00
afe339396f test(common): skip some DatePipe tests in old Chrome where Intl is buggy (#15784) 2017-08-02 15:52:27 -07:00
c4b51bf689 docs(aio): replace old blog link in footer (#18448)
Fixes #18233
2017-08-02 15:46:25 -07:00
b65fe3e44e ci: remove chromium fold reference (#18445) 2017-08-02 15:44:26 -07:00
116ee334fb build(aio): use cli 1.3.0-rc (#18290) 2017-08-02 15:37:39 -07:00
dbc5c5817a docs: improve github labels by introducing "PR target" labels (#18436)
I also renamed all "pr_*" lables to "PR *" lables, removed obsolete
"chore" label, and added docs label.
2017-08-02 15:31:56 -07:00
baf4ce0dd0 build: enable TSLint on the packages folder (#18459)
porting PRs #18392 and #18441 to 4.x
2017-08-02 15:23:33 -07:00
24db1ed938 docs: add changelog for 4.3.3 2017-08-02 13:00:35 -07:00
82798e9d04 release: cut the 4.3.3 release 2017-08-02 12:57:34 -07:00
da8bb1b45b docs(aio): fixed list format in FormArray section 2017-07-31 11:40:27 -07:00
f5cbc2ee25 fix(compiler): fix for element needing implicit parent placed in top-level ng-container
fixes #18314
2017-07-31 11:40:20 -07:00
cbc1986c6f fix(aio): fix links to source for paths with symlinks
Fixes #18353
2017-07-31 11:39:47 -07:00
0982f993cb ci: short-circuit npm install for aio builds that use yarn only 2017-07-31 11:39:41 -07:00
a5a29b0591 docs(aio): delay ngUpgrade e2e test to avoid flakes 2017-07-31 11:39:36 -07:00
a8f3197f24 build: short-circuit build for AIO tasks 2017-07-31 11:39:31 -07:00
e6f37120fe docs(aio): fix deprecated protractor API usage
`browser.getLocationAbsUrl()` is deprecated.
We should use `browser.getCurrentUrl()` instead.
2017-07-31 11:39:25 -07:00
6840b7bda9 ci(aio): test the example e2e files using local build of Angular 2017-07-31 11:39:21 -07:00
68f458909a build(aio): ignore generated aot files
Assets such as images and data which are generated
by the aot build were not being ignored.
2017-07-31 11:39:14 -07:00
12acecf756 docs(aio): remove generated styles.css file
This file should have been ignored as it is created
during the build of the example
2017-07-31 11:39:10 -07:00
cfbed40ab6 build(aio): support overriding the Angular packages in examples with locally built ones 2017-07-31 11:39:03 -07:00
fe1a6b8e42 build(aio): refactor and test the example-boilerplate tool 2017-07-31 11:38:59 -07:00
13e29c4e89 ci: shard the aio example e2e tests 2017-07-31 11:38:53 -07:00
fd52b178ed ci(aio): support sharding of example e2e tests 2017-07-31 11:38:48 -07:00
ca1f071b2e build(aio): upgrade @angular/material to 2.0.0-meta.8 2017-07-31 11:38:43 -07:00
296adbbb72 build(aio): upgrade @angular/* to 4.3.1 2017-07-31 11:38:37 -07:00
c795ee1176 docs(aio): fix URLSearchParams interface link to MDN
Fixes #18367
2017-07-31 11:38:33 -07:00
b550618afd refactor(aio): move content-specific images to content/images/
Fixes #17053
2017-07-31 11:38:28 -07:00
d08d6eebff refactor(aio): rename unused directories to _unused 2017-07-31 11:38:23 -07:00
e9789abd05 fix(aio): fix link to logo in example 2017-07-31 11:38:17 -07:00
f2ec2cbb99 refactor(aio): move unused images to unused directories
This prevents the ServiceWorker from prefetching unnecessary files.
2017-07-31 11:38:09 -07:00
8de2ace80a docs: add changelog for 4.3.2 2017-07-27 15:51:46 -05:00
c977994864 release: cut the 4.3.2 release 2017-07-27 15:51:46 -05:00
12b8e1af55 Revert "fix(router): should throw when lazy loaded module doesn't define any routes (#15001)"
This reverts commit be49e0ee93.
2017-07-27 13:05:36 -07:00
9a188485f5 ci: correct bad bazel merge 2017-07-27 12:43:29 -07:00
45a10419bc Revert "build: Bazel builds ngfactories for packages/core (#18289)"
This reverts commit bcea196530.
2017-07-27 10:51:41 -07:00
2245748c14 test(compiler): fix xliff2 integration test for the 4.3 branch (#18363)
Closes #18363
2017-07-27 10:20:34 -07:00
bcea196530 build: Bazel builds ngfactories for packages/core (#18289)
PR Close #18289
2017-07-26 16:31:26 -07:00
b9e32c833a fix(router): child CanActivate guard should wait for parent to complete (#18110)
Closes #15670

PR Close #18110
2017-07-26 17:52:47 -05:00
be49e0ee93 fix(router): should throw when lazy loaded module doesn't define any routes (#15001)
Closes #14596

PR Close #15001
2017-07-26 16:49:50 -05:00
bf95655a1a docs(aio): add my details as a contributor (#18315)
PR Close #18315
2017-07-26 16:49:50 -05:00
6bf5b84fa4 fix(aio): correctly process markdown link in "Browser Support" (#18349)
The markdown processor expects an empty line between an opening tag and the
markdown content. (If there is no empty line, the content is interpreted as
plain HTML.)
Previously, the line between the opening `<td>` and the content contained
whitespace, which caused the content to be interpreted as HTML and not markdown.

Fixes #18312

PR Close #18349
2017-07-26 16:11:11 -05:00
4836565ca7 docs(aio): update examples to 4.3 2017-07-26 12:08:29 -05:00
750e4e8156 docs(aio) - Fixed link to the glossary dash-case term (#18311)
PR Close #18311
2017-07-26 12:08:29 -05:00
a0846194b7 fix(compiler): add equiv & disp attributes to Xliff2 ICU placeholders (#18283)
Fixes #17344

PR Close #18283
2017-07-26 12:08:29 -05:00
bcf6b90c95 docs(platform-server): inline PlatformOptions and add doc strings (#18264)
Fix documentation for the options passed into renderModule and
renderModuleFactory.

PR Close #18264
2017-07-26 12:08:29 -05:00
3ca2a0aa37 refactor(compiler-cli): add support for browser compiler bundle (#17979)
PR Close #17979
2017-07-26 12:08:29 -05:00
b4be96c65d ci: use chrome stable (#18307) 2017-07-26 12:08:29 -05:00
434ff5fecb build: update bazel rules to latest (#18289) 2017-07-26 12:08:24 -05:00
a1bb9c2d42 fix(core): invoke error handler outside of the Angular Zone (#18269)
In Node.JS console.log/error/warn functions actually resuls in a socket
write which in turn is considered by Zone.js as an async task.

This means that if there is any exception during change detection in a platform-server
application the error handler will make the Angular Zone unstable which
in turn will cause change detection to run on next tick and cause an
infinite loop.

It is also better to run the error handler outside of the Angular Zone
in general on all platforms so that an error in the error handler itself doesn't cause an
infinite loop.

Fixes #17073, #7774.

PR Close #18269
2017-07-26 12:04:47 -05:00
7e626bef0a ci: force precise on Travis (#18282)
PR Close #18282
2017-07-26 12:04:47 -05:00
a1e83a8ed2 test: fix bad merge (#18267)
PR Close #18267
2017-07-26 12:04:47 -05:00
cbeb197aa5 fix(animations): export BrowserModule as apart of BrowserAnimationsModule (#18263)
PR Close #18263
2017-07-26 12:04:47 -05:00
0330fa6b82 docs(aio): pngcrush all pngs (#18243)
PR Close #18243
2017-07-26 12:04:47 -05:00
97135e8fd5 fix(platform-server): don't clobber parse5 properties when setting (#18237)
element properties.

Fixes #17050.

We now store all element properties in a separate 'properties' bag.

PR Close #18237
2017-07-26 12:04:47 -05:00
35bd07fc7b refactor(common): CleanUp HttpClient's imports (#18120)
PR Close #18120
2017-07-26 12:04:47 -05:00
a8ac77b645 fix(compiler): allow numbers for ICU message cases in lexer (#18095)
Closes #18095
Fixes #17799
2017-07-26 12:04:47 -05:00
9ecd377a51 ci(aio): fix aio payload script 2017-07-26 12:04:47 -05:00
76171bd8b4 test(upgrade): fail tests when there are AngularJS errors (#18209) 2017-07-26 12:04:47 -05:00
1f106d75bc fix(upgrade): throw error if trying to get injector before setting (#18209)
Previously, `undefined` would be returned.
This change makes it easier to identify incorrect uses/bugs.
(Discussed in https://github.com/angular/angular/pull/18213#issuecomment-316191308.)
2017-07-26 12:04:47 -05:00
a4fae8c405 aio: debounce search and delay index building (#18134)
* feat(aio): debounce search requests

* feat(aio): delay loading search worker and index
2017-07-26 12:04:46 -05:00
33c07b3394 fix(aio): invalid formatting in architecure.md (#18159)
Introduced in e110a80caf (diff-9ac9c6a9277eea9856d75249a7c0a40aL127)
2017-07-26 12:00:01 -05:00
c9d06e676f docs(aio): replace old blog link (#18252)
Fixes #18233
* Docs(aio): Replaced old blog link Now with the Link to the new Angular.io Blog
* Removed double braces
2017-07-26 12:00:01 -05:00
c7c65d9fda docs: fixing invisible tag in README (#18245) 2017-07-26 12:00:01 -05:00
257a9e3e6f ci: test bazel builds on travis (#18240) 2017-07-26 12:00:01 -05:00
c7c0a1688e docs(aio): Fixed typo with closing div 2017-07-26 12:00:00 -05:00
7e95e2b0ba docs(aio): Fix http guide 2017-07-26 12:00:00 -05:00
ddc286f4b5 docs: fix wrong link in CONTRIBUTING.md (#18228)
The link to the CONTRIBUTING.md file was not correct
2017-07-26 12:00:00 -05:00
3d17a3672e docs(router): minor typo (#18226)
Fix a minor typo in the description of a router spec.
2017-07-26 12:00:00 -05:00
61d253f5fd docs(aio): fix typo in NgModule FAQs (#18211)
Fix #18133. Fix typo 'added' to 'add' in the 'Why does lazy loading create a child injector' section.
2017-07-26 12:00:00 -05:00
54be25a7a1 docs: add changelog for 4.3.1 2017-07-19 12:54:45 -07:00
b1757037fb release: cut the 4.3.1 release 2017-07-19 12:53:17 -07:00
f0476fcff0 fix(compiler-cli): don't generate empty <target/> when extracting xliff
Fixes #15754
2017-07-19 09:50:09 -07:00
a5c4bb5b96 fix(animations): make sure @.disabled works in non-animation components
Note 4.3 only!

Prior to this fix when [@.disabled] was used in a component that
contained zero animation code it wouldn't register properly because the
renderer associated with that component was not an animation renderer.
This patch ensures that it gets registered even when there are no
animations set.
2017-07-19 09:50:03 -07:00
4c1f32b0db fix(animations): do not crash animations if a nested component fires CD during CD
Closes #18193
2017-07-19 09:49:57 -07:00
383d8969ab fix(animations): always camelcase style property names that contain auto styles
Closes #17938
2017-07-19 09:49:47 -07:00
333ffd8d32 fix(animations): capture cancelled animation styles within grouped animations
Closes #17170
2017-07-19 09:49:42 -07:00
d4679a0bc2 docs(aio): fix typo in Router documentation
Fix title and link to RouteConfigLoadEnd documentation
2017-07-19 15:02:14 +01:00
4ce29f3a5b fix(platform-server): provide XhrFactory for HttpClient 2017-07-18 14:19:18 -07:00
17b7bc3e06 fix(common): send flushed body as error instead of null
fix #18181
2017-07-18 10:58:27 -07:00
f19bd5f4f3 docs(http): Make name of injected HttpTestingController consistent 2017-07-18 10:54:42 -07:00
d503d25f29 docs(platform-server): add doc string for PlatformOptions 2017-07-18 10:54:37 -07:00
5d275e994a fix(router): terminal route in custom matcher 2017-07-18 10:54:32 -07:00
d8c8b13bb8 docs: fix typo 2017-07-18 10:54:26 -07:00
4671168635 fix(compiler): ensure jit external id arguments names are unique
Fixes: #17558, #17378, #8676
2017-07-18 10:54:21 -07:00
1ac78bfd5d fix(router): canDeactivate guards should run from bottom to top
Closes #15657.
2017-07-18 10:54:15 -07:00
4340beacea fix(router): should navigate to the same url when config changes
Closes #15535
2017-07-18 10:54:09 -07:00
ec89f378fc fix(router): should run resolvers for the same route concurrently
Fixes #14279
2017-07-18 10:54:04 -07:00
4dd6863bc2 docs(aio): fix HttpClient setting new header sample 2017-07-18 10:53:58 -07:00
37c626e673 fix(aio): remove title attribute from CodeExampleComponent
This was causing browser to add an unwanted tooltip that appeared
when the user hovers over the code.

See #17524
2017-07-18 17:55:54 +01:00
f0a110928b fix(aio): add quote to module 2017-07-18 17:54:51 +01:00
c39e7d1eb2 fix(aio): do not wrap <code-tabs> tab labels
Fixes #17751
2017-07-18 17:45:20 +01:00
799bffb431 docs(aio): fix cheatsheet layout for narrow screens
* Tell the app that this will have no Table of Contents, since we have no
h2 headings anyway.
* Remove all the `nbsp;` from the code since that doesn't help with layout
* Remove side padding from sidenav-content when screen is narrow
* Restyle the cheatsheet table when the screen is narrow
2017-07-18 17:33:36 +01:00
fda607cc2f build(aio): fail doc-gen if referenced images are missing 2017-07-18 11:46:15 +01:00
cc3aa68123 docs(aio): fix broken image sources 2017-07-18 11:46:15 +01:00
306621d2d6 docs(aio): fix up broken links 2017-07-18 11:46:15 +01:00
d204f7aa2a build(aio): abort doc-gen on dangling links 2017-07-18 11:46:14 +01:00
a94f5e8cbb build(aio): abort doc-gen if an example is missing
Closes #16936
2017-07-18 11:46:14 +01:00
1390afef23 docs: fix HttpClient sample 2017-07-17 14:18:41 -07:00
b0346a6e45 docs(aio): fix HttpClient's interceptor sample 2017-07-17 14:18:41 -07:00
e5da059994 docs(http): fix "Expecting and answering requests" example mistake
Possibly overlooked testing documentation mistake fixed:
- `http.get('/data')` probably ought to be paired with `httpMock.expectOne('/data')` instead of `httpMock.expectOne('/data')`.
2017-07-17 14:18:41 -07:00
ac92c3bb26 docs: fix HttpClient logging's sample 2017-07-17 14:18:41 -07:00
87157d7089 docs(http): fixed syntax error in AuthInterceptor example 2017-07-17 14:18:41 -07:00
611dd12f0f ci: add GK and PBD to aio content and marketing groups 2017-07-17 14:18:41 -07:00
969ce9dc2b fix(aio): remove title from callout 2017-07-15 15:39:40 +01:00
34834a9e79 fix(aio): remove unused news.html file
Although outdated and not used, the file would be picked up and showed in search
results.
2017-07-15 15:29:59 +01:00
6e2ddccc2c build(aio): render type parameters of API function exports
Fixes #18123
2017-07-15 08:54:34 +01:00
55742e4737 Revert "revert: revert: ci(aio): exclude changes in aio/content folder"
This reverts commit 3d85f72652.

Still causing repeated flakes on master.
2017-07-14 14:55:56 -07:00
0091b1e8db refactor(upgrade): clean up some types 2017-07-14 14:55:46 -07:00
a0b06befb6 docs: add changelog for 4.3.0 2017-07-14 13:12:37 -07:00
4fbb5b29ea release: cut the 4.3.0 release 2017-07-14 12:50:40 -07:00
e0fa727594 fix(aio): document XSRF protection in HttpClient 2017-07-14 12:42:37 -07:00
3ecc5e5398 fix(common): rename HttpXsrfModule to HttpClientXsrfModule 2017-07-14 12:40:52 -07:00
f7686d4124 Revert "fix(animations): make sure @.disabled works in non-animation components"
This reverts commit 01a2688848.
2017-07-14 11:00:29 -07:00
01a2688848 fix(animations): make sure @.disabled works in non-animation components
Note 4.3 only!

Prior to this fix when [@.disabled] was used in a component that
contained zero animation code it wouldn't register properly because the
renderer associated with that component was not an animation renderer.
This patch ensures that it gets registered even when there are no
animations set.
2017-07-14 10:34:58 -07:00
8e56c3cb30 docs: fix type error in HttpClient sample 2017-07-14 09:35:25 -07:00
7955cacec4 build(aio): turn on debugging of the payload.sh script to debug ci failures 2017-07-13 22:50:05 -07:00
dd04f09483 feat(common): on-by-default XSRF support in HttpClient (#18108)
Fixes #18100
2017-07-13 17:22:02 -07:00
3d85f72652 revert: revert: ci(aio): exclude changes in aio/content folder
This reverts commit 72143e80da.

it seems that the previous build failure was a travis flake.

reverting the revert...
2017-07-13 16:22:57 -07:00
9f28e838d3 fix(common): expose reportProgress option on HttpClient API (#18083) 2017-07-13 16:19:52 -07:00
ddb766e456 feat(compiler): do not evaluate metadata expressions that can use references (#18001) 2017-07-13 16:16:56 -07:00
72143e80da revert: ci(aio): exclude changes in aio/content folder
This reverts commit 1bf7ba87a0.

The commit caused master builds to fail with:

```
$ scripts/payload.sh
error Command failed with exit code 1.
error Command failed with exit code 1.
```
https://travis-ci.org/angular/angular/jobs/253405260#L1024
2017-07-13 15:32:44 -07:00
bc1ea8c54b docs: rewrite 'Server Communication' doc guide to use HttpClient (#18079) 2017-07-13 15:22:07 -07:00
45ffe54ae4 fix(tsc-wrapped): support as and class expressions (#16904) 2017-07-13 15:17:16 -07:00
1bf7ba87a0 ci(aio): exclude changes in aio/content folder 2017-07-13 15:13:37 -07:00
db96c963a8 fix(aio): add <hr> in between overloads 2017-07-13 14:58:33 -07:00
18559897a0 fix(common): document HttpClient, fixing a few other issues 2017-07-13 14:58:33 -07:00
ce0f4f0d7c fix(tsc-wrapped): report errors for invalid ast forms (#17994)
Fixes: #17993
2017-07-13 14:55:59 -07:00
4f1e4ffa4e fix(common): don't guess Content-Type for FormData bodies (#18104)
Fixes #18096
2017-07-13 12:28:20 -07:00
f0beb4d750 docs(aio): add Dart as a language option (#18080) 2017-07-13 12:21:28 -07:00
bc3b2ac251 docs(aio): Updated resources to UI Components (#18067)
With https:// the site gives console errors, because it loads fonts with http://
2017-07-13 12:19:31 -07:00
ffda3e41e0 build(aio): simplify the primary overload's anchor
The primary link to a member should simply be its name, and not require
the parameter list.
2017-07-13 12:16:20 -07:00
a301dba68f build(aio): improve API docs layout and styling 2017-07-13 12:16:20 -07:00
04f3a4a7a5 build(aio): fix githubLinks line numbers
The API docs have changed. The line numbers are now found in
`startingLine` and `endingLine` properties rather than the `location`
property, which moved into the `fileInfo` property anyway.
2017-07-13 12:16:20 -07:00
f06ce9adc8 build(aio): truncate API overview parameters at one line 2017-07-13 12:16:20 -07:00
660eec4a23 build(aio): upgrade to dgeni-packages 0.20.0-rc.5
This fixes unwanted extra overloads in interfaces and abstract classes
This provides the overload grouping support and fixes API doc line numbers
2017-07-13 12:16:20 -07:00
be3352a084 build(aio): render grouped overloads 2017-07-13 12:16:20 -07:00
998049ec9b build(aio): truncate API overview parameters at one line 2017-07-13 12:16:20 -07:00
a7ea0086ee ci: fast-forward to master/HEAD on all circle jobs (#18101)
This problem was introduced by a bad merge.
2017-07-13 12:16:02 -07:00
edb8375a5f docs: adjust the release schedule with the 4.3.0-rc.0 release date 2017-07-11 15:52:06 -07:00
26b9492315 docs(aio): Added resource link to amexio-ng-extensions [duplicate of #17785] (#17790) 2017-07-11 15:06:14 -07:00
e110a80caf docs(aio): change Angular Module to NgModule (#16964) 2017-07-11 15:05:20 -07:00
20127c1456 docs: fix typos and grammar (#17818) 2017-07-11 13:00:53 -07:00
a50d935a48 docs(benchpress): fix android broken links (#17568) 2017-07-11 12:54:34 -07:00
7c479f073e docs: document using Bazel (#17701) 2017-07-11 12:48:50 -07:00
bbf2133fa9 docs: update ECMAScript info (#17801) 2017-07-11 12:44:56 -07:00
4300439ab2 docs: improve grammar and wording on CONTRIBUTING.md (#17855) 2017-07-11 12:40:30 -07:00
ec14679668 docs: add @angular/animations to list (#17488)
@angular/animations was missing from the SemVer supported API surface list, now added.
2017-07-11 12:30:01 -07:00
df06e8b7a4 fix(router): fix outdated homepage url in NPM package (#17899) 2017-07-11 12:00:56 -07:00
1b1a6ba0bb docs: fix 404 link to SFEIR website (#17913)
Also, I moved SFEIR training description to the "onsite" section since SFEIR doesn't deliver online training.
2017-07-11 12:00:27 -07:00
876ca9ee3a docs(aio): fix host usage in styleguide (#17932) 2017-07-11 11:58:26 -07:00
d9b03be08f test: git ignore e2e test folders (#17984) 2017-07-11 11:55:24 -07:00
b6aad07634 build: remove duplicate dependency on TypeScript
TypeScript was added as a dependency in 9a7f5d580. I assume the intention was to
upgrade the existing devDependency instead.
2017-07-11 11:53:43 -07:00
3d0406c247 docs: update required Node/npm versions in DEVELOPER.md 2017-07-11 11:53:43 -07:00
db3bcc939e docs: fix CHANGELOG typo (#18026) 2017-07-11 11:51:46 -07:00
4d45fe6fb5 fix(aio): fix tab animations on CodeTabsComponent
In our attempt to remove the material ripple effect from tab labels, we were
killing all `transform`-based animations on other `md-tab-group` elements, such
as animating the content when entering/leaving. (This wasn't an issue on Chrome,
because it didn't respect our `!important` flag.)
This commit fixes it by properly hiding the ripple effect (using a feature
introduced in angular/material2@e4789c7b8) and allowing other animations to
execute normally.

Fixes #17998
2017-07-11 11:49:22 -07:00
076ea2281f test(aio): add tests for CodeTabsComponent 2017-07-11 11:49:22 -07:00
aec39c28d8 refactor(aio): remove unnecessary comments/imports, improve indentation 2017-07-11 11:49:22 -07:00
b9525ece77 docs: Unbreak README Formatting (#18043)
- Makes headers consistent
 - Removes extra `)`
 - Makes browserstack line on a separate line
2017-07-11 11:48:37 -07:00
719101338a docs: does please -> does (#18044)
Fixes grammar issue.
2017-07-11 11:46:57 -07:00
e131f6bbe8 docs: various minor formatting changes (#18046) 2017-07-11 11:46:34 -07:00
a9757ec674 docs: Fix code example in the ChangeDetectorRef docs (#18051)
Minor example fix: mark the 'ref' constructor parameter as a private property
2017-07-11 11:45:32 -07:00
9003770f02 docs: fix style in helper text (#18055) 2017-07-11 11:43:52 -07:00
e8bbf86e66 build(aio): add terms from heading to the search index 2017-07-11 15:04:37 +01:00
3a0886dc12 build(aio): capture all the headings from a doc in the vFile.headings property 2017-07-11 15:04:37 +01:00
062a7aa2cf build(aio): revert to general purpose search algorithm
Now that we have upgraded to the latest lunr search engine, the results
from the standard `search` method are more appropriate.
So we do not need to create our own special queries to get good results.
2017-07-11 15:04:37 +01:00
e28f097fc2 ci: add aio/content to aio group
This commit also simplifies the rules for the aio content and marketing groups
2017-07-11 11:55:09 +01:00
b30c5fc874 docs(aio): fix dangling links 2017-07-11 11:44:05 +01:00
d52ab8e2c9 build(aio): fix matchUpDirectiveDecorators processor 2017-07-11 11:44:05 +01:00
df7b875f6c build(aio): fix mergeDecoratorDocs processor 2017-07-11 11:44:05 +01:00
0e71836cd5 docs(aio): fix potential invalid jsdoc tag 2017-07-11 11:44:05 +01:00
470a7c6bcd build(aio): use dedicated overview for decorator API docs 2017-07-11 11:44:05 +01:00
3abf208235 build(aio): update doc-gen templates 2017-07-11 11:44:05 +01:00
92c18d167e build(aio): fix mergeDecoratorDocs processor 2017-07-11 11:44:05 +01:00
99b38f52cb build(aio): fix matchUpDirectiveDecorators processor 2017-07-11 11:44:05 +01:00
633ec30291 build(aio): fix test description 2017-07-11 11:44:05 +01:00
57cfcb0830 build(aio): refactor filterMemberDocs to be more general
Now it also filters function-overloads, hence the name change.
2017-07-11 11:44:05 +01:00
433d479a1e build(aio): upgrade to dgeni-packages v0.20.0-rc.1 2017-07-11 11:44:05 +01:00
7c4ac68e66 build(aio): remove unused script and GitHub token
Since 808bd4af4, we are no longer pre-verifying PRs before uploading the build
artifacts to the preview server, thus we no longer need the
`travis-preverify-pr.sh` script or the `GITHUB_TEAM_MEMBERSHIP_CHECK_KEY`
variable.
2017-07-11 11:03:29 +01:00
20556346a3 feat(aio): add API endpoint for notifying about PR updates
This commit adds an API endpoint for notifying the preview server about PR
updates (`/pr-updated`). According to the update, the preview server can take
several actions. Currently, it will only check and (if necessary) update the
PR's preview visibility (but more actions could be supported in the future).
The API can be used with an automatic trigger (e.g. a GitHub webhook) to
instantly update a PR's preview visibility when it changes.

Fixes #16526
2017-07-10 12:30:45 +01:00
5a417b8514 feat(aio): implement a way to check and update a PR\'s preview visibility
Previously, `BuildCreator#changePrVisibility()` would throw an error if the PR's
visibility was already up-to-date or if the PR directory did not exist (e.g. was
removed). This method was only used from inside `BuildCreator#create()`, which
had already checked for the existence of the directories.

This commit renames `changePrVisibility()` to `updatePrVisibility()` and makes
it more "forgiving" (i.e. it will only throw if both public and non-public
directories exist). This allows it to be used on events that may or may not have
caused the PR's visibility to change (e.g. a GitHub webhook triggered whenever a
PR's labels change).
2017-07-10 12:30:45 +01:00
8cfc2e2ec0 refactor(aio): unify error messages for invalid requests to upload-server
Previously, there was a distinction between GET requests to invalid URLs and all
other requests. This was mainly because the upload-server only accepts GET
requests, but that is not a hard limitation and may change in the future.

Thus, it makes sense to return a 404 response for requests to invalid URLs
regardless of the method used.
2017-07-10 12:30:45 +01:00
11647e4c78 refactor(aio): use dedicated constants.ts file for e2e-specific constants 2017-07-10 12:30:45 +01:00
9e1b61326c refactor(aio): move script to a more relevant directory 2017-07-10 12:30:45 +01:00
cb7609109d fix(aio): fix text blurring when hovering over item in resources
Fixes #17907
2017-07-10 12:24:10 +01:00
b3d90365b6 fix(aio): add new common/http package into API list 2017-07-10 12:23:47 +01:00
cc611c93b6 docs: add changelog for 4.3.0-rc.0 2017-07-07 22:10:17 -07:00
8928a58796 release: cut the 4.3.0-rc.0 release 2017-07-07 22:07:13 -07:00
05a33d5035 docs: add changelog for 4.2.6 2017-07-07 22:03:53 -07:00
09f1609f81 style(http): fix linting error in http/testing (#18002) 2017-07-07 17:02:07 -07:00
c723d42d0a refactor: fix typos (#18000) 2017-07-07 16:55:17 -07:00
9dd550fa1e ci(aio): only deploy latest commits to staging/production (#17988)
Fixes #17941
2017-07-07 16:35:07 -07:00
abbac4bc69 feat(aio): use new ngo (#17977) 2017-07-07 16:34:47 -07:00
671a175dfb fix(compiler-cli): fix relative source paths on windows for extracted msg (#17915)
Fixes #16639
2017-07-07 16:33:40 -07:00
c1474f33be feat(compiler-cli): add parameters to ngc main needed by bazel rules (#17885) 2017-07-07 16:29:39 -07:00
0ede642cb9 docs(aio): Update NgStyle and NgClass to use quoted keys 2017-07-07 16:17:33 -07:00
9c1f6fd06f fix(compiler): emits quoted keys only iff they are quoted in the original template
fixes #14292
2017-07-07 16:17:33 -07:00
798947efa4 feat(compiler): adds support for quoted object keys in the parser 2017-07-07 16:17:33 -07:00
7ae8ad6aab fix(compiler): fix types 2017-07-07 16:17:33 -07:00
9c3386b1b7 fix(compiler): remove i18n markup even if no translations (#17999)
Fixes #11042
2017-07-07 16:16:49 -07:00
2ba3ada27f revert: "refactor(compiler-cli): remove the dependency on fs in codegen.ts (#17738)"
This reverts commit b116901400.
2017-07-07 16:16:25 -07:00
8e28382e4a feat(animations): support disabling animations for sub elements
Closes #16483
2017-07-07 14:58:40 -07:00
3203639d7d fix(animations): ensure :animating queries collect previous animation elements properly 2017-07-07 14:58:40 -07:00
f85b543cc1 fix(animations): properly detect state transition changes for object literals 2017-07-07 14:58:40 -07:00
c81ad9d19d feat(common): two missing features in HttpClient (#17996)
- Add params to HttpRequest API
- Add optional description to testing APIs
2017-07-07 14:56:36 -07:00
37797e2b4e feat(common): new HttpClient API
HttpClient is an evolution of the existing Angular HTTP API, which exists
alongside of it in a separate package, @angular/common/http. This structure
ensures that existing codebases can slowly migrate to the new API.

The new API improves significantly on the ergonomics and features of the legacy
API. A partial list of new features includes:

* Typed, synchronous response body access, including support for JSON body types
* JSON is an assumed default and no longer needs to be explicitly parsed
* Interceptors allow middleware logic to be inserted into the pipeline
* Immutable request/response objects
* Progress events for both request upload and response download
* Post-request verification & flush based testing framework
2017-07-07 12:09:32 -07:00
2a7ebbe982 refactor: move DOCUMENT from platform/browser to common 2017-07-07 12:09:32 -07:00
72747e5213 ci: disable sauce-connect logging for realz (#17995)
follow up on #17947
2017-07-07 11:59:40 -07:00
504500de50 fix(aio): activate ServiceWorker updates asap (#17699)
Previouly, whenever a new ServiceWorker update was detected the user was
prompted to update (with a notification). This turned out to be more distracting
than helpful. Also, one would get notifications on all open browser tabs/windows
and had to manually reload each one in order for the whole content (including
the app) to be updated.

This commit changes the update strategy as follows:
- Whenever a new update is detected, it is immediately activated (and all
  tabs/windows will be notified).
- Once an update is activated (regardless of whether the activation was
  initiated by the current tab/window or not), a flag will be set to do a
  "full page navigation" the next time the user navigates to a document.

Benefits:
- All tabs/windows are updated asap.
- The updates are applied authomatically, without the user's needing to do
  anything.
- The updates are applied in a way that:
  a. Ensures that the app and content versions are always compatible.
  b. Does not distract the user from their usual workflow.

NOTE:
The "full page navigation" may cause a flash (while the page is loading from
scratch), but this is expected to be minimal, since at that point almost all
necessary resources are cached by and served from the ServiceWorker.

Fixes #17539
2017-07-07 11:17:19 -07:00
e1174f3774 fix(aio): home & marketing styles cleanup (#17926) 2017-07-07 11:16:51 -07:00
6bae73c076 refactor(common): replace Object.assign with the spread operator (#17982)
`Object.assign` is not available in all supported browsers and one had to
provide a polyfill. This commit replaces `Object.assign` with the spread
operator (`...`), which TypeScript will transpile to ES5-compatible code.
2017-07-07 08:55:29 -07:00
11db3bd85e fix(upgrade): bring the dynamic version closer to the static one
(#17971)

This commit changes the dynamic version of ngUpgrade to use `UpgradeHelper`,
thus bringing its behavior (wrt upgraded components) much closer to
`upgrade/static`. Fixes/features include:

- Fix template compilation: Now takes place in the correct DOM context, instead
  of in a detached node (thus has access to required ancestors etc).
- Fix support for the `$onInit()` lifecycle hook.
- Fix single-slot transclusion (including optional transclusion and fallback
  content).
- Add support for multi-slot transclusion (inclusing optional slots and fallback
  content).
- Add support for binding required controllers to the directive's controller
  (and make the `require` behavior more consistent with AngularJS).
- Add support for pre-/post-linking functions.

(This also ports the fixes from #16627 to the dynamic version.)

Fixes #11044
2017-07-07 08:54:39 -07:00
0193be7c9b feat(upgrade): fix support for directive.link in upgraded components
(#17971)

Although, pre- and post-linking functions are correctly called during directive
linking, directives with `link.post` would throw an error. Interestingly, having
`link.pre` only or defining `link: fn` (which is an alias for `link.post: fn`)
would not throw.

This commit removes this check and allows directives with pre- and/or
post-linking functions to work.
2017-07-07 08:54:09 -07:00
2ea73513ea refactor(upgrade): move shareable functionality to UpgradeHelper class (#17971)
This functionality can be potentionally re-used by the dynamic version.
2017-07-07 08:53:16 -07:00
67e9c62013 fix(upgrade): fix transclusion on upgraded components (#17971)
Previously, only simple, single-slot transclusion worked on upgraded components.
This commit fixes/adds support for the following:

- Multi-slot transclusion.
- Using fallback content when no transclusion content is provided.
- Destroy unused scope (when using fallback content).

Fixes #13271
2017-07-07 08:52:46 -07:00
227dbbcfba fix(language-service): ignore hover of symbols not in the TypeScript program (#17969)
Fixes: #17965
2017-07-07 08:47:28 -07:00
cb16e9c747 fix(tsc-wrapped): emit exports metadata in flat modules (#17893)
Fixes: #17888
2017-07-07 08:46:42 -07:00
3b2d2c467a fix(language-service): do not crash when hovering over a label definitions (#17974)
Fixes: #17972
2017-07-07 08:46:18 -07:00
ae27af7399 fix(router): encode URLs the same way AngularJS did (closer to spec) (#17890)
fixes #16067
2017-07-06 17:10:25 -07:00
c69fff15c9 fix(core): fix re-insertions in the iterable differ (#17891)
fixes #17852
2017-07-06 12:11:47 -07:00
dd7c1134e3 feat(compiler): update the schema by extracting from latest chrome (#17858)
adds:
- the slot element,
- the slot attribute on [Element],
- a few other attributes.
2017-07-06 12:11:34 -07:00
b116901400 refactor(compiler-cli): remove the dependency on fs in codegen.ts (#17738) 2017-07-06 12:11:21 -07:00
70981c601e feat(aio): serve-and-sync command (#17850) 2017-07-06 11:51:58 -07:00
f2f61c9cf0 ci: allow chuck to approve animations (#17940) 2017-07-06 11:49:44 -07:00
1bb2476804 docs(aio): add instructions for example e2e tests to README (#17819) 2017-07-06 11:15:31 -07:00
ec58246a1b docs(aio): add DevExtreme to the UI Components section of resources.json (#17939) 2017-07-06 11:15:15 -07:00
6fc5174a13 build: disable sauce connect logging (#17947)
this change is expected to mitigate the flakes on CI that occur when
we cat the log in the print-logs.sh
2017-07-06 11:00:00 -07:00
105e920b69 fix(animations): properly handle cancelled animation style application 2017-07-06 10:18:12 -07:00
858dea98e5 fix(animations): properly cleanup query artificats when animation construction fails 2017-07-06 10:18:12 -07:00
71ee0c5b03 ci(aio): raise polyfill payload limits 2017-07-06 14:46:53 +01:00
578bdeb522 fix(router): export missing UrlMatcher and UrlMatchResult types
Fixes #15140
2017-07-05 15:26:27 -07:00
6282a86135 ci: add angular.io content related groups to .pullapprove.yaml 2017-07-05 15:26:27 -07:00
e9b67243ed build(aio): upgrade to angular@4.2.4 and zone.js 2017-07-05 15:26:27 -07:00
fa1c187abc build: upgrade yarn to 0.24.6 2017-07-05 15:26:27 -07:00
b51697c197 ci: add Chuck to the owners of core (#17892) 2017-07-05 15:10:11 -07:00
c6b75b0823 docs: add animations package to CONTRIBUTING.md (#15413) 2017-07-05 14:34:13 -07:00
Joe
0d7e1a9b4e docs(changelog): Correct typos (#16966) 2017-07-05 14:33:47 -07:00
9d15d85391 docs: README - use correctly encoded link for npm badge (#17707)
closes #14990, an old PR that was approved but to old/difficult to merge
2017-07-05 14:33:25 -07:00
92d7ecf627 docs: shefali edits to Authors Style Guide (#17853) 2017-07-05 14:33:06 -07:00
9263da570f ci(aio): Fix the payload script only check for changes in aio/scripts 2017-07-03 10:40:19 +01:00
dc88e0a881 docs(aio): update quickstart to latest cli 2017-07-03 08:25:19 +01:00
fa34ed8bf3 ci(aio): use valid database path for Firebase payload size upload
Firebase does not allow `.` in the path, so when trying to upload payload size
data for branches like `4.2.x`, the following error is thrown:

```
HTTP Error: 400, Invalid path: Invalid token in path
```

This commit fixes it by replacing `.` with `_` in branch names.
2017-07-03 08:19:59 +01:00
f54a901b8d docs(aio): fix visual-studio-2015 typo
This fixes #17283
2017-07-03 08:12:28 +01:00
8a1a989a1c feat(router): add router-level events for GuardsCheck and Resolve (#17601) 2017-07-01 10:30:17 -07:00
b479ed9407 perf(core): refactor NgZone, decrease size by 1.2Kb (#17773)
- Remove getters
- Hide private methods for better property renaming

```
497893 May 31 11:26 core.umd.js
718073 May 31 11:26 core.umd.js.map
217108 May 31 11:26 core.umd.min.js
575092 May 31 11:26 core.umd.min.js.map
```

```
495594 May 31 11:28 core.umd.js
716943 May 31 11:28 core.umd.js.map
215826 May 31 11:28 core.umd.min.js
574401 May 31 11:28 core.umd.min.js.map
```
diff: 1,282
2017-07-01 10:29:56 -07:00
d5dc53ead8 ci(aio): avoid printing too large PWA report (and restore print-logs.sh)
There have been some issues lately with Travis jobs failing due to
`print-log.sh`. This is likely due to trying to print the Lighthouse PWA report,
which is too large.
This commit stops printing that report (since it was rarely used and is pretty
easy to acquire when needed) and restores the `print-logs.sh` script (that was
temporarily removed with dfcca66fd).
2017-07-01 14:40:36 +01:00
8e00161601 docs(aio): Add resources contributor info 2017-07-01 14:38:26 +01:00
01d4eae984 ci(aio): use correct URL for preview in PWA score test
In 4268c8289, the preview URLs were changed to not use the whole SHA, but just
the 7 first characters.
2017-06-30 13:02:28 +01:00
154154dde2 docs(aio): fix quickstart-cli bad HTML escape chars 2017-06-30 12:23:11 +01:00
4459e0c1c8 fix(aio): restore visible sidenav keyboard focus; shift TOC up
closes #17665
Restores keyboard focus that was removed by commit b8b91d3.
Raises the right-TOC by 20px (96px->76px) because was too far down.

To prevent keyboard focus on hidden child nodes,
also collapses inner expanded nodes when parent node is collapsed.
The implicit parent node of top nodes is always expanded.
2017-06-30 11:58:10 +01:00
b052ef5f1e fix(aio): do not include hidden content in window title
The window title is derived based on the current document's `<h1>` heading. Such
headings may contain hidden/non-visible content (e.g. textual name of font
ligatures: `<i class="material-icons">link</i>`) that should not be included in
the title.

This commit fixes this by using `innerText` (instead of `textContent`) to
extract the visible text from the `<h1>` heading. It will still fall back to
`textContent` on browsers that do not support `innerText` (e.g. Firefox 44).

Fixes #17732
2017-06-30 11:54:01 +01:00
40921bb927 docs: add changelog for 4.2.5 2017-06-29 17:19:57 -07:00
dfcca66fdc ci: remove print-logs.sh to try to fix failing builds on Travis 2017-06-29 14:54:34 -07:00
1ac9085b0a docs: add changelog for 4.3.0-beta.1 2017-06-29 14:41:40 -07:00
1cfe67dac4 release: cut the 4.3.0-beta.1 release 2017-06-29 14:38:52 -07:00
8d01db4638 docs: Updated router guide content and examples for paramMap
and queryParamMap, tracing, and incidental improvements.
closes #16991 and #16259 which it also fixes.
2017-06-29 09:35:39 -07:00
4268c82898 feat(aio): use shorter URLs for previews
Use the 7 first characters of the 40-chars long SHAs for shorter/cleaner URLs.
The collision probability is extremely low (since all SHAs are further
"namespaced" under the corresponding PR). In case of a collision, the second PR
will not be deployed, in order to avoid overwriting the original build.

(This is a design decision to keep the implementation simple. It can be changed
later if necessary.)
2017-06-29 09:35:22 -07:00
3c4eef99be fix(aio): clean up non-public previews
The previous clean-up code for PR directories on the preview server assumed that
all directories were named after the PR number. With the changes introduced
in #17640 it is possible to have PR directories that do not follow that naming
convention (e.g. "non-public" directories).

This PR ensures that both public and non-public directories are removed when
cleaning up.
2017-06-29 09:35:22 -07:00
96b17034e1 feat(aio): cross reference readme and docs styleguide 2017-06-29 09:35:04 -07:00
e47a77f941 docs(aio): update punctuation mark added in TOOLS guide 2017-06-29 09:33:12 -07:00
af14b1e384 test(animations): add proper tests to check multiple combinations of :enter/:leave animation queries 2017-06-28 18:18:10 -07:00
40f77cb563 fix(animations): properly collect :enter nodes that exist within multi-level DOM trees
Closes #17632
2017-06-28 18:18:10 -07:00
6c1a8daafc docs: correct grammar in CONTRIBUTING.md 2017-06-27 16:23:57 -07:00
d699c354db fix(animations): do not remove container nodes when children are queried by a parent animation
Closes #17746
2017-06-27 11:00:17 -07:00
34f3832af9 fix(animations): do not delay style() values before a stagger() runs
Closes #17412
2017-06-27 11:00:06 -07:00
f1626574dd fix(aio): build scripts-js before creating a new docker image for the preview server
When creating a new docker image for the preview server, the TypeScript source
code in `scripts-js/` is not copied over. Instead only the generated JavaScript
core in `scripts-js/dist/` are. Because of that, it is necessary to have run
`yarn build` before running `docker build`, so that the new docker image
contains the latest changes in `scripts-js/`.

This was previously part of the `create-image.sh` script, but was accidentally
removed in 21d213dfc.
2017-06-27 10:11:06 -07:00
68fc65dbcb ci: add npm postinstall back to the lint step so node_modules doesn't get out of date 2017-06-26 17:12:06 -07:00
693f79e88a docs: fix spelling of case variants in naming.md
unify variant forms of spelling letter cases (upper-case, uppercase, lower case)
2017-06-26 13:43:37 -07:00
448d9f9f46 test(compiler): add a test for components not part of any NgModule 2017-06-26 13:24:36 -07:00
8786ba95fb build(aio): boilerplate wont be removed by default now 2017-06-26 11:05:34 -07:00
97bb374218 fix(aio): Typo in Setup Anatomy documentation page
Solves #17076
2017-06-26 11:04:46 -07:00
233044e337 docs(aio): fix typo 2017-06-26 11:04:32 -07:00
f365a0f45c docs(aio): animations typos fixed 2017-06-26 11:04:13 -07:00
263c1a1d7e refactor: remove unused imports of the deprecated Renderer 2017-06-23 17:24:40 -07:00
3097083277 feat(compiler-cli): new compiler api and command-line using TypeScript transformers 2017-06-23 16:18:44 -07:00
43c187b624 refactor(forms): remove usage of deprecated Renderer 2017-06-23 16:12:52 -07:00
3165fd3dc9 refactor(router): remove usage of deprecated Renderer 2017-06-23 16:12:43 -07:00
e80851d98b fix(core): add needed closure compiler warning suppression 2017-06-23 14:44:00 -07:00
b754e600e3 feat(compiler): add support ::ng-deep
- /deep/ is deprecated and being removed from Chrome
- >>> is semantically invalid in a stylesheet
- sass will no longer support either in any version of sass

-> use ::ng-deep in emulated shadow DOM mode

Because the deep combinator is deprecated in the CSS spec,
`/deep/`, `>>>` and `::ng-deep` are also deprecated in emulated shadow DOM mode
and will be removed in the future.

see https://www.chromestatus.com/features/6750456638341120
2017-06-23 14:43:42 -07:00
81734cf7b6 refactor(compiler): add tracking comment for self-import detection
The underlying cause of #17386 needs to be investigated and as a
simple string compare should have been valid.
2017-06-23 14:43:24 -07:00
30f4fe26e0 docs(aio): cleanup rollup-config script 2017-06-23 11:55:55 -07:00
d6265dfcbe ci(aio): Change the firebase token 2017-06-23 11:55:20 -07:00
d51f86291f ci(aio): address comments 2017-06-23 11:55:20 -07:00
97ace57d39 ci(aio): fix test 2017-06-23 11:55:20 -07:00
86949e0c20 ci(aio): remove umd 2017-06-23 11:55:20 -07:00
6924780ae9 ci(aio): debug 2017-06-23 11:55:20 -07:00
1b0b69eeec ci(aio): add back deploy-preview 2017-06-23 11:55:20 -07:00
fa85389f62 ci(aio): updated limits 2017-06-23 11:55:20 -07:00
2e55857c82 ci(aio): rename limits file and address comments 2017-06-23 11:55:20 -07:00
ca970f5ee5 ci(aio): Also track umd.min.js file size 2017-06-23 11:55:20 -07:00
204a2cf942 ci(aio): Add payload size limit file 2017-06-23 11:55:20 -07:00
0440251919 ci(aio): upload aio payload size to firebase
ci(aio): Add timestamp and change data
2017-06-23 11:55:20 -07:00
08ecfd891d build: No longer need to bazel build twice 2017-06-23 11:54:51 -07:00
7395a64668 build: circleci workflows to run lint in parallel 2017-06-23 11:54:51 -07:00
979bfd07e1 refactor(aio): provide fallback values for secrets (useful during dev) 2017-06-23 11:54:20 -07:00
b6ce814279 refactor(aio): enable -u flag on preview server scripts 2017-06-23 11:54:20 -07:00
66088fef1a docs(aio): document preview server HTTP status codes 2017-06-23 11:54:20 -07:00
808bd4af41 ci(aio): deploy previews for all PRs
PRs that could not be automatically verified will not be publicly accessible,
until manually verified.
2017-06-23 11:54:20 -07:00
f90b35a85e test(aio): add e2e tests for non-public previews 2017-06-23 11:54:20 -07:00
8ae0eec230 feat(aio): enable previews for any PR
This commit introduces the ability to show previews for PRs by any author. It works as follows:

- The build artifacts of all PRs are uploaded to the preview server.
- Automatically verified PRs (i.e. from trusted authors or having a specific label) are deployed and
  publicly accessible as usual.
- PRs that could not be automatically verified are stored for later use (after re-verification).
- A PR can be marked as "trusted" and make its preview publicly accessible by adding the GitHub
  label specified in the `AIO_TRUSTED_PR_LABEL` env var of the preview server.

At the moment, there is no automatic mechanism for notifying the preview server about changes to the
PR's verification status. The PR's "visibility" will be checked and updated every time a new build
is uploaded.
2017-06-23 11:54:20 -07:00
0fe685102f refactor(aio): simplify preview server build events 2017-06-23 11:54:20 -07:00
a98440bb85 test(aio): add missing unit test for preview server 2017-06-23 11:54:20 -07:00
3112311134 test(aio): fix preview server tests on Windows 2017-06-23 11:54:20 -07:00
1b13bdea4b build(aio): upgrade preview server dependencies 2017-06-23 11:54:20 -07:00
3ce9d51a9c fix(aio): prefix location.assign with window.
No practical effect but clears the TS compiler warning.
2017-06-23 11:53:53 -07:00
14d2de13bb fix(aio): fix links on /about in Firefox
Fixes #17661
2017-06-23 11:53:22 -07:00
5713e7c9b6 refactor(aio): clean up aio-contributor template and styles 2017-06-23 11:53:22 -07:00
87206e1986 fix(aio): preserve newlines when copying code
Before 4f37f8643, we were using `innerText` to retrieved the code content for
copying. This preserved the text layout (including newlines), but suffered from
other issues (browser support, performance). With 4f37f8643 we switched to
`textContent`, which works well except in the following case:
When `prettify` formats the code to have line numbers, it removes the newlines
and uses `<li>` elements instead. This affects `textContent`.

This commit fixes this by keeping a reference of the code as text and using that
for copying.

Fixes #17659
2017-06-23 11:53:01 -07:00
414c7e956b ci: test merge commits on circle
We expect this behavior because it's what Travis does. Also it's better because we want
to test what happens if we merge the PR, not the status of the PR branch.
2017-06-23 11:52:41 -07:00
6191d53a78 docs(aio): Update resources.json - fixed language error 2017-06-23 11:52:22 -07:00
7d30ccc4a9 docs(aio): update resources - Add Compodoc - documentation tool for Angular app 2017-06-23 11:52:22 -07:00
494a0d064a fix(aio): fix topbar nav-item focus style
Fixing it requires upgrading `@angular/material` to v2.0.0-beta.7.

Fixes #17216
2017-06-23 11:51:17 -07:00
849200b576 docs: remove unnecessary newline 2017-06-23 11:50:48 -07:00
60273a941f docs: fix “under to hood” typo in changelog.md
closes #14856
2017-06-23 09:04:40 -07:00
7ba720a62a docs(aio): resources.json - replace “Angular 2” in titles/descriptions
closes #16965
2017-06-23 09:04:21 -07:00
eacc36bbd5 docs(aio): update Bash for Windows info
As of the Creator's Update, Bash on Ubuntu on Windows supports all npm commands. 
https://blogs.msdn.microsoft.com/commandline/2017/04/11/windows-10-creators-update-whats-new-in-bashwsl-windows-console/
Update setup documentation accordingly.
2017-06-23 09:04:04 -07:00
8b4acbbcbf docs(aio): minor fixes for the upgrade guide
Fixes #17093
2017-06-23 09:03:28 -07:00
b1fe63d081 fix(aio): add missing WeakMap polyfill 2017-06-23 09:03:07 -07:00
f2ee1dcdb7 fix(animations): do not validate style overlap errors in different transitions 2017-06-23 09:02:37 -07:00
21018af2bf docs(aio): replace “Angular 1” in upgrade phonecat script 2017-06-22 14:57:02 -07:00
67ffbae6f9 docs(aio): fix promises link in toh-pt4
closes #16050
2017-06-22 14:56:41 -07:00
5dd5bfde72 docs(aio): remove "_" from private property name
follow best practices from the documentation: https://angular.io/guide/styleguide#properties-and-methods
2017-06-22 14:55:42 -07:00
400486ced7 docs(aio): correct typos in Tour of Heroes HeroSearchService 2017-06-22 14:55:17 -07:00
1a947e4b75 docs(aio): Added resources to UI Components (#17635)
docs(aio): Added resources to UI Components
2017-06-22 14:52:58 -07:00
92bcfefc35 docs(aio): remove min, max & move built-in validators paragraph 2017-06-22 14:51:05 -07:00
133b5e6e36 docs(aio): added link to Russian Angular Courses 2017-06-22 14:46:24 -07:00
5c576d3b9d docs: add documentation for LTS versions 2017-06-22 14:45:36 -07:00
68b64a261a docs: add missing colon in the Constants section of NAMING.md 2017-06-22 14:40:33 -07:00
68f939ea8c docs: Fix Stack Overflow being repeatedly misspelt as a single word
(To see that it is two words, see e.g. the page title at https://stackoverflow.com/ or the
spelling at http://stackoverflow.com/tour)
2017-06-22 14:39:10 -07:00
8c129d73b8 docs: Fix some non-code being formatted as code in the router docs 2017-06-22 14:38:55 -07:00
1fc0d05565 docs: add changelog for 4.3.0-beta.0 2017-06-21 17:21:39 -07:00
20a04f9076 release: cut the 4.3.0-beta.0 release 2017-06-21 17:16:04 -07:00
02a38d3ea5 docs: add changelog for 4.2.4 2017-06-21 17:11:19 -07:00
37cdc4f759 docs(aio): ward's changes 2017-06-21 16:21:20 -07:00
b1dab181e0 docs(aio): change to overall prose 2017-06-21 16:21:20 -07:00
fd6c4e371b docs(aio): create author style guide 2017-06-21 16:21:20 -07:00
4352dd27c4 fix(compiler): avoid emitting self importing factories
Fixes: #17389
2017-06-21 16:19:43 -07:00
34cc3f2982 feat(aio): display “Searching ..." while building search index
closes #15923
2017-06-21 14:31:32 -07:00
97fd2480e7 fix(aio): fix patch script on windows
Running the patch script on Windows (with `patch` available) yields an invalid syntax warning, and does not apply patches.

```
kamik@T460p MINGW64 /d/work/angular/aio (master)
$ yarn postinstall
yarn postinstall v0.24.6
$ node tools/cli-patches/patch.js && uglifyjs node_modules/lunr/lunr.js -c -m -o src/assets/js/lunr.min.js --source-map
The syntax of the command is incorrect.
Done in 1.52s.
```
2017-06-21 13:51:35 -07:00
1d93cf2e85 build(aio): ensure all doc tests are run
It is not possible to run all the docs tests directly via the  jasmine CLI.
Instead we now have a small script that will run jasmine via its library.
2017-06-21 13:51:15 -07:00
3fb98fe4ea build(aio): do not recurse node_modules when loading examples in doc-gen 2017-06-21 13:51:15 -07:00
bb804dd3e9 feat(aio): select contributor group with URL “about?group=gde”
closes #17656
also adds test for ContributorListComponent.
2017-06-21 13:50:57 -07:00
0034bb28e5 fix(aio): restore component-styles/exclude hidden children 2017-06-21 11:33:19 -07:00
ca51e020cb fix(aio): redirect "cli-quickstart" to "quickstart" 2017-06-21 11:33:19 -07:00
d16852898f docs(aio): fix numbered list in testing.md
This list renders OK in the github UI but not at https://angular.io/guide/testing#setup
2017-06-20 16:43:26 -07:00
46ddf501a9 fix(tsc-wrapped): skip collecting metadata for default functions
Fixes: #17518
2017-06-20 14:22:49 -07:00
8c89cc4fc5 fix(compiler-cli): find lazy routes in nested module import arrays
Fixes: #17531
2017-06-20 14:21:14 -07:00
00874c27f4 docs(aio): update resource listing 2017-06-20 12:58:02 -07:00
c59c390cdc fix: argument destructuring sometimes breaks strictNullChecks
Destructuring of the form:

function foo({a, b}: {a?, b?} = {})

breaks strictNullChecks, due to the TypeScript bug https://github.com/microsoft/typescript/issues/10078.
This change eliminates usage of destructuring in function argument lists in cases where it would leak
into the public API .d.ts.
2017-06-20 12:56:08 -07:00
009651e14f refactor(core): remove toString() method from DefaultKeyValueDiffer
toString() from DefaultKeyValueDiffer is only used in tests and should not
be part of the production code. toString() methods from differs add
~ 0.3KB (min+gzip) to the production bundle size.
2017-06-20 12:55:20 -07:00
f194f18dbd fix(language-service): infer any ngForOf of type any
Fixes: #17611
2017-06-20 12:04:51 -07:00
4e6be15069 fix(language-service): rollup tslib into the language service package
Fixes: #17614
2017-06-20 11:50:20 -07:00
3e685f98c6 fix(forms): roll back breaking change with min/max directives
With 4.2, we introduced the min and max validator directives. This was actually a breaking change because their selectors could include custom value accessors using the min/max properties for their own purposes.

For now, we are rolling back the change by removing the exports. At the least, we should wait to add them until a major version. In the meantime, we will have further discussion about what the best solution is going forward for all validator directives.

Closes #17491.

----

PR #17551 tried to roll this back, but did not remove the dead code. This failed internal tests that were checking that all declared directives were used.
This PR rolls back the original PR and commit the same as #17551 while also removing the dead code.
2017-06-20 09:04:50 -07:00
6c8e7dd63e revert: fix(forms): temp roll back breaking change with min/max directives
This reverts commit 232bd9395d.
2017-06-20 09:04:50 -07:00
2447bd1bac fix(aio): leave results panel open when opening search result on new page
Fixes #17580
2017-06-19 15:12:46 -07:00
1c6a252596 build(aio): upgrade jasmine to v2.6.4
This version fixes the DISCONNECTED errors (described in #17543) and removes the
need to the workaround (8af203c).
The relevant jasmine commit is jasmine/jasmine@c60d66994.
2017-06-19 15:12:25 -07:00
d3c92a307a fix(router): update the version placeholder so that it gets replaced during the build
Fixes #17403
2017-06-19 15:11:06 -07:00
8f5836cb14 docs(TRIAGE_AND_LABELS): update labels to reflect the current state 2017-06-19 14:53:55 -07:00
319ce182db docs(RELEASE_SCHEDULE): fix version numbers for August/September releases 2017-06-19 14:46:23 -07:00
aa92f3a721 docs(RELEASE_SCHEDULE): update the release schedule w/ recent regression patch releases 2017-06-19 11:33:44 -07:00
afbb6bb797 docs: remove aio from changelog 2017-06-19 11:14:35 -07:00
4f37f86433 fix(aio): switch from innerText to textContent to support older browsers
`innerText` is not supported in Firefox prior to v45. In most cases (at least
the ones we are interested in), `innerText` and `textContent` work equally well,
but `textContent` is more performant (as it doesn't require a reflow).

From [MDN][1] on the differences of `innerText` vs `textContent`:

> - [...]
> - `innerText` is aware of style and will not return the text of hidden
>   elements, whereas `textContent` will.
> - As `innerText` is aware of CSS styling, it will trigger a reflow, whereas
>   `textContent` will not.
> - [...]

[1]: https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#Differences_from_innerText

Fixes #17585
2017-06-19 10:32:36 -07:00
3093c55e9e build(aio): update @angular/service-worker to 1.0.0-beta.16
This version includes a fix for potential cache corruption and invalid redirect behavior in rare cases.
2017-06-16 13:33:37 -07:00
5ac3919259 feat(core): update zone.js to 0.8.12 2017-06-16 12:13:14 -07:00
f58211d9d8 fix(aio): improve no-javascript screen 2017-06-16 12:04:45 -07:00
fe126cb737 fix(aio): remove unused icon reference and file
These icons are not there (and never were afaict).

Fixes #17561
2017-06-16 12:03:43 -07:00
adc1b129e4 fix(aio): correctly redirect /docs/ts/latest and /styleguide
Previously, we had redirect rules for Firebase for `/docs/ts/latest` and
`/styleguide`, but once the ServiceWorker was activated, it would take over
routing and rewrite these requests to `/index.html`.
This commit fixes it by excluding them from ServiceWorker routing.

Fixes #17542
2017-06-16 12:02:52 -07:00
9315ab88d7 test(compiler): fix typo "mamespace" 2017-06-16 11:17:15 -07:00
1ddbddb0db docs: add changelog for 4.2.3 2017-06-16 09:42:31 -07:00
232bd9395d fix(forms): temp roll back breaking change with min/max directives
With 4.2, we introduced the min and max validator directives. This was actually a breaking change because
their selectors could include custom value accessors using the min/max properties for their own purposes.

For now, we are rolling back the change by removing the exports.

Closes #17491.
2017-06-16 09:20:04 -07:00
956a7e95d7 docs(aio): re-add biography entry for devversion
With SHA 2c3e948e61 the biography of Paul Gschwendtner has been accidentally removed.

This re-adds the biography entry (picture still present) as requested on Slack.
2017-06-16 07:56:15 +01:00
ce00fa3627 build(aio): do not fail if check-env for the main angular project fails
Fixes #17434
2017-06-16 07:51:18 +01:00
3515860b15 build: fix link to DEVELOPER.md in check-environment.js 2017-06-16 07:51:18 +01:00
77e717e872 build(aio): remove dependency on build artifacts from parent folder 2017-06-16 07:51:18 +01:00
b46cc744b3 build: remove redundant line
The same value is set a few lines below.
2017-06-16 07:51:18 +01:00
2cc931ed2a fix(aio): add missing redirect rule for /styleguide
Fixes #17542
2017-06-16 07:49:51 +01:00
e096a85874 fix(animations): remove duplicate license header 2017-06-15 14:41:59 -07:00
2c3e948e61 docs(aio): update about page 2017-06-15 07:49:41 +01:00
53f57d74b8 feat(aio): add iphone pwa features 2017-06-15 07:47:49 +01:00
2b1de07f02 docs(aio): incorporate Ward's comments 2017-06-15 07:46:44 +01:00
fb877696bf docs(aio): add short section on built-in validators, copy edits 2017-06-15 07:46:44 +01:00
01173b9441 fix(aio): do not log messages in production
In dev mode, all messages passed to `Logger` will be logged.
In production mode, only warnings and errors will be logged.

Fixes #17453
2017-06-15 07:46:03 +01:00
0564dd25e2 refactor(aio): remove unused Logger dependencies 2017-06-15 07:46:03 +01:00
ba0f6decc3 build(aio): extra redirect rule 2017-06-15 07:45:47 +01:00
06a0cf2e31 docs(aio): http guide shows how to import toPromise operator from rxjs
Solves #17454
2017-06-15 07:45:12 +01:00
a8afa65a54 fix(aio): specify large image for PWA splash-screen 2017-06-14 09:36:54 -07:00
f73a4c229c build(aio): upgrade lighthouse to v2.1 2017-06-14 09:36:54 -07:00
d378a29565 ci(aio): fail the build if the PWA score is too low
Previously, there was an issue with testing the PWA score on staging and failing
the build was temporarily disabled. It works now, so we need to enable failing
the build is the score drops below some threshold.
2017-06-14 09:36:37 -07:00
2bdf2feea7 test(aio): add async beforeEach to prevent Chrome disconnects
Related to 3d5f520ff0 from #17405
2017-06-14 15:29:35 +01:00
607fb1fff8 fix(aio): always cover the whole footer with its background
Fixes #17465
2017-06-14 15:01:06 +01:00
38fc2a0055 fix(aio): fix trackBy demo in template-syntax article 2017-06-14 12:04:59 +01:00
0c07f8c099 test(platform-server): fix and re-enable integration tests 2017-06-13 15:50:23 -07:00
d8d21c77d5 ci: update github templates (#17466) 2017-06-13 14:49:13 -07:00
b4cd20cbbc fix(aio): make the footer links clickable on all browsers
The footer background (implemented via `footer:after`) had a higher `z-index`
than other footer elements and was obscuring the footer links on certain
browsers (Firefox, Edge, IE), which made them unclickable.
This commit lowers the index of `footer:after`, so that links are clickable on
these browsers.

Fixes #17460
2017-06-13 14:05:37 -07:00
f840afb983 ci: disable platform-server integration test as it is currently broken 2017-06-13 14:01:22 -07:00
93d1b4ed9d refactor(compiler): remove duplicate code 2017-06-13 13:37:33 -07:00
fa81c8eeb3 ci: use npm_install for bazel
using yarn_install polluted our node_modules cache because it disregards the npm_shrinkwrap.json
2017-06-13 13:35:01 -07:00
98308cd79c docs(aio): update typescript for examples/webpack to same as cli 2017-06-13 10:28:10 -07:00
052331fabc build(aio): add staging environment
You can now specify what environment you are building
by add it to the `yarn build` command. For example:

```
yarn build -- --env=stage
```

Moreover the `deploy-to-firebase.sh` script will automatically apply the
appropriate environment.
2017-06-13 13:43:36 +01:00
541c9a94bf docs(aio): i18n guide - updates for v4 2017-06-13 12:38:38 +01:00
12452d4ab4 build(aio): increase docs integration test timeouts
The API docs tests have very variable run times, depending
upon the build environment.
This change doubles their test timeout values to prevent
false-negative failures.
2017-06-13 11:56:45 +01:00
709a3f6de7 fix(aio): fix scrolling to elements near the bottom of the page
Previously, we always assumed that elements would be scrolled to the top of the
page, when calling `element.scrollIntoView()`. This is not true for elements
that cannot be scrolled to the top, e.g. when the viewport height is larger than
the height of the content after the element (common for small sections near the
end of the page).
In such cases, we would unnecessarily scroll up to account for the static
toolbar, which was unnecessary (since the element was not behind the toolbar
anyway) and caused ScrollSpy to fail to identify the scrolled-to section as
active.

This commit fixes it by ensuring that we do not scroll more than necessary in
order to align the top of the element with the bottom of the toolbar.

Fixes #17452
2017-06-13 11:54:05 +01:00
7caa0a8aa4 fix(aio): show search results when search box gets focus
Due to a previous commit, the search was only triggered
if the query changed, and not when the search box regained
focus.
2017-06-13 11:26:35 +01:00
0f56296c24 fix(aio): use locally hosted lunr library
The library is downloaded from npm but then
copied into the assets folder (and ignored by git)
as part of the postinstall step.
2017-06-13 11:26:35 +01:00
0a846a2fce fix(aio): make search results better
* update to latest version of lunr search
* add trailing wildcard to search terms to increase matches
* fix unwanted error when escape was pressed

Closes #17417
2017-06-13 11:26:35 +01:00
bffccf4622 fix(aio): fix buttons in "Home" and "Features"
Using `<a>` inside a `<button>` is not syntactically valid HTML and breaks on
some browsers (e.g. Firefox). Furthermore, clicking the button doesn't do
anything unless you click on the link (e.g. clicking on the padding around the
link does nothing), which is inconvenient and confusing.

Fixes #17448
2017-06-13 11:24:36 +01:00
fc774a1871 docs: clarify when non-null-assertion-operator is needed in template-syntax 2017-06-13 08:02:30 +01:00
d647db222c fix(aio): ensure that API filter page can display 3 columns in wide view
Fixes #17251
2017-06-13 07:41:10 +01:00
0c7eb93889 fix(aio): tidy up layout of api filter page
* Remove the "info-banner" styling from the filters.
* Fix alignment of the search box on a narrow screen (closes #17395)
* Remove unnecessary whitespace before section headers
2017-06-13 07:41:10 +01:00
0658e1da7f docs(aio): rename Upgrade docs to cheatsheet 2017-06-13 07:15:05 +01:00
d2d8e5d40f fix(aio): remove outline from search input on focus
Closes #17396
2017-06-13 06:56:21 +01:00
5e794492c1 build(aio): make deploy-to-firebase.sh executable 2017-06-12 16:14:17 -07:00
7a2d2efff8 docs: add changelog for 4.2.2 2017-06-12 15:50:10 -07:00
e95062d1df release: cut the 4.2.2 release 2017-06-12 15:50:10 -07:00
0268818fbb build(aio): update Google Analytics property id for the prod environment
This is the same property ID as the one used by the current angular.io.
2017-06-12 15:49:41 -07:00
234268eec2 ci(aio): deploy commits on the stable branch to production
The current stable branch is determined based on the current version mapped to
the npm `latest` tag (by replacing the patch version number with 'x' - e.g.
`1.2.3` --> `1.2.x`).
PRs against the stable branch will be deployed to the preview server (as long as
the rest of the requirements are met). Commits on the stable branch itself will
be deployed to production.

Fixes #16908
2017-06-12 15:49:22 -07:00
ed73d4f3ac refactor(compiler): don’t always compile .ngfactory.ts files by default
This puts the behavior introduced in 573b8611bc behind the new flag
`alwaysCompileGeneratedCode` to not break users that might have relied
on this behavior.
2017-06-12 15:27:02 -07:00
6ca46929fa fix(animations): properly collect :enter nodes in a partially updated collection
This PR fixes an issue where `query(':enter')` will only collect elements up until it an element that is found that isn't apart of the `:enter` query.

Closes #17440
2017-06-12 15:26:46 -07:00
185075d870 fix(animations): compute removal node height correctly 2017-06-12 12:18:26 -07:00
451257a2fd fix(animations): do not treat a 0 animation state as void 2017-06-12 12:18:15 -07:00
3d5f520ff0 test(aio): fix Chrome getting disconnected during unit tests
Chrome (v58+) often gets disconnected during unit tests (causing them to fail).
This has been happening locally (on Windows) and on Travis. The exact reasons
are not known, but it seems that some of the `AppComponent` tests are to blame.

Based on the discussion in https://github.com/jasmine/jasmine/issues/1327 (and
plenty of trial-and-error), using Jasmine's `done()` callback before each of
test (even calling it synchronously) fixes the issue.
2017-06-12 13:59:44 +01:00
a1065bfaf0 build(aio): upgrade Jasmine-related dependencies
According to https://github.com/jasmine/jasmine/issues/1327#issuecomment-306924549,
this might help with help with frequent DISCONNECTED errors (especially on Travis).
2017-06-12 13:59:44 +01:00
d6f345cc3c build(aio): upgrade Karma-related dependencies 2017-06-12 13:59:44 +01:00
d961911a98 docs(aio): fix broken example in upgrade guide
Fixes #17109
2017-06-11 18:37:27 +01:00
e543272eb3 fix(aio): remove gap between sidenav menus
Fixes #17394
2017-06-11 15:05:04 +01:00
c8c0ceeee9 build(bazel): fix the typescript path in the BUILD file (#17316) 2017-06-09 18:32:36 -07:00
afbc2b0082 build(aio): upgrade purify to deal with messed up comment in animations code 2017-06-09 18:31:50 -07:00
69ec1e2e31 build(aio): upgrade to @angular/*@4.2.1 2017-06-09 18:31:50 -07:00
ff15509bc7 build(aio): turn on webpack 3.0 scope-hoisting 2017-06-09 18:31:50 -07:00
7e22a2fc0b build(aio): remove duplicate webpack version 2017-06-09 18:31:50 -07:00
0a48c92d2c build(aio): upgrade to purify 0.0.24 that supports webpack 3.0 2017-06-09 18:31:50 -07:00
991ca92a9d build(aio): turn off vendor chunking
This was done to prevent webpack from generating cross chunk registry calls which prevent DCE.
2017-06-09 18:31:50 -07:00
c550f885a4 build(aio): upgrade to an unreleased version of cli with webpack 3.0-rc.0 2017-06-09 18:31:50 -07:00
851038c3a8 build(aio): upgrade @angular/service-worker to beta.15 2017-06-09 18:31:50 -07:00
df7774c018 docs(aio): restore animation original value (#17385) 2017-06-09 18:27:11 -07:00
15090a8ad4 docs: add changelog for 4.2.1 2017-06-09 16:11:29 -07:00
8575e3f71c release: cut the 4.2.1 release 2017-06-09 16:04:09 -07:00
90b0713e32 refactor(compiler): don’t write summaries for jit by default
The default is false externally but true internally at Google.
2017-06-09 15:58:53 -07:00
d56b7ed96d docs(aio): reorganise the sidenav menu (#16934)
Reorganizes the items in the sidenav menu and consolidates the quickstart
and cli-quickstart guides into one.
2017-06-09 14:48:53 -07:00
db5e5067a0 build(aio): update typescript to 2.3.2 (#17382) 2017-06-09 14:36:36 -07:00
0020dad595 docs(aio): update examples to 4.2 (#17367) 2017-06-09 14:35:35 -07:00
c2d31fb01e fix(http): move destructuring inside {Request,Response}Options ctor
Previously the RequestOptions/ResponseOptions classes had constructors
with a destructured argument hash (represented by the
{Request,Response}OptionsArgs type). This type consists entirely of
optional members.

This produces a .d.ts file which includes the constructor declaration:

constructor({param, otherParam}?: OptionsArgs);

However, this declaration doesn't type-check properly. TypeScript
determines the actual type of the hash parameter to be OptionsArgs | undefined,
which it then concludes does not have a `param` or `otherParam` member.

This is a bug in TypeScript ( https://github.com/microsoft/typescript/issues/10078 ).
As a workaround, destructuring is moved inside the method, where it does not produce
broken artifacts in the .d.ts.

Fixes #16663.
2017-06-09 14:34:39 -07:00
65d49d5c94 fix(aio): temporarily remove link to source from the API pages (#17371)
We need to come up with a better design (possibly involving an icon button) to
link to the source code (for viewing and/or editing).

Fixes #17254
2017-06-09 14:14:39 -07:00
3a99af2696 docs(packaging): update homepage in @angular/tsc-wrapped (#17352)
Motivation: `yarn outdated`, for exmaple, shows the homepage URL on the command line. If copy-pasting or clicking on the URL, it's nice to see the repo's page instead of a 404.
2017-06-09 13:35:23 -07:00
503fd1fbaf docs(aio): fix image width on the homepage 2017-06-09 13:32:52 -07:00
4c74dba2f3 docs(aio): update events page 2017-06-09 13:32:52 -07:00
33df13ad65 build(aio): update to 4.2 (#17369) 2017-06-09 13:31:12 -07:00
ce18c68eca fix(aio): temporarily remove the focus style of top-bar nav items
Temporarily addresses #17216 until we upgrade to an `@angular/material` version
that includes angular/material2@3bc82f6dc.
2017-06-09 20:37:12 +01:00
2d5623911a fix(aio): sidebar folder state after select item
Closes #17245 and #17253

When the user selects a doc item in the side nav:
1) expand folder(s) leading to the selected doc item
2) on a wide display, keep other already expanded folders open
3) on narrow (mobile) display, collapse other expanded folders

Used to do (3) when wide. Issue #17245 asks for (2).

That logic was bypassed for selected node when we allowed headers to have content
because that unintentionally expanded the header’s folder when selected.
Because the selected node is no longer a header with content, removing this exclusion
also means that folders are expanded/collapsed with above logic even for API pages.
2017-06-09 16:53:54 +01:00
a0b30e5dfb docs(aio): remove example specific .gitignore files
All the files that should be ignored are defined in the
`aio/content/examples/.gitigore` folder.
2017-06-09 14:33:21 +01:00
76a920651c docs(aio): remove cli-quickstart styles.css from git 2017-06-09 14:33:21 +01:00
ef6609a723 docs(aio): remove example specific styles from the shared boilerplate styles.css 2017-06-09 14:33:21 +01:00
c0dcb342f3 docs(aio): create styles.css snippet file for toh-pt5 example 2017-06-09 14:33:21 +01:00
8a9a5ecdd7 docs(aio): move example specific styles into router example app.css file 2017-06-09 14:33:21 +01:00
12c5ead39c docs(aio): do not ignore i18n example js file 2017-06-09 14:33:21 +01:00
3db6b6ca7a build(aio): ignore example files that are gitignored
Rather than hard coding excludes into the dgeni config,
use the fact that we are already ignoring the boilerplate
and generated files via the .gitignore file.
2017-06-09 14:33:21 +01:00
e894f5c399 fix(aio): expand the main content width when there is no ToC
Previously, the main content would always leave a 18% margin on the right to be
occupied by the ToC (even if there was no ToC).
This commit lets the main content expand to the right to occupy all the
available space when there is no ToC.

Fixes #17205
Fixes #17270
2017-06-09 13:33:51 +01:00
8524187869 fix(aio): restrain scrolling inside ToC (when cursor over ToC)
Previously, when scrolling the ToC and reaching the top/bottom, further
mousewheel events would result in scrolling the window (and thus the main
content). This is standard browser behavior. In the case of the ToC though, the
`ScrollSpy` would detect scrolling in the main content and scroll the active ToC
to entry into view, thus resetting the scroll position of the ToC.

Reproduction:
1. Open  `~/guide/template-syntax`.
2. Start scrolling through the long ToC.
3. Try to go to the bottom of the ToC.
4. Once you reach the bottom, the main content starts scrolling down.
5. The first section ("HTML in templates") becomes "active", so the ToC is
   scrolled back up to make its corresponding entry visible.
6. Go back to step 2.

This commit improves the UX, by not allowing the main content to scroll when the
cursor is ovr the ToC and the user has scrolled all the way to the top/bottom of
it.
2017-06-09 10:38:06 +01:00
f7422a9607 fix(aio): animate hamburger in/out
Fixes #17215
2017-06-09 08:17:48 +01:00
cf0a9e0730 docs: add changelog for 4.2.0 2017-06-08 15:38:20 -07:00
8e5beb024f release: cut the 4.2.0 release 2017-06-08 15:38:20 -07:00
576d6d8f86 feat(aio): update the home page and docs landing page content (#17325)
Closes #17268
Closes #17230
2017-06-08 15:26:15 -07:00
41a765d715 fix(aio): re-color code pretty print
closes #17246
2017-06-08 14:00:16 -07:00
f370fd36e0 docs: "TypeScript to JavaScript" code tab renamed “ES6 + Decorators”
closes #17260
2017-06-08 14:00:06 -07:00
a222c3e609 fix(forms): fix min and max validator behavior on non-numbers 2017-06-08 13:59:17 -07:00
5a71df0cb3 build(aio): rename features header 2017-06-08 12:57:42 -07:00
6a46cabb10 docs: security guide images
closes #17263
2017-06-08 12:57:13 -07:00
74673545c0 docs(aio): document the non-null assertion operator 2017-06-08 12:55:19 -07:00
75a311f250 fix(aio): style and fix hover color for features cta button (#17342) 2017-06-08 12:09:33 -07:00
391ed6334d fix(aio): copy code button overlap fix on mobile (#17302) 2017-06-08 12:08:03 -07:00
0940e6d6ed fix(aio): contributor img offset and hover fix (#17338) 2017-06-08 12:00:43 -07:00
4d2ee51bb0 fix(aio): remove glossary l-sub-section class (#17305) 2017-06-08 11:58:49 -07:00
680128bc09 fix(aio): alert, subsection and callout width fix (#17303) 2017-06-08 11:57:09 -07:00
5364b51979 fix(aio): scroll to top immediately when doc changes (#17310) 2017-06-08 11:56:36 -07:00
67ef0f0c8f fix(aio): api list column overflow fix (#17300) 2017-06-08 11:54:57 -07:00
e9886d701d fix(animations): evaluate substitutions on option param values 2017-06-08 10:12:52 -07:00
022835bab2 ci: update Chromium to 464641 (Chrome v59) 2017-06-08 09:36:35 -07:00
8be2e4c325 fix(aio): make the ToC left hand-side bar shorter (#17280)
Make the ToC left hand-side bar shorter, so that it starts at the initial bullet
and ends at the final bullet.

Fixes #17221
2017-06-08 00:56:00 -07:00
33ba3e31ed fix(aio): smoother transition from page with SideNav to homepage (#17312)
When navigating from a page with open SideNav to a page without closed SideNav,
the main content area animates from a non-zero left margin to zero left margin.
Additionally, the top-bar on the homepage is transparent, which allows the white
background behind the main content to be seen while the left margin is animated
to zero, making it appear as if something (e.g. the SideNav covers the top-bar).

This commit works around this issue, by not making the top-bar transparent
immediately when navigating to the homepage, but animating it from its blue
color to transparent with a delay.

Fixes #17248
2017-06-08 00:49:54 -07:00
cba2b3c72d docs(aio): add “nougat” to compat chart
closes #17262
2017-06-07 12:40:50 -07:00
a4a2901294 fix(aio): remove ... separator from search results
An ellipsis was used to separate the most relevant search
results from the alphabetic list. The separator was confusing
because it was not clear what it represented.

This has been removed and the most relevant results are now
indicated by styling with a more bold font and a bit of whitespace
between them and the rest of the results.

To keep things consistent, if there are fewer than 5 results all the
results are now displayed as priorityPages.

Closes #17233
2017-06-07 12:40:39 -07:00
bb46f54ad7 refactor(aio): use the SelectMenuComponent for all select menus
The API filters and the docs version switcher now use
the SelectMenuComponent.

Fixes #16367 and #17055
2017-06-07 11:27:10 -07:00
c9b930dd82 feat(aio): add aio-select component
Provide the functionality for select menus in a single reusable component.
2017-06-07 11:27:10 -07:00
a39f7d63bb docs(aio): use h1 rather than divs and hide heading anchors
In the marketing pages we do not want to show heading anchors on hover.
Previously, this was achieved by using div rather than heading elements.
Now we can use semantically accurate headings while hiding the anchor.

Closes #17244
Closes #17264
2017-06-07 11:26:27 -07:00
e317f7d51c feat(aio): do not display anchor if heading has no-anchor class 2017-06-07 11:26:27 -07:00
3ddd28d37d fix(aio): update contrast on mediumgray color 2017-06-07 11:26:13 -07:00
fe6b39d585 perf(animations): do not create a closure each time a node is removed 2017-06-07 11:16:17 -07:00
d837bfc2d7 fix(aio): fix scrolling to an element
Previously, the top-bar's height wasn't taken into account when scrolling an
element into view. As a result, the element would be hidden behind the top-bar.
Taking the top-bar height into account was not necessary before #17155, because
the top-bar was not fixed (i.e. it scrolled away).

This commit fixes the scrolling behavior by accounting for the top-bar's height
when scrolling an element into view.

(This partially reverts #17102.)

Fixes #17219
Fixes #17226
2017-06-07 14:37:46 +01:00
4759975be6 fix(aio): adjust SideNav top to avoid extra whitespace
Partially addresses #17096.
2017-06-07 13:37:30 +01:00
078a4b00a7 fix(aio): fix button alignment and jump
- Fix alignment on get started button on home page
- Remove jump by removing arrow from learn more button on home page
2017-06-07 09:11:20 +01:00
b00b80a45b feat(compiler-cli): introduce synchronous codegen API 2017-06-06 14:12:02 -07:00
269bbe0e7d fix(upgrade): call setInterval outside the Angular zone
This wraps the $interval service when using upgrade to run the
$interval() call outside the Angular zone. However, the callback is
invoked within the Angular zone, so changes still propagate to
downgraded components.
2017-06-06 14:11:21 -07:00
bb2fc6b8da refactor(platform-browser): Remove setGlobalVar from DOM adapter 2017-06-06 13:26:23 -07:00
d4e196035c build(aio): update features and presskit marketing pages 2017-06-06 13:08:48 -07:00
b8979c8701 fix(aio): fix and clean up topbar styling
Restore the changes introduced in #17075, which wre accidentally overwritten
while rebasing #17155. Also, simplify the topbar positioning rules.
2017-06-06 13:08:39 -07:00
bfdd3398f6 fix(aio): make ScrollSpy respond quicker to scroll events
Fixes ##17220
2017-06-06 13:08:30 -07:00
3a121a621f build(aio): migrate contribute page to html 2017-06-06 16:38:29 +01:00
c06f4fc702 docs(aio): remove tutorial from docs landing page 2017-06-06 16:38:09 +01:00
95f1ea2f12 fix(aio): topnav toolbar position styles
- Fixed topnav on all mobile
- Fixed topnav on all docs pages
- Absolute topnav on all marketing pages
- Cleanup and code consolidation for all top-menu styles
- Add styling to topnav links on focus
2017-06-06 14:51:19 +01:00
784347f61f fix(aio): ensure all views can indicate the active node (#17194)
When more than one node matches a url, the last
node defined in the navigation.json file won. This
meant that, for instance, items in both the
TopBarNarrow and the Footer views would not
indicate that they were active.

Now, each url is associated with a map of current
nodes keyed off their view.

Closes #17022
2017-06-05 23:36:22 -07:00
42176a7ac4 build(aio): upgrade ngo and purify (#17210) 2017-06-05 23:03:26 -07:00
76b4b80a23 fix(aio): fix search box overlap for small devices (#17075)
- Adjust search box height
- Adjust search box standard width and width for smaller devices
- Fix search jump outside of specified max width
2017-06-05 22:57:17 -07:00
7c78282ce8 docs: fix typo in 'Routes' docs 2017-06-05 11:18:43 -07:00
47c2a2e411 ci: switch CircleCI to 2.0
This lets us use a docker container to provide things like the Bazel build tool
2017-06-05 11:18:20 -07:00
5faf520067 build: Introduce Bazel build rules
So far this just compiles the core and common packages.
2017-06-05 11:18:20 -07:00
02d74cafba ci: update pullapprove to reflect animation ownership 2017-06-05 11:17:24 -07:00
734f30d14c build(aio): ignore .ngsummary.ts files in examples 2017-06-05 11:12:59 -07:00
f2d810febc fix(aio): fix ToC styling
- Make the left bar gray (instead of blue).
- Show gray dot when hovering over an element.
- Hide left bar and dots in embedded mode.
2017-06-04 15:12:29 +01:00
819514aeba fix(animations): ensure web-animations understands a numeric CSS perspective value
Closes #14007
2017-06-02 17:05:15 -07:00
b55adee982 perf(animations): only apply :leave flags if animations are set to run 2017-06-02 17:05:06 -07:00
4c32cb952f fix(router): opening links in new window
Shift-clicks on router-links should not prevent browser default action.

A follow on to:
1ac9dda93d
2017-06-02 17:32:12 -04:00
35f714e438 fix(aio): place progress bar at the top
Previously, the progress bar would be placed right under the static top bar. Now
that the top bar i not tatic any more, it makes more sense to place the progress
bar at the top of the page.

Fixes #17103
2017-06-02 17:31:53 -04:00
d5ce086089 build(aio): fix up API doc-gen templates
* Remove whitespace before type specifiers
* Generate `new` and `call` member info for interfaces
* Ensure that there is no double space after class names
2017-06-02 13:18:09 -04:00
82ec02daf8 docs: add changelog for 4.2.0-rc.2 2017-06-01 14:27:41 -07:00
8e7a3f031b release: cut the 4.2.0-rc.2 release 2017-06-01 14:25:19 -07:00
7822187b17 fix(aio): fix scrolling to top (#17102)
Previously, the `#top-of-page` element (used when scrolling to top) was placed
inside the content section (which at the time had zero top margin and padding).
Furthermore, there was a top offset applied when scrolling that took the static
top bar's height into account. Since now the top bar is not static any more and
the content section has a non-zero top padding, scrolling to top does not work
as expected.

This commit fixes this by:
- Moving the `#top-of-page` element to the top of the `aio-shell`.
- Stop accounting for the top bar's top.

Fixes #17006
2017-06-01 14:03:10 -07:00
068133ec85 fix(animations): do not retain deleted nodes during an non-removal animation (#17153)
Closes #17086
2017-06-01 14:02:41 -07:00
598fdad089 docs: update the release schedule (#17162) 2017-06-01 13:23:34 -07:00
ad6a57e0a3 perf(animations): do not place enterId values on elements for querying purposes (#17150) 2017-06-01 11:39:53 -07:00
230255f887 feat(compiler-cli): produce template diagnostics error messages (#17125)
Refactoring the compiler to use transformers moves the code generation
after type-checking which suppresses the errors TypeScript would
generate in the user code.

`TypeChecker` currently produces the same factory code that was
generated prior the switch to transfomers, getting back the same
diagnostics as before. The refactoring will allow the code to
diverge from the factory code and allow better diagnostic error
messages than was previously possible by type-checking the factories.
2017-06-01 10:13:50 -07:00
1338995ee9 fix(aio): fix home learn more button alignment (#17154) 2017-06-01 09:37:42 -07:00
47e4fca7fd fix(aio): swap feature headers for divs to remove anchors and fix feature image resizing (#17156) 2017-06-01 09:37:27 -07:00
665e7071fa fix(animations): always change to desired animation state even if no transition fires (#17025)
Fixes #16947
2017-05-31 15:36:41 -07:00
c20f60b144 fix(router): make remove trailing slash consistent with URL params
closes #16069
2017-05-31 14:35:47 -07:00
1408357198 docs: add details about the WeakMap polyfill for 4.x in the changelog (#17146) 2017-05-31 14:34:51 -07:00
1f9a3dd1e6 fix(aio): fix typo in web worker check (#17133) 2017-05-31 05:43:55 -05:00
11505fa0d8 fix(aio): disable search on browsers that don't support web workers 2017-05-31 05:22:39 -05:00
9326e062d8 fix(aio): googlebot polyfill fix 2017-05-31 05:22:39 -05:00
cb2cb7c3bd build(aio): display "call" and "new" members of interfaces in API docs 2017-05-31 08:45:50 +03:00
92d99ba279 build(aio): upgrade to dgeni-packages 0.19.1
This provides the fix where static class members were not being displayed
in API docs, closes #17024
2017-05-31 08:45:50 +03:00
dfbbbb5e3e build(aio): the the captured h1 as the title for the search index
If there is no title already provided, use the one captured from the renderedContent.
2017-05-31 08:45:31 +03:00
89f317915d build(aio): use the captured h1 as the title if necessary
If the doc does not already have a `title` tag
then use the one captured from the renderedContent in
the final JSON output, instead.
2017-05-31 08:45:31 +03:00
4d5fa5c855 build(aio): capture the h1 title and attach it to the document
The HTML post-processing now collects any h1
that is found in the renderedContent and attaches
it to the doc via the `doc.vFile.title` property.
2017-05-31 08:45:31 +03:00
2f35392cd8 fix(aio): make the search-pane larger (and improve the search-box) (#17105)
* fix(aio): make the search-pane larger

Fixes #17094

* feat(aio): give the search-box a type of "search"

This enables browsers to style it better (e.g. add an `x` button for clearing
the field, which allows users to quickly reset the search query and hide
results).
2017-05-30 15:15:54 -07:00
b056adc032 fix(aio): fix SideNav items alignment (#17106)
Fixes #17097
2017-05-30 15:15:43 -07:00
0d894a18fc fix(aio): fix ToC styling (#17110)
There seems to have been a bad rebase of #16228 on top of #16959, which affected
ToC styles from both PRs. This commit restores the horizontal line under `.h1`
elements and the vertical blue bar on the left-hand side of the ToC (with the
circle running along the bar to indicate the active section).

Fixes #17098
2017-05-30 15:15:31 -07:00
e5138081ec build: update router package.json placeholder (#17060) 2017-05-30 13:19:54 -07:00
8ffa483bb6 fix(compiler): enableLegacyTemplate should not be ignored (#17051)
Fixes #15555
2017-05-30 13:19:42 -07:00
ea8a43def0 feat(tsc-wrapped): always convert shorthand imports (#16898)
Now converts shorthand imports for every TypeScript target. Tsickle is able to expand index shorthand imports for every TypeScript target and module possibility.

Expanding shorthand imports for CommonJS modules is also helpful when testing in the browser. Module loaders like SystemJS are not able to understand directory imports (or index shorthand imports)
2017-05-30 10:46:54 -07:00
535d9da6b6 fix(common): always use 'other' case for locales with no plural rules (#16990)
Locales with no rules were using the wrong plural rule instead of the default.
2017-05-30 10:46:36 -07:00
18bf77204e feat(compiler): emit typescript nodes from an output ast (#16823) 2017-05-30 10:43:13 -07:00
160221c815 test(platform-server): fix target of TS outDir for integration test (#17118) 2017-05-30 10:40:03 -07:00
6220b49463 build(aio): upgrade to ngo with top-level NewExpression and CallExpression prefixing (#17063) 2017-05-27 11:46:52 -07:00
aa683a765d fix(aio): add polyfill for GoogleBot (#17062)
I chose to use unknown=polyfill option as per recommendation found at https://github.com/Financial-Times/polyfill-service/issues/852#issuecomment-272097936
2017-05-27 11:44:53 -07:00
b8b91d3418 feat(aio): marketing design refresh
- Add styling for active TOC item
- Add sidenav styles
- Change header tags to divs from index marketing page to remove anchors
- Fix use of card mixin and create separate card-docs class
- Add marketing styling
- Topnav styling when on home landing page
- Remove hamburger menu on home page
- Add fully rounded border to top nav toolbar search input
- Add mobile styles
- Add title banner to other marketing pages
2017-05-27 07:24:03 +01:00
0018acfede fix(aio): remove es2015 syntax from the onerror webmaster tools debugger (#17056) 2017-05-26 16:48:55 -06:00
51d7a65a2b docs: add changelog for 4.2.0-rc.1 2017-05-26 14:38:41 -07:00
a1724f7816 release: cut the 4.2.0-rc.1 release 2017-05-26 14:32:20 -07:00
d108479d84 fix(animations): use a lightweight renderer for non-animation components (#17003)
This reverts commit c0981b8e13.
2017-05-26 14:39:42 -06:00
cd5bc64658 docs(aio): update headers for toc (#16969) 2017-05-26 13:28:06 -06:00
5f723cb92c feat(aio): temporarily add debugging code for google crawler (#17046) 2017-05-26 13:25:33 -06:00
7ffb75f476 refactor(compiler): change bundle to flatModuleIndex in the code (#17028) 2017-05-26 09:13:28 -07:00
c0981b8e13 Revert "fix(animations): use a lightweight renderer for non-animation components (#17003)"
This reverts commit 3ab86bd661.
2017-05-26 08:55:23 -07:00
80e506563c Revert "refactor(compiler): change bundle to flatModuleIndex in the code (#17028)"
This reverts commit 5aa53d70aa.
2017-05-26 08:54:50 -07:00
694951096c feat(aio): provide noop service worker file
Use this file if we need to turn off the service worker in deployed sites
in an emergency where the worker has a bug that is blocking the application
from working.

Closes #16897
2017-05-26 14:24:41 +01:00
9e7e178585 build(aio): add google webmaster tools verification file
this file needs to remain in the repo for us to remain verified as owners of aio-staging.firebaseapp.com.
2017-05-26 01:25:58 -07:00
db3113ba16 build(aio): externalize @angular/cli patches into a js file
This improves code readability and maintainability.
2017-05-26 01:19:59 -07:00
3117f565c1 ci(aio): switch over to shared account for deployment to staging and production 2017-05-26 01:19:59 -07:00
8443d199b2 build(aio): use purify to include tslib
cli's scripts setup evals strings which requires too much escaping that bloats the code
2017-05-26 01:19:59 -07:00
8e2f72c644 build(aio): turn on pure_getters option in uglify 2017-05-26 01:19:59 -07:00
0c1d1e2396 build(aio): upgrade purify to 0.0.11 with better coverage 2017-05-26 01:19:59 -07:00
740450287d build(aio): upgrade ngo to 0.0.3 with static prop unhoisting 2017-05-26 01:19:59 -07:00
0c691af1d2 build(aio): start using tsc importHelpers option for the app
this means we'll be temporarily duplicating the helpers (onces included via scripts
and secondly imported via es imports) - once rxjs, core and material migrate over
to tslib, we can drop the scripts/global dupe.
2017-05-26 06:02:12 +01:00
5aa53d70aa refactor(compiler): change bundle to flatModuleIndex in the code (#17028) 2017-05-25 19:02:35 -06:00
3ab86bd661 fix(animations): use a lightweight renderer for non-animation components (#17003) 2017-05-25 18:54:35 -06:00
2538094e13 fix(aio): group topbar items into a single sidenav node when narrow screen (#17001)
The `TopBarNarrow` now only shows a single top level container, "About Angular",
and the original `TopBar` items will be children of this container.

The `TopBarNarrow` styling is changed to match the rest of the `SideNav`.
2017-05-25 17:44:27 -06:00
b37a0484d4 docs(aio): restore missing files (#16995) 2017-05-25 17:44:03 -06:00
4c5e28e53a build(aio): less verbose boilerplate generator (#16970) 2017-05-25 17:43:46 -06:00
e10d763446 fix(aio): correctly handle re-navigation to the empty path (#16997) 2017-05-25 17:43:34 -06:00
573b8611bc fix(compiler): compile .ngfactory.ts files even if nobody references them. (#16899)
This is especially important for library authors, as they will
not reference the .ngfactory.ts files.

Fixes #16741
2017-05-25 11:00:26 -06:00
966eb2fbd0 aio: add h1 title to floating table of contents (#16959)
* refactor(aio): use explicit CSS class for TOC container

This makes the styling less fragile to changes in the HTML

* fix(aio): schedule TocComponent.activeIndex updates via AsapScheduler

We use the `asap` scheduler because updates to `activeItemIndex` are triggered by DOM changes,
which, in turn, are caused by the rendering that happened due to a ChangeDetection.

Without asap, we would be updating the model while still in a ChangeDetection handler,
which is disallowed by Angular.

* refactor(aio): do not instantiate floating ToC if not displayed

* feat(aio): display the h1 at the top of the floating TOC

Closes #16900

* refactor(aio): combine the TOC booleans flags into a "type" state

* refactor(aio): remove unnecessary `hostElement` property

* fix(aio): ensure that transition works on TOC

* fix(aio): use strict equality in ToC template
2017-05-24 14:09:55 -06:00
b0c5018c70 build(aio): better error message for invalid links (#16993) 2017-05-24 11:59:06 -06:00
19a509a92c fix(aio): use a special version of the TopBar if the screen is narrow
If there is a `TopBarNarrow` nav view then use this when the screen is narrow.
Otherwise just use the normal `TopBar`.

This commit also creates such a narrow topbar view where the "Docs" item is
in a different position

Closes #16940
2017-05-24 09:01:57 +01:00
9e17a147ec fix(aio): align top-level nav-items consistently
Fixes #16939
2017-05-24 08:21:41 +01:00
eba59aaf87 refactor(compiler): add ability to produce stub .ngfactory / .ngsummary files (#16963)
These files are needed so that:
- user code can compile even without real codegen
- as tsc transformers cannot create but only change existing files
  in the transformation pipeline.
2017-05-23 14:40:50 -06:00
fa809ec8cf build: import tslib rather than output TS helpers (#16901) 2017-05-23 14:01:39 -06:00
1651a8f189 fix(tsc-wrapped): ignore |null and |undefined when collecting types (#16222) 2017-05-23 11:53:38 -06:00
27761b4500 fix(compiler): do not report type errors for arguments with @Inject (#16222)
Fixes #15424
2017-05-23 11:53:38 -06:00
a80ac0a8d3 fix(core): make decorators closure safe (#16905)
This is required as e.g. `token` from `@Inject` is
accessed in string form via makeParamDecorator
but as a property in the `ReflectiveInjector`.

Closes #16889 as this is a more general fix.
2017-05-23 11:52:40 -06:00
5af143e8e4 refactor(compiler): allow sync AOT compilation (#16832).
AOT compilation can be executed synchronously now,
if the `ReosurceLoader` returns a string directly
(and no `Promise`).
2017-05-23 10:41:23 -06:00
255d7226d1 ci: add vicb as owner to compiler-cli (#16832) 2017-05-23 10:41:23 -06:00
50abca4583 refactor(compiler): don’t rely on global reflector (#16832)
Using the global reflector made it impossible
to compile multiple programs at the same time.
2017-05-23 10:41:23 -06:00
de8d7c65f2 refactor(compiler): emit OutputAst and not sources (#16832)
This is in preparation for creating typescript nodes
directly from `OutputAst` nodes.
2017-05-23 10:41:23 -06:00
6123b9c0c6 refactor(compiler): make OutputAst contain the moduleName, not the filePath (#16832).
The goal of this change is to simplify the emitters,
as we will soon create a new one to emit TypeScript nodes directly.
2017-05-23 10:41:23 -06:00
3b28c75d1f test(aio): avoid warnings from Material during tests 2017-05-23 08:00:07 +01:00
368169dc15 feat(aio): add progress bar
closes #16110
2017-05-23 08:00:07 +01:00
f5b2ce0206 docs: update the release schedule (#16943) 2017-05-22 18:38:31 -06:00
78e3be12a4 docs: update the release schedule (#16942) 2017-05-22 18:25:49 -06:00
e7d9fd8056 fix(animations): repair flicker issues with WA polyfill (#16937)
Fixes #16919
Fixes #16918
2017-05-22 17:57:16 -06:00
08dfe91b95 feat(compiler): add location note to extracted xliff2 files (#16791)
Add source location as a note tag as `<note category="location">path/to/file.ts:start_line[,end_line]</note>`.
`[,end_line]` part is optional and specified only if the end line is different from the start line.

Fixes  #16531
2017-05-22 12:20:45 -06:00
85d4c4b82e feat(core): update zone.js to 0.8.10 and expose the flush method (#16860)
`flush()` can now be used from within fakeAsync tests to simulate moving
time forward until all macrotask events have been cleared from the
event queue.
2017-05-22 12:19:21 -06:00
6e41add867 feat(tsc-wrapped): support template literals in metadata collection (#16880)
Fixes: #16876
2017-05-22 12:19:09 -06:00
11c10b2ab8 fix(tsc-wrapped): resolve short-hand literal values to locals (#16873)
Fixes: #16872
2017-05-22 11:18:44 -06:00
98849de127 build: fix public-api:update gulp task (#16859)
PR #16834 makes the task faster but it doesn't work any more!
Reverting to the slower but correct task for now.
2017-05-22 11:07:21 -06:00
afd703d08c build: remove router-specific versioning process (#16810) 2017-05-22 11:06:46 -06:00
ce18fdb399 fix(aio): use the current version in the version picker
Previously we hardcoded the current version into the navigation items.
Now only previous versions are included there. The current version is
computed from the currentVersion info.

Closes #16909
2017-05-22 13:48:07 +01:00
670771da33 build(aio): make the postinstall script more Windows-friendly 2017-05-21 15:37:22 +01:00
c8b08f3a59 feat(aio): implement ScrollSpy service (to highlight the active section in ToC) 2017-05-20 12:08:38 +01:00
3d382dc750 docs: add changelog for 4.2.0-rc.0 2017-05-19 16:03:18 -07:00
9081f84543 release: cut the 4.2.0-rc.0 release 2017-05-19 15:54:52 -07:00
f1a9e3c1bb feat(animations): introduce routeable animation support 2017-05-19 13:45:22 -07:00
b10029c18b docs(animations): add documentation for new animation features 2017-05-19 12:52:04 -07:00
5d4f5434fd refactor(router): don't run the change detection every time an outlet is activated
fix(router): inside on push // SQUASH after review
2017-05-19 11:55:15 -07:00
81ca51a8f0 refactor(router): cleanup, simplification 2017-05-19 11:55:15 -07:00
6cb93c1fac fix(animations): only require one flushMicrotasks call when testing animations 2017-05-19 10:45:20 -07:00
eed67ddafb feat(aio): update aio-shell class when sidenav opens or closes 2017-05-19 14:10:00 +01:00
be9e8b99ff fix(aio): support IE via conditionally loaded polyfills
Closes #16519
2017-05-19 11:26:29 +01:00
8a0e5659c0 docs(aio): tidy up docs that use float clearing
Closes #16681
2017-05-19 09:47:53 +01:00
2842b0cc3d fix(aio): ensure that subsections clear floats correctly 2017-05-19 09:47:53 +01:00
a42322da0c feat(aio): code copy button has tooltip and aria-label
Based on optional title passed in from parent element such as CodeExample or CodeTabs.
Darkens uncovered copy button slightly as recommended for a11y.
PR #16808
2017-05-19 09:42:48 +01:00
4ccb2269a5 feat(aio): buttons for TOC "Contents" label
- Use buttons for the TOC “Contents” label when embedded-and-expandable or TOC on the right to satisfy a11y.
- Add aria-pressed setting for the toggles in TOC and NavItem.
- Clicking the right panel TOC “Contents” button scrolls to top.
- When embedded use same rotating caret as sidebar
- When embedded and no secondaries, “Content” is just a label.
- Gray background for focused buttons rather than outline because can’t get carets to work with outline.
2017-05-19 09:42:30 +01:00
b836aca999 docs(aio): rework of the upgrade guide
This commit was worked on by a number of people including
@filipesilva, @gkalpak and @wardbell. It contains changes that:

* remove unused files,
* fix the bootstrap approach to ensure that bootstrap is in the correct Zone
* fix unclosed code-example tags
* replace use of "we" with "you"
* remove broken dual router example

Related to angular/angular.io#3541
2017-05-19 09:42:17 +01:00
7d9f96abf0 fix(animations): make sure reuseable animation subtitutions work without default params (#16875) 2017-05-18 12:59:54 -07:00
86b7bd9c8e revert: refactor(router): cleanup, simplification
This reverts commit 44d48d9d7a.
2017-05-18 11:57:22 -07:00
a0a6029915 revert: refactor(router): don't run the change detection every time an outlet is activated
This reverts commit 198edb3109.
2017-05-18 11:57:22 -07:00
6531806996 build(aio): do not ignore is-on-https in lighthouse check
Lighthouse v1.6.5 treats localhost/1.2.7.0.0.1 as secure domains (i.e. as if they where HTTPS), so we need to stop handling the is-on-https audit specially.
2017-05-18 15:48:49 +01:00
3a604ba0bf fix(aio): fix PWA testing on Windows (and reduce flaky-ness)
Adding a delay after Lighthouse has run and before killing the Chrome process
avoids `ECONNREFUSED` errors on Windows and will hopefully prevent such errors
occasionally appearing on CI.

Based on info in:
https://github.com/paulirish/pwmetrics/issues/63#issuecomment-282721068
2017-05-18 15:48:49 +01:00
39f2977fa8 fix(aio): fix up typing errors in tests
The new version of Jasmine types identified issues with our unit tests.
2017-05-18 15:48:49 +01:00
faacbe4dac build(aio): upgrade to @angular/cli@1.1.0-rc.0 2017-05-18 15:48:49 +01:00
47c72e4627 perf(aio): load reflect-metadata polyfill only in the dev mode 2017-05-18 15:48:49 +01:00
59136fdbe4 build(aio): add ngo + purify 2017-05-18 15:48:49 +01:00
35d1922006 ci(aio): log the full PWA testing results
This will help diagnose errors or regressions in PWA scores.
2017-05-18 15:48:49 +01:00
b40aae54b7 fix(aio): fix PWA testing in cases where atob/btoa is necessary
In some cases (unclear when), traceviewer-js, used by Lighthouse under the hood,
assumes `atob`/`btoa` are defined in the global scope. This is true for browser
environments, but not on node.

As a result, some aggregations that required access to model-tracing failed to
produce results, dropping the overall PWA score.

This affected #16665 (e.g. commit 0de6eec7a).
2017-05-18 15:48:49 +01:00
baa3fbab46 build(aio): upgrade @angular/* and friends, remove obsolete deps 2017-05-18 15:48:49 +01:00
3361a7b834 build(aio): minor update-preview-server.sh improvements 2017-05-18 14:41:54 +01:00
0e13a5956c fix(aio): add small delay before autoscrolling
This delay allows any async layout to complete
before we autoscroll to a heading anchor.

Closes #16242
2017-05-18 14:37:45 +01:00
9466908c22 build(aio): add script for updating the preview server 2017-05-18 08:21:25 +01:00
93d27d283a build(aio): fix syntax error in preview server's Dockerfile 2017-05-18 08:21:25 +01:00
6f59a4a5b2 docs(aio): minor docs fixes for aio-builds-setup/ 2017-05-18 08:21:25 +01:00
71c3103312 build(aio): reduce images weight 2017-05-18 08:20:10 +01:00
198edb3109 refactor(router): don't run the change detection every time an outlet is activated 2017-05-17 19:32:04 -07:00
44d48d9d7a refactor(router): cleanup, simplification 2017-05-17 19:32:04 -07:00
712630ca65 perf(animations): reduce size of animations bundle
before:
animations.umd.js = 33k
animations.umd.min.js = 9.0k

after:
animations.umd.js = 31k
animations.umd.min.js = 7.9k
2017-05-17 16:30:36 -07:00
6416e79933 build: do not create the bundles when updating the public API
- 1.7x faster on my machine (2.7 vs 4.6 min)
- should solve the memory issue
2017-05-17 08:34:50 -07:00
238c5238a5 fix(aio): remove searchbox shrink animation 2017-05-17 08:22:28 +01:00
593fe5ed25 build(aio): enable HTTP/2 on the preview server (#16826)
Fixes #16780
2017-05-16 21:07:28 -07:00
54a6e4ff9e refactor(animations): make animation testing work with fixture.whenRenderingDone 2017-05-16 17:39:57 -07:00
8a6eb1ac78 refactor(animations): single animation engine code pass 2017-05-16 17:39:57 -07:00
16c8167886 feat(animations): introduce a wave of new animation features 2017-05-16 17:39:57 -07:00
d761059e4d fix(compiler-cli): allow '==' to compare nullable types (#16731)
Fixes: #16729

* fix(compiler-cli): diagnose issues in conditional of ternary

Fixes: #16730
2017-05-16 16:36:51 -07:00
c805082648 fix(platform-server): wait for async app initializers to complete before removing server side styles (#16712)
This fixes a flicker when transitioning from server rendered page to client rendered page in lazy loaded routes by waiting for the lazy loaded route to finish loading, assuming initialNavigation on the route is set to 'enabled'.

Fixes #15716
2017-05-16 15:14:55 -07:00
9a7f5d580f ci: update build to use TypeScript 2.3.2 (#16707) 2017-05-16 13:29:38 -07:00
af99cf2a41 build(aio): compute `{@link ...} titles more effectively (#16813)
If a usage of `{@link ...}` does not provide a title then
compute it based on the `title` and/or `name` properties
or set the link to invalid.

Closes #16811
2017-05-16 10:21:31 -07:00
221f85af3f fix(aio): no white band below toolbar when mobile
At 600px wide, the buttons on tool bar shrank from 64 to 56px.
Should shrink the content’s top padding from 64 to 56 as well.
2017-05-16 10:43:12 +01:00
a68ad6d58d feat(aio): sidenav headers should be focusable buttons
Sidenav headers had been anchors w/o hrefs. These can’t take focus which makes you can’t navigate through them with keyboard. For a11y purposes, this PR turns them into buttons.
2017-05-16 10:02:08 +01:00
7ae0440cca docs(aio): remove fundamentals/techniques intro pages 2017-05-16 09:45:48 +01:00
2ee7662737 test(aio): remove compileComponents from all tests
By reflex we began all component tests with an async `beforeEach` that called `compileComponents`.
In at least one case (`live-example.component.spec.ts`) that led to the `it` tests being async as well.
There is no need to call `.compileComponents` because CLI web pack + plugin inlines all templates and styles.
While `.compileComponents` was harmless, it added complexity and distraction which we should not inflict on future readers and testers.
2017-05-16 09:45:04 +01:00
44195858e6 docs(aio): fix toh e2e test 2017-05-16 09:42:59 +01:00
39b92f7e54 feat: introduce TestBed.overrideProvider (#16725)
This allows to overwrite all providers for a token, not matter
where they were defined.

This can be used to test JIT and AOT’ed code in the same way.

Design doc: https://docs.google.com/document/d/1VmTkz0EbEVSWfEEWEvQ5sXyQXSCvtMOw4t7pKU-jOwc/edit?usp=sharing
2017-05-15 13:12:10 -07:00
1eba623d12 fix(compiler-cli): import routing module with forRoot (#16438) 2017-05-15 13:11:39 -07:00
ea2b24fb4e fix: add typescript 2.3.2 typings test (#16738)
Closes #16663
2017-05-15 13:10:43 -07:00
a9d9aa18a0 build(aio): automatically link code blocks to API docs 2017-05-15 10:56:38 +01:00
ecc356ecea fix(aio): set focus back to search box on "escape"
For improved accessibility, the focus should be sent
back to the input box when we are displaying the
search results and the user hits ESC.

See #16005
2017-05-14 15:46:24 +01:00
98e31290a7 refactor(aio): centralise search ui management
Previously the logic for deciding when to display
the search result was spread between different
parts of the application and used non-intuitive logic
such as sending a blank results set to the searchResults.

This commit moves the management of displaying
the search results (and also setting focus of the
search input box) to the AppComponent. This makes
it easier to understand what happens and why; but
also allows the search UI components to be more
easily reused (such as embedding them in the 404
page).
2017-05-14 15:46:24 +01:00
7a759df49e refactor(aio): remove unused mock method 2017-05-14 15:46:24 +01:00
38c524d655 feat(core): introduce fixture.whenRenderingDone for testing (#16732) 2017-05-12 13:49:16 -07:00
06264645fd build: use subshells when changing directories
This prevents being left in the wrong directory in case of error.
2017-05-12 12:19:51 -07:00
21d213dfc7 refactor(aio): drop run (from yarn run), rename script and remove unnecessary cmds 2017-05-12 11:37:21 -07:00
3065fc6cca ci(aio): build aio-builds-setup scripts before pre-verifying PR
(Coincidentally), this wasn't an issue before fdfeaaf1f, because
pre-verification was run after `test.sh`, during which `aio-builds-setup` was
built.
Now that `deploy-staging.sh` is being run before `test.sh`, we need to build
the `aio-builds-setup` scripts first.
2017-05-12 11:37:21 -07:00
bcefc61da4 ci(aio): correctly catch PR preview pre-verification errors
Previously, `aio/aio-builds-setup/scripts/travis-preverify-pr.sh` was supposed
to exit with 1 if a PR did not meet the preconditions and 2 if an error occurred
during pre-verification.
It relied on the exit codes of the node script that did the actual work, but
didn't account for errors that would be thrown in the `sh` script itself (e.g.
if the node script was not available). This caused such errors to appear as
non-verified PRs, instead of real errors that should fail the build.

This commit swaps the exit codes, so that now a 2 means non-verified PR and 1
designates an error.
2017-05-12 11:37:21 -07:00
569b1e0eb7 fix(router): Wrap Promise-like instances in native Promises (#16759)
Hybrid apps (mix of Angular and AngularJS) might return AngularJS implementation
of Promises that do not play well with the change detection. Wrapping them in
native Promises fix this issue.

This could be the case when a Resolver returns a `$q` promise.
2017-05-12 10:03:54 -07:00
b83fe6f2a4 fix(upgrade): Prevent renaming of $inject property (#16706)
Use bracket notation to access $inject in downgradeInjectable to
support property renaming. Since the return type is any,
Closure compiler renames $inject.
2017-05-12 10:03:38 -07:00
b016984c04 docs(aio): resize images 2017-05-12 14:28:09 +01:00
90bc5b221b fix(aio): only register ServiceWorker in production mode
Since abb36e3cb, we no longer rely on the cli to set up ServiceWorker, but do it
manually as part of `yarn build`. When using `ng serve`, registering the
ServiceWorker fails, because we haven't created `ngsw-manifest.json` nor copied
`worker-basic.min.js` into dist.

This commit works around this, by only registering the service worker in
production mode (which is what the cli does too).

Caveat:
It is not possible to enable ServiceWorker with `ng serve`/`yarn start` and
using the `--prod` flag will try to register it, but fail because the necessary
files (`ngsw-manifest.json` and `worker-basic.min.js`) will not be available.
(As a work-around, you can use `yarn build` and serve the files in `dist/` with
`yarn http-server -- dist -p 4200`.)
2017-05-12 14:17:27 +01:00
37f1fcbfc8 docs: remove angular.io from changelog (#16723) 2017-05-11 23:46:55 -07:00
4a599eec45 ci: fix syntax error in deploy.sh (#16739) 2017-05-11 15:52:39 -07:00
fdfeaaf1f3 ci(aio): deploy previews early (right after build) (#16734)
Previously, PR previews were deployed after successfully running all tests.
While this makes sense for staging/production deployments, previews should be
available as soon as possible (and regardless of the outcome of tests).

Fixes #16705
2017-05-11 15:12:23 -07:00
decb4cc4a3 ci(aio): create previews for all PRs that touch non-spec files in aio/ or packages/ (#16733)
Previously, no previews would be deployed for PRs that didn't touch files inside
`aio/`. Now, previews will be deployed for PRs that touch non-spec files inside
either `aio/` or `packages/` (as long as other preconditions are met).

Partially addresses #16526.
2017-05-11 15:02:13 -07:00
44c7ac0fe9 fix(upgrade): use quote to prevent ClossureCompiler obfuscating $event. (#16724)
This is critical for AngularJS to get the $event object in template.
2017-05-11 13:54:04 -07:00
abb36e3cba fix(aio): switch to ngu-sw-manifest gen to unblock critical path (#16709) 2017-05-11 13:21:27 -07:00
84c30be164 docs: add saved replies (#16726) 2017-05-11 13:17:58 -07:00
5afaa39e68 refactor(compiler): produce more dense generated code (#16666)
This changes the formatting to be less verbose but still
tries to be readable.
2017-05-11 10:28:48 -07:00
ce1d7c4a6e refactor: use view engine also for NgModuleFactorys (#16658)
* refactor(core): provide error message in stack for reflective DI

Fixes #16355

* fix(compiler): make AOT work with `noUnusedParameters`

Fixes #15532

* refactor: use view engine also for `NgModuleFactory`s

This is a prerequisite for being able to mock providers
in AOTed code later on.
2017-05-11 10:26:02 -07:00
b9521b568f feat(compiler): support a non-null postfix assert (#16672)
Template expressions can now use a post-fix `!` operator
that asserts the target of the operator is not null. This is
similar to the TypeScript non-null assert operator. Expressions
generated in factories will be generated with the non-null assert
operator.

Closes: #10855
2017-05-11 10:15:54 -07:00
2eca6e67e1 test(aio): add tests for renderAttributes helper 2017-05-11 10:30:10 +01:00
c757e5794f build(aio): serve gzipped content from the preview server
Fixes #16699
2017-05-11 10:29:24 +01:00
67dc970ce4 docs(common): remove h1s from API docs
Only one h1 is allowed per document, and this is provided by the template.
So we cannot have any h1 tags (or `#` markdown shorthand) in any API docs.

Closes #16193
2017-05-11 08:15:19 +01:00
56ccd5e6a1 docs(aio): remove excess h1s from guides
Only one h1 is allowed per document.

(Also took the opportunity to remove unnecessary blank lines from these
docs, and a bit of general tidying.)

Closes #16193
2017-05-11 08:15:19 +01:00
bcbee13e26 build(aio): fail build if more than h1 is found in a doc
Closes #16193
2017-05-11 08:15:19 +01:00
d28a3f7878 docs(router): Change CanDeactivate to CanLoad (#16237)
fix mistake in docs. CanDeactivate should be CanLoad
2017-05-10 16:34:34 -07:00
162dffb7e8 docs: add changelog for 4.2.0-beta.1 2017-05-10 16:26:34 -07:00
0f0b9896b7 release: cut the 4.2.0-beta.1 release 2017-05-10 16:26:34 -07:00
e242e20ca3 fix(aio): style TOC scrollbar similar to other scrollbars 2017-05-10 15:02:44 +01:00
f148ebe99e docs(aio): remove warning when testing in the webpack guide 2017-05-10 15:02:21 +01:00
f795f649cf refactor(aio): remove redundant styles
Due to the new structure of `live-example`, the only style in
`_live-example.scss` was not applied. This is OK according to
https://github.com/angular/angular/issues/15935#issuecomment-295482503, since we
want it to take the full width.

Fixes #15935
2017-05-10 14:49:37 +01:00
063db641f8 fix(aio): style sidenav-content scrollbar similar to other scrollbars 2017-05-10 14:48:29 +01:00
b44f5c69e1 build(aio): make less verbose tools 2017-05-10 14:26:14 +01:00
56833a6171 docs(aio): more content fixes 2017-05-10 12:51:01 +01:00
efa2928547 docs(aio): add a progress reporter for the webpack guide 2017-05-10 11:54:39 +01:00
f5335d17ec build(aio): fail the doc-gen if there is an invalid {@link ...} tag
This fail behaviour is only turned on for `yarn docs`;
in `yarn docs-watch` you only receive a warning.
This is because you can get false errors when watching
since we don't parse all the docs in that case.
2017-05-10 11:39:07 +01:00
dc7d24267d feat(aio): update code style 2017-05-10 07:57:45 +01:00
412ab3f20c fix(aio): basic fix to the TOC styling
Without any major refactoring these changes bring the TOC much closer to
how the Google developer docs TOC looks.

Closes #16646
2017-05-10 07:49:59 +01:00
954c08e97c fix(aio): remove unwanted code styling from styleguide doc
Closes #16514
2017-05-10 07:49:03 +01:00
a2dcb7b476 build: update key for pushing to PACKAGE-builds repos (#16667) 2017-05-09 16:37:05 -07:00
bb0902c592 refactor(compiler-cli): move the expression expression type checker (#16562)
The expression type checker moved from the language service
to the compiler-cli in preparation to using it to check
template expressions.
2017-05-09 16:16:50 -07:00
9e661e58d1 docs(aio): image sweep (#16609)
* fix(aio): allow code blocks to clear floated images

Previously the negative margin on the code headings were causing
floated images to overlay the start of a code block. Now all code block
successfully clear all floated elements.

* feat(aio): add a `.clear` class for clearing floating images

* fix(aio): tidy up image styles

The css rules for `img.right` and `img.left` allow authors easy
access to floating an image on the left or right, respectively.

The `.image-display` rule which was always found on a figure
has been simplified so that all figures have this styling. It is very
unlikely that a figure will be used outside the content area; and
at this time it seems like `figure` is as good an indicator that we
want this kind of styling as anything.

Now that images are all tagged with width and height values, we cannot
assume to modify these dimensions via CSS as it can cause the image to
lose its correct proportions.  Until we find a better solition we must set
`height` to `auto` when the screen width is below 1300px to ensure that
these images maintain their proportions as they get shrunk to fit.

* docs(aio): general tidy up of image HTML in guides

Previously, the guides have a lot of inline image styling and unnecessary
use of the `image-display` css class.
Images over 700px are problematic for guide docs, so those have been given
specific widths and associated heights.

* docs(aio): use correct anchor for "back to the top" link

The `#toc` anchor does not work when the page is
wide enough that the TOC is floating to the side.

* build(aio): add `#top-of-page` to path variants for link checking

Since the `#top-of-page` is outside the rendered docs
the `checkAnchorLinks` processor doesn't find them
as valid targets for links.
Adding them as a `pathVariant` solves this problem
but will still catch links to docs that do not actually exist.

* fix(aio): ensure that headings clear floated images

* fix(aio): do not force live-example embedded image to 100% size

This made them look too big, generally. Leaving them with no size means
that they will look reasonable in large viewports and switch to 100% width
in narrow viewports.
2017-05-09 15:53:32 -07:00
d0e72a8f8f docs(*) fix dangling links in API docs (#16632)
* docs(animations): fix links to `Component` animations

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

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

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

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

* docs(router): fix links to methods

* docs(forms): fix links to methods

* docs(core): fix links to methods

* docs(router): fix API page links and an internal link
2017-05-09 15:51:37 -07:00
b44eb328e0 docs(core): remove link to non-existent class in InjectableDecorator (#16653)
Closes #16640
2017-05-09 15:51:23 -07:00
7b4a8d53a7 build(aio): remove "pure" property from pipe template (#16655)
This information is not relevant to users, right now.

Closes #16641
2017-05-09 15:44:10 -07:00
73505e2ff0 feat(aio): scrolling tweaks per 16619 (#16660) 2017-05-09 15:36:24 -07:00
e11f5294ab build(aio): run docs after plunkers and zips (in setup) 2017-05-09 14:33:40 +01:00
0190df9cf3 build(aio): local assets are not dangling links
Closes #16615
Closes #16616
2017-05-09 14:33:40 +01:00
1af42aedfa docs(aio): doc guide tweaks (GS thru Components)
Working through obvious non-image content defects, from top of menu (Getting Started) through Fundamentals/Components.
2017-05-09 14:27:27 +01:00
215611aa9e refactor(aio): rename auto-scroll -> scroll and refactor
Refactor inspired by @gkalpak feedback on PR #16619
2017-05-09 14:11:23 +01:00
98d83b2e2d feat(aio): scroll back to top when TOC more-items clicked to close
closes  #16482
Usability feature. When long embedded TOC, collapsing it should scroll user to TOC top, not leave in the middle of the page.
2017-05-09 14:11:23 +01:00
cf7689ea7b refactor(aio): simplify/clarify some observables 2017-05-09 14:10:58 +01:00
2848f0499f fix(aio): do not nav to an image url
closes #16608
Formerly, tried to navigate when user clicked an anchor with an image url (to view image in a new tab) resulting in 404.
Now ignores href URL with any extension and lets browser handle it.
2017-05-09 14:10:36 +01:00
5d4b36f80f fix(router): fix redirect to a URL with a param having multiple values (#16376)
fixes #16310

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

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

Fixes #15578

PR Close #16592
2017-05-08 17:49:02 -05:00
fcc91d862f fix(core): projected views should be dirty checked when the declaring component is dirty checked. (#16592)
Previously a projected view was only dirty checked when the
component in which it was inserted was dirty checked.

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

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

Fixes #14321
2017-05-08 17:48:58 -05:00
3887d8a429 feat(aio): close sidenav in narrow (mobile) mode when select a new document (#16617)
closes #16603
As before this PR, when wide (side-by-side), the sidenav open/close status only changes when nav to/from marketing page in which case it opens for guide/api and closes for marketing page.
2017-05-08 15:41:19 -07:00
041f57cb7d feat(aio): focus search when / is pressed (#16636)
This will aid accessibility.

Closes #16129
2017-05-08 15:40:32 -07:00
c5ce0408a1 docs(core): EventEmitter docs for isAsync defaults (#15780)
- solves #15758
2017-05-08 10:47:53 -07:00
98dd609f89 docs(animations): remove duplicate word (#16508) 2017-05-08 10:47:13 -07:00
6dc67772b0 docs(aio): move links from nav groups to items
Fundamentals and Techniques nav groups we also links to pages. This caused
counterintuitive behaviour when clicking on them.

This commit moves each link from the group item to a children item, called
Introduction.

Closes #16604
2017-05-07 08:14:10 +01:00
5cf64266f8 docs(aio): fix sizing of marketing doc images
This commit ensures that all the images in the marketing docs are correcly
sized.

Related to #16600
2017-05-06 14:35:24 +01:00
03513e9d70 fix(aio): constrain header-link styles
The CSS rule for positioning the automated header links was too general,
causing other links inside headings to be positioned incorrectly.

Closes #16573
2017-05-06 14:32:49 +01:00
b9ed97c0d9 fix(aio): do not display a Toc initially
Previously the `hasToc` was initialised to true, which caused a flash of
unwanted "Contents" [sic] even if the page was not going to need a ToC.

Closes #16597
2017-05-06 14:32:09 +01:00
799be9c98a feat(aio): TOC float right + service refactor
TOC appears in right panel when wide and hides embedded TOC
Right TOC panel height adjusts dynamically during scroll
Refactored `TocService` and its tests for clarity.
2017-05-06 07:13:31 +01:00
566dab1140 build(aio): upgrade to @angular/service-worker@1.0.0-beta.11 (#16594) 2017-05-05 16:16:55 -07:00
42dc2c19ee refactor(aio): remove redundant test
The search worker is now initialised from the `SearchBoxComponent`, which
has its own tests for this.

Closes #15593
2017-05-05 13:43:02 -07:00
518eb540aa refactor(aio): tweak the CSS to account for new CSS classes on aio-shell 2017-05-05 13:42:34 -07:00
309ada5df5 feat(aio): add helper CSS classes to the aio-shell for fine grained styling
Alternative to #16564
Closes #16549
2017-05-05 13:42:34 -07:00
9da63408b0 fix(http): flatten metadata for @angular/http/testing
@angular/http/testing used to publish a metadata structure which paralleled
the .d.ts structure. This causes ngc to write incorrect imports for this
bundle when compiling providers using MockBackend and other http testing
classes.

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

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

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

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

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

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

Fixes #15932.

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

Fixes #15761

PR Close #16392
2017-05-05 14:20:26 -04:00
547c363473 feat: add .ngsummary.ts files to support AOT unit tests
Design doc: https://docs.google.com/document/d/1VmTkz0EbEVSWfEEWEvQ5sXyQXSCvtMOw4t7pKU-jOwc/edit?usp=sharing
2017-05-05 13:23:53 -04:00
2714644528 docs(aio): fix broken links discovered May 4th 2017-05-05 11:05:22 +01:00
d27588b5fb feat(aio): api label styles
- Moved info bar section in pipe template to be the first section to match other templates
- Fixed label styling for type label
- Added label styling for status label
2017-05-05 11:04:55 +01:00
a8379a46cf docs(aio): remove toc from all marketing pages 2017-05-05 10:43:36 +01:00
b7caa3e024 fix(aio): do not route eplnkr URLs to / from ServiceWorker 2017-05-05 10:42:58 +01:00
3e33482386 feat(aio): should not send in-page navigations to Google Analytics
closes #16521
`LocationService` sends `GaService` a url stripped of fragment and query strings.
`GaService` already guards against re-send of the prior url so it will only report doc changes.
2017-05-05 10:37:36 +01:00
5057e16874 build(aio): throw an error if a code-example tag is not closed 2017-05-04 15:52:17 -07:00
9449eff6fd docs(aio): improve tutorial next-steps prose/links 2017-05-04 15:51:57 -07:00
03610526e5 docs(aio): remove hardcoded TOC 2017-05-04 15:51:37 -07:00
cd28df627c docs: add changelog for 4.2.0-beta.0 2017-05-04 14:41:39 -07:00
59d62bc5aa release: cut the 4.2.0-beta.0 version 2017-05-04 14:37:20 -07:00
8f46db3701 docs: add changelog for 4.1.1 2017-05-04 14:35:18 -07:00
109229246c test(compiler-cli): add test for missingTranslation parameter 2017-05-04 15:07:27 -04:00
5856298798 test: cleanup rxjs custom build
The latest rxjs release works with closure compiler out of the box.
We no longer need to compile our own.

Also put closure options into a file rather than using a shell script.
2017-05-04 15:07:27 -04:00
7f9c589ba3 feat(core): add begin and end renderer methods to track change detection 2017-05-04 15:07:27 -04:00
8931e71c5c build(aio): ensure that tutorial index arrives in the tutorial search area
Fixes #16457
2017-05-04 13:45:04 +01:00
5bc435eba3 feat(aio): provide icon for API packages in search 2017-05-04 13:45:04 +01:00
4dabec6a48 build(aio): compute search title for certain API docs 2017-05-04 13:45:04 +01:00
978376a46e build(aio): doc.searchTitle can override name in search results 2017-05-04 13:45:04 +01:00
895f47a9c2 refactor(aio): remove work-around for browsers without ServiceWorker support
This essentially reverts #15731, which is no longer necessary after
angular/mobile-toolkit@eeb4b22 (which is included in v1.0.0-beta.10).
2017-05-04 12:28:19 +01:00
aec65dee71 refactor(aio): simplify DocViewer 2017-05-04 12:23:49 +01:00
2f66932bd1 fix(aio): make aio-top-menu .nav-link cover the whole <li>
Discussed in https://github.com/angular/angular/pull/16513/files#r114630560.
2017-05-03 19:34:58 -07:00
919ff12377 fix(aio): cheatsheet table layout fix 2017-05-03 19:34:12 -07:00
6748aeabb6 build(aio): update to dgeni-packages 0.19.0
This contains an updated dependency to TypeScript 2.1, which supports the
language constructs that we are using in Angular.
2017-05-03 19:33:58 -07:00
b3e63c09ab fix(upgrade): initialize all inputs in time for ngOnChanges()
Previously, non-bracketed inputs (e.g. `xyz="foo"`) on downgraded components
were initialized using `attrs.$observe()` (which uses `$evalAsync()` under the
hood), while bracketed inputs (e.g. `[xyz]="'foo'"`) were initialized using
`$watch()`. If the downgraded component was created during a `$digest` (e.g. by
an `ng-if` watcher), the non-bracketed inputs were not initialized in time for
the initial call to `ngOnChanges()` and `ngOnInit()`.

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

Fixes #16212
2017-05-03 19:32:57 -07:00
77b8a76f2e feat(aio): toc styling
- TOC styling
- TOC container placeholder
2017-05-03 19:32:41 -07:00
55b8de9fdd build(aio): lint examples 2017-05-03 13:44:41 -07:00
eb56ab38dc fix(aio): remove top bar menu item focus jump 2017-05-03 13:43:42 -07:00
f29c6bbc6f docs(aio): fix missing title warnings
This commit provides missing titles for Press kit.
License appears not to want a title.
ngmodule and resources2 are no longer needed.
2017-05-03 13:42:10 -07:00
464701a899 docs(aio): revert removal of tutorial examples
These files were inadvertently removed in #16488 but are actually still referenced.

Closes #16503
2017-05-03 13:41:05 -07:00
5b96fb9320 build(aio): rename src/content to src/generated
This commit will definitely require a clean up of your
working folder:

```
cd aio
git clean -xdf
yarn setup
```
2017-05-03 13:40:46 -07:00
1cfb263ee3 docs(aio): hide the copy button for code in StyleGuide tables. 2017-05-03 13:38:25 -07:00
9ca2b4c967 feat(aio): set “avoid” class by convention (filename has “.avoid.”)
Most important for StyleGuide which lost example css class in migration.
Also hides copy for “avoid” files.
2017-05-03 13:30:45 -07:00
673d8ae583 feat(aio): add attribute utils for code atty interpretation.
These utils support flexible, natural attribute interpretation as applied to code-example and code-pane. Then apply those utils to code-example and live-example
2017-05-03 13:30:45 -07:00
8760bf7be4 build(aio): fix paths to template macros in overview-dump template 2017-05-03 13:30:11 -07:00
ea02073c84 build(aio): mark API docs as not having a TOC 2017-05-03 13:30:11 -07:00
b051d7ff48 build(aio): refactor API templates for clean start 2017-05-03 13:30:11 -07:00
cade722e48 build(aio): upgrade to dgeni-packages@0.18.0
This contains a fix for the typescript module reader.
Previously, TS modules that were of the form:

```
a/b/index.ts
```

Would be given the name `index` and id of `a/b/index`.
This is not desirable, so the new version of dgeni-packages/typescript
removes this `index` from the id and name, which results in name of
`b` and id of `a/b`.
2017-05-03 13:30:11 -07:00
58817f55e1 fix(aio): do not collapse API code example indentation 2017-05-03 13:30:11 -07:00
3f1d7f7a76 build(aio): add the api folder to the list of template folders 2017-05-03 13:30:11 -07:00
c8dc116951 docs(aio): fixing new url on glossary date pipe 2017-05-03 13:29:04 -07:00
9684d78cae build: update concurrently to latest version
The regression in `concurrently` v3.2.0 (which made us roll back to v3.1.0
in #14378) has been fixed in v3.3.0 (see kimmobrunfeldt/concurrently#89).
2017-05-03 09:35:57 -07:00
71f5b73296 docs: fix links in api docs 2017-05-03 09:22:32 +01:00
5ba8c14893 docs(aio): remove unnecessary anchor links from styleguide 2017-05-03 09:21:18 +01:00
ea9d8a6bc7 docs(aio): move pipes guide under components 2017-05-03 09:01:05 +01:00
9650ff0824 docs(aio): add hero “Zero” to toh-6
Update to in-memory-web-api should handle id=0.
Make sure this works by having a hero with id=0 in ToH.
Coincidentally delete lingering dead app/ folders
Todo: fix ToH images (which have to do anyway)
2017-05-03 08:03:55 +01:00
00dce1698a docs(aio): grammatical fix. remove duplicate word 'our' 2017-05-03 08:03:03 +01:00
c946a929b7 refactor(compiler): simplify AOT tests 2017-05-02 15:51:54 -07:00
21c96a5af1 feat(aio): sidenav styling extended 2017-05-02 15:14:21 -07:00
a0b9c23100 feat(aio): support hiding the copy button on code-examole components
In the API docs there are occasions where we do not wish the code snippet
to have a copy button. This commit supports that by providing a new `hideCopy`
attribute.
2017-05-02 15:14:03 -07:00
cb5bc76766 feat(aio): move search results under search box
This enables keyboarders to tab from the search box into the results.
Important for a11y according to issue #16005.
2017-05-02 15:13:40 -07:00
1c8772a879 fix(aio): delete guide/index.md which is no longer used 2017-05-02 15:13:15 -07:00
79ed0e7121 feat(aio): display API icons in search results
Add API symbols for `let` and `var` so don’t have to translate those types into `const`
Also replace <hr> in search results HTML with ellipses icon.
2017-05-02 15:12:58 -07:00
0c69903123 feat(aio): top 5 weighted search results shown when many area results 2017-05-02 15:12:58 -07:00
04dc24820d feat(aio): comment cleanup, API table styles
- API table styling
- Cleanup on resource page comments
2017-05-02 10:57:54 -07:00
e263e19a2a fix(core): don’t stop change detection because of errors
- prevents unsubscribing from the zone on error
- prevents unsubscribing from directive `EventEmitter`s on error
- prevents detaching views in dev mode if there on error
- ensures that `ngOnInit` is only called 1x (also in prod mode)

Fixes #9531
Fixes #2413
Fixes #15925
2017-05-01 18:56:25 -04:00
ac220fc2bb docs(aio): fix image size on homepage 2017-05-01 15:52:51 -07:00
3b80472bad style(aio): fix comment on postProcessHtml processor
Fixes https://github.com/angular/angular/pull/16336#discussion_r113891332
2017-05-01 15:52:51 -07:00
ca17d4f639 build(aio): auto-fill width/height to all image tags
Parse all `<img>` tags, during doc-gen, and insert the width and height of
the sourceed image, if neither are already specified.

Warnings are reported if the `<img>` tag has no `src` attribute or the image
cannot be loaded.

The work is done in the `addImageDimensions` post-processor, which must be
configured with a `basePath` so that it knows where to find the images.

Closes #15888
2017-05-01 15:52:51 -07:00
64335d3521 build(aio): capture and log errors and warnings when post-processing HTML 2017-05-01 15:52:51 -07:00
9945ce2259 build(aio): move copyContentAssets processor to the base package
This allows other processors who need to know about the copyContentAssets
processors to ensure that the runs after the content has been copied.
2017-05-01 15:52:51 -07:00
6d9da73090 build(aio): move attribute utils to helpers folder
This allows these utility functions to be reused across packages.
2017-05-01 15:52:51 -07:00
c889fb1ef5 build(aio): include new packages in docs-watch 2017-05-01 15:52:51 -07:00
d32bc5df3e feat(aio): add tooltip to nav node if none specified 2017-05-01 15:52:35 -07:00
efaf502e95 feat(aio): tell user when no search results
closes #16294
2017-05-01 15:51:44 -07:00
ff32c53099 docs(aio): fix lots of broken links
Closes #16317
2017-05-01 15:51:26 -07:00
235eb17cca build(aio): improve info-bar template
The "npm module" and "NgModule" are now rendered correctly.

Closes #16055
2017-05-01 15:51:03 -07:00
aaa562898f fix(aio): correct position of sidenav icons 2017-05-01 15:50:34 -07:00
c8fd904c32 fix(aio): remove max width on marketing pages and footer
- Removed the max-width on all marketing pages
- Moved the footer so that it extends fully horizontally on all screen sizes
2017-05-01 15:50:17 -07:00
65a8f7f6c9 fix(aio): search result styling
- Changed search result link hover state to white to be more legible
- Increased the max-height on search results container to remove the jitter
- Changed search results to have space-around vs space-between for more appropriate spacing
2017-05-01 15:49:46 -07:00
f32bfcdbe5 build(aio): convert triple backtick blocks to code-example tags
Closes #16246
2017-04-30 09:07:28 -07:00
24b9067047 build(aio): remove unused {@exampleTabs} inline tag 2017-04-30 09:07:28 -07:00
de8de84cea test(aio): confirm ga tracks user’s # fragment clicks within a page (#16441)
This was the behavior and we think we still want to do it.
Added comment and test to confirm that is our present intention.
2017-04-30 09:07:12 -07:00
8d300ffbfc fix(aio): header click should always toggle expand/collapse (#16439)
Also adds class tests for this NavItemComponent.
Not (yet) testing effects on the templated HTML
2017-04-30 09:07:00 -07:00
f74dafcb07 docs(aio): Add numbers and steps to Tutorial navigation (#16421) 2017-04-30 09:06:36 -07:00
065b76d14c feat(core): upgrade dep on zone.js to 0.8.9 (#16401)
PR Close #16401
2017-04-28 22:50:48 -05:00
253345c0c0 fix(language-service): remove asserts for non-null expressions (#16422)
Reworked some of the code so asserts are no longer necessary.
Added additional and potentially redundant checks
Added checks where the null checker found real problems.

PR Close #16422
2017-04-28 22:50:31 -05:00
270d694ed2 docs(common): fix API docs for NgComponentOutlet (#16411)
fixes #16373

PR Close #16411
2017-04-28 18:11:24 -05:00
f4b771a0c6 feat(language-service): provide external file list to TypeScript (#16417)
Also ensures that it only calls base language service for files
that it contains.

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

Fixes #15880

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

This commit enables this use case.

Closes #12816
2017-04-28 17:41:31 -05:00
900a88b15d feat(core): allow custom selector when bootstrapping components (#15668)
- fixes #7136

PR Close #15668
2017-04-28 17:41:04 -05:00
cb384e8ed3 ci(language-service): update ci tests to official 2.3 build (#16415)
PR Close #16415
2017-04-28 17:40:53 -05:00
a2b2afb21c feat(aio): add marketing class to AppComponent <aio-shell> on mkt page (#16395)
Also navigation.json Doc page should be hidden in sidebar, shown in top
2017-04-28 15:34:20 -07:00
b70b9606eb docs(aio): apply guidelines to ts-to-js - adapt for aio site (#16054) 2017-04-28 15:34:00 -07:00
938406122e docs(aio): add missing word (#16328) 2017-04-28 15:33:23 -07:00
951a575db3 docs(aio): fix broken NgModules link in tutorial (#16398)
Brackets included in link title contents were breaking markdown
parsing, preventing correct link generation.
2017-04-28 15:32:46 -07:00
8c50457385 fix: public API golden files (#16414) 2017-04-28 09:48:15 -07:00
8c09d10ba9 fix: strictNullCheck support. (#16389) (#16389)
Fix #16357

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

Closes #16389

PR Close #16389
2017-04-28 09:15:00 -05:00
c04e51cb15 fix(aio): do not create ToC for file-not-found and fetching-error documents
Related to #16078.
2017-04-28 15:06:05 +01:00
7b94f493b9 feat(aio): code snippet source available & shown when code missing
Tells reader (usually the author) what code file is missing
Also when no linenums specified, turn them on if num of lines > 10
2017-04-28 11:07:45 +01:00
f1f04fa782 feat(aio): implement gkalpak review suggestions 2017-04-28 09:45:09 +01:00
4be1966a21 feat(aio): revise Docs page; docs version selector in sidenav 2017-04-28 09:40:39 +01:00
de25cfc0cb build(aio): move autolink-headings to post-processing (#16336)
The autolinking is now done on the `renderedContent` which means it also
captures and autolinks headings that were generated outside of markdown.

PR Close #16336
2017-04-27 23:42:04 -05:00
de36a9b718 fix(aio): improve positioning of heading-anchors 2017-04-27 23:42:04 -05:00
883a3250e4 fix(aio): ensure styling of icons is specific to usage
Previously the CSS styling for material icons was too broad and affected
all instances of icons. This commit constrains the position of copy button
icons only to copy buttons.
2017-04-27 23:42:04 -05:00
1ceb2f9c79 build(aio): add new post-process dgeni package
This package will allow us to do complex post-processing
on the HTML that is rendered by Nunjucks.
2017-04-27 23:42:04 -05:00
fbde2a8010 docs(aio): correct abbreviation (#16295)
change abbreviation from 'ES' to 'ES2015'. the 'ES2015' abbreviation is used elsewhere in the tutorial.
2017-04-27 21:39:46 -07:00
81925fa66d feat(forms): introduce min and max validators (#15813)
PR Close #15813
2017-04-27 17:39:17 -05:00
6e2abcd5fc feat(compiler-cli): add param to set MissingTranslationStrategy on ngc (#15987)
This commit adds a new parameter to ngc named `missingTranslation`  to set the MissingTranslationStrategy for AoT, it takes the value `error`, `warning` or `ignore`.

Fixes #15808

PR Close #15987
2017-04-27 17:38:59 -05:00
3f46645f5f feat(aio): add Table of Contents (toc) component. (#16078) 2017-04-27 15:32:46 -07:00
2a7f63650c build(aio): update @angular/service-worker to v1.0.0-beta.10 2017-04-27 10:14:32 +01:00
cd5b1f306a refactor(aio): move /guide/docs.md to /marketing/docs.md
Because:
1. `docs` feels like a "top level" page, similar to `features`, `resources`, `events` etc.
2. This enables the ServiceWorker to pre-fetch/cache the document (similar to what happens with all
   other direct children of `content/docs/`), without the need for special-casing it in
   `ngsw-manifest.json`.
2017-04-27 10:14:32 +01:00
749bcf3d9c feat(aio): cache external resources in the ServiceWorker
Cache resources that are necessary for displaying the basic pages when offline.
2017-04-27 10:14:32 +01:00
a9027a2570 fix(aio): fix ServiceWorker routing 2017-04-27 10:14:32 +01:00
72e32b1f17 fix(aio): update files ignored by the ServiceWorker
Fixes #16198
2017-04-27 10:14:32 +01:00
96648ba98a fix(aio): fix incorrect image URLs in guides 2017-04-27 10:14:32 +01:00
6561d46349 refactor(aio): move content-related images to content/images/ 2017-04-27 10:14:32 +01:00
2e5e37ac58 refactor(aio): move unused images to unused/ sub-directories 2017-04-27 10:14:32 +01:00
6bac4e65ce build(aio): update dgeni-packages to 0.17.2 (#16358)
This version has fix for the jsdoc parser, which was
causing false negative warnings and errors in the doc
gen.

Closes #16319
2017-04-26 14:53:33 -07:00
a28f5eeed3 docs: update 4.1.0 changelog, remove aio 2017-04-26 12:11:45 -07:00
c0c50133e3 docs: update 4.1.0 changelog, remove aio 2017-04-26 12:11:03 -07:00
b9723f9765 docs: add changelog for 4.1.0 2017-04-26 10:52:42 -05:00
cb35c26d70 release: cut the 4.1.0 release 2017-04-26 10:49:19 -05:00
bb52e22ecf feat(aio): api pages styling
- Banner class code consolidation for API pages
- Set up temporary table of contents class and file
- API pages title styling
- Add color styling to doc-type listed on each API details page
- Classes and SCSS variables refactor
- Mobile optimization on headers, info-banner, and API pages
- API page table custom styling
- API Class Overview template code overview into table format
2017-04-26 14:31:54 +01:00
35a2dfc177 fix(aio): resource nav 2017-04-26 09:48:33 +01:00
d8e2829e5b feat(aio): boilerplate:add cleans (removes) before adding 2017-04-26 09:23:32 +01:00
ac5e6baced fix(aio): AppComponent should scroll only once when location changes 2017-04-26 09:20:00 +01:00
710b4a3503 feat(aio): layout max width and design cleanup
- Content container now has a max width and made the body background the same offwhite color so the cut-off is not visible
- Sidenav will always remain at the left of the page
- Added a max width to the api banner of filter search inputs
- Left aligned content container so it is flush with sidenav
- Changed API filter width to match size of filter results
2017-04-26 08:57:30 +01:00
5331fc1aab build(aio): turn on dangling link checking 2017-04-25 14:09:08 +01:00
9b7f2ce6c3 test(aio): add missing test for AppComponent 'starting' feature 2017-04-25 12:30:32 +01:00
11b2f62ed2 feat(aio): don't animate sidenav on launch. 2017-04-25 07:42:53 +01:00
e7c37d77a8 feat(aio): copy code snackbar and design updates
- Add snackbar and pointer cursor for copy code button inside aio-code components
- Flex cenetered content in features page
- Removed duplicate global css class
- Add styles to links inside of sub-sections
- Remove focus outline on top nav bar links
2017-04-25 07:36:23 +01:00
1762047bc0 build(aio): fix other dgeni templates
The function and interface templates were overriding the
wrong block.
2017-04-25 07:35:34 +01:00
9a4c8d543d build(aio): fix rendering of Decorator API docs
The templates were a bit out and we were not merging the
correct properties.

Added some docs and tests for the processor.

Related to #16208
2017-04-25 07:35:34 +01:00
f5aaa55f21 build(aio): ignore the VERSION constant correctly
We were filtering this document from the docs list but
not removing it from the module export lists.

We can actually filter it out much easier at the TypeScript
parsing point, which means we do not need the
`filterIgnoredDocs` processor any more.

Closes #16287
2017-04-25 07:33:50 +01:00
23e6502ef3 fix(aio): copy button placement fix
Added material-icons back in used throughout codebase prevoiusly renamed
2017-04-25 07:08:06 +01:00
ff0f53c915 build(aio): include missing packages in the docs
These packages were not included in the configuration of the doc-gen, so
were not being rendered.
2017-04-25 06:56:41 +01:00
64ef69fb34 feat(aio): api page column layout 2017-04-25 06:51:04 +01:00
249cd8c2ec docs(aio): remove _blank target (#16205) 2017-04-24 11:23:45 -07:00
d1fb066d07 fix(upgrade): use correct attribute name for upgraded component's bindings (#16128)
Previously, when using a different property/attribute name for an upgraded
component's binding (e.g. `bindings: {propName: '<attrName'}`), the property and
attribute names were swapped (e.g. using `attrName` as the property name and
`propName` as the attribute name). This resulted in unexpected behavior.

This commit fixes this using the correct names for properties and attributes.

This only affects `upgrade/dynamic`. `upgrade/static` works correctly already.

Fixes #8856

PR Close #16128
2017-04-24 12:14:03 -05:00
2f977312be fix(router): forward the query parameters in the ng1 -> ng2 url sync (#16249)
fixes #16067

PR Close #16249
2017-04-24 12:13:47 -05:00
feda017c50 docs(aio): Fix decorator JS feature explanation (#16214) 2017-04-24 09:54:36 -07:00
2991221551 docs(aio): remove duplicate as (#16265)
the word `as` incorrectly appears consecutively
2017-04-24 09:51:38 -07:00
d7719aa0f5 perf(aio): improve unit test rebuild time 2017-04-24 14:30:16 +01:00
54e587a46d fix(aio): fix URL redirection for API pages 2017-04-24 14:15:43 +01:00
4ac5096232 docs(aio): revised "Docs" page 2017-04-24 14:00:51 +01:00
3d06b18fee docs(aio): topics in navigation.json alphabetized per section 2017-04-24 14:00:51 +01:00
446153675f docs(aio): revise info architecture in navigation.json 2017-04-24 14:00:51 +01:00
bb1850a912 docs(aio): relocate images to match docs 2017-04-24 14:00:51 +01:00
93516ea8a1 docs(aio): rename cb- files and a few others 2017-04-24 14:00:51 +01:00
c3fa8803d3 fix(aio): use SVG icons for page load sensitive UI
The side nav and menu buttons need to appear early on in the loading of the page.
Currently we are using icon fonts with ligatures to get icons for these areas.
This can result in a flash of unstyled font.

By replacing these with SVG icons, we get a better user experience.
By overriding the `MdIconRegistry` we can inline the SVG source, which
means that there will never by a delay in rendering the icons.

The new `CustomMdIconRegistry` expects a multi-provider containing an array
of `SvgIconInfo` objects. These objects hold the name and SVG source of the
icon. When `MdIconComponent` requests an SVG icon we will get it from the
pre-loading cache, if available, before delegating back to the original
`MdIconRegistry`.

Note that SVG versions of `md-icon` do not apply the `material-icons` CSS
class to the element, so the styling for the icons that we are preloading
has been changed to use `.mat-icon` instead.

Closes #16100
2017-04-24 13:14:21 +01:00
3cad5da5a4 build(aio): refactor dgeni packages
This is to tidy up the `author-packagse`, which currently duplicates a
lot of the configuration in the main packages. We need to
DRY this up so that we don't fall foul of a change in one being missed in
the other.
2017-04-23 22:50:33 +01:00
7a8bd99ab1 docs(aio): correct some minor typos in the form validation cookbook (#16068) 2017-04-21 13:37:28 -07:00
7520ddcf40 feat(aio): dont set query params during search #16125 (#16217)
closes #16125

API search still updates query params as sending someone a pre-filtered API search link is  handy.

While typing in the search box no longer updates the URL in the addr bar, you can still create a link like `~/?search=animations` and it will open the search dialog and profile the search box as it may be useful to email such a thing to someone.
2017-04-21 13:36:37 -07:00
9c1318d731 fix(aio): strip leading slashes from path (and improve DRY-ness) (#16238)
Previously, the path returned by `LocationService.path()` preserved leading
slashes, which resulted in requests with consequtive slashes in the URL. Such
requests would fail (with a 404) on staging.

This commit fixes it, by removing leading slashes from the path. It also
refactors `LocationService` a bit, converting path to an observable,
`currentPath` (similar to `currentUrl`), and applies certain clean-ups (e.g.
stripping slashes, query, hash) in one place, which simplifies consumption.

Closes #16230
2017-04-21 13:35:40 -07:00
062fc4afee docs(aio): change hardcoded links to the old site (#16196) 2017-04-21 10:10:19 -07:00
87ec8d13ce docs(aio): remove doble title from setup 2017-04-21 16:26:08 +01:00
cf034f759a feat(aio): api page styles
Changed description from h3 to h2 to match the other header
Created api page classes for consistent styling
Add styles for info-bar section
Wrapped pre tags for code not to go off of screen
2017-04-21 16:24:37 +01:00
b0c5d21f31 fix(aio): header anchor placement
Adjusted left-margin so that the anchor icon does not push the header in
2017-04-21 16:09:19 +01:00
cbe5f78c1a docs(aio): fix old jade on DI 2017-04-21 16:01:20 +01:00
4598af23c0 docs(aio): adjust zips/plunker paths 2017-04-21 09:56:45 +01:00
d855e90524 docs: add changelog for 4.1.0-rc.0 2017-04-21 00:15:23 -05:00
897fc87620 docs: add changelog for 4.0.3 2017-04-21 00:12:38 -05:00
b37f5fc59b release: cut the 4.1.0-rc.0 release 2017-04-21 00:12:10 -05:00
9730351048 build(aio): compute which examples to include when watching guide docs (#16213)
PR Close #16213
2017-04-20 22:16:21 -05:00
ce687550ae build(aio): run docs before docs-watch (#16213)
This helps to ensure that the full docs have been
generated before we begin watching.

You can disable this by providing the `--watch-only`
flag. E.g. `yarn docs-watch -- --watch-only`.
2017-04-20 22:16:16 -05:00
563b909279 build(aio): give the authors-package tests long enough not to flake (#16213) 2017-04-20 22:16:10 -05:00
c390b06da2 feat(aio): add prettier network fail page (#16139) 2017-04-20 22:15:16 -05:00
db4e9ea04a feat(aio): add <current-location> embedded component (#16139) 2017-04-20 22:15:04 -05:00
5e6a3ff6a7 refactor(aio): rename DocumentContents url to id and tidy up (#16139)
Dgeni is now providing the `id` for all the documents to be viewed. So we
no longer need to add this to the DocumentContents object.

There are some notable changes in the refactoring:

`DocumentService`:

* The id of the document to render is now obtained from `LocationService.path()`.
* The `getFileNotFoundDoc` and `getErrorDoc` methods have been extracted from
the `fetchDocument` method.

`AppComponent`:

* the `pageId` is now computed in a separate `setPageId` method.

`AppComponen` spec file:

* The `TestHttp` has had the hard coded documents removed and replaced with
a function that will generate docs as needed.
2017-04-20 22:14:58 -05:00
d0dcabd700 build(aio): add the id to the DocumentContents at doc-gen time (#16139) 2017-04-20 22:14:51 -05:00
6ed812ff75 feat(aio): add LocationService.path() method (#16139)
This enables things like embedded components easy access to a clean version
of the current location path.
2017-04-20 22:14:43 -05:00
5461182e25 docs(aio): make glossary links work again (#16201) 2017-04-20 20:11:27 -07:00
cbe95f3d25 feat(aio): add code-of-conduct to footer #16105 (#16216)
closes #16105
2017-04-20 20:09:58 -07:00
ce57b6fb45 fix(aio): material code tab arrow animation (#16206) 2017-04-20 14:52:02 -07:00
134f542b36 docs(aio): fix spacing on l-sub-sections 2017-04-20 16:30:59 +01:00
c3727f330b docs(aio): fix aot TOC list items 2017-04-20 16:30:59 +01:00
d313aad671 docs(aio): remove js examples 2017-04-20 16:04:06 +01:00
a54fe634ee docs(aio): move file to the right folder 2017-04-20 16:02:07 +01:00
ccb6c45466 docs(aio): rename http guide 2017-04-20 16:01:44 +01:00
800b1b060e fix(aio): autoscroll & add #top-of-page
* Scrolls to hash element or top of page when no hash.
* Scrolls down a bit (80px) to account for top menu overhang.
* No longer scrolls when the hash element is not found.
* Adds `<a id="top-of-page"></a>` which will benefit future efforts to
navigate there from within a page.
2017-04-20 10:47:05 +01:00
ab03852234 fix(aio): accessibility items in search and home
Index: Changed h3s to h2s given hierarchy
Index: Aligned text and image blocks to be centered
Index: Announcement bar button darkened for appropriate contrast
Search Results: Changed to list items in unordered list to accommodate accessibility and updated styles accordingly
2017-04-20 10:28:40 +01:00
f90258162a fix(aio): handle clicks deep within anchor tags 2017-04-20 10:16:37 +01:00
745731e1a3 fix(compiler): make I18NHtmlParser provider AoT-compliant (#15980)
PR Close #15980
2017-04-19 22:46:40 -05:00
11b0213d20 fix(compiler): suppress another closure warning (#16137)
closure compiler warns in generated .ngfactory.ts files:
```
WARNING - property createInternal already defined on superclass module$contents$..$core$src$linker$ng_module_factory_NgModuleInjector; use @override to override it
```

PR Close #16137
2017-04-19 22:46:32 -05:00
cd29d68f3c refactor(tsc-wrapped): cleanup (#16178)
PR Close #16178
2017-04-19 22:46:23 -05:00
da668848c9 fix(core): distribute externs for testability API (#16179)
Workaround for #11119

PR Close #16179
2017-04-19 22:46:11 -05:00
bfd5f27525 feat(aio): add e2e (#15976)
PR Close #15976
2017-04-19 22:36:23 -05:00
9f66c9c1d1 feat(aio): page not found layout and designs (#16089)
Add 404 svg image
h1 custom styling

PR Close #16089
2017-04-19 22:35:58 -05:00
1259fe75c9 feat(aio): 404 page (#16089) 2017-04-19 22:35:50 -05:00
e9db74f937 fix(aio): style mods and content udpates (#16138)
Fixed capitalization in sidenav menu items
Add min height property to sidenav-content for better viewing on short pages or high resolution screens
Add dividier between change log items as before to h2
Table adjustments to reduce off-screen items
Update home page banner text and icon change, and fix banner img and mobile alignment
Fix and add links in doc landing page and change card footer text to reflect correct name
Removed docs landing page to rebase with master

PR Close #16138
2017-04-19 22:35:12 -05:00
f99cb96533 fix(aio): revert resize to HostListener; delete device svc (#16143)
Angular change detection bug -> no page update on resize.
Reverting to `@HostListener('window:resize', ['$event.target.innerWidth'])` cures it.
Delete DeviceService which no longer serves a purpose.
Adjusted affected AppComponent and LiveExample tests.

PR Close #16143
2017-04-19 22:34:58 -05:00
1e848d696b feat(aio): add GH-style anchor links to headings (#16161)
Closes #16126

PR Close #16161
2017-04-19 22:34:46 -05:00
1bfa7c6f14 feat(aio): redirect old URLs to new ones (#16162)
There are external resources that link to the old URLs. In order to avoid
breaking them, the old URLs are redirected to the new ones.

Fixes #15795
Closes #16133

PR Close #16162
2017-04-19 22:34:32 -05:00
05d1008a08 docs(aio): fix bad cookbook URL references for aot-compiler (#16165)
PR Close #16165
2017-04-19 22:34:21 -05:00
9a98fc0f05 fix(aio): better styling for "disabled JavaScript" message (#16170)
PR Close #16170
2017-04-19 22:34:04 -05:00
2ca6258a0f fix(aio): correctly reload page to apply ServiceWorker update (#16170)
Previously, due ot a limitation/bug in AoT compilation and `useValue`, the
`global` injected into `SwUpdateNotificationsService` was always undefined,
which prevented it from actually reloading the page after activating a
ServiceWorker update.

This commit fixes it by switching to `useFactory`, which works correctly with
AoT.
2017-04-19 22:33:58 -05:00
24c34385ee feat(aio): make the ServiceWorker update process more intuitive/user-friendly (#16170)
Fixes #16093
2017-04-19 22:33:47 -05:00
e07b7ea114 docs(aio): fix broken regions 2017-04-19 15:52:55 +01:00
73c7503ae0 fix(aio): sidenav padding
Aligned padding to fit beneath the top nav
Add scroll bar styling inside sidenav menu
Increased font size of h2 to be different from h3 for better legibility
2017-04-19 14:05:36 +01:00
79db6c3d19 feat(aio): about page style changes
Added contributor info links as overlay
Made image larger as a focus
2017-04-19 14:00:35 +01:00
b6ddacdccf build(aio): add setup script 2017-04-19 13:50:18 +01:00
c9983e6440 docs(aio): Fix reference to the right example
Fix reference to the right example (it's the second route in the example the one showing the route parameter, not the first one)
2017-04-19 11:56:17 +01:00
51098c4f86 fix(aio): allow empty titles for contents pages
Now if you specifically provide an empty `@title` tag
for a contents file, the doc-gen will not complain and
the browser will just display a reasonable default.
2017-04-19 11:55:00 +01:00
4624406ce8 feat(aio): search results accessibility items
Add visually hidden class and apply to h2 in search results
Changed h2 group headers to h3s
Add roles to main and content
Fix API material icon placement
Image alt additions where needed
Add lang attribute to html tag
Add aria-label on search input
2017-04-19 11:52:24 +01:00
76269f4a1f docs(aio): fix the broken docs guide 2017-04-19 11:49:32 +01:00
50174d9fb5 build(aio): ability to generate zips 2017-04-19 11:34:39 +01:00
648de7dd86 build(aio): render titles correctly in content pages
If a document provided a title jsdoc tag then its h1
element was being rendered incorrectly as a markdown
paragraph.

This change renders the title as a markdown h1 tag
directly.

Fixes #16099
2017-04-19 10:42:38 +01:00
9d40ab9e20 docs(aio): rename ToH to match the guide name 2017-04-19 10:28:31 +01:00
691e86c9bf docs(aio): fix minor typos in deployment guide 2017-04-19 10:21:53 +01:00
8fa4453aec docs(aio): Testing Guide: Second matcher parameter 2017-04-19 10:19:57 +01:00
93d8f8cd63 docs(aio): add VS Code advice to readme.md 2017-04-19 10:19:11 +01:00
c2fca3d9e0 fix(aio): api list container centered 2017-04-19 10:18:39 +01:00
8b31178647 docs(aio): remove styling comments from cheatsheet
These comments were not designed to be rendered.
2017-04-19 10:14:41 +01:00
e951612af2 fix(aio): set the pageId to the file-not-found URL if the doc is not available
Previously, the `AppComponent.pageId` was set via the current URL, rather than
the document being displayed. This is only really noticeable when the URL does not
match a valid doc and we are actually displaying a 404 page.

Now we compute the `pageId` from the  URL of the document being viewed,
which is returned from the  `DocumentService.currentDocument` observable instead.
2017-04-19 09:09:31 +01:00
b668c2c781 build(aio): IDEs should only parse the src files
I found that VS Code was taking an age to bring up the intellisense
for TypeScript source files in the `aio/src` folder.
I believe that this is because it was trying to parse all the files in
the `aio/content/examples` folder as well, which is not relevant to the
web app development.

This change restricts the root `aio/tsconfig.json` to only the entry points
for the app, the unit tests and e2e tests.
2017-04-19 08:36:05 +01:00
ecd0348d96 build(aio): extract the title from the content if necessary
Documents can specify their title via the `title` or `name` jsdoc tags.

This change adds that, if neither are provided, the first `<h1>` element
is removed from the `renderedContent` and used for the title.

If there is still no title then it is set to the empty string and a warning
is logged.
2017-04-18 15:20:04 -07:00
69b86925b3 feat(aio): set the document title in the browser title 2017-04-18 15:20:04 -07:00
5293794316 fix: turn on nullability in the code base. 2017-04-18 12:07:33 -07:00
728c9d0632 fix(platform-browser): Update types for TypeScript nullability support
Closes #15898
2017-04-18 12:07:33 -07:00
01d93f3af8 fix(upgrade): Update types for TypeScript nullability support
Closes #15897
2017-04-18 12:07:33 -07:00
a0d124bd91 fix(router): relax nullability requirements 2017-04-18 12:07:33 -07:00
57bc245cb4 fix(forms): Update types for TypeScript nullability support
This reverts commit 6d930d2fc5.
2017-04-18 12:07:33 -07:00
bc431888f3 fix(router): Update types for TypeScript nullability support
This reverts commit ea8ffc9841.
2017-04-18 12:07:33 -07:00
ec028b8109 fix(http): Update types for TypeScript nullability support
This reverts commit 268884296a.
2017-04-18 12:07:33 -07:00
014594fe8f feat: add support for TS 2.3 2017-04-18 08:28:55 -07:00
3c8a61e40c feat: add support for TS 2.2 2017-04-18 08:28:55 -07:00
bccfaa46ec fix(core): benchmarks - enable ng1 benchmark again
Also make it match the ng2 benchmark.
2017-04-18 08:28:31 -07:00
2f442062d2 fix(benchpress): chrome - prevent trace buffer overflow 2017-04-18 08:28:31 -07:00
840cb3d69e build: bump protractor to 4.0.14 2017-04-18 08:28:31 -07:00
7dfa0b9da9 fix(aio): about page
Header now visible fully when card if flipped to back info

Contributor website links fixed
2017-04-17 17:43:43 -07:00
f5d0fac800 feat(aio): about/contributor page rebased and tweaked 2017-04-17 17:43:43 -07:00
baecb553a6 fix(aio): fix linting issues 2017-04-17 17:43:43 -07:00
6e89f0bf8d feat(aio): about page styles
contributor fix

contributor card styling updates

button styling and container size fix

remove button and add image border

selection filter for buttons

header only show when group selected and styles

initial flip card funcitonality and data change

selected buttons styling

complete flip func and card style

flip feature

contributor group changes

fixes
2017-04-17 17:43:43 -07:00
f21ff904c2 fix(language-service): respect baseUrl compiler option
Fixes #15974
2017-04-17 14:36:49 -07:00
38a7e0d1c7 fix(compiler): ignore calls to unresolved symbols in metadata
This only shows up in the language service. Calls to symbols
that are not resolve resulted in null instead of being resolved
causing the language service to see exceptions when the null
was not expected such as in the animations array.

Fixes #15969
2017-04-17 14:36:08 -07:00
90814e4449 feat(upgrade): fixes for allow setting the angularjs lib at runtime
- always have a value for `angular`, even if no angular is on the page
- use `const` instead of `function` to allow to export a variable `module`
  without breaking tsickle / closure.
2017-04-17 14:35:55 -07:00
e927aeae86 feat(upgrade): allow setting the angularjs lib at runtime (#15168)
Readds 8ad464d90e.
2017-04-17 14:35:55 -07:00
a77b126d72 fix(compiler): Inform user where Quoted error was thrown 2017-04-17 10:19:09 -07:00
82417b3ca5 fix(router): prevent RouterLinkActive from causing an infinite CD loop
fixes #15825
2017-04-17 10:15:44 -07:00
5b141fbf27 fix(compiler): support <ng-container> whatever the namespace
fixes #14257
2017-04-17 10:14:15 -07:00
268884296a Revert "fix(http): Update types for TypeScript nullability support"
This reverts commit c36ec9bf60.

Broke in G3.
2017-04-17 09:56:09 -07:00
ea8ffc9841 Revert "fix(router): Update types for TypeScript nullability support"
This reverts commit 56c46d70f7.

Broke in G3.
2017-04-17 09:56:09 -07:00
6d930d2fc5 Revert "fix(forms): Update types for TypeScript nullability support"
This reverts commit 6649743a2d.

Broke in G3.
2017-04-17 09:56:09 -07:00
2ddf3bcdd1 fix(language-service): look for type constructors on canonical symbol 2017-04-17 09:49:31 -07:00
0a3a9afe58 fix(language-service): infer correct type of ?. expressions
Fixes #15885
2017-04-17 09:48:52 -07:00
5a88d2f68b fix(language-service): only use canonical symbols
Language service was treating some alias TypeScript symbols as if
they where the canonical symbol. If the symbol in scope is an alias
of another symbol the symbol should be converted to the canonical
symbol.
2017-04-17 09:24:31 -07:00
7165eb15bd build(aio): add div with class around content
Closes #16037
2017-04-17 13:43:42 +01:00
e20a72280b feat(aio): when select node in sidebar close other expanded nodes 2017-04-17 07:53:38 +01:00
abecf3eb6d build(aio): move the transforms folder into the tools folder 2017-04-16 22:05:23 +01:00
7c418a7e06 style(aio): add missing semi-colon 2017-04-16 21:38:00 +01:00
58f080a325 build(aio): add doc-watch yarn task for docs authors
This task is suitable for day to day docs authoring.

This task cuts corners, which makes it much faster than a full `yarn docs`
run but it does not produce completely valid output.
In general this isgood enough for authors to see their changes as they make them.

The task is triggered by a call to

```
yarn docs-watch
```

This sets up watchers on the `aio/contents` and `packages` folders.
Any changes to files below these folders new doc generation run to start.
The input to the generation is confined to a collection of files related
to the changed file. For example:

* a change to a file in `aio/content/marketing` will generate all the
marketing files.
* a change to a file in `aio/content/tutorial` or `aio/examples/toh-*`
will generate all the tutorial files (and their embedded examples).
* a change to a file in `aio/guide` or `aio/examples` (but not a `toh-`
example) will generate the appropriate guide and its embedded examples
* a change to a file in `packages` or `packages/examples` will generate
the appropriate API doc and its embedded examples.

Be aware that the mapping between docs and its examples are based on doc file
and example folder structure being equivalent. Sometimes a doc will reference
an example in a different folder, in which case the generated doc will be
inaccurate. Mostly this is not a big problem.
2017-04-16 20:56:10 +01:00
be719e4817 docs(aio): fix jade leftover from toh5 2017-04-16 20:32:40 +01:00
11b54f69e5 feat(aio): edit page link styling and placement 2017-04-16 11:28:27 +01:00
4a3c66fe22 feat(aio): fixed sidenav, moved footer inside of sidenav container (#16028)
When content pages were short, the footer would take up a large part
of the display area and the side nav would look like it was shorter than
it really was.

This change moves the footer into the main content area so that the
nav always extends to the full length the browser.
2017-04-16 11:10:17 +01:00
9a5084412d feat(aio): force plunker to embedded-style on narrow (mobile) screens
Regular plunker is unusable on narrow screen
Refactors LiveExampleComponent and adds tests.
Refactor width detection to `DeviceService` because need to know width change in 2 places.
Keep “disable” option add in earlier spikes because simple and potentially useful in future.
2017-04-16 08:12:48 +01:00
24670667f1 feat(aio): detect mobile device and tell user live-example is not available
Adds DeviceService to detect mobile device and listen for window resize events.
2017-04-16 08:12:48 +01:00
3f307ff061 style(aio): fix indentation on location service spec
Closes #15589
2017-04-15 22:17:33 +01:00
7433da546f build(aio): give intellisense to the examples 2017-04-15 22:15:54 +01:00
eda2a7b2dc ci(aio): do not fail if PWA score testing fails on staging
Currently, running `yarn test-pwa-score` right after deploying to staging fails
with the error:

```
{ Error: Unable to load the page: timeout reached ...  code: 'PAGE_LOAD_ERROR' }
```

As a temporary fix, this commit prevents the build from failing because of PWA
score errors (until we identify the cause and fix it).
2017-04-15 17:14:28 +01:00
196203f6d7 feat(aio): implement resources with resources.json 2017-04-15 16:53:42 +01:00
46b0c7a18c docs(aio): fix links to quickstart on homepage 2017-04-15 13:37:38 +01:00
b6a0098aa3 ci(aio): make deploy-staging.sh executable 2017-04-15 13:33:48 +01:00
7d986ae5dc feat(aio): smaller typography, code header pad 2017-04-15 10:39:16 +01:00
a2bdcc9ba8 feat(aio): callout, code ex header styles
lighten up code ex background
2017-04-15 10:34:13 +01:00
624b5a5f83 feat(aio): filetree and top bar hover styles 2017-04-15 10:30:23 +01:00
b57c9605ce feat(aio): pwa bg color and name 2017-04-15 10:27:16 +01:00
49dfc9fe2d feat(aio): scroll bar styling 2017-04-15 10:25:24 +01:00
8f9ba62dc3 feat(aio): positioning UX for nav and search 2017-04-15 10:25:24 +01:00
16673fa38b build(aio): remove unused config code 2017-04-15 10:24:21 +01:00
49d97e1216 ci(aio): verify that the Lighthouse PWA score remains above a threshold 2017-04-15 10:23:45 +01:00
a73050de48 ci(aio): convert deploy-staging to a shell script 2017-04-15 10:23:45 +01:00
2535769a65 feat(aio): allow reloading page from ServiceWorker update notification 2017-04-15 10:23:45 +01:00
b1a3c47766 fix(aio): add better message for disabled JavaScript 2017-04-15 10:23:45 +01:00
8479e9e6d7 feat(aio): high res screen spacing 2017-04-15 10:23:16 +01:00
c0b1bbea3e feat(aio): add log rotation in preview server 2017-04-15 10:22:40 +01:00
092f0df7a6 test(aio): remove dross from NavMenuComponent spec 2017-04-15 10:22:01 +01:00
dfc81c3dab feat(aio): sort search results by area/title
Display area names in all caps
Exclude results with no title because they don’t show & can’t be clicked.
Should find these and give their docs a title.
2017-04-15 10:19:32 +01:00
6649743a2d fix(forms): Update types for TypeScript nullability support
This reverts commit 2e47a0d19f.
2017-04-14 15:10:26 -07:00
56c46d70f7 fix(router): Update types for TypeScript nullability support 2017-04-14 14:31:17 -07:00
c36ec9bf60 fix(http): Update types for TypeScript nullability support 2017-04-14 13:53:25 -07:00
86396a43e9 Revert "fix(compiler): ignore calls to unresolved symbols in metadata (#15970)"
This reverts commit ce47d33cd9.
2017-04-14 11:20:12 -07:00
590e68c251 Revert "feat(upgrade): allow setting the angularjs lib at runtime (#15168)"
This reverts commit 8ad464d90e.

Breaks G3.
2017-04-14 11:20:12 -07:00
bd704c90dd fix(compiler): fix build error in xliff2 2017-04-14 11:20:12 -07:00
ea4afebeb9 refactor(router): drop the InternalRoute interface 2017-04-14 09:08:13 -07:00
886cca028f refactor(router): misc refactoring 2017-04-14 09:08:13 -07:00
4054055d0d feat(compiler): add source files to xmb/xliff translations (#14705)
Fixes #14190
2017-04-14 09:06:25 -07:00
09c4cb2540 feat(compiler): Implement i18n XLIFF 2.0 serializer (#14185)
- Ensure that the result passes OASIS XLIFF 2.0 schema validation
- Use <ph/> for self-closing placeholder tags
- Use <pc></pc> for other placeholder tags
- Check for the correct XLIFF file version
- Add ICU support

fixes #11735
2017-04-14 09:05:00 -07:00
8ad464d90e feat(upgrade): allow setting the angularjs lib at runtime (#15168)
This PR adds an ability to reset the angularjs library, which is often needed when Angular
is loaded lazily using RequireJS.
2017-04-14 09:04:28 -07:00
65af9641c2 fix(packaging): increased buffer size (#15840) 2017-04-14 09:03:57 -07:00
cb5a7efa91 fix(core): key-value differ changes iteration (#15968)
fixes #14997
2017-04-14 09:03:16 -07:00
ce47d33cd9 fix(compiler): ignore calls to unresolved symbols in metadata (#15970)
This only shows up in the language service. Calls to symbols
that are not resolve resulted in null instead of being resolved
causing the language service to see exceptions when the null
was not expected such as in the animations array.

Fixes #15969
2017-04-14 09:02:32 -07:00
2e47a0d19f Revert "fix(forms): Update types for TypeScript nullability support (#15859)" (#15977)
This reverts commit 6a2e08d0a8.
2017-04-13 18:03:42 -07:00
6a2e08d0a8 fix(forms): Update types for TypeScript nullability support (#15859) 2017-04-13 17:14:08 -07:00
fdb3f26448 refactor(compiler): cleanup (#15960) 2017-04-13 11:56:00 -07:00
14b7dfa007 fix(aio): create a proper commit link on preview comments (#15941)
Previously, only a few characters of the SHA would appear on the preview link
comment posted on the PR. This was usually enough for GitHub to create a link to
the corresponding commit, but it was possible to have collisions with other
commits with the same first characters (which prevented GitHub from identifying
the correct commit and create a link.)

This commit fixes this issue by including the full SHA on the commentso GitHub
can identify the correct commit and create the link. GitHub will automatically
truncate the link text (by default to 7 chars unless more are necessary to
uniquely identify the commit).
2017-04-13 11:55:33 -07:00
9394835db4 fix(platform-server): handle innerText (#15818) 2017-04-13 11:54:57 -07:00
70b1d6dd9d fix(tsc-wrapped): collect new expressions with no arguments (#15908)
Fixes #15906
2017-04-13 11:53:26 -07:00
d263595c63 ci(aio): do not fail when re-deploying preview for the same PR/SHA
Previously, when trying to upload the build artifacts for a PR/SHA that was
already successfully deployed (e.g. when re-running a Travis job), the preview
server would return a 403 and the build would fail.

Since we have other mechanisms to verify that the PR author is trusted and the
artifacts do indeed come from the specified PR and since the new artifacts
should be the same with the already deployed ones (same SHA), there is no reason
to fail the build. The preview server will reject the request with a special
HTTP status code (409 - Conflict), which the `deploy-preview` script will
recognize and exit with 0.
2017-04-13 11:26:21 +01:00
9cb5964b4d docs: add changelog for 4.1.0-beta.1 2017-04-12 14:49:29 -07:00
3ad0cc5736 release: cut the 4.1.0-beta.1 release 2017-04-12 14:39:22 -07:00
f09fd6ec16 test(aio): add sidenav tests and refactor related tests 2017-04-12 14:17:14 -07:00
8cfa58715c feat(aio): hide side nav in mobile mode
Don’t show the side nav in mobile (not side-by-side) view when arriving or navigating.
Only show it by request.

The side nav should continue to appear in wide mode (side-by-side) when navigating from a marketing page to a guide page.
2017-04-12 14:17:14 -07:00
909264feb5 hr update 2017-04-12 21:10:05 +01:00
cc1ed77dd8 consolidated and moved api-list scss 2017-04-12 21:10:05 +01:00
7d69a91bfe table updates, live example add, shield logo res 2017-04-12 21:10:05 +01:00
a6545ddd4d filetree and subsection edits 2017-04-12 21:10:05 +01:00
498bd64d9c code style updates 2017-04-12 21:10:05 +01:00
ad9a3a2d3b features page and code/table fixes 2017-04-12 21:10:05 +01:00
2da0f1639f feat(aio): filtree updates 2017-04-12 21:10:05 +01:00
3ec58ecea0 feat(aio): hr styling 2017-04-12 21:10:05 +01:00
061475402c docs(aio): final migration from old site 2017-04-12 21:01:55 +01:00
8f1359d25f docs(aio): make events.html current (#15913)
docs(aio): make events.html current
2017-04-12 12:36:45 -07:00
8659bd2c4b docs(aio): template -> ng-template (#15912) 2017-04-12 12:28:09 -07:00
4a052cd343 build(aio): upgrade to @angular/material#2.0.0-beta.3 (#15606) 2017-04-12 12:25:11 -07:00
28c2a71cfc docs(aio): revert file-trees back to original structure
This is an auto-migration from angular.io
2017-04-12 12:24:02 -07:00
69b37fff26 build(aio): remove unused Rho package 2017-04-12 12:24:02 -07:00
df619adc76 docs(aio): update to remark syntax 2017-04-12 12:24:02 -07:00
374bf1ed98 build(aio): implement the remark renderer
The implementation adds three plugins to the remark processor:

* remove support for code blocks triggered by indented
text - only gfm triple backticks are supported; and also adds support for
dgeni inline tags.

* ignore content within `code-example` and `code-tabs` elements. This prevents
the content being accidentally treated as markdown

* ignore dgeni inline tags, e.g. `{@link ... }` to prevent the content of
the links from being accidentally treated as markdown
2017-04-12 12:24:02 -07:00
540581da3e fix(language-service): Update types for TypeScript nullability support 2017-04-12 11:36:19 -07:00
6f5fccfeb7 fix: Update types for TypeScript nullability support in examples 2017-04-12 11:36:19 -07:00
14669f20bf fix(benchpress): Update types for TypeScript nullability support 2017-04-12 11:36:19 -07:00
075f3f8c9f feat(aio): search results layer fix and responsive table 2017-04-12 14:46:31 +01:00
2798c1bbec feat(aio): code block styles with header 2017-04-12 14:29:03 +01:00
38d75d410e feat(animations): Update types for TypeScript nullability support
Closes #15870
2017-04-11 18:13:52 -07:00
04fb29b589 test(aio): add test for escaped newline in CodeComponent 2017-04-11 16:03:21 -07:00
9037593ab8 fix(aio): left align code in aio-code components 2017-04-11 16:03:21 -07:00
3ced940b5a build(aio): ability to generate plunkers 2017-04-11 16:00:37 -07:00
f5a98d98c8 docs: add changelog for 4.0.2 2017-04-11 15:32:41 -07:00
0799f184dc fix(aio): v2 - when browser lacks service worker, disable sw feature 2017-04-11 14:26:22 -07:00
c530c5d317 fix(aio): when browser lacks service worker, disable sw feature 2017-04-11 14:26:22 -07:00
91b2e394d5 ci: add jasonaden to the router 2017-04-11 11:16:02 -07:00
a487563768 fix(router): fix query param parsing 2017-04-11 11:15:11 -07:00
0ab04bd62c refactor(router): cleanup & simplifications 2017-04-11 11:15:11 -07:00
46ce3317c3 test(router): enable running the campaign in non-ES6 browsers
Closes #15806.
2017-04-10 15:43:42 -07:00
83527fd4fb test(router): test preloading when a module is already loaded 2017-04-10 16:35:47 -06:00
6d12aa978d fix(router): the preloader use the module from the loaded config 2017-04-10 16:35:47 -06:00
96aa2365ae fix(tsc-wrapped): ensure valid path separators in metadata
* Fixes that `tsc-wrapped` stores invalid path separators in the bundled metadata files. Previous errors could have been: `Cannot find module '.corecoordinationnique-selection-dispatcher'.` (See https://github.com/angular/material2/issues/3834)
* Fixes failing tests on Windows. Now all tooling tests are green on Windows.

Related to #15403
2017-04-10 16:01:38 -06:00
258d5392d5 fix(language-service): detect when there isn't a tsconfig.json
Fixes #15874
2017-04-10 16:01:05 -06:00
09d9f5fe54 fix(compiler): Update types for TypeScript nullability support 2017-04-10 15:26:33 -06:00
d8b73e4223 fix(common): Update types for TypeScript nullability support 2017-04-10 15:26:33 -06:00
4c566dbfbb fix(aio): api search input fix and style 2017-04-10 13:47:24 +01:00
bde9771991 fix(language-service): parse extended i18n forms 2017-04-04 15:34:12 -06:00
fe0d02fc47 fix(language-service): initialize static reflector correctly
Fixes #15768
2017-04-04 15:00:46 -06:00
7b005aadc1 style(router): fix typo in router preloader method 2017-04-04 14:12:45 -06:00
7764c5c697 fix(language-service): avoid throwing exceptions when reporting metadata errors 2017-04-04 14:11:51 -06:00
c6917d9d4f build(aio): update boilerplate to new folder structure 2017-04-04 04:19:49 -06:00
25132bff86 feat(aio): marketing page styles 2017-04-03 15:48:52 -07:00
0e38bf9de0 build(aio): new migration 2017-04-03 15:41:05 -07:00
309bae0a0b feat(aio): display “code sample missing” message when no code sample
Not having code in a `<code-example>` or `<code-tabs>` is presumed to be an error.
Hides the copy button as well.
2017-04-02 22:37:16 +01:00
ae70293df3 feat(aio): add DtComponent to view/change the raw contents 2017-04-02 22:15:57 +01:00
1e623a3710 feat(aio): add original style for feature page
fixes link to quick start; moves $unit to constants
2017-04-02 22:10:39 +01:00
928e2543cd fix(aio): currentNode url should not contain hash or search 2017-04-02 11:41:35 +01:00
92e14a36f9 test(aio): ensure AppComponent.pageId has no search or hash 2017-04-02 11:41:35 +01:00
34a1990c57 fix(aio): trim code blocks before rendering 2017-04-02 11:40:40 +01:00
e4c3882a81 fix(aio): fix presskit.html typos 2017-04-02 10:20:25 +01:00
62f9738a9a test(aio): enable linting of transforms/ and add rules for jasmine 2017-04-01 20:56:16 +01:00
a562c64ed6 test(aio): enable tslint rule for focused jasmine tests/suites 2017-04-01 20:56:16 +01:00
8c726ea87e fix(aio): preserve space after anchor elements
Sometimes, depending on the length of lines, anchor elements would be formatted
incorrectly by `html.prettyPrint` and the space right after the element was
removed.

This was apparently caused by a bug in `html.prettyPrint` in combination with
its default behavior of wrapping lines at a specific limit (70 chars). Since the
output is only meant to be used as JSON string data, wrapping the lines makes it
less readable by adding unnecessary `\n`.

This commit disables the line wrapping, which effectively avoids the bug that
was responsible for incorrectly formatting anchor elements and surrounding
space.

Related to #15681.
2017-04-01 18:23:01 +01:00
c8be3960a0 style(aio): fix minor syntax error 2017-04-01 11:49:08 +01:00
759af8b56b feat(aio): add id to doc-viewer container based on current url
This enables page specific styling via CSS.
2017-04-01 11:49:08 +01:00
97deb01b1f feat(aio): add about component and data 2017-04-01 07:49:45 +01:00
ad639d783f feat(aio): add contribute marketing page 2017-04-01 07:45:42 +01:00
e1c2e50d92 docs(aio): move bio images into content folder 2017-04-01 07:17:24 +01:00
dd4e3f8704 build(aio): copy content image assets 2017-04-01 07:17:24 +01:00
08941aa0c7 build(aio): process marketing docs that have .md extension
See #15661
2017-03-31 17:32:16 -07:00
03fb766428 feat(aio): shell code styling 2017-03-31 17:13:36 -07:00
2454a3b641 build(aio): process contributor.json file 2017-03-31 17:13:25 -07:00
3e793f079d build(aio): fix empty docplaster processing 2017-03-31 17:13:06 -07:00
5fbb0d050c fix(language-service): resolve any parameter types to any result 2017-03-31 11:37:39 -07:00
71a8627c5d fix(language-service): improve resilience to incomplete information 2017-03-31 11:37:39 -07:00
5c38012980 fix(aio): contributor.html typos 2017-03-31 11:37:09 -07:00
7c2ce296d3 feat(aio): add footer background 2017-03-31 11:36:56 -07:00
9d37d86223 feat(aio): docs landing page with styles, logo res fix 2017-03-31 11:36:56 -07:00
21ef5a1961 feat(aio): docs landing page with styles, logo res fix 2017-03-31 11:36:56 -07:00
46f8a6dd85 docs(aio): remove unnecessary blank lines 2017-03-31 16:22:08 +01:00
0aa90c6be4 feat(aio): add presskit and correct "/logos/angular2/" 2017-03-31 11:24:46 +01:00
c05a8cf7bb build(aio): copy examples boilerplate 2017-03-31 09:57:43 +01:00
4c21114087 feat(aio): remove google feedback 2017-03-31 09:37:57 +01:00
65bb2373ae fix(aio): remove "v.2" from index.html "title" 2017-03-31 08:24:44 +01:00
8c925bca71 build(aio): update rho to new version
This version changes the expected syntax for emphasis.
The original Rho renderer uses `*` for strong an `_` for em.
But it is more standard in markdown to use `**` or `__` for bold
and `*` or `_` for em.
2017-03-31 08:08:08 +01:00
330a8c90e4 docs(aio): quickstarts are now in the guide folder 2017-03-31 08:05:33 +01:00
d8c35c893b docs(aio): move quickstarts and glossary into guide 2017-03-31 08:05:33 +01:00
0fe308c0ef docs(aio): remove docs that are unwanted or in the wrong place 2017-03-31 08:05:33 +01:00
2d14c3b17a docs(aio): ensure blank lines before HTML blocks in markdown 2017-03-31 08:05:33 +01:00
8ef621ad2a fix(compiler): fix inheritance for AOT with summaries (#15583)
Allows to inherit ctor args, lifecycle hooks and statics from a class
in another compilation unit. 
Will error if trying to inherit from a class in another compilation unit 
that has an `@Component` / `@Directive` / `@Pipe` / `@NgModule`.
2017-03-30 14:51:29 -07:00
28bf222a6a feat(aio): add footer links with GoogleFeedbackService (#15605) 2017-03-30 14:46:25 -07:00
9e883f5873 feat(aio): improve ProgressiveWepApp-ability (#15628)
Previous Lighthouse score: 52/100
New Lighthouse score: 95+/100

Fixes #15588
2017-03-30 12:35:15 -07:00
43a9619e57 feat(aio): overall margin, code, alert styles 2017-03-29 23:55:43 -07:00
f518e3a75f feat(aio): code cpy btn temp fix and footer ext 2017-03-29 23:55:43 -07:00
146b30796e feat(aio): code blocks, copy bttn, a tag hover 2017-03-29 23:55:43 -07:00
5942b2b27c feat(aio): footer repeat background 2017-03-29 23:55:43 -07:00
330b1090f4 refactor(aio): move media queries to mixin 2017-03-29 23:55:43 -07:00
3ccbe28d9f feat(aio): enable activating available ServiceWorker updates (#15561) 2017-03-29 23:55:03 -07:00
67719f2185 docs: add changelog for 4.1.0-beta.0 2017-03-29 16:56:11 -07:00
6388768d73 release: cut the 4.1.0-beta.0 release 2017-03-29 16:55:47 -07:00
1dda05a965 docs: add changelog for 4.0.1 2017-03-29 16:30:34 -07:00
14fd78fd85 fix(core): fix inheritance in JIT mode for TS 2.1 (#15599)
Fixes #15502
2017-03-29 16:14:51 -07:00
a9321b1387 fix(language-service): correctly determine base members of types (#15600)
Fixes #15460
2017-03-29 16:14:37 -07:00
19cb503531 docs(http): remove deprecated stuff and outdated plunkrs (#15598) 2017-03-29 15:11:59 -07:00
9f2acf54bc feat(aio): refactors AppComponent and its kids + sidenav hiding (#15570)
-hides sidenav when current doc is not in sidenav menu
-displays top menu on the side as nodes instead of mini top menu
2017-03-29 14:13:40 -07:00
9c77a7cdaf fix(compiler): throw when a component defines both template and templateUrl (#15572)
Closes #15566
2017-03-29 10:26:48 -07:00
d58a242fe7 refactor(router): cleanup & simplification (#15436) 2017-03-29 09:44:04 -07:00
910c0d9ee7 fix(core): Update types for TypeScript nullability support (#15472) 2017-03-29 09:34:45 -07:00
331b9f6425 fix(language-service): don't require reflect-metadata module to be provided (#15569)
Fixes #15568
2017-03-29 09:34:21 -07:00
49162784a8 docs(core): fix API docs for Injector.get 2017-03-28 16:57:22 -07:00
0c36f2353d perf(router): don't create new serializer every time UrlTree.toString is called (#15565) 2017-03-28 16:17:48 -07:00
a580f8c61f fix(animations): make sure style calculations are not computed too early (#15540)
Closes #15507
2017-03-28 16:07:49 -07:00
f368381d12 fix(router): should run CanActivate after CanDeactivate guards
Closes #14059
Closes #15467
2017-03-28 15:51:33 -07:00
7c2f795ea6 refactor(router): fix tests structure 2017-03-28 15:51:17 -07:00
93d48f1d89 fix(core): fix the key/value differ (#15539)
fixes #15457
2017-03-28 15:50:11 -07:00
861953c95c feat(aio): add LiveExampleComponent (#15544) 2017-03-28 14:41:50 -07:00
aa16ccda79 fix(core): check for undefined on normalizeDebugBindingValue (#15503)
DebugServices is parsing false atributes values incorrectly.
Parse5 expects a string value for attributes, but currently boolean is being sent.

Closes #15494
2017-03-28 13:33:07 -07:00
6269d28bb0 fix(language-service): improve performance of updateModuleAnalysis() (#15543) 2017-03-28 13:32:46 -07:00
d438b88f19 fix(compiler): ignore errors when evaluating base classes (#15560)
Fixes #15536
2017-03-28 13:32:34 -07:00
8e03f65645 refactor(router): improve flatten fn
closes #15505
2017-03-28 09:39:20 -07:00
606b8fafb0 refactor(router): use object spread operator instead of merge fn 2017-03-28 09:38:58 -07:00
b7fa5dec21 fix(core): improve error msg for invalid KeyValueDiffer.diff arg (#15489)
Closes #15402
2017-03-28 09:37:40 -07:00
a5c972aa8b fix(language-service): be resilient to invalidate ordering (#15470)
Fixes #15466
2017-03-28 09:37:24 -07:00
d05aa70c6b docs(core): fix typo and example in InjectionToken doc (#15449)
The doc included an example that didn't use InjectionToken.
2017-03-28 09:37:08 -07:00
eac99c1b16 build(aio): do not HTML format code-example contents (#15554)
The markdown renderer passes its output through an HTML pretty printer.
While this is good in most cases, it makes a mess of elements that expect
their content to be left untouched.

The pretty printer already ignores `pre` tags (and other built-ins) by
default. This fix allows us to specify other tags that should be left
alone.

Further it actually specifies this option for `code-example` and `code-pane`
tags, which expect to contain preformatted content.
2017-03-28 08:22:44 -07:00
b7a89cec59 feat(aio): show top-nav with same styling as side-nav when window is narrow
Fixes #15490
2017-03-28 11:48:28 +01:00
9e0d7be014 build(aio): fix angular-cli config typo 2017-03-28 10:49:52 +01:00
99951911d5 fix(aio): selectedNodes should work for URLs ending with a slash
The mapping was not accounting for the fact that URLs with or without
a trailing slash are actually the same node.
2017-03-28 10:48:51 +01:00
fd72fad8fd docs(aio): update migrated content from anguar.io 2017-03-28 10:21:46 +01:00
ff82756415 fix(aio): ensure DocumentService doesn't crash on bad JSON 2017-03-28 10:21:46 +01:00
d28243d5fc test(aio): the tutorial link no longer ends with a slash
And since the navigation opens to the initial page, we don't need
to click the link.
2017-03-28 10:21:46 +01:00
447e534350 build(aio): render ALL code-examples, not just the first 2017-03-28 10:21:46 +01:00
cda887896a build(aio): include top level docs in content 2017-03-28 10:21:46 +01:00
09b548db75 build(aio): update Rho to a version that accepts custom-elements 2017-03-28 10:21:46 +01:00
920bf373fe fix(language-service): guard access to Symbol.members (#15529)
Fixes #15528 

What is the current behavior?
The language service access TypeScript's Symbol.members without checking for null or undefined.
What is the new behavior?
The access is guarded.
2017-03-27 17:40:48 -07:00
a9ae4daab2 ci: add tbosch and vicb as approvers of the language service (#15530) 2017-03-27 17:38:43 -07:00
15662efec4 build(aio): update project config for @angular/cli v1.0.0
This is a follow-up to 487a0e1. The changes are based on [this wiki entry][1].

[1]: https://github.com/angular/angular-cli/wiki/stories-1.0-update.
2017-03-27 11:55:26 -07:00
5846c46b76 build(aio): remove unused gulp dependency 2017-03-27 11:55:26 -07:00
816b389759 docs: in doc comments, replace [aA]ngular2 with Angular (#15463) 2017-03-27 09:44:35 -07:00
6605dd1c7c docs(aio): correct spelling in overview 2017-03-27 14:36:05 +01:00
837ed788f4 feat(aio): add code-example and code-tabs
* move embedded components to EmbeddedModule
* add PrettyPrint service; load pretty print js dynamically
* make code-example to syntax highlighting w/ `prettyPrintOne`
* add code-tabs
* Implement copy code button
2017-03-27 12:25:34 +01:00
2e4fe7fd2e docs(aio): add test content 2017-03-27 12:25:34 +01:00
52ea193638 build(aio): left align code regions 2017-03-27 10:10:34 +01:00
5e3ef775d5 build(aio): remove naughty fdescribe from utils spec 2017-03-27 10:10:34 +01:00
228238e602 refactor(aio): move SearchService initialisation into SearchBoxComponent
The AppComponent really doesn't need to know about the search service.
2017-03-27 09:24:38 +01:00
a6fd22c399 docs(aio): fix typo 2017-03-27 09:15:50 +01:00
1616cae5cf build(aio): add renderExamples processor
This processor will eventually replace the `{@example}` inline tags
because it provides a cleaner approach that also supports tabbed examples
straight out of the box.

The idea is that authors will simply add a `path` and (optionally) a `region`
attribute to `<code-example>` or `<code-pane>` elements in their docs.
This indicates to dgeni that the relevant example needs to be injected
into the content of this element.

For example, assume that there is an example file `toh-pt1/index.hml` with
a region called `title`, which looks like:

```
<h1>Tour of Heroes</h1>
```

Then the document author could get this to appear in the docs as a
standalone example:

```
<code-example path="toh-pt1" region="title"></code-example>
```

Or as part of a tabbed group:

```
<code-tabs>
  <code-pane path="toh-pt1" region="title"></code-pane>
</code-tabs>
```

If no `path` attribute is provided then the element is ignored, which
enables authors to provide inline code instead:

```
<code-example>
 Some &lt;html&gt escaped code
</code-example>
```

Also all attributes other than `path` and `region` are ignored and passed
through to the final rendered output allowing the author to provide
styling hints:

```
<code-example path="toh-pt1" region="title" linenums"15" class="important">
</code-example>
```
2017-03-25 21:32:30 +00:00
d5cf684d99 build(aio): refactor getExampleRegion into a reusable service 2017-03-25 21:32:30 +00:00
c9e51d9911 feat(aio): add new classes, table and images styling (#15478) 2017-03-25 14:21:40 +00:00
b2830384f5 build(aio): upgrade @angular/service-worker to v1.0.0-beta.8 2017-03-25 07:27:42 +00:00
487a0e1b5d build(aio): upgrade @angular/cli to v1.0.0 2017-03-25 07:27:42 +00:00
8fe42e58b3 build(aio): upgrade @angular/* to v4.0.0 2017-03-25 07:27:42 +00:00
afb17a5b6e feat(aio): block code examples style fix 2017-03-25 06:55:59 +00:00
b8f3533d53 feat(aio): search input animation 2017-03-25 06:55:59 +00:00
4918cd241f feat(aio): search results and code margins styling 2017-03-25 06:55:59 +00:00
45983301d5 feat(aio): footer styling 2017-03-25 06:55:59 +00:00
acf57def13 feat(aio): marketing responsive items and footer 2017-03-25 06:55:59 +00:00
800591db00 feat(aio): add a and ol to standard typo styles 2017-03-25 06:55:59 +00:00
159c98c202 feat(aio): search result stying, add footer 2017-03-25 06:55:59 +00:00
c837b3dfb9 feat(aio): terminal code styling and code mixin 2017-03-25 06:55:59 +00:00
53b89ec312 fix(compiler): allow single quotes into named interpolations (#15461)
Fixes #15318
2017-03-24 15:10:41 -07:00
c17b912eb9 refactor: use object spread operator rather than merge (#15426) 2017-03-24 14:45:33 -07:00
8785b2bf6d fix(router): shouldn't execute CanLoad when a route has been loaded
Closes #14475
Closes #15438
2017-03-24 14:38:38 -07:00
fb1be83a1b refactor(router): polishing 2017-03-24 14:38:23 -07:00
ea848f74af docs: clarify querying all descendants (#15400)
Fixes #14417
Updated example to illustrate @ContentChildren default behavior (only query direct children), and how to query for nested elements/all descendants.
2017-03-24 14:36:55 -07:00
b8d5f87f96 feat(compiler): support ICU messages in XLIFF
Fixes #12636
Closes #15068
2017-03-24 14:35:28 -07:00
95afaf495b test(compiler): refactor i18n integration test 2017-03-24 14:35:10 -07:00
d92930e975 docs: fixed broken links (#15455)
Closes #15446
2017-03-24 08:14:23 -07:00
c2892dada3 docs: revert the move of CONTRIBUTING.md to docs/CONTRIBUTING.md
Because the root path has a special meeting for GitHub, Jeremy, unicorns and red arrows.
2017-03-23 20:57:49 -07:00
b2b1195534 docs: update the contributing link one more time :-) 2017-03-23 19:26:25 -07:00
e1b09e3bcc docs: update CONTRIBUTING link in README.md 2017-03-23 19:25:46 -07:00
c65b75443e docs: add the 4.0.0 code name to the changelog 2017-03-23 17:46:02 -07:00
db0dca3fc1 docs: add a note about exclusion of symbols prefixed with ɵ from our public api surface (#15440) 2017-03-23 17:21:52 -07:00
7a715b2403 docs: add changelog for 4.0.0 2017-03-23 16:48:54 -07:00
1ba296644d release: cut the 4.0.0 release 2017-03-23 16:45:16 -07:00
b800a0c824 fix: prevent strictNullChecks support until #15432 is fixed (#15434) 2017-03-23 14:54:19 -07:00
0dda01e37c fix(compiler): correctly handle when toString is exported (#15430)
Fixes #15420
2017-03-23 13:38:01 -07:00
c8ab5cb0c5 fix(compiler): assume queries with no matches as static (#15429)
This has the side effect of allowing `@Input` and `@ContentChild`
on the same property if the query is static (see the bug description
for details).

Fixes #15417
2017-03-23 13:37:45 -07:00
92084f2b6a fix(platform-browser): setAttribute should work with xmlns namespace (#14874)
Closes #14865
2017-03-23 12:52:06 -07:00
08f2f08d74 fix(router): should pass new data to Observable when query params change (#15387)
Fixes #15290
2017-03-23 10:43:14 -07:00
376088da70 build(aio): delete content folder before doc-gen (#15414)
This should prevent false-positive e2e test runs where stale files
are left lying around.
2017-03-23 10:23:09 -07:00
73808dd38b build(aio): upgrade to @angular@4.0.0-rc.6 (#15412) 2017-03-22 23:52:43 -07:00
ee03418b10 release: cut the 4.0.0-rc.6 release 2017-03-22 23:09:47 -07:00
da700d1842 docs: move markdown docs from root dir to docs/ and remove obsolete files (#15410) 2017-03-22 22:50:12 -07:00
de87c47dd9 docs: spelling errors 2017-03-22 21:28:24 -07:00
1060805a1f docs: fix spelling 2017-03-22 21:28:24 -07:00
08d86751b9 fix(compiler): only log template deprecation warning once (#15364) 2017-03-22 21:26:53 -07:00
9319b5f329 docs(common): update ngFor docs to new as syntax (#15166) 2017-03-22 17:18:22 -07:00
26f6bd4d3b ci(travis): update excluded branch to g3 (#15391) 2017-03-22 17:15:38 -07:00
edb2571a59 docs: spelling error (#15406) 2017-03-22 17:14:56 -07:00
98cb974796 docs(router): fix typo in ParamMap api doc (#15397) 2017-03-22 17:14:11 -07:00
8b414222aa fix(aio): do not fallback to index.html for file requests (#15401)
Previously, all URLs were rewritten to `index.html` in order to support
deep-linking. This works when navigating to URLs that correspond to existing
resources. E.g. navigating to `/tutorial` returns `index.html` and then the
`DocViewer` takes over and requests `tutorial.json`.
Navigating to a non-existent URL (e.g. `/foo`), will return `index.html`, which
in turn requests (the non-existent) `foo.json` and throws an error when trying
to parse the returned `index.html` as JSON.

This commit fixes it by only rewriting URLs that do not request a file (i.e. do
not include a `.` in the last path segment).

Fixes #15398
2017-03-22 15:31:47 -07:00
ea49a95bd9 fix(upgrade): component injectors should not link the module injector tree (#15385) 2017-03-22 15:22:38 -07:00
a50d79df47 fix(compiler-cli): adding missing format xliff for the extractor (#15386)
To generate XLF files with ng-xi18n we could use the format parameter "xlf" or "xlif". The real name is "xliff" not "xlif", so this probably was a typo. This PR adds "xliff" as can be expected
2017-03-22 15:12:02 -07:00
64285a2171 docs: update 4.0.0-rc.5 release schedule (#15288) 2017-03-22 13:26:12 -07:00
941f194a83 docs: spelling errors (#15375) 2017-03-22 13:25:35 -07:00
8b4edcc7ad build(aio): output {@example} tags as <code-example> elements (#15382) 2017-03-22 13:24:40 -07:00
c58499786c fix(tsc-wrapped): use windows friendly path normalization in bundler (#15374)
Fixes #15289

PR Close #15374
2017-03-21 22:30:57 -05:00
1bcbcfd56f revert: build(aio): implement prerendering (#15346)
This reverts commit d0bc83ca27.

Protractor-based prerendering is flakey on Travis and takes several minutes to
complete, slowing down the build. Prerendering has a lower impact now that we
use a ServiceWorker. We will revisit in the future (probably using a
`PlatformServer`-based approach).

PR Close #15346
2017-03-21 19:05:36 -05:00
90d2518d9a fix(compiler): look for flat module resources using declaration module path (#15367)
`ngc` would look for flat module resources relative to the flat module index.
`ngc` now looks for flat module resources relative to the `.d.ts` file that declarates
the component.

Fixes #15221

PR Close #15367
2017-03-21 19:05:03 -05:00
7354949763 feat(tsc-wrapped): record original location of flattened symbols (#15367)
Added an "origins" section to the flat module `.metadata.json` files
that records where the original symbols was declared. This allows
correctly calculating relative path references recorded in metadata.
2017-03-21 19:05:00 -05:00
5efc86069f fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.

However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.

As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:

```ts
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```

Or, if you want to change the mode  based on locale or platform,
you can use a factory:

```ts
import {shouldUseBuffering} from 'my/lib';

....
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```

Closes #15079.

PR Close #15256
2017-03-21 16:47:18 -05:00
97149f9424 fix(core): update peer dep on zone.js to ^0.8.5 (#15365)
Closes #15185

PR Close #15365
2017-03-21 16:47:01 -05:00
bac265fdc2 refactor(core): misc cleanup (#15366)
PR Close #15366
2017-03-21 16:46:51 -05:00
e59e5e24b9 build(aio): upgrade to rxjs@5.2.0 2017-03-21 15:20:29 -05:00
9e5d4781cb refactor(aio): cleanup polyfill imports and realign them with the latest cli blueprint
This shouldn't change anything. But it's interesting that we used to have this  import
that seemed bogus, but there were no compilation or rutime errors.
2017-03-21 15:20:28 -05:00
fc1f6efe0d build(aio): fix paths to "index" pages
Content pages like `tutorial/index.md` were being mapped to `tutorial.index.json`,
which meant that they could only be rendered if you browsed to `/tutorial/index`.

This didn't sit well so now these pages are mapped to `tutorial.json`, which
means that you browser to them via `/tutorial/` or just `/tutorial`.

Fixed #15335
2017-03-21 15:20:28 -05:00
c9710d4fb5 build(aio): upgrade @angular/cli to 1.0.0-rc.4 2017-03-21 15:20:28 -05:00
cf16f3b0dd build(aio): update @angular to 4.0.0-rc.5 and zone.js to 0.8.4 2017-03-21 15:20:28 -05:00
a9e91115bf build(aio): add version into navigation.json
The navigation.json is now passed through the dgeni pipeline.
The source file has been moved to `aio/content/navigation.json`
but the generated file will now appear where the original source file
was found, `aio/src/content/navigation.json`.

Everything inside `aio/src/content` is now generated and ignored by git.

The `processNavigationMap` processor in this commit adds the current version
information to the navigation.json file and verifies the relative urls in
the file map to real documents.

The navigationService exposes the versionInfo as an observable, which the
AppComponent renders at the top of the sidenav.
2017-03-21 15:20:28 -05:00
90f699fdcf build(aio): ensure that internal document links work with base href 2017-03-21 15:20:28 -05:00
fd7b855cfc test(aio): fix test descriptions for ordering of processors 2017-03-21 15:20:28 -05:00
20aab64c65 test(aio): use MockLogger in AppComponent tests
This component sends a lot of messages to the console, which makes the
test run less easy to follow.
2017-03-21 15:20:28 -05:00
2eb027a793 build(aio): don't process unnecessary example files in doc-gen
This lowers the `yarn docs` processing time by about 40% (from 50 secs
to 30 secs).
2017-03-21 15:20:28 -05:00
b0a7bc77ee build(aio): remove cheatsheet processing and content
This will be replaced by a single file migrated from angular.io
2017-03-21 15:20:28 -05:00
4e10faf1eb build(aio): add version into navigation.json
The navigation.json is now passed through the dgeni pipeline.
The source file has been moved to `aio/content/navigation.json`
but the generated file will now appear where the original source file
was found, `aio/src/content/navigation.json`.

Everything inside `aio/src/content` is now generated and ignored by git.

The `processNavigationMap` processor in this commit adds the current version
information to the navigation.json file and verifies the relative urls in
the file map to real documents.

The navigationService exposes the versionInfo as an observable, which the
AppComponent renders at the top of the sidenav.
2017-03-21 15:20:28 -05:00
a0c6d44e18 build(aio): ensure that internal document links work with base href 2017-03-21 15:20:28 -05:00
9bc998c7a1 build(aio): use forked version of Rho rendering engine
The original Rho is too strict when it comes to markdown headings.
It requires that there be a blank line separating the heading and the
next paragraph.  The forked version here fixes that; but the Rho project
will not merge it as it goes against there basic rules.
2017-03-21 15:20:28 -05:00
1a0c6d89b1 build(aio): do not render ignored docs 2017-03-21 15:20:28 -05:00
8c12374c4c build(aio): do not render private classes and members 2017-03-21 15:20:28 -05:00
45e2126273 refactor(aio): removed dead code 2017-03-21 15:20:28 -05:00
41497b052d feat(aio): font change and toolbar shadow 2017-03-21 15:20:28 -05:00
068cad1c1b build: update to angular 4.0.0-rc.4 and service-worker@1.0.0-beta.7 2017-03-21 15:20:28 -05:00
31ef92fc36 build(aio): fix generated github links
The change from `modules` to `packages` needed to be applied to these links.
2017-03-21 15:20:28 -05:00
b4081e3713 build(aio): update to dgeni-packages 0.17.0
This new version fixes the problem with mistaking
content inside inline HTML blocks as tags

Related to #15199
2017-03-21 15:20:28 -05:00
c8b4a33a7f ci(aio): lower prerender browser instances
Hopefully this will reduce aio test flakes
2017-03-21 15:20:28 -05:00
a13ddf2e8a feat(aio): expand nav menu branch of select item on page load 2017-03-21 15:20:28 -05:00
64beae9527 fix(core): mark components for check when host events trigger. (#15359)
Fixes #15352

PR Close #15359
2017-03-21 14:27:01 -05:00
15a082c74e fix(platform-server): throw a better error message for relative URLs (#15357)
Unlike in the browser, on the server there is no concept of a document origin.
Thus, it is illegal to make requests for relative URLs against Http on platform-server.

Currently this fails with a vague error:

Error: Uncaught (in promise): Error at resolvePromise

This change adds explicit validation and a friendlier error message:

Error: URLs requested via Http on the server must be absolute. URL: /testing

Another option considered was to track the concept of an origin for the platform
and automatically prepend it to relative URLs. This would cause automatic "local
RPCs" to be made, though, which would be an unexpected and undesirable default
behavior.

Fixes #15349

PR Close #15357
2017-03-21 14:26:51 -05:00
fbccd5cd38 fix(animations): ensure empty animate() steps work at the end of a sequence (#15328)
Closes #15310
Closes #15328

PR Close #15328
2017-03-21 14:26:43 -05:00
1e8b132ade refactor(compiler): only produce log expressions for elements / text (#15350)
This change reduces the amount of generated code by only adding `log`
calls for elements and text nodes.

We need the `log` calls to allow users to jump to the right place
in the template via source maps. However, we only need it for element
and text nodes, but not for directives, queries, … as for them we 
first locate the corresponding element or text node.

Related to #15239

PR Close #15350
2017-03-21 14:26:30 -05:00
431eb309f3 fix(core): provide NgModuleRef in ViewContainerRef.createComponent. (#15350)
This is needed to support the corner cases:
- usage of a `ComponentFactory` that was created on the fly via `Compiler`
- overwriting of the `NgModuleRef` that is associated to a
  `ComponentFactory` by the `ComponentFactoryResolver` from
  which it was read.

Fixes #15241
2017-03-21 14:26:26 -05:00
8e6995c91e fix(core): stringify shouldn't throw when toString returns null/undefined (#14975)
Fixes #14948

PR Close #14975
2017-03-21 12:20:44 -05:00
0759911431 docs(compiler-cli): mention that .ngsummary.json files should be gitignore'd (#15047)
PR Close #15047
2017-03-21 12:20:38 -05:00
1d7693c1e1 fix(compiler): use attribute id to merge translations (#15302)
We extracted ids from i18n attributes but forgot to use them when merging the translations, resulting in an error about missing translations even when they were correctly defined.

Fixes #15234

PR Close #15302
2017-03-21 12:20:31 -05:00
16e0423085 revert: feat(compiler-cli): support metadata file aliases (#15331)
This reverts commit 0ab49d4cec.

PR Close #15331
2017-03-21 12:20:14 -05:00
c2ffb6bfcd build: remove use of alias metadata (#15331) 2017-03-21 12:20:06 -05:00
2489e4ba1b fix(animations): correct the main entry path in package.json (#15300)
PR Close #15300
2017-03-20 22:36:37 -05:00
94da80148e fix(animations): stringify boolean values as 1 and 0 (#15311)
Closes #15247
Closes #15311

PR Close #15311
2017-03-20 22:36:29 -05:00
764e90f9bb fix(compiler): don’t call check if we don’t need to (#15322)
If a directive has not bindings nor has a `ngDoCheck` / `ngOnInit`
lifecycle hook, don’t generate a `check` call.

This does not have an impact on the behavior, but produces
less code.

PR Close #15322
2017-03-20 22:36:20 -05:00
9bf2fb4a74 fix(animations): ensure enter/leave cancellations work (#15323)
Closes #15315
Closes #15323

PR Close #15323
2017-03-20 22:36:11 -05:00
de3d2eeeba fix(platform-server): interpret Native view encapsulation as Emulated on the server (#15155)
PR Close #15155
2017-03-20 17:14:09 -05:00
a805d00256 ci(forms): add tina as secondary for forms (#15262)
PR Close #15262
2017-03-20 17:13:52 -05:00
61135bc842 fix: remove left over debugger statement (#15309)
PR Close #15309
2017-03-20 17:13:44 -05:00
fa36ffda14 Revert "fix(compiler): shouldn't throw when Symbol is used as DI token (#13701)" (#15319)
This reverts commit 8b5c6b2732.

This feature is not compatible with the `Injector.get` which now only 
takes `Type` or `InjectableToken`. `Symbol` is not a valid type.

Closes #15183

PR Close #15319
2017-03-20 17:13:37 -05:00
d3eda7a5b5 feat(router): add ParamMap.keys to get a list of parameters 2017-03-20 09:19:32 -07:00
a755b715ed feat(router): introduce ParamMap to access parameters
The Router use the type `Params` for all of:
- position parameters,
- matrix parameters,
- query parameters.

`Params` is defined as follow `type Params = {[key: string]: any}`

Because parameters can either have single or multiple values, the type should
actually be `type Params = {[key: string]: string | string[]}`.

The client code often assumes that parameters have single values, as in the
following exemple:

```
class MyComponent {
sessionId: Observable<string>;

constructor(private route: ActivatedRoute) {}

ngOnInit() {
    this.sessionId = this.route
      .queryParams
      .map(params => params['session_id'] || 'None');
}
}

```

The problem here is that `params['session_id']` could be `string` or `string[]`
but the error is not caught at build time because of the `any` type.

Fixing the type as describe above would break the build because `sessionId`
would becomes an `Observable<string | string[]>`.

However the client code knows if it expects a single or multiple values. By
using the new `ParamMap` interface the user code can decide when it needs a
single value (calling `ParamMap.get(): string`) or multiple values (calling
`ParamMap.getAll(): string[]`).

The above exemple should be rewritten as:

```
class MyComponent {
sessionId: Observable<string>;

constructor(private route: ActivatedRoute) {}

ngOnInit() {
    this.sessionId = this.route
      .queryParamMap
      .map(paramMap => paramMap.get('session_id') || 'None');
}
}

```

Added APIs:
- `interface ParamMap`,
- `ActivatedRoute.paramMap: ParamMap`,
- `ActivatedRoute.queryParamMap: ParamMap`,
- `ActivatedRouteSnapshot.paramMap: ParamMap`,
- `ActivatedRouteSnapshot.queryParamMap: ParamMap`,
- `UrlSegment.parameterMap: ParamMap`
2017-03-20 09:19:32 -07:00
a9d5de0e56 refactor(router): misc minor updates 2017-03-20 09:19:32 -07:00
f634c62cb3 test: add systemjs+umd integration test (#14196)
This test ensures the `__esModule` is set on UMD bundles, thus making them compatible with SystemJS@^0.22.3.

Followup from https://github.com/frankwallis/plugin-typescript/issues/185.

PR Close #14196
2017-03-19 12:23:07 -05:00
f8c075ae27 fix(core): don’t create a comment for components with empty template. (#15260)
Fixes #15143

PR Close #15260
2017-03-19 12:22:26 -05:00
aeb99645bb test(animations): test various combinations of animations with host bindings (#15251)
PR Close #15251
2017-03-19 12:21:54 -05:00
0d3e314df0 fix(core): trigger host animations for elements that are removed. (#15251)
Fixes #14813
Fixes #15193
2017-03-19 12:21:42 -05:00
28ce68a13d refactor(core): view engine - change BindingType to BindingFlags (#15251) 2017-03-19 12:21:37 -05:00
80075afe8a fix(animations): only process element nodes through the animation engine (#15268)
Closes #15267
Closes #15268

PR Close #15268
2017-03-19 10:50:07 -05:00
bcc29ffdd1 build: update rollup (#15258)
PR Close #15258
2017-03-17 17:39:19 -05:00
0c43535ccc fix(core): only apply WrappedValue to the binding of the pipe (#15257)
Previously, a pipe that returned a `WrappedValue` would force the change
of the next bound property, independent of the binding in which the pipe
was used.

Now only the binding in which the `WrappedValue` is used will be assumed
as changed.

Fixes #15116

PR Close #15257
2017-03-17 17:38:36 -05:00
49829b4a4d build: add package names to secondary endpoint package.json files (#15253)
Fixes #14736

PR Close #15253
2017-03-17 16:52:55 -05:00
5c5c2ae405 fix(platform-server): setup NoopAnimationsModule in ServerModule by default (#15131)
This is so that server side rendering does not throw an exception when it encounters animations on the server side and does not need the user to explicitly setup NoopAnimationsModule in their app server module.

Fixes #15098, #14784.

PR Close #15131
2017-03-17 16:21:51 -05:00
6e9264a79c fix(tsc-wrapped): emit flat module format correctly on Windows (#15215)
File name needed to be normalized before comparison when using
synthetic file names.

Fixes #15192

PR Close #15215
2017-03-17 15:35:28 -05:00
a6fb78ee3c fix(animations): make sure non-transitioned leave operations cancel existing animations (#15254)
Closes #15213

PR Close #15254
2017-03-17 15:35:11 -05:00
d0bc83ca27 build(aio): implement prerendering
The current implementation is based on @igorminar's [angular-io-v42][1]. It is
using Protractor to request all docs URLs, let them fallback to `/index.html`
and save the rendered page.

[1]: https://github.com/IgorMinar/angular-io-v42/tree/05508ab3/tools/prerenderer

Fixes #15104
2017-03-17 15:31:22 -05:00
b5b2fed54d refactor(aio): re-arrange npm scripts 2017-03-17 15:31:22 -05:00
4cef5dddc6 build(aio): use own .gitignore file 2017-03-17 15:31:22 -05:00
f92591054b fix(animations): make sure easing values work with web-animations (#15195)
Closes #15115
Closes #15195

PR Close #15195
2017-03-17 13:53:19 -05:00
2a0e55ffb5 fix(core): allow tree shaking of component factories and styles (#15214)
Closure compiler is very sensitive to top level function calls.
This commit makes the function calls `createComponentFactory`
and `createRendererTypeV2` logic-less.

Fixes #15181

PR Close #15214
2017-03-17 13:52:57 -05:00
9429032da1 feat(upgrade): use ComponentFactory.inputs/outputs/ngContentSelectors (#15214)
DEPRECATION:
- the arguments `inputs` / `outputs` / `ngContentSelectors` of `downgradeComponent`
  are no longer used as Angular calculates these automatically now.
- Compiler.getNgContentSelectors is deprecated. Use
  ComponentFactory.ngContentSelectors instead.
2017-03-17 13:52:50 -05:00
791534f2f4 feat(core): expose inputs, outputs and ngContentSelectors on ComponentFactory. (#15214)
E.g. for a component like this:
```
@Component({
  template: ‘<ng-content select=“child”></ng-content>’
})
class MyComp {
  @Input(‘aInputName’)
  aInputProp: string;

  @Output(‘aEventName’)
  aOuputProp: EventEmitter<any>;
}
```

the `ComponentFactory` will now contain the following:
- `inputs = {aInputProp: ‘aInputName’}`
- `outputs = {aOutputProp: ‘aOutputName’}`
- `ngContentSelectors = [‘child’]`
2017-03-17 13:52:41 -05:00
604546c287 refactor(upgrade): don’t rely on compiler internals (#15214)
Uses `Element.matches` to match selectors, instead
of copying the code from our compiler.
2017-03-17 13:52:34 -05:00
c66437fc13 fix(animations): only treat view removals as void state transitions (#15245)
Closes #15223

PR Close #15245
2017-03-17 13:48:25 -05:00
8415910375 fix(compiler): add an empty content for source file of non mapped code. (#15246)
Before this when using ngc, tools tried to load `ng://…<component>.ts`
if `…<component>.ts` was the source file of a template.

PR Close #15246
2017-03-17 13:48:09 -05:00
5486e5417b feat(forms): allow to compile forms in strictNullChecks mode (#14679)
Closes #14667

PR Close #14679
2017-03-17 13:47:12 -05:00
2d78c8cc05 docs: add changelog for 4.0.0-rc.5 2017-03-17 10:18:16 -07:00
52bed7f9b3 release: cut the 4.0.0-rc.5 release 2017-03-17 10:16:53 -07:00
7fb45283df fix(compiler-cli): update the tsc-wrapped dependency version (#15226) 2017-03-17 09:41:28 -07:00
b7212f5afe docs: add changelog for 4.0.0-rc.4 2017-03-16 20:10:54 -07:00
4e25601c4d release: cut the 4.0.0-rc.4 release 2017-03-16 20:10:53 -07:00
add7829cb7 docs: add changelog for 2.4.10 2017-03-16 20:10:53 -07:00
a52184bdda fix(core): update peer dep on zone.js to ^0.8.4 (#15209) 2017-03-16 20:10:53 -07:00
410aa33005 build: fix paths to typings files so tsickle resolves imports correctly
Fixes #15080
2017-03-16 17:34:29 -07:00
0ab49d4cec feat(compiler-cli): support metadata file aliases 2017-03-16 17:34:29 -07:00
994089d36b fix(compiler): always use ng:// prefix for sourcemap urls (#15218)
Fixes:
- In G3, filePaths don’t start with a `/` and therefore became relative.
- Always using the `ng://` prefix groups angular resources in the same
  way for AOT and JIT.
2017-03-16 17:33:17 -07:00
d2fbbb44ae fix(core): update peer dep on zone.js to ^0.8.4 (#15209)
Closes #15180
Closes #15185
2017-03-16 13:23:09 -07:00
77fd91d615 fix(core): ErrorHandler should not rethrow an error by default (#15077) (#15208)
ErrorHandler can not throw errors because it will unsubscribe itself from
the error stream.

Zones captures errors and feed it into NgZone, which than has a Rx Observable
to feed it into ErrorHandler. If the ErroHandler throws, then Rx will teardown
the observable which in essence causes the ErrorHandler to be removed from the
error handling. This implies that the ErrorHandler can never throw errors.

Closes #14949
Closes #15182
Closes #14316
2017-03-16 12:58:41 -07:00
492153a986 fix(compiler): make sourcemaps work in AOT mode
Inlcuded fixes:
- include preamble in generated source map
- always add a mapping for line/col 0 so that the
  generated sourcemap is not sparse
- use a uniue sourceUrl for inline templates even
  in the AOT case
2017-03-16 12:56:56 -07:00
c0e05e6f03 fix(tsc-wrapped): emit js files in all cases 2017-03-16 12:56:56 -07:00
73a46205a0 build(tsc-wrapped): update tsickle to version 0.21.6
Update tsickle to version 0.21.6 which fixes a bug where input source maps which specified filenames differently than the names supplied to tsc didn't get composed with tsc's source maps.  Also adds a test that the bug was fixed.
2017-03-16 12:56:56 -07:00
992aa17361 build: add source maps into NPM distribution (#15159)
Previous to 2.x there were some source maps distrubted, but they didn't go
all the way back to the TypeScript sources and they weren't available for
all JavaScript distrubted to NPM.

With this change source maps will be available for FESM distributions as
well as UMD and will go all the way back to TypeScript sources.

Fixes #15184
2017-03-16 12:55:15 -07:00
a4076c70cc fix(platform-browser): prevent clobbered elements from freezing the browser
see
4f69d38f09
2017-03-16 10:16:39 -07:00
52bbc9baf4 refactor(platform-browser): cleanup HtmlSanitizer specs 2017-03-16 10:16:39 -07:00
26d4ce29e8 fix(forms): ensure observable validators are properly canceled (#15132)
Observable subscriptions from previous validation runs should be canceled
before a new subscription is created for the next validation run.
Currently the subscription that sets the errors is canceled properly,
but the source observable created by the validator is not. While this
does not affect validation status or error setting, the source
observables will incorrectly continue through the pipeline until they
complete. This change ensures that the whole stream is canceled.

AsyncValidatorFn previously had an "any" return type, but now it more
explicitly requires a Promise or Observable return type. We don't
anticipate this causing problems given that any other return type
would have caused a runtime error already.
2017-03-16 10:15:17 -07:00
41f61b0b5b test: integration test that Angular apps compile with TS 2.2 (#15153) 2017-03-16 09:13:48 -07:00
f92d644c95 ci: disable Android 4.1, 4.2 and 4.3 in SauceLabs (#14461)
These browsers are not supported anymore: https://wiki.saucelabs.com/pages/viewpage.action?pageId=67012495

Tried to switch them to BrowserStack, but the emulators are too slow to run the full campaign (time out in tests, and disconnect eventually).
2017-03-16 09:13:07 -07:00
923d0c56e7 fix: correct UMD resolutions for platform-browser_animations (#15190)
Fixes #15114
2017-03-15 17:14:20 -07:00
dd36d413ba build: update symlink scripts for Windows (#14987) 2017-03-15 17:13:54 -07:00
013d806b79 fix(platform-server): handle styles with extra ':'s correctly (#15189)
Previously, style values were parsed with a regex that split on /:+/.

This causes errors for CSS such as

div {
  background-url: url(http://server.com/img.png);
}

since the regex would split the background-url line into 3 values instead of 2.

Now, the : character is detected with indexOf, avoiding this error.

A test was added to verify the behavior is correct.
2017-03-15 17:13:31 -07:00
6e98757665 fix(core): use presence of .subscribe to detect observables rather then Symbol.observable (#15171)
Fixes #14298
Fixes #14473
Fixes #14926
2017-03-15 17:13:03 -07:00
313158132d Revert "fix(core): ErrorHandler should not rethrow an error by default (#15077)"
This reverts commit 6559425b07.
2017-03-15 16:29:24 -07:00
6772c913c7 fix(aio): scroll to hash fragment element on URL change 2017-03-15 16:11:30 -07:00
b11d0119ac feat(aio): top bar typography, sidenav size 2017-03-15 16:11:30 -07:00
637a489996 refactor(aio): indent and org cleanup 2017-03-15 16:11:30 -07:00
c2bd357825 feat(aio): initial design commit
Implemented style guide elements to top header bar, side hamburger nav menu, content and search. Consolidated SCSS files to styles folder. Fixed PWA test.
2017-03-15 16:11:30 -07:00
4870f910d6 feat(aio): hide search results when click outside search elements
Clicking anywhere except on the search results and the search box will
now hide the search results

Closes #15095
2017-03-15 16:11:30 -07:00
c95a3048ce fix(aio): SearchBoxComponent should send query on click
The input may still have focus when the user hits ESC,
causing the search to be hidden.

If the user then clicks on the input again, they would expect
it to reopen the results.
2017-03-15 16:11:30 -07:00
0e6eb6d719 test(aio): fill in missing API page unit tests 2017-03-15 16:11:30 -07:00
09574fc285 build(aio): yarn test --sourcemap=false for faster dev/test cycles 2017-03-15 16:11:29 -07:00
4347cb2119 ci(aio): whitelist 'aio-contributors' for deploying PR previews 2017-03-15 16:11:29 -07:00
f600d4e9e4 refactor(aio): move window:resize handler into component 2017-03-15 16:11:29 -07:00
eaa04354d5 fix(aio): intercept all clicks on anchors
Previously we had the `LinkDirective` which intercepted clicks on anchors
outside the doc viewer. Now we intercept "all" link clicks within the app.
2017-03-15 16:11:29 -07:00
3f7cfde476 fix(aio): ignore private exports
Closes #14992
2017-03-15 16:11:29 -07:00
62d5543b01 fix(animations): make sure easing values are applied to an empty animate() step (#15174)
Closes #15115
Closes #15174
2017-03-15 15:31:06 -07:00
f1b33ab7b1 fix(http): Make ResponseOptionsArgs an interface (#14607) (#14623)
closes #13708
2017-03-15 15:28:52 -07:00
029d0f25e5 fix(router): fix query parameters with multiple values (#15129)
fixes #14796
2017-03-15 15:27:19 -07:00
3f38c6fdcd fix(animations): always fire callbacks even for noop animations (#15170)
Closes #15170
2017-03-15 13:41:00 -07:00
80112a9ea1 fix: fix path locally to empty.js (#15073) 2017-03-15 13:40:24 -07:00
795638e18b ci: remove unused import from integration test (#15175) 2017-03-15 13:39:00 -07:00
322bf7a0d5 Revert "refactor(upgrade): don’t rely on compiler internals"
This reverts commit 8e2c8b3e4d.
2017-03-15 13:23:31 -07:00
cd981499f9 Revert "feat(core): expose inputs, outputs and ngContentSelectors on ComponentFactory."
This reverts commit 1171f91a80.
2017-03-15 13:23:10 -07:00
c439742a54 Revert "feat(upgrade): use ComponentFactory.inputs/outputs/ngContentSelectors"
This reverts commit a3e32fb7e1.
2017-03-15 13:22:54 -07:00
a3e32fb7e1 feat(upgrade): use ComponentFactory.inputs/outputs/ngContentSelectors
DEPRECATION:
- the arguments `inputs` / `outputs` / `ngContentSelectors` of `downgradeComponent`
  are no longer used as Angular calculates these automatically now.
- Compiler.getNgContentSelectors is deprecated. Use
  ComponentFactory.ngContentSelectors instead.
2017-03-15 11:42:12 -07:00
1171f91a80 feat(core): expose inputs, outputs and ngContentSelectors on ComponentFactory.
E.g. for a component like this:
```
@Component({
  template: ‘<ng-content select=“child”></ng-content>’
})
class MyComp {
  @Input(‘aInputName’)
  aInputProp: string;

  @Output(‘aEventName’)
  aOuputProp: EventEmitter<any>;
}
```

the `ComponentFactory` will now contain the following:
- `inputs = {aInputProp: ‘aInputName’}`
- `outputs = {aOutputProp: ‘aOutputName’}`
- `ngContentSelectors = [‘child’]`
2017-03-15 11:42:12 -07:00
8e2c8b3e4d refactor(upgrade): don’t rely on compiler internals
Uses `Element.matches` to match selectors, instead
of copying the code from our compiler.
2017-03-15 11:42:12 -07:00
b00fe20afd fix(compiler): support interface types in injectable constuctors (#14894)
Fixes #12631
2017-03-15 09:24:56 -07:00
36ce0afff6 fix(animations): support multiple state names per state() call (#15147)
Closes #14732
Closes #15147
2017-03-15 09:24:09 -07:00
5c0ea20bd0 build(tsc-wrapped): use tsickleCompilerHost for initial file load
In order for tsickle's new support for input source maps to work, the tsickleCompilerHost must be used for the initial load of source files, since that's when the inline source maps are read and stripped.
2017-03-15 09:23:36 -07:00
49764a5bff build(tsc-wrapped): update tsickle to version 0.21.5 2017-03-15 09:23:36 -07:00
4f7d62adac fix(platform-server): fix an exception when HostListener('window:scroll') is used on the server (#15019) 2017-03-14 20:48:01 -07:00
c10c060d20 feat(common): support as syntax in template/* bindings (#15025)
* feat(common): support `as` syntax in template/* bindings

Closes #15020

Showing the new and the equivalent old syntax.
- `*ngIf="exp as var1”`
   => `*ngIf="exp; let var1 = ngIf”`
- `*ngFor="var item of itemsStream |async as items”`
   => `*ngFor="var item of itemsStream |async; let items = ngForOf”`

* feat(common): convert ngIf to use `*ngIf="exp as local“` syntax

* feat(common): convert ngForOf to use `*ngFor=“let i of exp as local“` syntax

* feat(common): expose NgForOfContext and NgIfContext
2017-03-14 20:46:29 -07:00
5fe2d8fd80 fix(core): update peer dep on zone.js to ^0.8.2 (#15078) 2017-03-14 20:42:39 -07:00
5c34066058 fix(compiler): only warn for @Injectable classes with invalid args.
In v2.x, users had to annotate classes that they intended to use as tokens with `@Injectable`. This is no longer required in v4.x for tokens,
and we now require the constructor parameters of classes annotated
with `@Injectable` to be statically analyzable by ngc.

This commit reduces the error into a warning
if the constructor parameters do not meet this condition.

DEPRECATION:
- Classes annotated with `@Injectable` but whose constructor’s parameter types
  are not statically analyzable by ngc will produce a warning.

Closes #15003
2017-03-14 19:52:53 -07:00
50ab06e29d fix(compiler): generated code should pass noUnusedLocals check
Closes #14797
2017-03-14 19:52:53 -07:00
06fc42bc44 fix(core): don’t throw if queries change during change detection.
Throwing on query changes would be a breaking change compared to v2.
Also discovers a bug with querying manually projected content, see #15117.

Related to #14748
Closes #14925
2017-03-14 19:52:53 -07:00
959a03a61f fix(compiler): fix utf8encode, move to sharted utils, add tests (#15076) 2017-03-14 17:13:39 -07:00
3b1956bbf2 fix(compiler): warning prints "WARNING" instead of "ERROR" (#15125) 2017-03-14 17:12:44 -07:00
3c15916e17 fix(compiler): Improve error message for missing annotations (#14724)
Currently, it says:
Unexpected value 'FuzzyTimePipe in
javascript/angular2/example/search/fuzzy_time.ts' declared by the module
'SearchModule in javascript/angular2/example/search/search_module.ts'

The new error message also suggests: 'Please add a @Pipe/@Directive/@Component annotation.'
2017-03-14 17:12:18 -07:00
ff60c041f6 test(platform-server): add initial e2e tests for platform-server (#15061) 2017-03-14 17:11:39 -07:00
13686bb518 fix: element injector vs module injector (#15044)
fixes #12869
fixes #12889
fixes #13885
fixes #13870

Before this change there was a single injector tree.
Now we have 2 injector trees, one for the modules and one for the components.
This fixes lazy loading modules.

See the design docs for details:
https://docs.google.com/document/d/1OEUIwc-s69l1o97K0wBd_-Lth5BBxir1KuCRWklTlI4

BREAKING CHANGES

`ComponentFactory.create()` takes an extra optional `NgModuleRef` parameter.
No change should be required in user code as the correct module will be used
when none is provided

DEPRECATIONS

The following methods were used internally and are no more required:
- `RouterOutlet.locationFactoryResolver`
- `RouterOutlet.locationInjector`
2017-03-14 16:26:17 -07:00
f093501501 fix(platform-server): support svg elements with namespaced attributes (#15101) 2017-03-14 15:40:55 -07:00
80649ea03c fix(platform-server): correctly implement get href in parse5 adapter (#15022) 2017-03-14 15:38:24 -07:00
778f7d6f33 fix(forms): remove equalsTo validator (#15050)
This API was introduced only in a beta release, and is being removed because we found it to be incorrect prior to launch. For more information about why this is being removed, see https://github.com/angular/angular/pull/15050.
2017-03-14 15:37:51 -07:00
2c5a671341 fix: don't instantiate providers with ngOnDestroy eagerly. (#15070)
BREAKING CHANGE:

Perviously, any provider that had an ngOnDestroy lifecycle hook would be created eagerly.

Now, only classes that are annotated with @Component, @Directive, @Pipe, @NgModule are eager. Providers only become eager if they are either directly or transitively injected into one of the above.

This also makes all `useValue` providers eager, which
should have no observable impact other than code size.

EXPECTED IMPACT:
Making providers eager was an incorrect behavior and never documented.
Also, providers that are used by a directive / pipe / ngModule stay eager.
So the impact should be rather small.

Fixes #14552
2017-03-14 14:32:26 -07:00
0aad270267 refactor(platform-browser): move platform-browser/animations to animations/browser (#15130)
Closes: #15130
2017-03-14 11:55:49 -07:00
221899a930 ci: fix incorrect github credetials (#15146) 2017-03-14 11:49:33 -07:00
060a2d11e5 ci(aio): deploy previews from aio-master (#15137) 2017-03-14 10:28:52 -07:00
abbbb4d52c ci: do not use shell to expand secure tokens to prevent leaks 2017-03-14 10:27:56 -07:00
ccd38dd54d ci: changing deployment token 2017-03-14 10:27:56 -07:00
cdc882bd36 feat: introduce source maps for templates (#15011)
The main use case for the generated source maps is to give
errors a meaningful context in terms of the original source
that the user wrote.

Related changes that are included in this commit:

* renamed virtual folders used for jit:
  * ng://<module type>/module.ngfactory.js
  * ng://<module type>/<comp type>.ngfactory.js
  * ng://<module type>/<comp type>.html (for inline templates)
* error logging:
  * all errors that happen in templates are logged
    from the place of the nearest element.
  * instead of logging error messages and stacks separately,
    we log the actual error. This is needed so that browsers apply
    source maps to the stack correctly.
  * error type and error is logged as one log entry.

Note that long-stack-trace zone has a bug that 
disables source maps for stack traces,
see https://github.com/angular/zone.js/issues/661.

BREAKING CHANGE:

- DebugNode.source no more returns the source location of a node.  

Closes 14013
2017-03-14 09:16:15 -07:00
1c1085b140 feat(aio): add google analytics (#15081) 2017-03-13 18:08:23 -07:00
914797a8ff feat(upgrade): support multi-slot projection in upgrade/static (#14282)
Closes #14261
2017-03-13 17:34:53 -07:00
ab40fcb068 docs(aio): fix relative links
The migrator was updated to automatically fix these links.
See fca5fb0280
and 3927b7a038

The result of this is that, going forward, we should ask
authors to include the path from the base href to the thing
being linked. E.g. guide/architecture#intro
2017-03-13 16:56:23 -07:00
1847550ad1 docs(aio): move cookbooks into guide
Also update all docs with migrated versions from latest angular.io

Fixes #14941
2017-03-13 16:56:23 -07:00
6497633529 feat(aio): improve search results functionality
* Ensure that all indexed documents are displayed in the search results.
(Previously the guide documents were not appearing because we only showed
results that had a `name` property, rather than a `name` or `title`.)
* Group the results by their containing folder (e.g. api, guide, tutorial, etc).
* Hide the results when the user hits the ESC key.
* Hide the results when the user clicks on a search result

Closes #14852
2017-03-13 16:55:52 -07:00
8850098ea4 build(aio): ensure API docs are generated in the correct place (#15103)
The move of the source code from modules/@angular to packages, caused a
problem with the path to the API docs.
2017-03-13 16:53:47 -07:00
eedca09d73 build(aio): generate the api-list.json file from the API docs 2017-03-13 16:52:58 -07:00
7b6dbf0952 fix(aio): LocationService search should handle corner cases
Adds tests and fixes corners cases for both `search()` and `setSearc()`
for things like empty queries and param keys that need encoding.

This commit refactors the `LocationService` to rely upon the `PlatformLocation`
rather than using `window.history` directly. This makes testing easier but also
makes the code simpler since `PlatformLocation` deals with platforms that
do not support history for us.
2017-03-13 16:52:58 -07:00
e6c81d2a42 Revert "refactor(platform-browser): move platform-browser/animations to animations/browser (#15043)"
This reverts commit 195b863ea4.
2017-03-13 15:46:44 -07:00
498a95148b Revert "build(animations): adjust animations/browser source to new standard for automatic build (#15043)"
This reverts commit 21a18d6ceb.
2017-03-13 15:46:07 -07:00
21a18d6ceb build(animations): adjust animations/browser source to new standard for automatic build (#15043) 2017-03-13 14:39:42 -07:00
195b863ea4 refactor(platform-browser): move platform-browser/animations to animations/browser (#15043) 2017-03-13 14:39:19 -07:00
75147ff008 fix(aio): remove invalid brace from CSS (#15122) 2017-03-13 13:36:22 -07:00
018e5c979b fix(platform-server): fix get/set title in parse5 adapter (#14965) 2017-03-13 13:22:03 -07:00
e7dab7e6c1 feat(aio): hard code a "Home" image link into the toolbar
Closes #15017
2017-03-13 12:55:11 -07:00
26efa3a25c style(aio): tidy up SCSS files 2017-03-13 12:55:11 -07:00
893652a813 fix(aio): upgrade to zone.js 0.7.8 (#15099)
This new version supports empty jasmine it clauses.
2017-03-13 12:53:45 -07:00
6559425b07 fix(core): ErrorHandler should not rethrow an error by default (#15077) 2017-03-13 11:27:01 -07:00
df914ef4bf fix(core): don’t recreate TemplateRef when used as a reference. (#15066)
This was a regression introduced in v4 rc.0.

Fixes #14873
2017-03-13 10:44:12 -07:00
4e1cf5b41a build(aio): replace all occurrences of env vars on a line in aio-builds-setup 2017-03-13 10:30:49 -07:00
0c5f893f6e test(aio): improve test description and expectations 2017-03-13 10:30:49 -07:00
17f5f3b32c ci(aio): fix clean-up script on ngbuilds.io 2017-03-13 10:30:49 -07:00
3bb59902f7 docs(aio): add more docs about aio-builds-setup 2017-03-13 10:30:49 -07:00
b804a488c5 feat(aio): make it easy to keep relevant logs outside the docker container 2017-03-13 10:30:49 -07:00
cbde75e77b feat(aio): redirect HTTP to HTTPS 2017-03-13 10:30:49 -07:00
413e11fac2 build(aio): remove redundant arg 2017-03-13 10:30:49 -07:00
0e2dd76c3b build: remove obsolete ci-lite/ directory and files (#14994)
The directory was removed in 91fe3aadb but then accidentally re-introduced while
rebasing and merging ab0db66bf.
2017-03-13 10:29:45 -07:00
ff71eff157 refactor(core): use flags in Renderer2.setStyle instead of booleans (#15045)
BREAKING CHANGE: (since v4 rc.1)
- `Renderer2.setStyle` no longer takes booleans but rather a
  bit mask of flags.
2017-03-13 09:45:04 -07:00
fa1920a02b feat(aio): enable deep-linking on deployed apps (until prerendering is done) (#15049) 2017-03-13 09:35:16 -07:00
71cd2957f7 ci: add wardbell and gkalpak to aio approvers (#15030) 2017-03-13 09:34:40 -07:00
6c8638cf01 feat(core): allow to provide multiple default testing modules (#15054)
This can be used to e.g. add the NoopAnimationsModule by default:

```
TestBed.initTestEnvironment([
  BrowserDynamicTestingModule,
  NoopAnimationsModule
], platformBrowserDynamicTesting());
```
2017-03-10 16:55:32 -08:00
8b5c6b2732 fix(compiler): shouldn't throw when Symbol is used as DI token (#13701)
Closes #13314
2017-03-10 15:26:37 -08:00
601494734c Revert "fix(core): ErrorHandler should not rethrow an error by default (#13534)"
This reverts commit 1aebea52e1.
2017-03-10 15:05:48 -08:00
1aebea52e1 fix(core): ErrorHandler should not rethrow an error by default (#13534)
Closes #14949
Closes #13159
Closes #8993
2017-03-10 14:44:14 -08:00
920b3d259d feat(aio): support @angular/service-worker using the CLI generated service worker manifest (#15042) 2017-03-10 14:05:29 -08:00
fce55d87d2 feat(aio): add Kapunahele animations v2 (#15023) 2017-03-10 14:05:00 -08:00
53d62fa7d0 ci: use angular-builds credentials for publishing artifacts (#15072) 2017-03-10 14:03:40 -08:00
a69afeb614 ci: skip root pullapproval for packages directory (#15071) 2017-03-10 13:54:28 -08:00
5f9fb911f7 fix(compiler): improve error msg for unexpected closing tags (#14747)
Closes #6652
2017-03-10 13:05:17 -08:00
d17d4a3b54 docs: add changelog for 4.0.0-rc.3 2017-03-10 12:26:19 -08:00
814dc107d9 release: cut the 4.0.0-rc.3 release 2017-03-10 12:21:52 -08:00
bebedfed24 build: build modules and examples for karma 2017-03-08 17:35:20 -08:00
2b44854885 build: fix paths for examples tests 2017-03-08 16:29:28 -08:00
b74ab83d2c refactor: update paths from modules/@angular to packages 2017-03-08 16:29:28 -08:00
da8ea350b2 refactor: More generic build.sh file 2017-03-08 16:29:28 -08:00
1efd508217 build: update package.json to remove babel. 2017-03-08 16:29:28 -08:00
58dd4673cd refactor: remove babel config files 2017-03-08 16:29:28 -08:00
72563b61fb build: fix rollup config file paths 2017-03-08 16:29:28 -08:00
5aed1e36b8 refactor: move secondary entry point rollup configs. 2017-03-08 16:29:28 -08:00
8573e36574 build: fix file paths after moving modules/@angular/* to packages/* 2017-03-08 16:29:28 -08:00
3e51a19983 refactor: move angular source to /packages rather than modules/@angular 2017-03-08 16:29:27 -08:00
5ad5301a3e feat(aio): add API list page (#14899) 2017-03-08 13:08:19 -08:00
174d4c8ef7 ci(aio): do not deploy PR if preconditions not met
This avoids incorrectly failing the build if the PR author is not a member of one of the whitelisted GitHub teams.
2017-03-07 18:24:45 -08:00
4ca772eea3 refactor(aio): move scripts into scripts/ directory 2017-03-07 18:24:45 -08:00
093d69f0f0 ci(aio): only deploy a preview if the PR touched relevant files 2017-03-07 18:24:45 -08:00
b4ec80b21d docs(aio): document arg for auto-restarting the docker container on boot 2017-03-07 18:24:45 -08:00
a4476654aa refactor(aio): use more intuitive log filepath 2017-03-07 18:24:45 -08:00
4210d2b4b1 test(aio): fix e2e tests 2017-03-07 18:24:45 -08:00
aa30c50144 feat(aio): make it easier to create a docker image (less variables to overwrite) 2017-03-07 18:24:45 -08:00
fd34a58e13 fix(aio): ensure NGBUILDS_IO_KEY is not printed
Gaining access to another PR's JWT, would allow faking that PR's author wrt to
GitHub team membership verification for as long as the JWT is valid (currently
90 mins).
2017-03-07 18:24:45 -08:00
e40f81b564 ci(aio): fail the build if preview deployment fails 2017-03-07 18:24:45 -08:00
5ab2e28703 ci(aio): bringing in #14888 (because no patience) 2017-03-07 18:24:45 -08:00
a3a7cf2090 build(aio): allow overwriting env vars at build time 2017-03-07 18:24:45 -08:00
d9d9d9de6f build(aio): allow passing parameters to docker build 2017-03-07 18:24:45 -08:00
7e67f37fc4 ci(aio): test aio-builds-setup as part of the aio job 2017-03-07 18:24:45 -08:00
d275667da0 build(aio): upgrade to latest and pin major pm2 version 2017-03-07 18:24:45 -08:00
03a5fd01c9 fix(aio): do not hardcode the domain in preview link comments 2017-03-07 18:24:45 -08:00
d28ea80db8 build(aio): always compile before running tests 2017-03-07 18:24:45 -08:00
0e9277b4c3 style(aio): change mock value for consistency 2017-03-07 18:24:45 -08:00
2796790c7d feat(aio): verify uploaded builds based on JWT from Travis 2017-03-07 18:24:45 -08:00
028b274750 feat(aio): support passing secrets as files to the docker container 2017-03-07 18:24:45 -08:00
3ed1f64d43 feat(aio): implement BuildVerifier 2017-03-07 18:24:45 -08:00
96f11dad18 feat(aio): implement GithubTeams 2017-03-07 18:24:45 -08:00
060d02eb82 fix(aio): remove unnecessary repoSlug parameter from GithubApi 2017-03-07 18:24:45 -08:00
951e653b0c feat(aio): implement GithubApi.getPaginated() 2017-03-07 18:24:45 -08:00
37348989f0 feat(aio): make githubToken mandatory for GithubApi 2017-03-07 18:24:45 -08:00
c5644e5a0d refactor(aio): add assertNotMissingOrEmpty() helper 2017-03-07 18:24:45 -08:00
c8d87a936b feat(aio): add support for HTTPS (certificates provided by host - fallback to self-signed) 2017-03-07 18:24:45 -08:00
6b8413f7b3 build(aio): update TypeScript (and other dependencies) 2017-03-07 18:24:45 -08:00
bc831ff4a4 feat(aio): check resolution of external URLs in HEALTHCHECK 2017-03-07 18:24:45 -08:00
8a8d4fe24f test(aio): fix typos (repoSlag --> repoSlug) 2017-03-07 18:24:45 -08:00
9df9bdc0f5 style(aio): correctly type tuple 2017-03-07 18:24:45 -08:00
c8ead9bcd0 refactor(aio): use types intead of interfaces for functions 2017-03-07 18:24:45 -08:00
115164033b ci(aio): add initial implementation for aio-builds setup 2017-03-07 18:24:45 -08:00
794f8f4e6a build(aio): update .gitignore 2017-03-07 18:24:45 -08:00
ad3b44aef7 RendererV2 -> Renderer2 rename (#14998)
* refactor: rename `RendererV2` into `Renderer2`

BREAKING CHANGE (since 4.0 rc.1):
- rename `RendererV2` to `Renderer2`
- rename `RendererTypeV2` to `RendererType2`
- rename `RendererFactoryV2` to `RendererFactory2`
2017-03-07 16:36:12 -08:00
5df998d086 fix(router): do not finish bootstrap until all the routes are resolved (#14762)
DEPRECATION:

Use `RouterModule.forRoot(routes, {initialNavigation: 'enabled'})` instead of
`RouterModule.forRoot(routes, {initialNavigtaion: true})`.

Before doing this, move the initialization logic affecting the router
from the bootstrapped component to the boostrapped module.

Similarly, use `RouterModule.forRoot(routes, {initialNavigation: 'disabled'})`
instead of `RouterModule.forRoot(routes, {initialNavigation: false})`.

Deprecated options: 'legacy_enabled', `true` (same as 'legacy_enabled'),
'legacy_disabled', `false` (same as 'legacy_disabled').

The "Router Initial Navigation" design document covers this change.
Read more here:
https://docs.google.com/document/d/1Hlw1fPaVs-PCj5KPeJRKhrQGAvFOxdvTlwAcnZosu5A/edit?usp=sharing
2017-03-07 14:27:20 -08:00
1cff1250ba refactor: remove old compiler options (#14891)
DEPRECATION:
- `CompilerOptions.debug` has no effect any more, as the compiler
  always produces the same code independent of debug mode.
2017-03-07 11:16:27 -08:00
07122f0ad9 fix(upgrade): populate upgraded component's view before creating the controller (#14289)
Previously, the relative order of the AngularJS compiling/linking operations was
not similar to AngularJS's, resulting in inconsistent behavior for upgraded
components (which made upgrading to Angular less straight forward).

This commit fixes it, by following the compiling/linking process of AngularJS
more closely.

Main differences:

- The components view is already populated when the controller is instantiated
  (and subsequent hooks are called).
- The correct DOM content is available when running the `$onChanges`, `$onInit`,
  `$doCheck` hooks. Previously, the "content children" were still present, not
  the "view children".
- The same for pre-linking.
- The template is compiled in the correct DOM context (e.g. has access to
  ancestors). Previously, it was compiled in isolation, inside a dummy element.

For reference, here is the order of operations:

**Before**

1. Compile template
2. Instantiate controller
3. Hook: $onChanges
4. Hook: $onInit
5. Hook: $doCheck
6. Pre-linking
7. Collect content children
8. Insert compiled template
9. Linking
10. Post-linking
11. Hook: $postLink

**After**

1. Collect content children
2. Insert template
3. Compile template
4. Instantiate controller
5. Hook: $onChanges
6. Hook: $onInit
7. Hook: $doCheck
8. Pre-linking
9. Linking
10. Post-linking
11. Hook: $postLink

Fixes #13912
2017-03-07 09:32:52 -08:00
ebd446397a fix(aio): reimplement the top menu dropping into the side bar
I couldn't find the CSS for the `.small` class to make it look nice.
2017-03-06 22:27:32 -08:00
55189b1b85 refactor(aio): simplify and document the NavigationService 2017-03-06 22:27:32 -08:00
b017fbe48e style(aio): rename local variable 2017-03-06 22:27:32 -08:00
0d6aa0caed style(aio): rename const to camelCase 2017-03-06 22:27:32 -08:00
b70c881c00 docs(aio): fix paths to images 2017-03-06 22:27:32 -08:00
0d63e2a586 docs(aio): copy devguide images from angular.io 2017-03-06 22:27:32 -08:00
d83b7ba4c0 refactor(aio): rename activeNodes to selectedNodes
This keeps the naming consistent with the nav-menu
and nav-item component properties
2017-03-06 22:27:32 -08:00
46d6e8d191 fix(aio): reimplement side-nav 2017-03-06 22:27:32 -08:00
61ef756ef2 fix(aio): ensure that only one request for navigation.json is made 2017-03-06 22:27:32 -08:00
3529813ca0 fix(aio): move interfaces into their own files to workaround compile weirdness
For some reason the tree-shaker is not picking up these interfaces
(perhaps TS is not passing it through) when they are in the same file
as their related services. This results in a distracting warning message.
2017-03-06 22:27:32 -08:00
b81693b30c fix(aio): no need for path and url properties in nav 2017-03-06 22:27:32 -08:00
5815983178 fix(aio): correctly intercept links with LinkDirective 2017-03-06 22:27:32 -08:00
fe962f6de7 fix(aio): LocationService urls should never start with a slash
There is a weirdness in the Angular Location service.
If the `baseHref` is only a single slash (`'/'`) then it
changes it to be an empty string (`''`). The effect of this
is that `Location.normaliseUrl(url)` does not strip off the
leading slash from url paths.

The problem is that the leading slash only appears on the
initial Location path, and not on urls that arrive from subscribing
to the Location service.

This commit is a workaround this problem.
2017-03-06 22:27:32 -08:00
04e14589c4 docs(aio): make home doc the default home page
Now the `/` url will display the home page.

Closes #14849
2017-03-06 22:27:32 -08:00
d6c1ccaf14 fix(aio): emit a hard-coded doc if file-not-found fails
Closes #14848
2017-03-06 22:27:32 -08:00
4abd6f333c fix(aio): map the empty url to the correct doc path 2017-03-06 22:27:32 -08:00
dd50922747 refactor(aio): move document path computation
Do the path computation before doing the cache look up.
2017-03-06 22:27:32 -08:00
66cc88c8a8 fix(aio): ensure that only one request per document is made 2017-03-06 22:27:32 -08:00
b44bc9c022 test(aio): add mock services 2017-03-06 22:27:32 -08:00
b7e76cc2e1 ci: re-enable publishing master artifacts (#14973) 2017-03-06 18:03:38 -08:00
3651d8d673 fix: throw for synthetic properties / listeners by default (#14880)
This allows to detect the case that the animation module is not loaded.
2017-03-06 17:15:08 -08:00
ba4b6f58d9 fix(core): allow to use the Renderer outside of views. (#14882)
Fixes #14872
2017-03-06 17:08:22 -08:00
6cd3326b55 fix(compiler): don’t throw for empty array literal in assignments (#14878)
Closes #14782
2017-03-06 17:01:45 -08:00
6bc6482765 fix(compiler): improve error message when a module imports itself (#14646)
Closes #14644
2017-03-06 17:00:25 -08:00
f2adb2900d refactor: remove the symlink hack from tsc-wrapped (#14837) 2017-03-06 15:22:33 -08:00
8343fb7740 refactor: remove lang.ts (#14837) 2017-03-06 15:22:29 -08:00
84a65cf788 refactor: remove global from facade/lang (#14837) 2017-03-06 15:22:22 -08:00
b0e0839075 refactor: remove facade/collection (#14837) 2017-03-06 15:22:14 -08:00
4fe0b90948 refactor: remove facade/browser (#14837) 2017-03-06 15:22:06 -08:00
928c5657c8 refactor: remove EventEmitter from facade (#14837)
As of right now each module has its own copy of the EventEmitter
contributing to bloat.
2017-03-06 15:21:39 -08:00
728fe472f8 ci: replace '| head -n1' with 'git log -1' due to broken pipe breaking -o pipefail 2017-03-05 11:53:45 -08:00
32990307fe ci: turn on bash xtrace in publish-build-artifacts.sh to debug deploy failure on master 2017-03-05 11:43:25 -08:00
00fdcf4e58 build: allow check-environment.js to be run directly 2017-03-05 08:41:26 -08:00
ab0db66bf7 build(aio): move gulp tasks to package.json
Generate the docs with `yarn docs`.
Test the doc generation code with `yarn docs-test`

The docs are automatically built as part of the `yarn build` task,
so there is no need to rebuild them in the test_aio.sh file
2017-03-05 08:41:26 -08:00
8757656508 build(aio): upgrade to angular 4.0.0-rc.2 2017-03-05 08:41:26 -08:00
01ff427685 test(aio): reimplemented all the commented-out unit tests 2017-03-05 08:41:26 -08:00
2ebfa2ff31 test(aio): add placeholder test descriptions 2017-03-05 08:41:26 -08:00
b09ee424bf refactor(aio): reorganize search service for easier testing 2017-03-05 08:41:26 -08:00
b8321e2f7d ci: add comment and remove debugging printenv statement 2017-03-05 08:12:55 -08:00
b8f0c3dc7b ci: redo how env variables are set and shared in ci to prevent collisions 2017-03-05 08:03:38 -08:00
91fe3aadbc ci: delete obsolete files and move scripts/ci-lite/ to scripts/ci/ 2017-03-05 08:03:38 -08:00
a24e652f2b ci: clean up CI logging, folding, add build time logging, and improve error handling (#14425) 2017-03-02 00:22:24 -08:00
207298cd3a build(aio): generate marketing docs JSON files 2017-03-02 00:21:06 -08:00
62eafa4eec test(aio): fix up links in app e2e test 2017-03-02 00:21:06 -08:00
4626ca2bff build(aio): add file-not-found doc 2017-03-02 00:21:06 -08:00
38bb744008 fix(aio): remove external HTML and SCSS from app component 2017-03-02 00:21:06 -08:00
dca83ec738 feat(aio): add search service and search UI 2017-03-02 00:21:06 -08:00
71e22b8d11 feat(aio): implement doc and navigation UI 2017-03-02 00:21:06 -08:00
371dc4744c feat(aio): add navigation service 2017-03-02 00:21:06 -08:00
4767f107fb feat(aio): add logger service 2017-03-02 00:21:06 -08:00
5ae4b77d8b feat(aio): add document service 2017-03-02 00:21:06 -08:00
887d32a9bf feat(aio): add location service 2017-03-02 00:21:06 -08:00
3883b736c0 build(aio): content documents should have a contents field 2017-03-02 00:21:06 -08:00
c2e672cd1c docs(aio): add NOTES 2017-03-02 00:21:06 -08:00
93c0ab7131 fix(aio): remove previous files 2017-03-02 00:21:06 -08:00
e6e8123bdd build: update to yarn 0.21.3 (#14805) 2017-03-01 23:58:05 -08:00
49aa50886a docs: add 2.4.9 release notes 2017-03-01 23:22:56 -08:00
180b705227 release: cut the 4.0.0-rc.2 release 2017-03-01 22:46:11 -08:00
0f94b93c81 docs: add changelog for 4.0.0-rc.2 2017-03-01 22:44:18 -08:00
de57b2d9fd docs: update 2.4.9 release schedule 2017-03-01 22:43:38 -08:00
9560ad81b9 fix(animations): make animations work in AOT (#14775) 2017-03-01 17:13:06 -08:00
3168ef75da build: fix secondary entry point es5 output and core Rx references (#14820)
Secondary entry points (testing, static, etc) are rolled up into a
single ESM/ES2015 file, then downleveled to ESM/ES2015. This downleveling
was not working and was producing ESM/ES2015. Also, the @angular/core
package's .babelrc file was missing reference to Rx Observable which
broke the UMD bundle.

Fixes #14730
2017-03-01 15:59:09 -08:00
b6e6fc1724 docs: fix changelog to list npm command for Windows (#14812)
Closes #14809
2017-03-01 15:37:16 -08:00
dd499010be ci: add NGBUILDS_IO_KEY to .travis.yaml for ngbuilds.io integration 2017-03-01 15:28:10 -08:00
d2803da8b6 ci: add AlexE and Jason to the build-and-ci pullapprove group 2017-03-01 15:28:10 -08:00
a6996a9cdd fix(tsc-wrapped): validate metadata in static members of a class (#14772)
Fixes #13481
2017-03-01 14:45:00 -08:00
6bae7378b1 fix(language-service): tolerate errors in decorators (#14634)
Fixes #14631
2017-03-01 13:23:34 -08:00
7a66a4115b test(language-service): test @angular/language-service can be loaded by tsserver.js (#14721) 2017-03-01 13:22:46 -08:00
79fc1e3959 fix(compiler): apply element bindings before host bindings (#14823) 2017-03-01 12:17:43 -08:00
9402df92de test(platform-server): enable meta tag and title service specs for server (#14574)
Fix CSS selector syntax to allow single and double quotes. Needed for meta tag service selector to work properly on parse5.

Fixes #14565.
2017-03-01 11:19:22 -08:00
47bdc2b0b7 fix(platform-server): don't setup Testability and TestabilityRegistry on the server (#14510) 2017-03-01 11:16:56 -08:00
49b462e815 test: closure integration test for change detection (#14691) 2017-03-01 08:05:22 -08:00
5753de50f0 fix(core): fix isComponentView() and isEmbeddedView() tests (#14789)
fixes #14778
2017-03-01 08:03:14 -08:00
d1182af1a4 refactor: change remaining <template> to <ng-template> (#14706) 2017-03-01 08:02:37 -08:00
bc9e1debf2 docs: changelog - fix else example (#14766)
The else syntax needs a `ng-template`.
2017-03-01 08:02:02 -08:00
fc9e6b2a0a docs: add details about OpaqueToken deprecation in the changelog (#14790) 2017-03-01 08:01:08 -08:00
968995a4c6 fix(upgrade): fix upgrade component Closure optimization. (#14801)
$scope and $element are passed to AngularJS, which is not optimized
together with the app. That means properties must be quoted to prevent
renaming.
2017-03-01 06:49:25 -08:00
5ba55b0e04 fix(compiler): fix identifier names of EMPTY_MAP / EMPTY_ARRAY (#14806) 2017-02-28 14:16:26 -08:00
126fda2613 perf: delete pre-view-engine core, compiler, platform-browser, etc code (#14788)
After the introduction of the view engine, we can drop a lot of code that is not used any more.

This should reduce the size of the app bundles because a lot of this code was not being properly tree-shaken by today's tools even though it was dead code.
2017-02-27 23:08:19 -08:00
e58cb7ba08 docs: fix animations module instructions in the changelog (#14729)
Closes #14728
2017-02-27 16:17:14 -08:00
5caab71f7d refactor: make identifiers for generated code small to improve dev size 2017-02-27 14:50:41 -08:00
d2e42567a6 fix(core): call lifecycle hooks for siblings in declaration order 2017-02-27 14:50:41 -08:00
14d37fe052 refactor(core): move NodeType and ProviderType into NodeFlags
Also removes `ng-reflect` attributes for element properties.
2017-02-27 14:50:41 -08:00
f356041f09 docs: update version in changelog to reflect RC.1 (not 0) (#14740) 2017-02-27 11:26:16 -08:00
77682a3397 fix(compiler): quote animation in RendererTypeV2 and skip if empty (#14773) 2017-02-27 11:23:37 -08:00
213e210a93 docs: changelog - add anchor to the FESM section 2017-02-25 20:17:02 -08:00
c868457e21 docs: improve Flat ES Modules docs 2017-02-25 20:15:50 -08:00
f32f4de95c docs: more changelog fixes 2017-02-24 18:24:18 -08:00
26ed2621a3 docs: fix typo in the changelog 2017-02-24 18:22:30 -08:00
c7d1b3664b docs: update release schedule due to bad 4.0.0-rc.0 release 2017-02-24 18:08:28 -08:00
da79ad3cec build: cut 4.0.0-rc.1
rc.0 is not part of the repo history because of a missing fix that was discovered after publishing to npm
2017-02-24 18:03:23 -08:00
7b02eae0e8 build: manually bump tsc-wrapped version to rc.0 2017-02-24 17:57:55 -08:00
0c01d990bf docs: add changelog for 4.0.0-rc.0 2017-02-24 17:57:55 -08:00
2602b039b4 fix(animations): ignore triggers that are registered multiple times (#14723) 2017-02-24 16:28:14 -08:00
9186068df1 fix(animations): always create a new AnimationRenderer
E.g. for no view encapsulation, the delegate will always be the same.
Nevertheless, we still need to create a new `AnimationRenderer` per
component.

Attention: This change will conflict with a local mod in G3.
2017-02-24 16:27:45 -08:00
8824e39325 refactor(platform-browser): extract animations providers into separate file
This is needed so that we can use them in a local modification in G3.

Attention: This change will conflict with a local mod in G3.
2017-02-24 16:27:45 -08:00
932a02f1c5 build(language-service): fix tsconfig needed for language-service rollup (#14717) 2017-02-24 15:16:23 -08:00
3c9a46c231 fix(core): fix directive instantiation (#14715)
this issue was discovered in g3 and the patch was confirmed there.

we should add a test as a followup up change.
2017-02-24 13:03:55 -08:00
436a179552 fix(animations): properly cache renderer and namespace triggers (#14703)
- Don’t use the animation renderer if a component
  used style encapsulation but no animations.
- The `AnimationRenderer` should be cached in the same
  lifecycle as its delegate.
- Trigger names need to be namespaced per component type.
2017-02-24 12:10:19 -08:00
5094aef8fd fix(compiler-cli): fix flat module import on Windows (#14712) 2017-02-24 11:52:18 -08:00
93ddd38107 refactor(animations): make modules and bundles into plural Animations (#14695) 2017-02-24 09:36:58 -08:00
32c2fd5c9f refactor(animations): change NoOp -> Noop (#14690) 2017-02-24 00:32:19 -08:00
1f3198cb50 feat(aio): copy example code from angular.io 2017-02-23 23:23:58 -08:00
3e34ba01bd docs(aio): migrate content docs from angular.io
This content was generated by a tool: https://github.com/petebacondarwin/aio-migrator
2017-02-23 23:23:58 -08:00
c3247c64a4 docs(aio): remove unused partial file 2017-02-23 23:23:58 -08:00
1282da1b14 feat(aio): support unannotated JSON example files 2017-02-23 23:23:58 -08:00
1c08f1a6b2 fix(aio): remove unused extractTitleFromGuides processor 2017-02-23 23:23:58 -08:00
dfed388139 fix(aio): convert API and content docs to JSON 2017-02-23 23:23:58 -08:00
5e9474d24c feat(aio): include guide and tutorial in the doc generation 2017-02-23 23:23:58 -08:00
b92f52649b fix(aio): remove unused getExampleFilename service 2017-02-23 23:23:58 -08:00
3f8d5ac478 feat(aio): support annotating JSON files with doc-regions
This change allows the example writer to add doc-region annotations to
files that do not allow comments. This is done by creating a clone of the
file and adding `.annotated` to the file name. This new file can contain
inline `// ...` comments that can be used to annotate the doc regions.

Example:

**package.json**

```
{
  "name": "angular.io",
  "version": "0.0.0",
  "main": "index.js",
  "repository": "git@github.com:angular/angular.git",
  "author": "Angular",
  "license": "MIT",
  "private": true,
}
````

**package.json.annotated**

```
{
  "name": "angular.io",
// #docregion version
  "version": "0.0.0",
// #enddocregion
  "main": "index.js",
  "repository": "git@github.com:angular/angular.git",
  "author": "Angular",
  "license": "MIT",
  "private": true,
}
````

This region can then be referenced in examples just like any other doc region:

```
{@example 'package.json' region="version"}
```
2017-02-23 23:23:58 -08:00
bee567afad fix(aio): add @suppress tag that is used in the API docs 2017-02-23 23:23:58 -08:00
649bab8ff8 fix(aio): handle html docregions that do not end on the same line 2017-02-23 23:23:58 -08:00
6a9251874b fix(aio): region parser error line numbers were off by one 2017-02-23 23:23:58 -08:00
c208f97461 fix(aio): correctly handle "empty" region names 2017-02-23 23:23:58 -08:00
2da3844673 build(language-service): support deep import bundling of language services (#14689) 2017-02-23 22:53:17 -08:00
41da5998cd feat(router): add an option to rerun guards and resolvers when query changes (#14624)
Closes #14514
Closes #14567
2017-02-23 22:12:30 -08:00
be8510356a fix(animations): microtasks should not be timeouts (#14687) 2017-02-23 21:23:57 -08:00
01907bafb0 build(platform-server): update parse5 to v3 (#14538) 2017-02-23 21:14:04 -08:00
39f56fafdd feat(compiler-cli): add an outFile option to ng-xi18n
Fixes #11416
Closes #14508
Closes #14657
2017-02-23 20:39:46 -08:00
234f05996c feat(compiler-cli): add a locale option to ng-xi18n
Fixes #12303
Closes #14537
2017-02-23 20:39:46 -08:00
e99d721612 feat(compiler): Add a enableLegacyTemplate option to support <template>
When the `enableLegacyTemplate` is set to `false`, `<template>` tags and the
`template` attribute are no more used to define angular templates but are
treated as regular tag and attribute.

The default value is `true`.

In order to define a template, you have to use the `<ng-template>` tag.

This option applies to your application and all the libraries it uses. That is
you should make sure none of them rely on the legacy way to defined templates
when this option is turned off (`false`).
2017-02-23 20:03:16 -08:00
bf8eb41248 feat(compiler): introduce <ng-template>, deprecate <template> and template attribute
The rationale of this change is to improve the inter-operability with web
components that might make use of the `<template>` tag.

DEPRECATION

The template tags and template attribute are deprecated:

    <template ngFor [ngFor]=items let-item><li>...</li></template>
    <li template="ngFor: let item of items">...</li>

should be rewritten as:

    <ng-template ngFor [ngFor]=items let-item><li>...</li></ng-template>

Note that they still be supported in 4.x with a deprecartion warning in
development mode.

MIGRATION

- `template` tags (or elements with a `template` attribute) should be rewritten
as a `ng-template` tag,
- `ng-content` selectors should be updated to referto a `ng-template` where they
use to refer to a template: `<ng-content selector="template[attr]">` should be
rewritten as `<ng-content selector="ng-template[attr]">`
- if you consume a component relying on your templates being actual `template`
elements (that is they include a `<ng-content selector="template[attr]">`). You
should  still migrate to `ng-template` and make use of `ngProjectAs` to override
the way `ng-content` sees the template:
`<ng-template projectAs="template[attr]">`
- while `template` elements are deprecated in 4.x they continue to work.
2017-02-23 20:03:16 -08:00
3f519207a4 refactor(compiler): misc + add a test for directives on inline templates 2017-02-23 20:03:16 -08:00
ee747f7d0c refactor(core): change abstract classes for interfaces (#12324)
BREAKING CHANGE: Because all lifecycle hooks are now interfaces
the code that uses 'extends' keyword will no longer compile.

To migrate the code follow the example below:

Before:
```
@Component()
class SomeComponent extends OnInit {}
```
After:
```
@Component()
class SomeComponent implements OnInit {}
```

we don't expect anyone to be affected by this change.

Closes #10083
2017-02-23 18:04:51 -08:00
a23634dfd0 fix(common): do not reference deprecated classes in providers (#14523) (#14523)
References to `NgFor` are now an alias for `NgForOf` instead of a
derived class.

Fixes #14521
2017-02-23 17:23:56 -08:00
c53621be8e build: resolve review comments on flat modules PR and fix more bugs (#14660) 2017-02-23 16:39:44 -08:00
4b54c0e23f refactor(core): enable new animations dsl
Also deletes old tests that are not needed any
more with the new view engine.
2017-02-23 13:59:16 -08:00
ccb636c2e9 refactor: deprecate RootRenderer / Renderer
Use `RendererV2` instead of `Renderer` now. `Renderer` can still be injected
and delegates to `RendererV2`.

Use `RendererFactoryV2` instead of `RootRenderer`. `RootRenderer` cannot be used
anymore.

BREAKING CHANGE:
- `RootRenderer` cannot be used any more, use `RendererFactoryV2` instead.
  Note: `Renderer` can still be injected/used, but is deprecated.
2017-02-23 13:59:16 -08:00
d3a98c74d6 feat(core): enable new view engine 2017-02-23 13:59:16 -08:00
187f7b68f2 refactor(animations): always remove elements right away unless they have a leave animation 2017-02-23 13:02:45 -08:00
835e18709d refactor(animations): always flush animations when inserting children 2017-02-23 13:02:45 -08:00
36b78e9502 refactor(animations): defer the noop engine's event deregistration 2017-02-23 13:02:45 -08:00
4301dce7b0 fix(packaging): properly build the core-testing bundle 2017-02-23 12:57:07 -08:00
6277f16187 fix: small fixes for view engine 2017-02-23 12:57:07 -08:00
e8d2743cfb feat(animations): noop animation module and zone fixes (#14661) 2017-02-23 08:51:00 -08:00
ab3527c99b refactor(core): view engine - misc
- fix bug when detaching view from `ApplicationRef`
- fix integration of adding `ng-reflect` attributes
  in debug mode.
2017-02-23 08:26:47 -08:00
5049a50bf6 fix(core): host bindings and host listeners for animations
Host bindings / listeners for animation properties should use
the renderer of the component view.
2017-02-23 08:26:47 -08:00
6b7937f112 test: fix flaky e2e inbox-app test due to net::ERR_SSL_PROTOCOL_ERROR from fetching google fonts (#14665)
example broken build: https://travis-ci.org/angular/angular/jobs/204456086#L2355
2017-02-22 22:00:01 -08:00
175dbce354 build: check yarn version in check-environment (#14499)
As discussed in
https://github.com/angular/angular/pull/14382#discussion_r100620839.
2017-02-22 20:55:25 -08:00
e8a27447c4 ci: update local chrome to v56
Change required in previous commit ab96257bc that upgrades the CLI version.
env.sh: protractor v.5 requires a later version of chromium. Upping to 433059/Chrome 56.
2017-02-22 17:53:56 -08:00
9a2ea55bff build(aio): upgrade to CLI beta.32 and MD beta.2 2017-02-22 17:53:56 -08:00
a26eb4c04e test(aio): redefine pipe test as a pending test to confirm code example 2017-02-22 17:53:56 -08:00
801b09066b fix(compiler-cli): import shallow import to @angular/upgrade/static correctly (#14658)
Fixes #14648
2017-02-22 17:23:08 -08:00
a1d4769199 feat: add a PLATFORM_ID token that provides a platform id Object. (#14647) 2017-02-22 16:49:46 -08:00
88bc143431 fix: app ids for better <style> management for ssr (#14632)
Currently styles are rendered to the root component element, which ensures they're cleaned up automatically
when the client application is bootstrapped. This is less than ideal as progressive rendering can cause HTML
to be rendered before the CSS is loaded, causing flicker.

This change returns to rendering <style> elements in the <head>, and introduces a mechanism for removing
them on client bootstrap. This relies on associating the server and client bootstrap. Another way to think
of this is that the client, when bootstrapping an app, needs to know whether to expect a server rendered
application exists on the page, and to identify the <style> elements that are part of that app in order
to remove them.

This is accomplished by providing a string TRANSITION_ID on both server and client. For most applications,
this will be achieved by writing a client app module that imports BrowserModule.withServerTransition({appId: <id>}).
The server app module will import this client app module and therefore inherit the provider for
TRANSITION_ID. renderModule[Factory] on the server will validate that a TRANSITION_ID has been provided.
2017-02-22 16:06:21 -08:00
830393d234 refactor(animations): support browser animation rendering (#14578) 2017-02-22 15:14:49 -08:00
88755b0dae build(aio): update dgeni-packages to 0.16.8 (#14597) 2017-02-22 11:27:09 -08:00
c9bfc59a21 fix(tsc-wrapped): use agreed on options names (#14630) 2017-02-22 10:57:01 -08:00
fcc1d17ccb fix(compiler-cli): avoid generating unnecessary factories 2017-02-21 20:48:55 -08:00
de795ea233 perf: distrubute smaller bundled code and include es2015 bundle
TypeScript compiler will now build to ES2015 code and modules. Babili is used to minify ES2015
code, providing an initial optimization that we couldn't previously get just from Uglify. Uses
Babel to convert ES2015 to UMD/ES5 code, and Uglify to minimize the output.
2017-02-21 20:48:55 -08:00
738d93caf7 refactor: rewrite private export using the ɵ prefix 2017-02-21 20:48:55 -08:00
bb0460b93b refactor(core): don’t use switch fall through but rather multiple ifs
V8 does this internally any ways. This way, we can also keep the existing
dirty checking order, which some apps sadly rely on.
2017-02-21 09:12:21 -08:00
90226f7714 refactor(core): conditionally disable tests for the view engine. 2017-02-21 09:12:21 -08:00
7db93310f1 fix: view engine - fix some corner cases 2017-02-21 09:12:21 -08:00
32012a1ffb refactor(core): view engine - move handleEvent function from view to element
Some versions of TypeScript are super slow to compile functions that
contain a lot of `if` conditions in them. Splitting the handle event
expressions per element is similar to what we did in the old codegen.
2017-02-21 09:12:21 -08:00
58ba4f0409 fix(compiler): make view engine work with Aot 2017-02-21 09:12:21 -08:00
2ddd1c3ed2 Revert "fix(http): Make ResponseOptionsArgs an interface (#14607)"
This reverts commit fbe4b76f2d.
2017-02-20 19:48:53 -08:00
c2d5f203a5 Revert "feat(router): add an option to rerun guards and resolvers when query changes"
This reverts commit c2e0f71a78.
2017-02-20 19:48:43 -08:00
670f2eca00 Revert "fix(router): do not finish bootstrap until all the routes are resolved (#14608)"
This reverts commit 2a191cae2d.
2017-02-20 19:48:23 -08:00
2a191cae2d fix(router): do not finish bootstrap until all the routes are resolved (#14608)
Fixes #12162
closes #14155
2017-02-20 18:37:38 -08:00
c2e0f71a78 feat(router): add an option to rerun guards and resolvers when query changes
Closes #14514
Closes #14567
2017-02-20 18:01:51 -08:00
fbe4b76f2d fix(http): Make ResponseOptionsArgs an interface (#14607)
closes #13708
2017-02-20 17:55:03 -08:00
874243279d feat(forms): add option to use browser's native validation and angular forms (#13566)
Also renames NgNovalidate -> NgNoValidate

Closes #13573
2017-02-20 16:36:48 -08:00
551fe50ebd feat(forms): introduce AsyncValidator interface (#13483)
Closes #13398
2017-02-20 16:26:51 -08:00
d6a58f9f70 feat(core): make new Inject() optional for deps specified as InjectionToken (#14486)
fixes #10625
2017-02-20 16:20:45 -08:00
5f3c8441e4 refactor(router): misc
closes #14517
2017-02-20 16:19:20 -08:00
78e8814103 feat(router): add RouteConfigLoadStart and RouteConfigLoadEnd events 2017-02-20 16:19:05 -08:00
7df6f46c1c feat(router): introduce RouteConfigLoaded event
Closes #14036
2017-02-20 16:19:05 -08:00
601fd3e305 fix(platform-webworker): integrate review feedback
closes #14581
2017-02-20 16:17:58 -08:00
cdf99cf68b refactor(platform-webworker): cleanup 2017-02-20 16:17:43 -08:00
3517f28609 feat(platform-webworker): renderer v2 integration 2017-02-20 16:17:43 -08:00
f38dbfbd64 refactor(platform-webworker): misc cleanup 2017-02-20 16:17:43 -08:00
1bdf7061b8 release: cut v4.0.0-beta.8 2017-02-18 15:00:33 -08:00
cc3afc888f docs: add changelog for v4.0.0-beta.8 2017-02-18 14:56:45 -08:00
5129e8e47c docs(router): fix typo in canLoad interface doc comment (#14519) 2017-02-18 14:28:45 -08:00
0cf753be30 docs: add changelog for v2.4.8 2017-02-18 14:18:42 -08:00
c4a6263a01 feat(aio): replace take(1) with more semantic first() (#14571) 2017-02-17 22:52:57 -08:00
45eac233eb feat(aio): fill in NavMap from current doc inventory (#14516)
A port of existing navigation. NOT the final information architecture.
2017-02-17 22:50:16 -08:00
ab26b6518d fix(platform-browser): allow to mix shadow dom with non shadow dom
Allow to style components that don’t use shadow dom inside of components that do.

This reverts 53cf2ec573
and adds a test for this case.

Related to #7887
2017-02-17 17:18:55 -08:00
778ded9fcf refactor: rename ComponentRenderTypeV2 to RendererTypeV2 2017-02-17 17:18:55 -08:00
b9f17a9cb2 fix: make all tests green with new view engine and JIT
Note that this does not yet include enabling the view engine
by default.

Included refactoring:
- view engine: split namespace of elements / attributes already
  when creating the `NodeDef`
- view engine: when injecting the old `Renderer`, use an implementation
  that is based on `RendererV2`
- view engine: store view queries in the component view, not
  on the host element
2017-02-17 17:18:55 -08:00
74ce121dba feat(aio): temporarily include ‘content’ folder among production assets (#14548) 2017-02-16 17:10:51 -08:00
96d06f7f09 fix(upgrade): Prevent property renaming for $inject.
Switch to bracket notation for `directiveFactory.$inject`, otherwise Closure Compiler will (property) rename it, since the output type is `any`.
2017-02-16 15:35:50 -08:00
8c20aaa328 fix(aio): use cleanUrls option rather than bruteforce rewriting rule (#14547)
the cleanUrls option is smarter and looks at headers and mime type to route requests correctly.
2017-02-16 15:26:59 -08:00
b1a79fd2ec ci: simplify validate-commit-message empty line logic 2017-02-16 14:57:23 -08:00
6c20e6ca2e docs(core): fix typo in animation docs 2017-02-16 14:57:23 -08:00
88eb3b2ce8 fix(aio): fix prod build (#14541)
Fixes push to staging.
2017-02-16 14:46:30 -08:00
0fa3895d5b feat(compiler): implement style encapsulation for new view engine (#14518)
Included refactoring:
- splits the `RendererV2` into a `RendererFactoryV2` and a `RendererV2`
- makes the `DebugRendererV2` a private class in `@angular/core`
- remove `setBindingDebugInfo` from `RendererV2`, but rename `RendererV2.setText` to 
  `RendererV2.setValue` and allow it on comments and text nodes.

Part of #14013
2017-02-16 13:55:55 -08:00
ba17dcbf2b refactor(animations): multiple group animations should tally-up delays correctly 2017-02-16 12:10:32 -08:00
88e3d7af9f refactor(animations): do not inherit past styles into sub timelines 2017-02-16 12:10:32 -08:00
3dbd9a04d4 fix(aio): fix staging build travis config (#14539) 2017-02-16 11:44:24 -08:00
b36f60c74c docs(router): fix broken link (#14431)
Closes #14430
2017-02-16 11:32:17 -08:00
57461e9ed7 docs(router): fix guards API docs (#14528) 2017-02-16 10:26:53 -08:00
612f120208 fix(platform-server): default unspecified sections of the url to empty string (#14512) 2017-02-16 10:18:55 -08:00
4a56b6e7f6 ci: fix getLatestLabel (#14535) 2017-02-16 08:57:58 -08:00
724ca373e7 build: produce metadata bundles for @angular modules (#14509)
Closes #14509
2017-02-16 08:15:30 -08:00
3b896709a9 feat(tsc-wrapped): add an option to ngc to bundle metadata (#14509)
Closes #14509
2017-02-16 08:15:30 -08:00
9a6f3d637f feat(aio): add sidenav driven by navigation data (#14429) 2017-02-15 11:22:37 -08:00
56f232cdd7 fix(platform-server): read initial location from INITIAL_CONFIG if present 2017-02-15 09:14:59 -08:00
047cda5b3c fix(platform-server): reflect properties to attributes for known elements, for serialization 2017-02-15 09:14:59 -08:00
9559d3e949 feat(platform-server): support @angular/http from @angular/platform-server
This change installs HttpModule with ServerModule, and overrides bindings to
service Http requests made from the server with the 'xhr2' NPM package.

Outgoing requests are wrapped in a Zone macro-task, so they will be tracked
within the Angular zone and cause the isStable API to show 'false' until they
return. This is essential for Universal support of server-side HTTP.
2017-02-15 09:14:59 -08:00
30380d010b fix(platform-server): render styles in app component instead of <head>
This ensures when the tree is serialized to the client and the app is later bootstrapped,
the <style> tags created during server-side rendering are destroyed.
2017-02-15 09:14:59 -08:00
17486fd696 fix(platform-server): allow multiple instances of platformServer and platformDynamicServer 2017-02-15 09:14:59 -08:00
0e2fd9d91a build: update .pullapprove (#14506)
* build: update .pullapprove

Add tbosch/vicb/chuckjaz to more projects.

* Update .pullapprove.yml
2017-02-15 09:00:21 -08:00
4e7752a12a feat(compiler): integrate compiler with view engine (#14487)
Aspects: di, query, content projection

Included refactoring:
- use a number as query id
- use a bloom filter for aggregating matched queries of nested elements
- separate static vs dynamic queries

Part of #14013
2017-02-15 08:36:49 -08:00
e9ba7aa4f8 docs: update schedule by adding one more beta (#14494)
The new view engine is behind schedule. We agreed to slip the release by one more week.
2017-02-14 21:42:38 -08:00
bb9c7ae6e7 feat: RendererV2 integration (#14469) 2017-02-14 21:03:18 -08:00
b4d444a0a7 feat(platform-server): add API to render Module and ModuleFactory to string (#14381)
- PlatformState provides an interface to serialize the current Platform State as a string or Document.

- renderModule and renderModuleFactory are convenience methods to wait for Angular Application to stabilize and then render the state to a string.

- refactor code to remove defaultDoc from DomAdapter and inject DOCUMENT where it's needed.
2017-02-14 16:14:40 -08:00
2f2b65bd38 fix(core): suppress a Closure Compiler warning (#14484) 2017-02-14 14:44:16 -08:00
269cf42b72 build: add the tslint gulp task (#14481) 2017-02-14 14:16:50 -08:00
8b81bb1eb6 feat(compiler): generate shallow imports compiler generated references (#14388) 2017-02-14 13:33:06 -08:00
e4e9dbe33d feat(compiler): integrate compiler with view engine - change detection tests work (#14412)
Included refactoring:
- make ViewData.parentIndex point to component provider index
- split NodeType.Provider into Provider / Directive / Pipe
- make purePipe take the real pipe as argument to detect changes
- order change detection:
  1) directive props
  2) renderer props

Part of #14013

PR Close #14412
2017-02-13 17:02:00 -06:00
1dc9be4b7d fix(aio): support ValueModule symbols in the TypeScript source (#14464)
In #14388 the following syntax is used in the source:

```
import * as view_utils from './linker/view_utils';
import * as viewEngine from './view/index';
…
export {view_utils as ɵview_utils};
export {viewEngine as ɵviewEngine};
```

The usage of `export {... as ...}` was not being recognised by dgeni.

It is now being recognised and a temporary dummy output file is being
rendered. Later we will either ignore this doctype altogether or find
a better way of rendering it.
2017-02-13 14:46:44 -08:00
221b7a1176 build: use ts-api-guardian v0.2.1 (#14408) 2017-02-13 14:46:07 -08:00
d3f174a57f ci: fix validate-commit-messages 2017-02-10 20:57:33 -08:00
8dd16bbe67 test: add missing change to test-main.js 2017-02-10 20:31:30 -08:00
5279d06e88 ci: re-format sources (#14413)
PR Close #14413
2017-02-10 19:05:45 -06:00
adc54302cb test: make integration test more reliable (#14413)
Use a fresh yarn cache
tsickle bugfix to write case-sensitive filenames for Mac
2017-02-10 19:05:34 -06:00
0f161ce27a fix: validation messages support animations scope 2017-02-10 19:05:00 -06:00
563334e2c9 ci: remove left over fdescribe 2017-02-10 19:05:00 -06:00
b565301186 fix(compiler): REVERT allow absolute style urls (#14365)
This reverts commit 6b9aa2ca3d.
2017-02-10 18:23:58 -06:00
1ece7366c8 fix(forms): getRawValue should correctly work with nested FormGroups/Arrays (#12964)
Closed #12963

PR Close #12964
2017-02-10 15:04:25 -06:00
7ac38aa357 feat(compiler): add support for source map generation (#14258)
fixes #14125

PR Close #14258
2017-02-10 15:04:15 -06:00
53cf2ec573 fix(platform-browser): should only add styles with native encapsulation in shadow DOM (#14313)
Closes #7887

PR Close #14313
2017-02-10 15:03:20 -06:00
1cfbefebe3 fix(platform-browser): should not throw for debug attrs containing $ (#14353)
Closes #9566

PR Close #14353
2017-02-10 15:03:05 -06:00
e5a144d902 fix(compiler): improve error msg for unknown properties on (#14373)
ng-container/ng-content

Closes #14070

PR Close #14373
2017-02-10 15:03:05 -06:00
2c6dab970b fix(compiler): improve error message for unknown elements (#14373) 2017-02-10 15:03:05 -06:00
9e28568a8f feat(platform-server): Implement PlatformLocation for platformServer() (#14405)
This gives server-side apps a current URL including hash, but doesn't implement a state stack,
so back-and-forward navigation isn't possible.

PR Close #14405
2017-02-10 15:03:05 -06:00
db700dfc71 ci: exclude aio/ from build-and-ci pullapprove group
the aio/ has a separate build and ci setup that doesn't affect main repo, so it doesn't make
sense for the build-and-ci group to approve changes to that separate setup.
2017-02-10 13:02:24 -08:00
294c1cd7a7 build(aio): update to @angular/core@2.4.7
upgrade command used:

```
yarn upgrade @angular/{core,common,compiler,forms,http,platform-browser,platform-browser-dynamic,router,compiler-cli}
```
2017-02-10 13:02:24 -08:00
fafee5a493 build(aio): update to @angular/cli@1.0.0-beta.31 2017-02-10 13:02:24 -08:00
03e855ae8f build: allow users to specify --strictNullChecks (#14382)
PR Close #14382
2017-02-10 14:10:03 -06:00
96073e51c3 refactor(animations): introduce @angular/animation module (#14351)
PR Close: #14351
2017-02-10 14:10:03 -06:00
baa654a234 feat(compiler): integrate compiler with view engine - main integration tests work (#14284)
Part of #14013

PR Close #14284
2017-02-10 14:10:03 -06:00
dfe29934b6 test(forms): test undefined as argument to forms (#13720)
PR Close #13720
2017-02-10 14:10:03 -06:00
b988733553 test(aio): remove unnecessary hack from e2e tests (#14356)
May address #14347.
2017-02-09 17:22:08 -08:00
44bb337acc fix(compiler): disable non-components as an entry component (#14335)
PR Close #14335
2017-02-09 14:45:49 -08:00
56b3b3cbed ci: reenable validate-commit-messages gulp task as part of the CI lint task (#14385)
PR Close #14385
2017-02-09 14:32:40 -08:00
0dcac966b4 build: pin versions in integration/*/package.json (#14378)
Floating versions can break our CI. This happened with concurrently release last evening.
Ideally we should just check in the yarn.lock file but are blocked on https://github.com/yarnpkg/yarn/issues/2256

PR Close #14378
2017-02-09 14:32:40 -08:00
b9d293af03 build: first pass of de-duplicating tsconfig.json content (#14369)
PR Close #14369
2017-02-09 14:32:40 -08:00
4da7925ad5 feat(common): added typed overloaded for AsyncPipe.transform() (#14367)
BREAKING CHANGE: Classes that derive from `AsyncPipe` and override
`transform()` might not compile correctly. Use of  `async` pipe in
templates is unaffected.

Mitigation: Update derived classes of `AsyncPipe` that override
`transform()` to include the type parameter overloads.

Related to #12398

PR Close #14367
2017-02-09 14:32:39 -08:00
6b9aa2ca3d fix(compiler): allow absolute style urls (#14365)
Closes #4974

PR Close #14365
2017-02-09 14:32:39 -08:00
a696f4aade fix(compiler): improve error messages in aot compiler (#14333)
Do not print the stack trace when the component is not declared in the module.

PR Close #14333
2017-02-09 14:32:39 -08:00
bb4db2d8f3 feat(compiler): add target locale to the translation bundles (#14290)
PR Close #14290
2017-02-09 14:32:39 -08:00
4676df5833 fix(http): REVERT: remove dots from jsonp callback name (#13219)
This reverts commit 9e5617e41e.
2017-02-09 15:34:12 -06:00
45cc444154 fix(core): Remove ChangeDetectorRef Paramter from KeyValueDifferFactory and IterableDifferFactory (#14311)
BREAKING CHANGE:

- `KeyValueDifferFactory` and `IterableDifferFactory` no longer have `ChangeDetectorRef` as 
  a parameter. It was not used and has been there for historical reasons. If you call 
  `DifferFactory.create(...)` remove the `ChangeDetectorRef` argument.
2017-02-09 13:33:44 -08:00
56e2f84fe8 ci: run 'yarn install' for doc_test task (#14384) 2017-02-09 13:05:04 -08:00
600402d440 build(aio): big move of docs related files (#14361)
All the docs related files (docs-app, doc-gen, content, etc)
are now to be found inside the `/aio` folder.

The related gulp tasks have been moved from the top level
gulp file to a new one inside the `/aio` folder.

The structure of the `/aio` folder now looks like:

```
/aio/
  build/         # gulp tasks
  content/       #MARKDOWN FILES for devguides, cheatsheet, etc
    devguides/
    cheatsheets/
  transforms/    #dgeni packages, templates, etc
  src/
    app/
    assets/
    content/    #HTML + JSON build artifacts produced by dgeni from /aio/content.
                #This dir is .gitignored-ed
  e2e/           #protractor tests for the doc viewer app
  node_modules/ #dependencies for both the doc viewer builds and the dgeni stuff
                #This dir is .gitignored-ed
  gulpfile.js   #Tasks for generating docs and building & deploying the doc viewer
```

Closes #14361
2017-02-09 11:58:36 -08:00
5e7a2fa854 build: update jasmine to 2.4 (#14362)
PR Close #14362
2017-02-09 12:08:33 -06:00
881dce841f refactor(compiler): Load the translation bundle only once in the i18n html parser (#14362)
fixes #14322
2017-02-09 12:08:23 -06:00
c4817988ca feat(core): add isStable Observable property to ApplicationRef to indicate when it's stable and unstable (#14337)
PR Close #14337
2017-02-09 12:07:33 -06:00
b64946b5f9 ci: find latest tag when deeper than the git clone depth (#14231)
Since we have a shallow clone of the repository, it might be the case that the
latest tag (which we need for publishing the build artifacts) might not be in
the current history.

This commit incrementally deepens the clone until it finds a tag (or reaches a
max depth).

PR Close #14231
2017-02-09 12:06:02 -06:00
09b4bd0dfb docs(changelog): add changelog for 4.0.0-beta.7 2017-02-09 09:41:18 -08:00
c871af7b5a chore(release): cut the 4.0.0-beta.7 release 2017-02-09 09:36:10 -08:00
d1feb478a2 build(integration): fix tests (#14371)
Previously, the `integration/` tests were failing, because `concurrently "foo"`
does not inherit the `PATH` env var ([more info][1]).

This commit fixes it, by setting the `PATH` env var explicitly:
`concurrently "PATH=$PATH foo"`.

This commit also includes some minor refactoring of the `integration/` tests scripts:

- Move build-related operations to `ci-lite/build.sh` (for consistency).
- Use `yarn run ...` instead of `npm run ...` inside package.json scripts.
- Use global `yarn` (since we are already using it for `aio/`).
- Fix some `travis_fold` statements.

[1]: https://github.com/kimmobrunfeldt/concurrently/issues/61#issuecomment-252081610
2017-02-09 09:08:16 -08:00
c211ef9b2d docs: add documentation for integration test setup (#14368) 2017-02-09 09:06:19 -08:00
a7688d27f2 refactor(core): change typedef of NodeCheckFn to pass tsickle 2017-02-08 18:05:21 -06:00
24af51a623 fix(core): view engine - fix perf regressions (#14345)
- Make sure `NodeDef`s don’t fall into dictionary mode.
- Use strategy pattern to add debug information / checks, instead of constantly checking for `isDevMode`.
- introduce a very light weight `RendererV2` interface to not have duplicate
  code paths for direct and non direct rendering

The strategy pattern is implemented via the new `Services` object.

Part of #14013

PR Close #14345
2017-02-08 14:42:22 -06:00
f6b5965a63 fix(benchmarks): don’t force gc on the profile buttons (#14345)
This causes v8 to depotimize functions permanently in same cases.
2017-02-08 14:42:01 -06:00
7a4c25535d build: update public API with readonly (#13294)
PR Close #13294
2017-02-08 11:32:47 -06:00
ef32e6b0d0 fix: build and test fixes for TS 2.1 (#13294) 2017-02-08 11:32:40 -06:00
5c431cee02 build: remove post-processing of .d.ts files (#13294)
Note that the duplication in tsconfig.json files will be fixed in a followup CL now that we have tsconfig inheritance

BREAKING CHANGE: Angular 4 will support only TypeScript 2.1, so we no longer provide backwards compatibility to TS 1.8.
2017-02-08 11:32:34 -06:00
2ada3187a6 build: upgrade to TypeScript 2.1 (#13294) 2017-02-08 11:32:30 -06:00
c33fda2607 perf: Don’t subclass Error; resulting in smaller binary (#14160)
Subclassing errors is problematic since Error returns a
new instance. All of the patching which we do than prevent
proper application of source maps.

PR Close #14160
2017-02-07 19:18:26 -06:00
3c2842be96 refactor: remove unneeded output_emitter_utils (#14160) 2017-02-07 19:17:58 -06:00
94312f0980 perf(upgrade): unregister $doCheck watcher when destroying upgraded component (#14303)
PR Close #14303
2017-02-07 16:16:29 -06:00
5bccff0d7a fix(tsc-wrapped): use tsickle's new source map composition feature (#14150)
Tsickle transforms typescript code, which can change the location of code.
This can cause issues such as runtime stack traces reporting that errors
were raised on the incorrect line in the orginal source.  This change replaces
the DecoratorDownlevelCompilerHost and the TsickleCompilerHost with tsickle's
TsickleCompilerHost, which automatically composes tsickle's source maps with
typescript's source maps, so that line numbers are correctly reported at
runtime.

PR Close #14150
2017-02-07 16:16:29 -06:00
2e1413016e feat(aio): refactor DocViewer w/ services component builder (#14294)
Adds basic functionality to fetch documents and display them based on the v42 prototype 

https://github.com/igorMinar/angular-io-v42
2017-02-07 12:57:18 -08:00
a378aab9aa docs(compiler): incorrect method reference (#14314)
PR Close #14314
2017-02-07 12:45:15 -06:00
1e3dd3dd9b fix(upgrade): pass correct values to ngOnChanges for interpolation bindings (#14301)
Previously, the `previousValue` and `currentValue` arguments passed to the
`SimpleChange` constructor were swapped for interpolation bindings.

This commit also refactors the code, so that interpolation bindings and property
bindings share the same implementation, and fixes some broken tests (that hide
failures by allowing the `$exceptionHandler` to swallow thrown exceptions).

PR Close #14301
2017-02-07 12:45:14 -06:00
701074cf89 docs(core): fix typo (#14299)
Replace `than` with `then`.

PR Close #14299
2017-02-07 12:45:14 -06:00
e9a89c0693 test: protractor test for closure bundle (#14240)
PR Close #14240
2017-02-07 12:45:14 -06:00
NFM
d0366542fb docs(router): fix typos (#14213)
PR Close #14213
2017-02-07 12:45:14 -06:00
e58d683931 fix(compiler-cli): prevent ng-xi18n from emitting the compilation output (#14115)
fixes #13567

PR Close #14115
2017-02-07 11:56:23 -06:00
7036e04ec6 docs: add 4.0.0-beta.7 to the release schedule (#14341)
I messed up and accidentaly led the team to believe that the feature freeze was on Feb 15.

Because of this most work was planned to be done by Feb 15 and there is no way to finish it by the original
date of Feb 8. To remedy this situation we agreed to add one more beta to the release schedule.
2017-02-07 09:45:33 -08:00
d4ffa47ea6 fix(aio): correctly render decorator docs (#14328)
This commit updates the doc-gen to account
for the changes to the codebase for decorators.

There are actually three kinds of calls that create decorators:

* makeDecorator
* makePropDecorator
* makeParamDecorator

Also, the actual documentation for each
decorator is split between two exported symbols:

* `interface [DecoratorName]` contains the metadata fields
* interface [DecoratorName]Decorator` contains a
  "call member" which holds the general description of the decorator.

This processor now identifies all three decorator types, and pulls the
description of the callMember onto the main decorator doc description.

(There are some outstanding interfaces in the angular/angular project that
need to be re-exported from `/angular/modules/@angular/core/src/metadata.ts`
to ensure that the doc-gen is able to access them.)

Closes https://github.com/angular/angular.io/pull/2349
2017-02-07 00:04:25 -08:00
80b66edfa7 docs(zone): fix whitespace around backtick code
If there is no leading empty line then the markdown renderers get confused.
2017-02-06 12:08:57 -08:00
12f03b90fd build(aio): support guide authoring
This commit implements various tags, inline tags and changes the markdown
renderer to use Rho. This enables us to generate guide type documents.
2017-02-06 12:08:57 -08:00
470997ebb9 docs(aio): add cookbook doc 2017-02-06 12:08:57 -08:00
bcba0332a6 docs(aio): add examples to test cookbook doc 2017-02-06 12:08:57 -08:00
41db177d0c test(upgrade): test projection on downgraded components with structural directives (#14276)
Brings the tests of #14274 to master.

PR Close #14276
2017-02-03 15:08:26 -06:00
e4b76a493f ci: add petebacondarwin to the angular.io pullapprove group (#14268)
PR Close #14268
2017-02-03 15:08:02 -06:00
a2a290a83c ci: add 'public-api' pullapprove group (#14268) 2017-02-03 15:07:58 -06:00
14d7844b2b feat(core): view engine - integrate with ComponentFactory (#14237)
`ComponentFactory`s can now be created from a `ViewDefinitionFactory` via
`RefFactory.createComponentFactory`.

This commit also:
- splits `Services` into `Refs` and `RootData`
- changes `ViewState` into a bitmask
- implements `ViewContainerRef.move`

Part of #14013

PR Close #14237
2017-02-03 15:07:12 -06:00
388afa414e test(compiler): add integration like tests to compiler unit tests (#14157)
Closes PR #14157

PR Close #14157
2017-02-03 15:06:51 -06:00
4370049cea fix(build): make fsevents an optional dependency in npm (#13945)
PR Close #13945
2017-02-03 15:05:43 -06:00
fb91b2fe78 ci(aio): refactor the protractor config (#14248)
1. Use `jasmine` as framework instead of `jasmine2`.
   (Since angular/protractor@2bde92b, `jasmine2` is an alias for `jasmine`.)
2. Simplify the `chromeOptions` config by always setting.
   (If `process.env.CHROME_BIN` is not defined, `binary` will be ignored.)
2017-02-03 07:44:34 -08:00
0ba5bebf61 build: modularize the gulp file to be easier to maintain (#14259)
This is a precursor to bringing in some of the gulp tasks from angular.io,
which could lead to the gulpfile becoming unwieldy.
2017-02-03 00:10:41 -08:00
a9096437fd feat(aio): delete unused kruft 2017-02-02 23:28:00 -08:00
31d42d87c6 ci: bump node version to 6.9.5 and npm to 3.10.7
this is required by @angular/cli
2017-02-02 23:28:00 -08:00
20a7e26d1e build(aio): switch local angular-cli to @angular/cli
karma.conf merge with angular cli change
2017-02-02 23:28:00 -08:00
6e2c9cb586 feat(aio): add initial doc viewer
with lots of fixes from Igor and Ward <3
2017-02-02 23:28:00 -08:00
559cf9d192 docs(changelog): add changelog for 4.0.0-beta.6 2017-02-02 21:19:27 -08:00
1961332f26 chore(release): cut the 4.0.0-beta.6 release 2017-02-02 21:01:27 -08:00
f9b929f28d docs(changelog): add changelog for 2.4.6 2017-02-02 20:06:57 -08:00
69a4bb0bcd doc: standardize deprecation of preserveQueryParams (4.0 only) (#14236)
PR closes #14236
2017-02-01 16:48:19 -08:00
a7479f657a fix: ngModel should use rxjs/symbol/observable to detect observable (#14236)
PR closes #14236
2017-02-01 16:47:41 -08:00
bc20e8ac9d ci: increase git fetch depth to 150 2017-02-01 15:16:48 -08:00
a05e50fda3 feat(core): view engine - add missing DI features (#14225)
Part of #14013

PR Close #14225
2017-02-01 14:16:01 -06:00
ae7f5f37d2 refactor(core): view engine - remove ViewData.parentDiIndex (#14225)
Instead, calculate it on the fly

Part of #14013
2017-02-01 14:15:47 -06:00
45e1e36477 feat(core): view engine - add support for OnPush and detached views. (#14216)
Part of #14013

PR Close #14216
2017-02-01 14:15:47 -06:00
08ff67ea11 feat(core): view engine - add WrappedValue support (#14216)
Part of #14013
2017-02-01 14:15:38 -06:00
1bc5368ea0 fix: closure compiler warning (#14229)
PR Close #14229
2017-02-01 14:11:52 -06:00
093cc04748 fix(common): DatePipe parses input string if it's not a valid date in browser (#13895)
Closes #12334
Closes #13874

PR Close #13895
2017-02-01 14:01:58 -06:00
9d2c71269b refactor(common): remove isDate from facade (#13895) 2017-02-01 14:01:46 -06:00
80d3e14ce4 docs(contributing): fix typo (#14218) 2017-02-01 11:26:12 -08:00
ef48ee0a0a build(aio): remove formatting and styles from dgeni templates
Much of the formatting was hardcoded and copied from the old anguar.io
jade files. This gives us a clean start.

Also, more use has been made of include files to make the templates
easier to understand and manage.
2017-02-01 11:11:43 -08:00
ec8e68ed56 buid(aio): ignore example-region docs in keyword generation 2017-02-01 11:11:43 -08:00
0a29574d98 feat(core): view engine - support content projection (#14209)
Part of #14013

PR Close #14209
2017-02-01 09:29:51 -06:00
86b2b2504f feat(common): rename underlying NgFor class and add a type parameter (#14104)
Note, this affects the underlying class and should not affect usage.

DEPRECATION:
- the `NgFor` class is now deprecated. Use `NgForOf<T>` instead.
  IMPORTANT: Only the `NgFor` class is deprecated, not the `ngFor`
  directive. The `*ngFor` and related directives are unaffected by
  this change  as references to the `NgFor` class generated from
  templates will be automatically converted to references to
  `NgForOf<T>` without requiring any template modifications.
- `TrackByFn` is now deprecated. Use `TrackByFunction<T>` instead.

Migration:
- Replace direct references to the `NgFor` class to `NgForOf<any>`.
- Replace references to `TrackByFn` to `TrackByFunction<any>`.

BREAKING CHANGE:
A definition of `Iterable<T>` is now required to correctly compile
Angular applications. Support for `Iterable<T>` is not required at
runtime but a type definition `Iterable<T>` must be available.

`NgFor`, and now `NgForOf<T>`, already supports `Iterable<T>` at
runtime. With this change the type definition is updated to reflect
this support.

Migration:
- add "es2015.iterable.ts" to your tsconfig.json "libs" fields.

Part of #12398

PR Close #14104
2017-02-01 09:29:51 -06:00
69e14b500b feat(compiler): generate type parameters for generic type references (#14104) 2017-02-01 09:29:51 -06:00
1079b9381c feat(tsc-wrapped): record arity of generic classes (#14104) 2017-02-01 09:29:51 -06:00
7670cc1a86 feat(upgrade): export VERSION from upgrade/static (#14037)
PR Close #14037
2017-02-01 09:29:51 -06:00
ea63676970 refactor(upgrade): use shared code in downgradeNg2Component() (#14037)
This unified the implementations of dynamic's `downgradeNg2Component()` and
static's `downgradeComponent()`.
2017-02-01 09:29:51 -06:00
1367cd9569 fix(upgrade): respect hierarchical injectors for downgraded components (#14037)
Correctly wire up hierarchical injectors for downgraded components in
`upgrade/static`: Downgraded components inherit the injector of the first
downgraded component up the DOM tree.

This is similar to (part of) d91a86a, but for `upgrade/static`.

POSSIBLE BREAKING CHANGE:

In order to enable more control over the wiring of downgraded components and
their content (which eventually allows better control over features like
injector setup and content projection), it was necessary to change the
implementation of the directives generated for downgraed components.

The directives are now terminal and manually take care of projecting and
compiling their contents in the post-linking function. This is similar to how
the dynamic version of `upgrade` does it.

This is not expected to affect apps, since the relative order of individual
operations is preserved. Still, it is difficult to predict how every possible
usecase may be affected.
2017-02-01 09:29:51 -06:00
9aafdc7b02 feat(upgrade): allow non-element selectors for downgraded components (#14037)
This affects the dynamic version of `upgrade` and makes it more consistent with
the static version, while removing an artificial limitation.

This commit also refactors the file layout and code, in order to share code wrt
to dowgrading components between the dynamic and static versions.
2017-02-01 09:29:51 -06:00
1f90f29369 feat(upgrade): return a function (instead of array) from downgradeInjectable() (#14037)
This makes it more consistent with the dynamic version of `upgrade` and makes it
possible to share code between the dynamic and static versions.

This commit also refactors the file layout, moving common and dynamic-specific
files to `common/` and `dynamic/` directories respectively and renaming `aot/`
to `static/`.

Some private keys, used as AngularJS DI tokens, have also been renamed, but this
should  not affect apps, since these keys are undocumented and not supposed to
be used externally.

BREAKING CHANGE:

Previously, `upgrade/static/downgradeInjectable` returned an array of the form:

```js
['dep1', 'dep2', ..., function factory(dep1, dep2, ...) { ... }]
```

Now it returns a function with an `$inject` property:

```js
factory.$inject = ['dep1', 'dep2', ...];
function factory(dep1, dep2, ...) { ... }
```

It shouldn't affect the behavior of apps, since both forms are equally suitable
to be used for registering AngularJS injectable services, but it is possible
that type-checking might fail or that current code breaks if it relies on the
returned value being an array.
2017-02-01 09:29:51 -06:00
49fce37013 ci: fix .pullapprove.yaml'sfile conditions (#14214)
According to [the docs](http://docs.pullapprove.com/groups/conditions/), the correct keywords are `include`/`exclude`, without the trailing `s`.
2017-01-31 22:15:19 -08:00
676081fe66 ci(aio): fix and enable e2e tests on Travis (#14174) 2017-01-31 21:59:37 -08:00
e0e5e78835 fix: lint errors to make circle-ci green 2017-01-31 19:01:48 -06:00
b4214d60a6 fix(compiler): allow expressions or functions in extends (#14158)
Fixes #14154

PR Close #14158
2017-01-31 18:35:10 -06:00
8270bec343 fix: failing integration test 2017-01-31 16:29:13 -08:00
5921c872b6 fix(compiler): only lex messages that are needed by angular (#14208)
To avoid the lexer erroring on syntax not supported by Angular.

PR Close #14208
2017-01-31 16:21:55 -06:00
52b21275f4 feat(core): view engine - add debug information (#14197)
Creates debug information for the renderer,
and also reports errors relative to the
declaration place in the template.

Part of #14013

PR Close #14197
2017-01-31 16:21:54 -06:00
c48dd76f5c build: move typings_test to new integration test fixture (#14149)
PR Close #14149
2017-01-31 15:46:59 -06:00
49fb8143e8 fix(language-service): do not crash when Angular cannot be located (#14123)
Fixes #14122

PR Close #14123
2017-01-31 15:45:52 -06:00
5f2b3173d7 fix(http): use params without RequestOptions (#14101)
`params` has been introduced in 4.0.0-beta.0

Before:

    http.get(url, new RequestOptions({params: searchParams}))

After:

    http.get(url, {params: searchParams})

Fixes #14100

PR Close #14101
2017-01-31 15:44:49 -06:00
c87c3bec93 feat(router): deprecate preserveQueryParams,add queryParamsHandling (#14095)
PR Close #14095
2017-01-31 15:43:25 -06:00
2ffa1a71aa docs(forms): fix FormArray description (#14094)
Closes #14075

PR Close #14094
2017-01-31 15:42:42 -06:00
94f84c5d7e fix(forms): Verify functions passed into async validators returns Observable or Promise (#14053) 2017-01-31 12:15:56 -06:00
ff290af38c fix(common): introduce isObservable method (#14067)
Closes #8848

PR Close #14067
2017-01-31 12:14:19 -06:00
fe441186e7 fix(common): add PopStateEvent interface (#13400)
Closes #13378

PR Close #13400
2017-01-31 12:08:54 -06:00
f89d004c51 fix(forms): provide a method to compare options (#13349)
Closes #13268

PR Close #13349
2017-01-31 11:38:30 -06:00
6c7300c7de fix(forms): async validator cancels previous subscription when input has changed (#13222)
Fixes #12709
Fixes #9120
Fixes #10074
Fixes #8923

PR Close #13222
2017-01-31 11:37:25 -06:00
22058298d3 fix(closure): suppress some closure compiler warnings (#14198)
PR Close #14198
2017-01-30 18:34:14 -06:00
104c157ef6 build: fix red travis: fetch more github history (#14193) 2017-01-30 14:55:00 -08:00
1df9319af1 fix(forms): fix broken unit test (#14179) 2017-01-30 10:07:09 -08:00
d43c573ebc ci: fix compiler-cli paths (#14177) 2017-01-29 22:43:34 -08:00
a699a448fb ci: fix pullapprove groups and conditions (#14167)
- restrict root to be just root
- add fallback users to all groups
- fix indentation
- change order of users so that primary reviewers are first, follow by alpha-sorted secondaries, followed by fallback reviewers
2017-01-29 11:01:38 -08:00
7b7ae5fe56 feat(forms): add equalsTo validator (#14052)
PR Close: #14052
2017-01-29 12:22:24 -06:00
94b62c963d fix(common) add interface PipeTransform to Async pipe (#14049)
PR Close #14049
2017-01-29 12:18:55 -06:00
579567ca79 fix(router): fix CanActivateChild guard provided in a lazy loaded module (#13989)
Closes #12275

PR Close #13989
2017-01-29 12:17:03 -06:00
47d41d492b fix(router): fix navigation from the root component ngOnInit hook (#13932)
Closes #13795

PR Close #13932
2017-01-29 12:16:12 -06:00
e075b1ba83 fix(router): fix CanActivate redirect to the root on initial load (#13929)
Closes #13530

PR Close #13929
2017-01-29 12:15:46 -06:00
029f558d45 fix(forms): select shows blank line when nothing is selected in IE/Edge (#13903)
Closes #10010

PR Close #13903
2017-01-29 12:15:11 -06:00
c5ea03a023 feat(ngModel):handle ime events (#13891)
PR Close: #13891
2017-01-29 12:14:32 -06:00
c7245189e2 docs(developer): add description of npm-run to run locally installed npm scripts (#13765)
PR Close #13765
2017-01-29 12:12:38 -06:00
cd3901f774 fix(platform-browser): remove style nodes on destroy (#13744)
Closes #11746

PR Close #13744
2017-01-29 12:10:44 -06:00
a64c9b5d5b refactor(platform-browser): polishing (#13744) 2017-01-29 12:10:39 -06:00
863285a4b0 fix(core): add bootstrapped modules into platform modules list (#13740)
Closes #12015

PR Close #13740
2017-01-29 12:09:46 -06:00
5f40e5ba21 fix(testing): async/fakeAsync/inject/withModule helpers should pass through context to callback functions (#13718)
Make sure that context (`this`) that is passed to functions generated by test helpers is passed through to the callback functions. Enables usage of Jasmine's variable sharing system to prevent accidental memory leaks during test runs.
2017-01-29 12:08:53 -06:00
d69717cf79 feat(forms): add email validator (#13709)
Closes #13706

PR Close #13709
2017-01-29 12:07:05 -06:00
00979838ef refactor(upgrade): allow Closure advanced optimizations in UpgradeComponent (#13629)
Get rid of the dynamic invocation style used in `callLifecycleHook()`, which
would break under Closure Compiler's advanced optimizations.
Related to https://github.com/angular/angular/pull/13020#discussion_r93492935.

PR Close #13629
2017-01-29 12:02:52 -06:00
a277e97dd7 fix(core): ViewContainerRef.indexOf doesn't throw error when empty (#13220)
PR Close #13220
2017-01-29 11:50:23 -06:00
9e5617e41e fix(http): remove dots from jsonp callback name (#13219)
PR Close #13219
2017-01-29 11:49:40 -06:00
bc1320d926 docs: update COMITTER.md with info about pullapprove.com 2017-01-27 21:23:21 -08:00
77008e35ff ci: configure pullapprove to cover the whole repository 2017-01-27 21:23:21 -08:00
gc
01da4223d4 docs(public_api): change description (#13583)
* doc(public_api): change description

Benchpress has been moved to angular/angular in modules/@angular/benchpress

* docs(public_api): change description

Here means 'other projects',like angular-cli, Angular Material. And as we know, benchpress project has been moved to angular/angular in modules/@angular/benchpress. It should not be 'other projects'.
2017-01-27 20:52:02 -08:00
0854a5dea4 style(docs): update copyright years (#13736) 2017-01-27 20:47:14 -08:00
df7f5fc550 style: fix typo in CHANGELOG.md (#14009)
Correcting parameterize to parameterized at line 24
2017-01-27 20:29:17 -08:00
24ea3f022b test(compiler): don't print warnings from closure compiler (#14159)
fixes #14152
2017-01-27 18:25:17 -08:00
3368f29a4d ci: update typings test to use standard typings (#14156)
Closes #14156
2017-01-27 16:16:58 -08:00
8960d4990c test(aio): import zone.js in tests 2017-01-27 13:55:58 -08:00
4165fddfc4 ci(aio): deploy from CI to staging 2017-01-27 13:55:58 -08:00
c37af2af5a refactor(core): simplify ReflectiveInjector by removing code for Dart implementation (#14126)
ReflectiveInjector previously used two strategies for resolving dependencies. These
were to support the Dart implementation, but are no longer needed. A result of this
PR is there is no longer a 20 dependency limit and the generated code is smaller.

PR Close #14126
2017-01-27 13:22:32 -08:00
da41a954b5 docs: branding fixes (#14132)
Angular 1.x -> AngularJS
Angular 1 -> AngularJS
Angular1 -> AngularJS
Angular 2+ -> Angular
Angular 2.0 -> Angular
Angular2 -> Angular

I have deliberately not touched any of the symbol names as that would cause big merge collisions with Tobias's work.

All the renames are in .md, .json, and inline comments and jsdocs.

PR Close #14132
2017-01-27 15:03:11 -06:00
5a997ef4f0 docs: remove obsolete bundles/overview.md file (#14132) 2017-01-27 15:02:59 -06:00
d339d8b81d refactor(abstract): Use abstract keyword where possible to decrease file size. (#14112)
PR Close: #14112
2017-01-27 12:32:22 -08:00
827c3fe199 fix(compiler): fix missing translations handling (#14113)
PR Close #14113
2017-01-27 12:12:06 -06:00
8775ab9495 feat(compiler): allow missing translations (#14113)
closes #13861
2017-01-27 12:10:59 -06:00
5885c52c1f refactor(compiler): add ability to get the context around a ParseLocation (#14113) 2017-01-27 12:10:47 -06:00
80b9570dca ci: remove type checking on 1.8 (#14124)
PR Close #14124
2017-01-27 12:09:50 -06:00
f802194c18 refactor(core): have different data types for each node. (#14120)
Also have a new node type for queries.

This leads to less memory usage and better performance.

Deep Tree Benchmark results (depth 11):
- createAndDestroy (view engine vs current codegen):
  * pureScriptTime: 78.80+-4% vs 72.34+-4%
  * scriptTime: 78.80+-4% vs 90.71+-9%
  * gc: 5371.66+-108% vs 9717.53+-174%
  * i.e. faster when gc is also considered and about 2x less memory usage!
- update unchanged

Part of #14013
PR Close #14120
2017-01-27 12:08:54 -06:00
7ad616a177 fix(common): DatePipe doesn't throw for NaN (#14117)
Fixes #14103

PR Close #14117
2017-01-27 12:07:47 -06:00
670b680b0a refactor(size): Use abstract keyword where possible to decrease file size. (#14112) 2017-01-27 12:00:58 -06:00
f7fba74c58 feat(compiler): do not parse xtb messages not needed by angular (#14111)
fixes #14046

PR Close #14111
2017-01-27 11:52:57 -06:00
20b454cbc9 fix(upgrade): detect async downgrade component changes (#14039)
This commit effectively reverts 7e0f02f but for `upgrade/static`
as it was an invalid fix for #6385, that created a more significant
bug, which was that changes were not always being detected.

Angular 1 digests should be run inside the ngZone to ensure
that async changes are detected.

We don't know how to fix #6385 without breaking change detection
at this stage. That issue is triggered by async operations, such as
`setTimeout`, being triggered inside scope watcher functions.

One could argue that watcher functions should be pure and not do
work such as triggering async operations. It is possible that the
original use case could be supported by moving the debounce
logic into the watch listener function, which is only called if the
watched value actually changes.

See #13812

PR Close #14039
2017-01-27 11:51:55 -06:00
665dde2e5c refactor(compiler): improve error messages in aot compiler (#14017)
Previously aot compiler prints stack traces when it fails to resolve.
New behavior: aot compiler outputs the error message.
Example: https://gist.github.com/bowenni/a7fe81d916e8cd4a06b0e133436f40fb

PR Close #14017
2017-01-27 11:49:38 -06:00
4d5a4d89cd test(integration): add an env for testing closure builds (#14130)
* feat: add an env for testing closure builds
* build(npm): add dev dependency on yarn (and remove dev props for readability)
* build: refactor integration test runner
2017-01-27 09:17:50 -08:00
e130bc171f feat(aio): add initial angular-cli scaffold (#14118)
- adds initial CLI-generated app
- adds material toolbar
- initial (very rough) scss setup, lifted from angular/material
- initial routing scaffold w/ homepage
2017-01-27 00:20:51 -08:00
b141a227fb ci(aio): run docs-tests in travis (#14097) 2017-01-26 23:47:07 -08:00
b7763559cd build(aio): move doc-gen stuff from angular.io (#14097) 2017-01-26 23:46:59 -08:00
d1d0ce7613 build(aio): update node dependencies for doc-gen (#14097) 2017-01-26 23:46:56 -08:00
2dd9654004 docs(http): vanilla links do not need link tags (#14097) 2017-01-26 23:46:51 -08:00
e35c25d2ce docs(router): remove invalid jsdoc tags (#14097)
The `@selector` tags are not valid.
Dgeni should be able to extract this information
from the directive annotation metadata.
2017-01-26 23:46:38 -08:00
1e729d7ba2 feat(core): add query support to view engine
Part of #14013
closes #14084
2017-01-25 17:44:56 -08:00
fc8694ed11 refactor(core): view engine, refactor runtime data
Structure in a better way, in preparation for queries.
2017-01-25 17:44:42 -08:00
05b2b49711 fix(compiler): allow empty translations for attributes (#14085)
fixes #13897
2017-01-25 17:43:19 -08:00
3ef73c2b19 feat(NgComponentOutlet): add NgModule support to NgComponentOutlet directive (#14088)
Allow NgComponentOutlet to dynamically load a module, then load a component from
that module. Useful for lazy loading code, then add the lazy loaded code to the
page using NgComponentOutlet.

Closes #14043
2017-01-25 17:41:08 -08:00
4106d18172 build(aio): add angular.io package.json and yarn.lock file
closes #14098
2017-01-25 17:38:56 -08:00
1ce7fd7827 ci: add pullapprove config for angular.io 2017-01-25 17:38:33 -08:00
c4ecaeda64 ci: add support for 'aoi' scope in commit messages for angular.io 2017-01-25 17:38:33 -08:00
b28f01bb7f docs: create angular.io directory and add a placeholder file 2017-01-25 17:38:33 -08:00
4487 changed files with 287459 additions and 112574 deletions

6
.bazelrc Normal file
View File

@ -0,0 +1,6 @@
# Disable sandboxing because it's too slow.
# https://github.com/bazelbuild/bazel/issues/2424
build --spawn_strategy=standalone
# Performance: avoid stat'ing input files
build --watchfs

55
.circleci/config.yml Normal file
View File

@ -0,0 +1,55 @@
# Configuration file for https://circleci.com/gh/angular/angular
# Note: YAML anchors allow an object to be re-used, reducing duplication.
# The ampersand declares an alias for an object, then later the `<<: *name`
# syntax dereferences it.
# See http://blog.daemonl.com/2016/02/yaml.html
# To validate changes, use an online parser, eg.
# http://yaml-online-parser.appspot.com/
# Settings common to each job
anchor_1: &job_defaults
working_directory: ~/ng
docker:
- image: angular/ngcontainer:0.0.2
# After checkout, rebase on top of master.
# Similar to travis behavior, but not quite the same.
# See https://discuss.circleci.com/t/1662
anchor_2: &post_checkout
post: git pull --ff-only origin "refs/pull/${CI_PULL_REQUEST//*pull\//}/merge"
version: 2
jobs:
lint:
<<: *job_defaults
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: angular-{{ .Branch }}-{{ checksum "yarn.lock" }}
- run: yarn install --freeze-lockfile --non-interactive
- run: ./node_modules/.bin/gulp lint
build:
<<: *job_defaults
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: angular-{{ .Branch }}-{{ checksum "yarn.lock" }}
- run: bazel run @yarn//:yarn
- run: bazel build ...
- save_cache:
key: angular-{{ .Branch }}-{{ checksum "yarn.lock" }}
paths:
- "node_modules"
workflows:
version: 2
default_workflow:
jobs:
- lint
- build

View File

@ -1,39 +1,57 @@
<!--
IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOUT INVESTIGATING
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
-->
**I'm submitting a ...** (check one with "x")
```
[ ] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
```
## I'm submitting a...
<!-- Check one of the following options with "x" -->
<pre><code>
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report <!-- Please search GitHub for a similar issue or PR before submitting -->
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
</code></pre>
**Current behavior**
<!-- Describe how the bug manifests. -->
## Current behavior
<!-- Describe how the issue manifests. -->
**Expected behavior**
<!-- Describe what the behavior would be without the bug. -->
**Minimal reproduction of the problem with instructions**
## Expected behavior
<!-- Describe what the desired behavior would be. -->
## Minimal reproduction of the problem with instructions
<!--
If the current behavior is a bug or you can illustrate your feature request better with an example,
please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).
-->
**What is the motivation / use case for changing the behavior?**
<!-- Describe the motivation or the concrete use case -->
## What is the motivation / use case for changing the behavior?
<!-- Describe the motivation or the concrete use case. -->
**Please tell us about your environment:**
<!-- Operating system, IDE, package manager, HTTP server, ... -->
* **Angular version:** 2.0.X
## Environment
<pre><code>
Angular version: X.Y.Z
<!-- Check whether this is still an issue in the most recent Angular version -->
* **Browser:** [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
<!-- All browsers where this could be reproduced -->
Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
* **Language:** [all | TypeScript X.X | ES6/7 | ES5]
For Tooling issues:
- Node version: XX <!-- run `node --version` -->
- Platform: <!-- Mac, Linux, Windows -->
* **Node (for AoT issues):** `node --version` =
Others:
<!-- Anything else relevant? Operating system version, IDE, package manager, HTTP server, ... -->
</code></pre>

View File

@ -1,10 +1,15 @@
**Please check if the PR fulfills these requirements**
## PR Checklist
Please check if your PR fulfills the following requirements:
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
**What kind of change does this PR introduce?** (check one with "x")
## PR Type
What kind of change does this PR introduce?
<!-- Please check the one that applies to this PR using "x". -->
```
[ ] Bugfix
[ ] Feature
@ -12,25 +17,27 @@
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] angular.io application / infrastructure changes
[ ] Other... Please describe:
```
**What is the current behavior?** (You can also link to an open issue here)
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
Issue Number: N/A
**What is the new behavior?**
## What is the new behavior?
**Does this PR introduce a breaking change?** (check one with "x")
## Does this PR introduce a breaking change?
```
[ ] Yes
[ ] No
```
If this PR contains a breaking change, please describe the impact and migration path for existing applications: ...
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->
**Other information**:
## Other information

5
.gitignore vendored
View File

@ -1,6 +1,8 @@
.DS_STORE
/dist/
bazel-*
e2e_test.*
node_modules
bower_components
@ -17,8 +19,9 @@ modules/.vscode
# Don't check in secret files
*secret.js
# Ignore npm debug log
# Ignore npm/yarn debug log
npm-debug.log
yarn-error.log
# build-analytics
.build-analytics

1
.mailmap Normal file
View File

@ -0,0 +1 @@
Michał Gołębiowski-Owczarek <m.goleb@gmail.com>

2
.nvmrc
View File

@ -1 +1 @@
6.6.0
6.9.5

View File

@ -1,6 +1,30 @@
# Configuration for pullapprove.com
# See ownership spreadsheet:
#
# Approval access and primary role is determined by info in the project ownership spreadsheet:
# https://docs.google.com/spreadsheets/d/1-HIlzfbPYGsPr9KuYMe6bLfc4LXzPjpoALqtYRYTZB0/edit?pli=1#gid=0&vpid=A5
#
# === GitHub username to Full name map ===
#
# alexeagle - Alex Eagle
# alxhub - Alex Rickabaugh
# chuckjaz - Chuck Jazdzewski
# Foxandxss - Jesús Rodríguez
# gkalpak - George Kalpakas
# IgorMinar - Igor Minar
# jasonaden - Jason Aden
# juleskremer - Jules Kremer
# kara - Kara Erickson
# matsko - Matias Niemelä
# mhevery - Misko Hevery
# petebacondarwin - Pete Bacon Darwin
# pkozlowski-opensource - Pawel Kozlowski
# robwormald - Rob Wormald
# tbosch - Tobias Bosch
# tinayuangao - Tina Gao
# vicb - Victor Berchet
# vikerman - Vikram Subramanian
# wardbell - Ward Bell
version: 2
@ -9,24 +33,267 @@ group_defaults:
reset_on_reopened:
enabled: true
approve_by_comment:
enabled: true
approve_regex: '^(Approved|:\+1:|LGTM)'
enabled: false
groups:
config:
root:
conditions:
files:
- "*.yml"
- "*.json"
teams:
- repoowners
include:
- "*"
exclude:
- "aio/*"
- "integration/*"
- "modules/*"
- "packages/*"
- "tools/*"
users:
- IgorMinar
- mhevery
public-api:
conditions:
files:
include:
- "tools/public_api_guard/*"
users:
- IgorMinar
- mhevery
build-and-ci:
conditions:
files:
include:
- "*.yml"
- "*.json"
- "*.lock"
- "tools/*"
exclude:
- "tools/@angular/tsc-wrapped/*"
- "tools/public_api_guard/*"
- "aio/*"
users:
- IgorMinar #primary
- alexeagle
- jasonaden
- mhevery #fallback
integration:
conditions:
files:
- "integration/*"
users:
- alexeagle
- mhevery
- tbosch
- vicb
- IgorMinar #fallback
core:
conditions:
files:
- "packages/core/*"
users:
- tbosch #primary
- chuckjaz
- mhevery
- vicb
- IgorMinar #fallback
animations:
conditions:
files:
- "packages/animations/*"
- "packages/platform-browser/animations/*"
users:
- matsko #primary
- chuckjaz #fallback
- mhevery #fallback
- IgorMinar #fallback
compiler/i18n:
conditions:
files:
- "packages/compiler/src/i18n/*"
users:
- vicb #primary
- tbosch
- IgorMinar #fallback
- mhevery #fallback
compiler:
conditions:
files:
- "packages/compiler/*"
users:
- tbosch #primary
- vicb
- chuckjaz
- mhevery
- IgorMinar #fallback
compiler-cli:
conditions:
files:
- "tools/@angular/tsc-wrapped/*"
- "modules/@angular/compiler/*"
- "modules/@angular/compiler-cli/*"
teams:
- compiler-owners
- repoowners
- "packages/compiler-cli/*"
users:
- alexeagle
- chuckjaz
- vicb
- tbosch
- IgorMinar #fallback
- mhevery #fallback
common:
conditions:
files:
- "packages/common/*"
users:
- pkozlowski-opensource #primary
- vicb
- IgorMinar #fallback
- mhevery #fallback
forms:
conditions:
files:
- "packages/forms/*"
users:
- kara #primary
- tinayuangao #secondary
- IgorMinar #fallback
- mhevery #fallback
http:
conditions:
files:
- "packages/http/*"
users:
- vikerman #primary
- alxhub
- IgorMinar #fallback
- mhevery #fallback
language-service:
conditions:
files:
- "packages/language-service/*"
users:
- chuckjaz #primary
- tbosch #secondary
- vicb
- IgorMinar #fallback
- mhevery #fallback
router:
conditions:
files:
- "packages/router/*"
users:
- jasonaden
- vicb
- IgorMinar #fallback
- mhevery #fallback
upgrade:
conditions:
files:
- "packages/upgrade/*"
users:
- petebacondarwin #primary
- gkalpak
- IgorMinar #fallback
- mhevery #fallback
platform-browser:
conditions:
files:
- "packages/platform-browser/*"
users:
- tbosch #primary
- vicb #secondary
- IgorMinar #fallback
- mhevery #fallback
platform-server:
conditions:
files:
- "packages/platform-server/*"
users:
- vikerman #primary
- alxhub
- vicb
- tbosch
- IgorMinar #fallback
- mhevery #fallback
platform-webworker:
conditions:
files:
- "packages/platform-webworker/*"
users:
- vicb #primary
- tbosch #secondary
- IgorMinar #fallback
- mhevery #fallback
benchpress:
conditions:
files:
- "packages/benchpress/*"
users:
- tbosch #primary
# needs secondary
- IgorMinar #fallback
- mhevery #fallback
angular.io:
conditions:
files:
include:
- "aio/*"
exclude:
- "aio/content/*"
users:
- petebacondarwin #primary
- IgorMinar
- gkalpak
- mhevery #fallback
angular.io-guide-and-tutorial:
conditions:
files:
include:
- "aio/content/*"
exclude:
- "aio/content/marketing/*"
- "aio/content/navigation.json"
- "aio/content/license.md"
users:
- juleskremer #primary
- Foxandxss
- stephenfluin
- wardbell
- petebacondarwin
- gkalpak
- IgorMinar #fallback
- mhevery #fallback
angular.io-marketing:
conditions:
files:
include:
- "aio/content/marketing/*"
- "aio/content/navigation.json"
- "aio/content/license.md"
users:
- juleskremer #primary
- stephenfluin
- petebacondarwin
- gkalpak
- IgorMinar #fallback
- mhevery #fallback

View File

@ -1,7 +1,8 @@
language: node_js
sudo: false
dist: trusty
node_js:
- '6.6.0'
- '6.9.5'
addons:
# firefox: "38.0"
@ -10,30 +11,52 @@ addons:
# needed to install g++ that is used by npms's native modules
- ubuntu-toolchain-r-test
packages:
# needed to install g++ that is used by npms's native modules
- g++-4.8
# https://docs.travis-ci.com/user/jwt
jwt:
# SAUCE_ACCESS_KEY<=secret for NGBUILDS_IO_KEY to work around travis-ci/travis-ci#7223, unencrypted value in valentine as NGBUILDS_IO_KEY>
# we alias NGBUILDS_IO_KEY to $SAUCE_ACCESS_KEY in env.sh and set the SAUCE_ACCESS_KEY there
- secure: "L7nrZwkAtFtYrP2DykPXgZvEKjkv0J/TwQ/r2QGxFTaBq4VZn+2Dw0YS7uCxoMqYzDwH0aAOqxoutibVpk8Z/16nE3tNmU5RzltMd6Xmt3qU2f/JDQLMo6PSlBodnjOUsDHJgmtrcbjhqrx/znA237BkNUu6UZRT7mxhXIZpn0U="
branches:
except:
- g3_v2_0
- g3
cache:
yarn: true
directories:
- ./node_modules
- ./.chrome/chromium
- ./aio/node_modules
env:
global:
# GITHUB_TOKEN_ANGULAR
# 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.
- secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
- secure: "aCdHveZuY8AT4Jr1JoJB4LxZsnGWRe/KseZh1YXYe5UtufFCtTVHvUcLn0j2aLBF0KpdyS+hWf0i4np9jthKu2xPKriefoPgCMpisYeC0MFkwbmv+XlgkUbgkgVZMGiVyX7DCYXVahxIoOUjVMEDCbNiHTIrfEuyq24U3ok2tHc="
# FIREBASE_TOKEN
# This is needed for publishing builds to the "aio-staging" and "angular-io" firebase projects.
# This token was generated using the aio-deploy@angular.io account using `firebase login:ci` and password from valentine
- secure: "L5CyQmpwWtoR4Qi4xlWQh/cL1M6ZeJL4W4QAr4HdKFMgYt9h+Whqkymyh2NxwmCbPvWa7yUd+OiLQUDCY7L2VIg16hTwoe2CgYDyQA0BEwLzxtRrJXl93TfwMlrUx5JSIzAccD6D4sjtz8kSFMomK2Nls33xOXOukwyhVMjd0Cg="
# ANGULAR_PAYLOAD_FIREBASE_TOKEN
# This is for payload size data to "angular-payload-size" firebase project
# This token was generated using the payload@angular.io account using `firebase login:ci` and password from valentine
- secure: "SxotP/ymNy6uWAVbfwM9BlwETPEBpkRvU/F7fCtQDDic99WfQHzzUSQqHTk8eKk3GrGAOSL09vT0WfStQYEIGEoS5UHWNgOnelxhw+d5EnaoB8vQ0dKQBTK092hQg4feFprr+B/tCasyMV6mVwpUzZMbIJNn/Rx7H5g1bp+Gkfg="
matrix:
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
- CI_MODE=e2e EXPERIMENTAL_ES2015_DISTRO=1
- CI_MODE=e2e
- CI_MODE=e2e_2
- CI_MODE=js
- CI_MODE=saucelabs_required
- CI_MODE=browserstack_required
# deactivated, see #19768
# - CI_MODE=browserstack_required
- CI_MODE=saucelabs_optional
- CI_MODE=browserstack_optional
- CI_MODE=aio_tools_test
- CI_MODE=aio
- CI_MODE=aio_e2e AIO_SHARD=0
- CI_MODE=aio_e2e AIO_SHARD=1
- CI_MODE=bazel
matrix:
fast_finish: true
@ -41,11 +64,19 @@ matrix:
- env: "CI_MODE=saucelabs_optional"
- env: "CI_MODE=browserstack_optional"
before_install:
# source the env.sh script so that the exported variables are available to other scripts later on
- source ./scripts/ci/env.sh print
install:
- ./scripts/ci-lite/install.sh
- ./scripts/ci/install.sh
script:
- ./scripts/ci-lite/build.sh && ./scripts/ci-lite/test.sh
after_script:
- ./scripts/ci-lite/cleanup.sh
- ./scripts/ci/build.sh
- ./scripts/ci/test.sh
# deploy is part of 'script' and not 'after_success' so that we fail the build if the deployment fails
- ./scripts/ci/deploy.sh
- ./scripts/ci/angular.sh
# all the scripts under this line will not quickly abort in case ${TRAVIS_TEST_RESULT} is 1 (job failure)
- ./scripts/ci/cleanup.sh
- ./scripts/ci/print-logs.sh

25
BUILD.bazel Normal file
View File

@ -0,0 +1,25 @@
package(default_visibility = ["//visibility:public"])
exports_files(["tsconfig.json"])
# This rule belongs in node_modules/BUILD
# It's here as a workaround for
# https://github.com/bazelbuild/bazel/issues/374#issuecomment-296217940
filegroup(
name = "node_modules",
srcs = glob([
# Performance workaround: list individual files
# This won't scale in the general case.
# TODO(alexeagle): figure out what to do
"node_modules/typescript/**",
"node_modules/zone.js/**",
"node_modules/rxjs/**/*.d.ts",
"node_modules/rxjs/**/*.js",
"node_modules/@types/**/*.d.ts",
"node_modules/tsickle/**",
"node_modules/hammerjs/**/*.d.ts",
"node_modules/protobufjs/**",
"node_modules/bytebuffer/**",
"node_modules/reflect-metadata/**",
"node_modules/minimist/**/*.js",
]),
)

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +0,0 @@
# Pushing changes into the Angular 2 tree
Please see [Using git with Angular repositories](https://docs.google.com/document/d/1h8nijFSaa1jG_UE8v4WP7glh5qOUXnYtAtJh_gwOQHI/edit)
for details about how we maintain a linear commit history, and the rules for committing.
As a contributor, just read the instructions in [CONTRIBUTING.md](CONTRIBUTING.md) and send a pull request.
Someone with committer access will do the rest.
## The `PR: merge` label and `presubmit-*` branches
We have automated the process for merging pull requests into master. Our goal is to minimize the disruption for
Angular committers and also prevent breakages on master.
When a PR has `pr_state: LGTM` and is ready to merge, you should add the `pr_action: merge` label.
Currently (late 2015), we need to ensure that each PR will cleanly merge into the Google-internal version control,
so the caretaker reviews the changes manually.
After this review, the caretaker adds `zomg_admin: do_merge` which is restricted to admins only.
A robot running as [mary-poppins](https://github.com/mary-poppins)
is notified that the label was added by an authorized person,
and will create a new branch in the angular project, using the convention `presubmit-{username}-pr-{number}`.
(Note: if the automation fails, committers can instead push the commits to a branch following this naming scheme.)
When a Travis build succeeds for a presubmit branch named following the convention,
Travis will re-base the commits, merge to master, and close the PR automatically.
Finally, after merge `mary-poppins` removes the presubmit branch.
## Administration
The list of users who can trigger a merge by adding the `zomg_admin: do_merge` label is stored in our appengine app datastore.
Edit the contents of the [CoreTeamMember Table](
https://console.developers.google.com/project/angular2-automation/datastore/query?queryType=KindQuery&namespace=&kind=CoreTeamMember)

View File

@ -17,15 +17,15 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
## <a name="question"></a> Got a Question or Problem?
Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](https://stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [Stack Overflow](https://stackoverflow.com/questions/tagged/angular) where the questions should be tagged with tag `angular`.
StackOverflow is a much better place to ask questions since:
Stack Overflow is a much better place to ask questions since:
- there are thousands of people willing to help on StackOverflow
- there are thousands of people willing to help on Stack Overflow
- questions and answers stay available for public viewing so your question / answer might help someone else
- StackOverflow's voting system assures that the best answers are prominently visible.
- Stack Overflow's voting system assures that the best answers are prominently visible.
To save your and our time we will be systematically closing all the issues that are requests for general support and redirecting people to StackOverflow.
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
@ -147,7 +147,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
* All public API methods **must be documented**. (Details TBC).
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
**100 characters**. An automated formatter is available, see
[DEVELOPER.md](DEVELOPER.md#clang-format).
[DEVELOPER.md](docs/DEVELOPER.md#clang-format).
## <a name="commit"></a> Commit Message Guidelines
@ -198,8 +198,7 @@ Must be one of the following:
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests
### Scope
@ -207,6 +206,7 @@ The scope should be the name of the npm package affected (as perceived by person
The following is the list of supported scopes:
* **animations**
* **common**
* **compiler**
* **compiler-cli**
@ -223,15 +223,13 @@ The following is the list of supported scopes:
* **upgrade**
* **tsc-wrapped**
There is currently few exception to the "use package name" rule:
There are currently a few exceptions to the "use package name" rule:
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
* **changelog**: used for updating the release notes in CHANGELOG.md
* **aio**: used for docs-app (angular.io) related changes within the /aio directory of the repo
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
Packaging
### Subject
The subject contains succinct description of the change:
@ -265,7 +263,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[dev-doc]: https://github.com/angular/angular/blob/master/DEVELOPER.md
[dev-doc]: https://github.com/angular/angular/blob/master/docs/DEVELOPER.md
[github]: https://github.com/angular/angular
[gitter]: https://gitter.im/angular/angular
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html

View File

@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2014-2016 Google, Inc. http://angular.io
Copyright (c) 2014-2017 Google, Inc. http://angular.io
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -3,25 +3,21 @@
[![Join the chat at https://gitter.im/angular/angular](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/pr?style=flat)](http://issuestats.com/github/angular/angular)
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/issue?style=flat)](http://issuestats.com/github/angular/angular)
[![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://badge.fury.io/js/%40angular%2Fcore)
[![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://www.npmjs.com/@angular/core)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
*Safari (7+), iOS (7+), Edge (14) and IE mobile (11) are tested on [BrowserStack][browserstack].*
Angular
=========
Angular is a development platform for building mobile and desktop web applications. This is the
repository for [Angular 2][ng2] Typescript/JavaScript (JS).
Angular2 for [Dart][dart] can be found at [dart-lang/angular2][ng2dart].
# Angular
Angular is a development platform for building mobile and desktop web applications using Typescript/JavaScript and other languages.
## Quickstart
[Get started in 5 minutes][quickstart].
## Want to help?
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
@ -29,9 +25,5 @@ guidelines for [contributing][contributing] and then check out one of our issues
[browserstack]: https://www.browserstack.com/
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
[dart]: http://www.dartlang.org
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
[ng2]: http://angular.io
[ngDart]: http://angulardart.org
[ngJS]: http://angularjs.org
[ng2dart]: https://github.com/dart-lang/angular2
[ng]: http://angular.io

View File

@ -1,158 +0,0 @@
# Triage Process and Github Labels for Angular 2
This document describes how the Angular team uses labels and milestones
to triage issues on github. The basic idea of the process is that
caretaker only assigns a component and type (bug, feature) label. The
owner of the component than is in full control of how the issues should
be triaged further.
Once this process is implemented and in use, we will revisit it to see
if further labeling is needed.
## Components
A caretaker should be able to determine which component the issue
belongs to. The components have a clear piece of source code associated
with it.
* `comp: animations`: `@matsko`
* `comp: benchpress`: `@tbosch`
* `comp: build & ci`: `@IgorMinar` -- All build and CI scripts
* `comp: common`: `@mhevery` -- This includes core components / pipes.
* `comp: core & compiler`: `@tbosch` -- Because core and compiler are very
intertwined, we will be treating them as one.
* `comp: forms`: `@kara`
* `comp: http`: `@jeffbcross`
* `comp: i18n`: `@vicb`
* `comp: language service`: `@chuckjaz`
* `comp: metadata-extractor`: `@chuckjaz`
* `comp: router`: `@vicb`
* `comp: testing`: `@juliemr`
* `comp: upgrade`: `@mhevery`
* `comp: web-worker`: `@vicb`
* `comp: zones`: `@mhevery`
There are few components which are cross-cutting. They don't have
a clear location in the source tree. We will treat them as a component
even thought no specific source tree is associated with them.
* `comp: docs`: `@naomiblack`
* `comp: packaging`: `@IgorMinar`
* `comp: performance`: `@tbosch`
* `comp: security`: `@IgorMinar`
## Type
What kind of problem is this?
* `type: RFC / discussion / question`
* `type: bug`
* `type: chore`
* `type: feature`
* `type: performance`
* `type: refactor`
## Caretaker Triage Process
It is the caretaker's responsibility to assign `comp: *` to each new
issue as they come in. The reason why we limit the responsibility of the
caretaker to this one label is that it is likely that without domain
knowledge the caretaker could mislabel issues or lack knowledge of
duplicate issues.
## Component's owner Triage Process
At this point we are leaving each component owner to determine their own
process for their component.
It will be up to the component owner to determine the order in which the
issues within the component will be resolved.
Several owners have adopted the issue categorization based on
[user pain](http://www.lostgarden.com/2008/05/improving-bug-triage-with-user-pain.html)
used by Angular 1. In this system every issue is assigned frequency and
severity based on which the total user pain score is calculated.
Following is the definition of various frequency and severity levels:
1. `freq(score): *` How often does this issue come up? How many developers does this affect?
* low (1) - obscure issue affecting a handful of developers
* moderate (2) - impacts auxiliary usage patterns, only small number of applications are affected
* high (3) - impacts primary usage patterns, affecting most Angular apps
* critical (4) - impacts all Angular apps
1. `severity(score): *` - How bad is the issue?
* inconvenience (1) - causes ugly/boilerplate code in apps
* confusing (2) - unexpected or inconsistent behavior; hard-to-debug
* broken expected use (3) - it's hard or impossible for a developer using Angular to accomplish something that Angular should be able to do
* memory leak (4)
* regression (5) - functionality that used to work no longer works in a new release due to an unintentional change
* security issue (6)
These criteria are then used to calculate a "user pain" score as follows:
`pain = severity × frequency`
### Assigning Issues to Milestones
Any issue that is being worked on must have:
* An `Assignee`: The person doing the work.
* A `Milestone`: When we expect to complete this work.
We aim to only have at most three milestones open at a time:
* Closing Milestone: A milestone with a very small number of issues, about to release.
* Current Milestone: Work that we plan to complete within one week.
* Next Milestone: Work that is > 1 week but current for the team.
The [backlog](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Amilestone)
consists of all issues that have been triaged but do not have an assignee or milestone.
## Triaged vs Untrained PRs
PRs should also be label with a `comp: *` so that it is clear which
primary area the PR effects.
Because of the cumulative pain associated with rebasing PRs, we triage PRs daily, and
closing or reviewing PRs is a top priority ahead of other ongoing work.
Every triaged PR must have a `pr_action` label assigned to it and an assignee:
* `pr_action: review` -- work is complete and comment is needed from the assignee.
* `pr_action: cleanup` -- more work is needed from the current assignee.
* `pr_action: discuss` -- discussion is needed, to be led by the current assignee.
* `pr_action: merge` -- the PR should be merged. Add this to a PR when you would like to
trigger automatic merging following a successful build. This is described in [COMMITTER.md](COMMITTER.md).
In addition, PRs can have the following states:
* `pr_state: LGTM` -- PR may have outstanding changes but does not require further review.
* `pr_state: WIP` -- PR is experimental or rapidly changing. Not ready for review or triage.
* `pr_state: blocked` -- PR is blocked on an issue or other PR. Not ready for review or triage.
Note that an LGTM state does not mean a PR is ready to merge: for example, a reviewer might set the
LGTM state but request a minor tweak that doesn't need further review, e.g., a rebase or small
uncontroversial change.
PRs do not need to be assigned to milestones, unless a milestone release should be held for that
PR to land.
## Special Labels
### action:design
More active discussion is needed before the issue can be worked on further. Typically used for
`type: feature` or `type: RFC/discussion/question`
[See all issues that need discussion](https://github.com/angular/angular/labels/action:%20Design)
### cla
Managed by googlebot. Indicates whether a PR has a CLA on file for its author(s). Only issues with
`cla:yes` should be merged into master.
### WORKS_AS_INTENDED
Only used on closed issues, to indicate to the reporter why we closed it.

17
WORKSPACE Normal file
View File

@ -0,0 +1,17 @@
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "build_bazel_rules_typescript",
remote = "https://github.com/bazelbuild/rules_typescript.git",
tag = "0.0.5",
)
load("@build_bazel_rules_typescript//:defs.bzl", "node_repositories")
node_repositories(package_json = "//:package.json")
git_repository(
name = "build_bazel_rules_angular",
remote = "https://github.com/bazelbuild/rules_angular.git",
tag = "0.0.1",
)

67
aio/.angular-cli.json Normal file
View File

@ -0,0 +1,67 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "site"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"generated",
"app/search/search-worker.js",
"favicon.ico",
"pwa-manifest.json",
"google385281288605d160.html"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "aio",
"serviceWorker": false,
"styles": [
"styles.scss"
],
"scripts": [
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"next": "environments/environment.next.ts",
"stable": "environments/environment.stable.ts",
"archive": "environments/environment.archive.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "scss",
"component": {
"inlineStyle": true
}
}
}

48
aio/.gitignore vendored Normal file
View File

@ -0,0 +1,48 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/out-tsc
/src/generated
/tmp
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
testem.log
/typings
yarn-error.log
# e2e
/e2e/*.js
/e2e/*.map
protractor-results*.txt
# System Files
.DS_Store
Thumbs.db
# copied dependencies
src/assets/js/lunr*

126
aio/README.md Normal file
View File

@ -0,0 +1,126 @@
# Angular documentation project (https://angular.io)
Everything in this folder is part of the documentation project. This includes
* the web site for displaying the documentation
* the dgeni configuration for converting source files to rendered files that can be viewed in the web site.
* the tooling for setting up examples for development; and generating plunkers and zip files from the examples.
## Developer tasks
We use `yarn` to manage the dependencies and to run build tasks.
You should run all these tasks from the `angular/aio` folder.
Here are the most important tasks you might need to use:
* `yarn` - install all the dependencies.
* `yarn setup` - install all the dependencies, boilerplate, plunkers, zips and run dgeni on the docs.
* `yarn setup-local` - same as `setup`, but use the locally built Angular packages for aio and docs examples boilerplate.
* `yarn build` - create a production build of the application (after installing dependencies, boilerplate, etc).
* `yarn build-local` - same as `build`, but use `setup-local` instead of `setup`.
* `yarn start` - run a development web server that watches the files; then builds the doc-viewer and reloads the page, as necessary.
* `yarn serve-and-sync` - run both the `docs-watch` and `start` in the same console.
* `yarn lint` - check that the doc-viewer code follows our style rules.
* `yarn test` - watch all the source files, for the doc-viewer, and run all the unit tests when any change.
* `yarn e2e` - run all the e2e tests for the doc-viewer.
* `yarn docs` - generate all the docs from the source files.
* `yarn docs-watch` - watch the Angular source and the docs files and run a short-circuited doc-gen for the docs that changed.
* `yarn docs-lint` - check that the doc gen code follows our style rules.
* `yarn docs-test` - run the unit tests for the doc generation code.
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally. Add the option `--local` to use your local version of Angular contained in the "dist" folder.
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
* `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 example-e2e` - run all e2e tests for examples
- `yarn example-e2e --setup` - force webdriver update & other setup, then run tests
- `yarn example-e2e --filter=foo` - limit e2e tests to those containing the word "foo"
- `yarn example-e2e --setup --local` - run e2e tests with the local version of Angular contained in the "dist" folder
* `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
There are two types of content in the documentation:
* **API docs**: descriptions of the modules, classes, interfaces, decorators, etc that make up the Angular platform.
API docs are generated directly from the source code.
The source code is contained in TypeScript files, located in the `angular/packages` folder.
Each API item may have a preceding comment, which contains JSDoc style tags and content.
The content is written in markdown.
* **Other content**: guides, tutorials, and other marketing material.
All other content is written using markdown in text files, located in the `angular/aio/content` folder.
More specifically, there are sub-folders that contain particular types of content: guides, tutorial and marketing.
We use the [dgeni](https://github.com/angular/dgeni) tool to convert these files into docs that can be viewed in the doc-viewer.
The [Authors Style Guide](https://angular.io/guide/docs-style-guide) prescribes guidelines for
writing guide pages, explains how to use the documentation classes and components, and how to markup sample source code to produce code snippets.
### Generating the complete docs
The main task for generating the docs is `yarn docs`. This will process all the source files (API and other),
extracting the documentation and generating JSON files that can be consumed by the doc-viewer.
### Partial doc generation for editors
Full doc generation can take up to one minute. That's too slow for efficient document creation and editing.
You can make small changes in a smart editor that displays formatted markdown:
>In VS Code, _Cmd-K, V_ opens markdown preview in side pane; _Cmd-B_ toggles left sidebar
You also want to see those changes displayed properly in the doc viewer
with a quick, edit/view cycle time.
For this purpose, use the `yarn docs-watch` task, which watches for changes to source files and only
re-processes the the files necessary to generate the docs that are related to the file that has changed.
Since this task takes shortcuts, it is much faster (often less than 1 second) but it won't produce full
fidelity content. For example, links to other docs and code examples may not render correctly. This is
most particularly noticed in links to other docs and in the embedded examples, which may not always render
correctly.
The general setup is as follows:
* Open a terminal, ensure the dependencies are installed; run an initial doc generation; then start the doc-viewer:
```bash
yarn
yarn docs
yarn start
```
* Open a second terminal and start watching the docs
```bash
yarn docs-watch
```
>Alternatively, try the consolidated `serve-and-sync` command that builds, watches and serves in the same terminal window
```bash
yarn serve-and-sync
```
* Open a browser at https://localhost:4200/ and navigate to the document on which you want to work.
You can automatically open the browser by using `yarn start -o` in the first terminal.
* Make changes to the page's associated doc or example files. Every time a file is saved, the doc will
be regenerated, the app will rebuild and the page will reload.
* If you get a build error complaining about examples or any other odd behavior, be sure to consult
the [Authors Style Guide](https://angular.io/guide/docs-style-guide).

View File

@ -0,0 +1,3 @@
scripts-js/lib
scripts-js/node_modules
scripts-js/**/test

View File

@ -0,0 +1,168 @@
# Image metadata and config
FROM debian:jessie
LABEL name="angular.io PR preview" \
description="This image implements the PR preview functionality for angular.io." \
vendor="Angular" \
version="1.0"
VOLUME /aio-secrets
VOLUME /var/www/aio-builds
EXPOSE 80 443
# Build-time args and env vars
ARG AIO_BUILDS_DIR=/var/www/aio-builds
ARG TEST_AIO_BUILDS_DIR=/tmp/aio-builds
ARG AIO_DOMAIN_NAME=ngbuilds.io
ARG TEST_AIO_DOMAIN_NAME=$AIO_DOMAIN_NAME.localhost
ARG AIO_GITHUB_ORGANIZATION=angular
ARG TEST_AIO_GITHUB_ORGANIZATION=angular
ARG AIO_GITHUB_TEAM_SLUGS=angular-core,aio-contributors
ARG TEST_AIO_GITHUB_TEAM_SLUGS=angular-core,aio-contributors
ARG AIO_NGINX_HOSTNAME=$AIO_DOMAIN_NAME
ARG TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_DOMAIN_NAME
ARG AIO_NGINX_PORT_HTTP=80
ARG TEST_AIO_NGINX_PORT_HTTP=8080
ARG AIO_NGINX_PORT_HTTPS=443
ARG TEST_AIO_NGINX_PORT_HTTPS=4433
ARG AIO_REPO_SLUG=angular/angular
ARG TEST_AIO_REPO_SLUG=test-repo/test-slug
ARG AIO_TRUSTED_PR_LABEL="aio: preview"
ARG TEST_AIO_TRUSTED_PR_LABEL="aio: preview"
ARG AIO_UPLOAD_HOSTNAME=upload.localhost
ARG TEST_AIO_UPLOAD_HOSTNAME=upload.localhost
ARG AIO_UPLOAD_MAX_SIZE=20971520
ARG TEST_AIO_UPLOAD_MAX_SIZE=20971520
ARG AIO_UPLOAD_PORT=3000
ARG TEST_AIO_UPLOAD_PORT=3001
ENV AIO_BUILDS_DIR=$AIO_BUILDS_DIR TEST_AIO_BUILDS_DIR=$TEST_AIO_BUILDS_DIR \
AIO_DOMAIN_NAME=$AIO_DOMAIN_NAME TEST_AIO_DOMAIN_NAME=$TEST_AIO_DOMAIN_NAME \
AIO_GITHUB_ORGANIZATION=$AIO_GITHUB_ORGANIZATION TEST_AIO_GITHUB_ORGANIZATION=$TEST_AIO_GITHUB_ORGANIZATION \
AIO_GITHUB_TEAM_SLUGS=$AIO_GITHUB_TEAM_SLUGS TEST_AIO_GITHUB_TEAM_SLUGS=$TEST_AIO_GITHUB_TEAM_SLUGS \
AIO_LOCALCERTS_DIR=/etc/ssl/localcerts TEST_AIO_LOCALCERTS_DIR=/etc/ssl/localcerts-test \
AIO_NGINX_HOSTNAME=$AIO_NGINX_HOSTNAME TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_NGINX_HOSTNAME \
AIO_NGINX_LOGS_DIR=/var/log/aio/nginx TEST_AIO_NGINX_LOGS_DIR=/var/log/aio/nginx-test \
AIO_NGINX_PORT_HTTP=$AIO_NGINX_PORT_HTTP TEST_AIO_NGINX_PORT_HTTP=$TEST_AIO_NGINX_PORT_HTTP \
AIO_NGINX_PORT_HTTPS=$AIO_NGINX_PORT_HTTPS TEST_AIO_NGINX_PORT_HTTPS=$TEST_AIO_NGINX_PORT_HTTPS \
AIO_REPO_SLUG=$AIO_REPO_SLUG TEST_AIO_REPO_SLUG=$TEST_AIO_REPO_SLUG \
AIO_SCRIPTS_JS_DIR=/usr/share/aio-scripts-js \
AIO_SCRIPTS_SH_DIR=/usr/share/aio-scripts-sh \
AIO_TRUSTED_PR_LABEL=$AIO_TRUSTED_PR_LABEL TEST_AIO_TRUSTED_PR_LABEL=$TEST_AIO_TRUSTED_PR_LABEL \
AIO_UPLOAD_HOSTNAME=$AIO_UPLOAD_HOSTNAME TEST_AIO_UPLOAD_HOSTNAME=$TEST_AIO_UPLOAD_HOSTNAME \
AIO_UPLOAD_MAX_SIZE=$AIO_UPLOAD_MAX_SIZE TEST_AIO_UPLOAD_MAX_SIZE=$TEST_AIO_UPLOAD_MAX_SIZE \
AIO_UPLOAD_PORT=$AIO_UPLOAD_PORT TEST_AIO_UPLOAD_PORT=$TEST_AIO_UPLOAD_PORT \
AIO_WWW_USER=www-data \
NODE_ENV=production
# Create directory for logs
RUN mkdir /var/log/aio
# Add extra package sources
RUN apt-get update -y && apt-get install -y curl
RUN curl --silent --show-error --location https://deb.nodesource.com/setup_6.x | bash -
RUN curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/backports.list
# Install packages
RUN apt-get update -y && apt-get install -y \
chkconfig \
cron \
dnsmasq \
nano \
nodejs \
openssl \
rsyslog \
yarn
RUN apt-get install -t jessie-backports -y nginx
RUN yarn global add pm2@2
# Set up log rotation
COPY logrotate/* /etc/logrotate.d/
RUN chmod 0644 /etc/logrotate.d/*
# Set up cronjobs
COPY cronjobs/aio-builds-cleanup /etc/cron.d/
RUN chmod 0744 /etc/cron.d/aio-builds-cleanup
RUN crontab /etc/cron.d/aio-builds-cleanup
RUN printenv | grep AIO_ >> /etc/environment
# Set up dnsmasq
COPY dnsmasq/dnsmasq.conf /etc/
RUN sed -i "s|{{\$AIO_NGINX_HOSTNAME}}|$AIO_NGINX_HOSTNAME|g" /etc/dnsmasq.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$AIO_UPLOAD_HOSTNAME|g" /etc/dnsmasq.conf
RUN sed -i "s|{{\$TEST_AIO_NGINX_HOSTNAME}}|$TEST_AIO_NGINX_HOSTNAME|g" /etc/dnsmasq.conf
RUN sed -i "s|{{\$TEST_AIO_UPLOAD_HOSTNAME}}|$TEST_AIO_UPLOAD_HOSTNAME|g" /etc/dnsmasq.conf
# Set up SSL/TLS certificates
COPY nginx/create-selfsigned-cert.sh /tmp/
RUN chmod a+x /tmp/create-selfsigned-cert.sh
RUN /tmp/create-selfsigned-cert.sh "selfcert-prod" "$AIO_NGINX_HOSTNAME" "$AIO_LOCALCERTS_DIR"
RUN /tmp/create-selfsigned-cert.sh "selfcert-test" "$TEST_AIO_NGINX_HOSTNAME" "$TEST_AIO_LOCALCERTS_DIR"
RUN rm /tmp/create-selfsigned-cert.sh
RUN update-ca-certificates
# Set up nginx (for production and testing)
RUN sed -i -E "s|^user\s+\S+;|user $AIO_WWW_USER;|" /etc/nginx/nginx.conf
RUN rm -f /etc/nginx/conf.d/*
RUN rm -f /etc/nginx/sites-enabled/*
COPY nginx/aio-builds.conf /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_BUILDS_DIR}}|$AIO_BUILDS_DIR|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_DOMAIN_NAME}}|$AIO_DOMAIN_NAME|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_LOCALCERTS_DIR}}|$AIO_LOCALCERTS_DIR|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_LOGS_DIR}}|$AIO_NGINX_LOGS_DIR|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTP}}|$AIO_NGINX_PORT_HTTP|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTPS}}|$AIO_NGINX_PORT_HTTPS|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$AIO_UPLOAD_HOSTNAME|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_MAX_SIZE}}|$AIO_UPLOAD_MAX_SIZE|g" /etc/nginx/conf.d/aio-builds-prod.conf
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$AIO_UPLOAD_PORT|g" /etc/nginx/conf.d/aio-builds-prod.conf
COPY nginx/aio-builds.conf /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_BUILDS_DIR}}|$TEST_AIO_BUILDS_DIR|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_DOMAIN_NAME}}|$TEST_AIO_DOMAIN_NAME|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_LOCALCERTS_DIR}}|$TEST_AIO_LOCALCERTS_DIR|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_LOGS_DIR}}|$TEST_AIO_NGINX_LOGS_DIR|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTP}}|$TEST_AIO_NGINX_PORT_HTTP|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_NGINX_PORT_HTTPS}}|$TEST_AIO_NGINX_PORT_HTTPS|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_HOSTNAME}}|$TEST_AIO_UPLOAD_HOSTNAME|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_MAX_SIZE}}|$TEST_AIO_UPLOAD_MAX_SIZE|g" /etc/nginx/conf.d/aio-builds-test.conf
RUN sed -i "s|{{\$AIO_UPLOAD_PORT}}|$TEST_AIO_UPLOAD_PORT|g" /etc/nginx/conf.d/aio-builds-test.conf
# Set up pm2
RUN pm2 startup systemv -u root > /dev/null
RUN chkconfig pm2-root on
# Set up the shell scripts
COPY scripts-sh/ $AIO_SCRIPTS_SH_DIR/
RUN chmod a+x $AIO_SCRIPTS_SH_DIR/*
RUN find $AIO_SCRIPTS_SH_DIR -maxdepth 1 -type f -printf "%P\n" \
| while read file; do ln -s $AIO_SCRIPTS_SH_DIR/$file /usr/local/bin/aio-${file%.*}; done
# Set up the Node.js scripts
COPY scripts-js/ $AIO_SCRIPTS_JS_DIR/
WORKDIR $AIO_SCRIPTS_JS_DIR/
RUN yarn install --production --freeze-lockfile
# Set up health check
HEALTHCHECK --interval=5m CMD /usr/local/bin/aio-health-check
# Go!
WORKDIR /
CMD aio-init && tail -f /dev/null

View File

@ -0,0 +1,2 @@
# Periodically clean up builds that do not correspond to currently open PRs
0 12 * * * root /usr/local/bin/aio-clean-up >> /var/log/cron.log 2>&1

View File

@ -0,0 +1,16 @@
# Do not read /etc/resolv.conf. Get servers from this file instead.
no-resolv
server=8.8.8.8
server=8.8.4.4
# Listen for DHCP and DNS requests only on this address.
listen-address=127.0.0.1
# Force an IP address for these domains.
address=/{{$AIO_NGINX_HOSTNAME}}/127.0.0.1
address=/{{$AIO_UPLOAD_HOSTNAME}}/127.0.0.1
address=/{{$TEST_AIO_NGINX_HOSTNAME}}/127.0.0.1
address=/{{$TEST_AIO_UPLOAD_HOSTNAME}}/127.0.0.1
# Run as root (required from inside docker container).
user=root

View File

@ -0,0 +1,9 @@
/var/log/aio/clean-up.log /var/log/aio/init.log /var/log/aio/verify-setup.log {
compress
create
delaycompress
missingok
monthly
notifempty
rotate 6
}

View File

@ -0,0 +1,13 @@
/var/log/aio/nginx/*.log /var/log/aio/nginx-test/*.log {
compress
create
delaycompress
missingok
monthly
notifempty
rotate 6
sharedscripts
postrotate
service nginx rotate >/dev/null 2>&1
endscript
}

View File

@ -0,0 +1,9 @@
/var/log/aio/upload-server-*.log {
compress
copytruncate
delaycompress
missingok
monthly
notifempty
rotate 6
}

View File

@ -0,0 +1,110 @@
# Redirect all HTTP traffic to HTTPS
server {
server_name _;
listen {{$AIO_NGINX_PORT_HTTP}} default_server;
listen [::]:{{$AIO_NGINX_PORT_HTTP}};
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
# Ideally we want 308 (permanent + keep original method),
# but it is relatively new and not supported by some clients (e.g. cURL).
return 307 https://$host:{{$AIO_NGINX_PORT_HTTPS}}$request_uri;
}
# Serve PR-preview requests
server {
server_name "~^pr(?<pr>[1-9][0-9]*)-(?<sha>[0-9a-f]{7,40})\.";
listen {{$AIO_NGINX_PORT_HTTPS}} ssl http2;
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl http2;
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
ssl_certificate_key {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.key;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
root {{$AIO_BUILDS_DIR}}/$pr/$sha;
disable_symlinks on from=$document_root;
index index.html;
gzip on;
gzip_comp_level 7;
gzip_types *;
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
location "~/[^/]+\.[^/]+$" {
try_files $uri $uri/ =404;
}
location / {
try_files $uri $uri/ /index.html =404;
}
}
# Handle all other requests
server {
server_name _;
listen {{$AIO_NGINX_PORT_HTTPS}} ssl http2 default_server;
listen [::]:{{$AIO_NGINX_PORT_HTTPS}} ssl http2;
ssl_certificate {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.crt;
ssl_certificate_key {{$AIO_LOCALCERTS_DIR}}/{{$AIO_DOMAIN_NAME}}.key;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
# Health check
location "~^/health-check/?$" {
add_header Content-Type text/plain;
return 200 '';
}
# Upload builds
location "~^/create-build/(?<pr>[1-9][0-9]*)/(?<sha>[0-9a-f]{40})/?$" {
if ($request_method != "POST") {
add_header Allow "POST";
return 405;
}
client_body_temp_path /tmp/aio-create-builds;
client_body_buffer_size 128K;
client_max_body_size {{$AIO_UPLOAD_MAX_SIZE}};
client_body_in_file_only on;
proxy_pass_request_headers on;
proxy_set_header X-FILE $request_body_file;
proxy_set_body off;
proxy_redirect off;
proxy_method GET;
proxy_pass http://{{$AIO_UPLOAD_HOSTNAME}}:{{$AIO_UPLOAD_PORT}}$request_uri;
resolver 127.0.0.1;
}
# Notify about PR changes
location "~^/pr-updated/?$" {
if ($request_method != "POST") {
add_header Allow "POST";
return 405;
}
proxy_pass_request_headers on;
proxy_redirect off;
proxy_method POST;
proxy_pass http://{{$AIO_UPLOAD_HOSTNAME}}:{{$AIO_UPLOAD_PORT}}$request_uri;
resolver 127.0.0.1;
}
# Everything else
location / {
return 404;
}
}

View File

@ -0,0 +1,20 @@
#!/bin/bash
set -eu -o pipefail
# Variables
confFile=/tmp/$1.conf
domainName=$2
outDir=$3
# Create certificate
cp /etc/ssl/openssl.cnf "$confFile"
echo "[subjectAltName]" >> "$confFile"
echo "subjectAltName = DNS:$domainName, DNS:*.$domainName" >> "$confFile"
mkdir -p $outDir
openssl req -days 365 -newkey rsa:2048 -nodes -sha256 -x509 \
-config "$confFile" -extensions subjectAltName -subj "/CN=$domainName" \
-out "$outDir/$domainName.crt" -keyout "$outDir/$domainName.key"
chmod -R 400 "$outDir"
cp "$outDir/$domainName.crt" /usr/local/share/ca-certificates

View File

@ -0,0 +1,2 @@
/dist
/node_modules

View File

@ -0,0 +1,81 @@
// Imports
import * as fs from 'fs';
import * as path from 'path';
import * as shell from 'shelljs';
import {HIDDEN_DIR_PREFIX} from '../common/constants';
import {GithubPullRequests} from '../common/github-pull-requests';
import {assertNotMissingOrEmpty} from '../common/utils';
// Classes
export class BuildCleaner {
// Constructor
constructor(protected buildsDir: string, protected repoSlug: string, protected githubToken: string) {
assertNotMissingOrEmpty('buildsDir', buildsDir);
assertNotMissingOrEmpty('repoSlug', repoSlug);
assertNotMissingOrEmpty('githubToken', githubToken);
}
// Methods - Public
public cleanUp(): Promise<void> {
return Promise.all([
this.getExistingBuildNumbers(),
this.getOpenPrNumbers(),
]).then(([existingBuilds, openPrs]) => this.removeUnnecessaryBuilds(existingBuilds, openPrs));
}
// Methods - Protected
protected getExistingBuildNumbers(): Promise<number[]> {
return new Promise((resolve, reject) => {
fs.readdir(this.buildsDir, (err, files) => {
if (err) {
return reject(err);
}
const buildNumbers = files.
map(name => name.replace(HIDDEN_DIR_PREFIX, '')). // Remove the "hidden dir" prefix
map(Number). // Convert string to number
filter(Boolean); // Ignore NaN (or 0), because they are not builds
resolve(buildNumbers);
});
});
}
protected getOpenPrNumbers(): Promise<number[]> {
const githubPullRequests = new GithubPullRequests(this.githubToken, this.repoSlug);
return githubPullRequests.
fetchAll('open').
then(prs => prs.map(pr => pr.number));
}
protected removeDir(dir: string) {
try {
if (shell.test('-d', dir)) {
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
(shell as any).chmod('-R', 'a+w', dir);
shell.rm('-rf', dir);
}
} catch (err) {
console.error(`ERROR: Unable to remove '${dir}' due to:`, err);
}
}
protected removeUnnecessaryBuilds(existingBuildNumbers: number[], openPrNumbers: number[]) {
const toRemove = existingBuildNumbers.filter(num => !openPrNumbers.includes(num));
console.log(`Existing builds: ${existingBuildNumbers.length}`);
console.log(`Open pull requests: ${openPrNumbers.length}`);
console.log(`Removing ${toRemove.length} build(s): ${toRemove.join(', ')}`);
// Try removing public dirs.
toRemove.
map(num => path.join(this.buildsDir, String(num))).
forEach(dir => this.removeDir(dir));
// Try removing hidden dirs.
toRemove.
map(num => path.join(this.buildsDir, HIDDEN_DIR_PREFIX + String(num))).
forEach(dir => this.removeDir(dir));
}
}

View File

@ -0,0 +1,23 @@
// Imports
import {getEnvVar} from '../common/utils';
import {BuildCleaner} from './build-cleaner';
// Constants
const AIO_BUILDS_DIR = getEnvVar('AIO_BUILDS_DIR');
const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN', true);
const AIO_REPO_SLUG = getEnvVar('AIO_REPO_SLUG');
// Run
_main();
// Functions
function _main() {
console.log(`[${new Date()}] - Cleaning up builds...`);
const buildCleaner = new BuildCleaner(AIO_BUILDS_DIR, AIO_REPO_SLUG, AIO_GITHUB_TOKEN);
buildCleaner.cleanUp().catch(err => {
console.error('ERROR:', err);
process.exit(1);
});
}

View File

@ -0,0 +1,3 @@
// Constants
export const HIDDEN_DIR_PREFIX = 'hidden--';
export const SHORT_SHA_LEN = 7;

View File

@ -0,0 +1,110 @@
// Imports
import {IncomingMessage} from 'http';
import * as https from 'https';
import {assertNotMissingOrEmpty} from './utils';
// Constants
const GITHUB_HOSTNAME = 'api.github.com';
// Interfaces - Types
interface RequestParams {
[key: string]: string | number;
}
type RequestParamsOrNull = RequestParams | null;
// Classes
export class GithubApi {
protected requestHeaders: {[key: string]: string};
// Constructor
constructor(githubToken: string) {
assertNotMissingOrEmpty('githubToken', githubToken);
this.requestHeaders = {
'Authorization': `token ${githubToken}`,
'User-Agent': `Node/${process.versions.node}`,
};
}
// Methods - Public
public get<T>(pathname: string, params?: RequestParamsOrNull): Promise<T> {
const path = this.buildPath(pathname, params);
return this.request<T>('get', path);
}
public post<T>(pathname: string, params?: RequestParamsOrNull, data?: any): Promise<T> {
const path = this.buildPath(pathname, params);
return this.request<T>('post', path, data);
}
// Methods - Protected
protected buildPath(pathname: string, params?: RequestParamsOrNull): string {
if (params == null) {
return pathname;
}
const search = (params === null) ? '' : this.serializeSearchParams(params);
const joiner = search && '?';
return `${pathname}${joiner}${search}`;
}
protected getPaginated<T>(pathname: string, baseParams: RequestParams = {}, currentPage: number = 0): Promise<T[]> {
const perPage = 100;
const params = {
...baseParams,
page: currentPage,
per_page: perPage,
};
return this.get<T[]>(pathname, params).then(items => {
if (items.length < perPage) {
return items;
}
return this.getPaginated<T>(pathname, baseParams, currentPage + 1).then(moreItems => [...items, ...moreItems]);
});
}
protected request<T>(method: string, path: string, data: any = null): Promise<T> {
return new Promise<T>((resolve, reject) => {
const options = {
headers: {...this.requestHeaders},
host: GITHUB_HOSTNAME,
method,
path,
};
const onError = (statusCode: number, responseText: string) => {
const url = `https://${GITHUB_HOSTNAME}${path}`;
reject(`Request to '${url}' failed (status: ${statusCode}): ${responseText}`);
};
const onSuccess = (responseText: string) => {
try { resolve(JSON.parse(responseText)); } catch (err) { reject(err); }
};
const onResponse = (res: IncomingMessage) => {
const statusCode = res.statusCode || -1;
const isSuccess = (200 <= statusCode) && (statusCode < 400);
let responseText = '';
res.
on('data', d => responseText += d).
on('end', () => isSuccess ? onSuccess(responseText) : onError(statusCode, responseText)).
on('error', reject);
};
https.
request(options, onResponse).
on('error', reject).
end(data && JSON.stringify(data));
});
}
protected serializeSearchParams(params: RequestParams): string {
return Object.keys(params).
filter(key => params[key] != null).
map(key => `${key}=${encodeURIComponent(String(params[key]))}`).
join('&');
}
}

View File

@ -0,0 +1,46 @@
// Imports
import {assertNotMissingOrEmpty} from '../common/utils';
import {GithubApi} from './github-api';
// Interfaces - Types
export interface PullRequest {
number: number;
user: {login: string};
labels: {name: string}[];
}
export type PullRequestState = 'all' | 'closed' | 'open';
// Classes
export class GithubPullRequests extends GithubApi {
// Constructor
constructor(githubToken: string, protected repoSlug: string) {
super(githubToken);
assertNotMissingOrEmpty('repoSlug', repoSlug);
}
// Methods - Public
public addComment(pr: number, body: string): Promise<void> {
if (!(pr > 0)) {
throw new Error(`Invalid PR number: ${pr}`);
} else if (!body) {
throw new Error(`Invalid or empty comment body: ${body}`);
}
return this.post<void>(`/repos/${this.repoSlug}/issues/${pr}/comments`, null, {body});
}
public fetch(pr: number): Promise<PullRequest> {
// Using the `/issues/` URL, because the `/pulls/` one does not provide labels.
return this.get<PullRequest>(`/repos/${this.repoSlug}/issues/${pr}`);
}
public fetchAll(state: PullRequestState = 'all'): Promise<PullRequest[]> {
console.log(`Fetching ${state} pull requests...`);
const pathname = `/repos/${this.repoSlug}/pulls`;
const params = {state};
return this.getPaginated<PullRequest>(pathname, params);
}
}

View File

@ -0,0 +1,45 @@
// Imports
import {assertNotMissingOrEmpty} from '../common/utils';
import {GithubApi} from './github-api';
// Interfaces - Types
interface Team {
id: number;
slug: string;
}
interface TeamMembership {
state: string;
}
// Classes
export class GithubTeams extends GithubApi {
// Constructor
constructor(githubToken: string, protected organization: string) {
super(githubToken);
assertNotMissingOrEmpty('organization', organization);
}
// Methods - Public
public fetchAll(): Promise<Team[]> {
return this.getPaginated<Team>(`/orgs/${this.organization}/teams`);
}
public isMemberById(username: string, teamIds: number[]): Promise<boolean> {
const getMembership = (teamId: number) =>
this.get<TeamMembership>(`/teams/${teamId}/memberships/${username}`).
then(membership => membership.state === 'active').
catch(() => false);
const reduceFn = (promise: Promise<boolean>, teamId: number) =>
promise.then(isMember => isMember || getMembership(teamId));
return teamIds.reduce(reduceFn, Promise.resolve(false));
}
public isMemberBySlug(username: string, teamSlugs: string[]): Promise<boolean> {
return this.fetchAll().
then(teams => teams.filter(team => teamSlugs.includes(team.slug)).map(team => team.id)).
then(teamIds => this.isMemberById(username, teamIds)).
catch(() => false);
}
}

View File

@ -0,0 +1,23 @@
export const runTests = (specFiles: string[], helpers?: string[]) => {
// We can't use `import` here, because of the following mess:
// - GitHub project `jasmine/jasmine` is `jasmine-core` on npm and its typings `@types/jasmine`.
// - GitHub project `jasmine/jasmine-npm` is `jasmine` on npm and has no typings.
//
// Using `import...from 'jasmine'` here, would import from `@types/jasmine` (which refers to the
// `jasmine-core` module and the `jasmine` module).
// tslint:disable-next-line: no-var-requires variable-name
const Jasmine = require('jasmine');
const config = {
helpers,
random: true,
spec_files: specFiles,
stopSpecOnExpectationFailure: true,
};
process.on('unhandledRejection', (reason: any) => console.log('Unhandled rejection:', reason));
const runner = new Jasmine();
runner.loadConfig(config);
runner.onComplete((passed: boolean) => process.exit(passed ? 0 : 1));
runner.execute();
};

View File

@ -0,0 +1,17 @@
// Functions
export const assertNotMissingOrEmpty = (name: string, value: string | null | undefined) => {
if (!value) {
throw new Error(`Missing or empty required parameter '${name}'!`);
}
};
export const getEnvVar = (name: string, isOptional = false): string => {
const value = process.env[name];
if (!isOptional && !value) {
console.error(`ERROR: Missing required environment variable '${name}'!`);
process.exit(1);
}
return value || '';
};

View File

@ -0,0 +1,141 @@
// Imports
import * as cp from 'child_process';
import {EventEmitter} from 'events';
import * as fs from 'fs';
import * as path from 'path';
import * as shell from 'shelljs';
import {HIDDEN_DIR_PREFIX, SHORT_SHA_LEN} from '../common/constants';
import {assertNotMissingOrEmpty} from '../common/utils';
import {ChangedPrVisibilityEvent, CreatedBuildEvent} from './build-events';
import {UploadError} from './upload-error';
// Classes
export class BuildCreator extends EventEmitter {
// Constructor
constructor(protected buildsDir: string) {
super();
assertNotMissingOrEmpty('buildsDir', buildsDir);
}
// Methods - Public
public create(pr: string, sha: string, archivePath: string, isPublic: boolean): Promise<void> {
// Use only part of the SHA for more readable URLs.
sha = sha.substr(0, SHORT_SHA_LEN);
const {newPrDir: prDir} = this.getCandidatePrDirs(pr, isPublic);
const shaDir = path.join(prDir, sha);
let dirToRemoveOnError: string;
return Promise.resolve().
// If the same PR exists with different visibility, update the visibility first.
then(() => this.updatePrVisibility(pr, isPublic)).
then(() => Promise.all([this.exists(prDir), this.exists(shaDir)])).
then(([prDirExisted, shaDirExisted]) => {
if (shaDirExisted) {
const publicOrNot = isPublic ? 'public' : 'non-public';
throw new UploadError(409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`);
}
dirToRemoveOnError = prDirExisted ? shaDir : prDir;
return Promise.resolve().
then(() => shell.mkdir('-p', shaDir)).
then(() => this.extractArchive(archivePath, shaDir)).
then(() => this.emit(CreatedBuildEvent.type, new CreatedBuildEvent(+pr, sha, isPublic))).
then(() => undefined);
}).
catch(err => {
if (dirToRemoveOnError) {
shell.rm('-rf', dirToRemoveOnError);
}
if (!(err instanceof UploadError)) {
err = new UploadError(500, `Error while uploading to directory: ${shaDir}\n${err}`);
}
throw err;
});
}
public updatePrVisibility(pr: string, makePublic: boolean): Promise<boolean> {
const {oldPrDir: otherVisPrDir, newPrDir: targetVisPrDir} = this.getCandidatePrDirs(pr, makePublic);
return Promise.
all([this.exists(otherVisPrDir), this.exists(targetVisPrDir)]).
then(([otherVisPrDirExisted, targetVisPrDirExisted]) => {
if (!otherVisPrDirExisted) {
// No visibility change: Either the visibility is up-to-date or the PR does not exist.
return false;
} else if (targetVisPrDirExisted) {
// Error: Directories for both visibilities exist.
throw new UploadError(409, `Request to move '${otherVisPrDir}' to existing directory '${targetVisPrDir}'.`);
}
// Visibility change: Moving `otherVisPrDir` to `targetVisPrDir`.
return Promise.resolve().
then(() => shell.mv(otherVisPrDir, targetVisPrDir)).
then(() => this.listShasByDate(targetVisPrDir)).
then(shas => this.emit(ChangedPrVisibilityEvent.type, new ChangedPrVisibilityEvent(+pr, shas, makePublic))).
then(() => true);
}).
catch(err => {
if (!(err instanceof UploadError)) {
err = new UploadError(500, `Error while making PR ${pr} ${makePublic ? 'public' : 'hidden'}.\n${err}`);
}
throw err;
});
}
// Methods - Protected
protected exists(fileOrDir: string): Promise<boolean> {
return new Promise(resolve => fs.access(fileOrDir, err => resolve(!err)));
}
protected extractArchive(inputFile: string, outputDir: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
const cmd = `tar --extract --gzip --directory "${outputDir}" --file "${inputFile}"`;
cp.exec(cmd, (err, _stdout, stderr) => {
if (err) {
return reject(err);
}
if (stderr) {
console.warn(stderr);
}
try {
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
(shell as any).chmod('-R', 'a-w', outputDir);
shell.rm('-f', inputFile);
resolve();
} catch (err) {
reject(err);
}
});
});
}
protected getCandidatePrDirs(pr: string, isPublic: boolean) {
const hiddenPrDir = path.join(this.buildsDir, HIDDEN_DIR_PREFIX + pr);
const publicPrDir = path.join(this.buildsDir, pr);
const oldPrDir = isPublic ? hiddenPrDir : publicPrDir;
const newPrDir = isPublic ? publicPrDir : hiddenPrDir;
return {oldPrDir, newPrDir};
}
protected listShasByDate(inputDir: string): Promise<string[]> {
return Promise.resolve().
then(() => shell.ls('-l', inputDir) as any as Promise<(fs.Stats & {name: string})[]>).
// Keep directories only.
// (Also, convert to standard Array - ShellJS provides custom `sort()` method for sorting file contents.)
then(items => items.filter(item => item.isDirectory())).
// Sort by modification date.
then(items => items.sort((a, b) => a.mtime.getTime() - b.mtime.getTime())).
// Return directory names.
then(items => items.map(item => item.name));
}
}

View File

@ -0,0 +1,16 @@
// Classes
export class ChangedPrVisibilityEvent {
// Properties - Public, Static
public static type = 'pr.changedVisibility';
// Constructor
constructor(public pr: number, public shas: string[], public isPublic: boolean) {}
}
export class CreatedBuildEvent {
// Properties - Public, Static
public static type = 'build.created';
// Constructor
constructor(public pr: number, public sha: string, public isPublic: boolean) {}
}

View File

@ -0,0 +1,87 @@
// Imports
import * as jwt from 'jsonwebtoken';
import {GithubPullRequests, PullRequest} from '../common/github-pull-requests';
import {GithubTeams} from '../common/github-teams';
import {assertNotMissingOrEmpty} from '../common/utils';
import {UploadError} from './upload-error';
// Interfaces - Types
interface JwtPayload {
slug: string;
'pull-request': number;
}
// Enums
export enum BUILD_VERIFICATION_STATUS {
verifiedAndTrusted,
verifiedNotTrusted,
}
// Classes
export class BuildVerifier {
// Properties - Protected
protected githubPullRequests: GithubPullRequests;
protected githubTeams: GithubTeams;
// Constructor
constructor(protected secret: string, githubToken: string, protected repoSlug: string, organization: string,
protected allowedTeamSlugs: string[], protected trustedPrLabel: string) {
assertNotMissingOrEmpty('secret', secret);
assertNotMissingOrEmpty('githubToken', githubToken);
assertNotMissingOrEmpty('repoSlug', repoSlug);
assertNotMissingOrEmpty('organization', organization);
assertNotMissingOrEmpty('allowedTeamSlugs', allowedTeamSlugs && allowedTeamSlugs.join(''));
assertNotMissingOrEmpty('trustedPrLabel', trustedPrLabel);
this.githubPullRequests = new GithubPullRequests(githubToken, repoSlug);
this.githubTeams = new GithubTeams(githubToken, organization);
}
// Methods - Public
public getPrIsTrusted(pr: number): Promise<boolean> {
return Promise.resolve().
then(() => this.githubPullRequests.fetch(pr)).
then(prInfo => this.hasLabel(prInfo, this.trustedPrLabel) ||
this.githubTeams.isMemberBySlug(prInfo.user.login, this.allowedTeamSlugs));
}
public verify(expectedPr: number, authHeader: string): Promise<BUILD_VERIFICATION_STATUS> {
return Promise.resolve().
then(() => this.extractJwtString(authHeader)).
then(jwtString => this.verifyJwt(expectedPr, jwtString)).
then(jwtPayload => this.verifyPr(jwtPayload['pull-request'])).
catch(err => { throw new UploadError(403, `Error while verifying upload for PR ${expectedPr}: ${err}`); });
}
// Methods - Protected
protected extractJwtString(input: string): string {
return input.replace(/^token +/i, '');
}
protected hasLabel(prInfo: PullRequest, label: string) {
return prInfo.labels.some(labelObj => labelObj.name === label);
}
protected verifyJwt(expectedPr: number, token: string): Promise<JwtPayload> {
return new Promise((resolve, reject) => {
jwt.verify(token, this.secret, {issuer: 'Travis CI, GmbH'}, (err, payload: JwtPayload) => {
if (err) {
reject(err.message || err);
} else if (payload.slug !== this.repoSlug) {
reject(`jwt slug invalid. expected: ${this.repoSlug}`);
} else if (payload['pull-request'] !== expectedPr) {
reject(`jwt pull-request invalid. expected: ${expectedPr}`);
} else {
resolve(payload);
}
});
});
}
protected verifyPr(pr: number): Promise<BUILD_VERIFICATION_STATUS> {
return this.getPrIsTrusted(pr).
then(isTrusted => Promise.resolve(isTrusted ?
BUILD_VERIFICATION_STATUS.verifiedAndTrusted :
BUILD_VERIFICATION_STATUS.verifiedNotTrusted));
}
}

View File

@ -0,0 +1,39 @@
// Imports
import {getEnvVar} from '../common/utils';
import {BuildVerifier} from './build-verifier';
// Run
_main();
// Functions
function _main() {
const secret = 'unused';
const githubToken = getEnvVar('AIO_GITHUB_TOKEN');
const repoSlug = getEnvVar('AIO_REPO_SLUG');
const organization = getEnvVar('AIO_GITHUB_ORGANIZATION');
const allowedTeamSlugs = getEnvVar('AIO_GITHUB_TEAM_SLUGS').split(',');
const trustedPrLabel = getEnvVar('AIO_TRUSTED_PR_LABEL');
const pr = +getEnvVar('AIO_PREVERIFY_PR');
const buildVerifier = new BuildVerifier(secret, githubToken, repoSlug, organization, allowedTeamSlugs,
trustedPrLabel);
// Exit codes:
// - 0: The PR can be automatically trusted (i.e. author belongs to trusted team or PR has the "trusted PR" label).
// - 1: An error occurred.
// - 2: The PR cannot be automatically trusted.
buildVerifier.getPrIsTrusted(pr).
then(isTrusted => {
if (!isTrusted) {
console.warn(
`The PR cannot be automatically verified, because it doesn't have the "${trustedPrLabel}" label and the ` +
`the author is not an active member of any of the following teams: ${allowedTeamSlugs.join(', ')}`);
}
process.exit(isTrusted ? 0 : 2);
}).
catch(err => {
console.error(err);
process.exit(1);
});
}

View File

@ -0,0 +1,34 @@
// Imports
import {getEnvVar} from '../common/utils';
import {uploadServerFactory} from './upload-server-factory';
// Constants
const AIO_BUILDS_DIR = getEnvVar('AIO_BUILDS_DIR');
const AIO_DOMAIN_NAME = getEnvVar('AIO_DOMAIN_NAME');
const AIO_GITHUB_ORGANIZATION = getEnvVar('AIO_GITHUB_ORGANIZATION');
const AIO_GITHUB_TEAM_SLUGS = getEnvVar('AIO_GITHUB_TEAM_SLUGS');
const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN');
const AIO_PREVIEW_DEPLOYMENT_TOKEN = getEnvVar('AIO_PREVIEW_DEPLOYMENT_TOKEN');
const AIO_REPO_SLUG = getEnvVar('AIO_REPO_SLUG');
const AIO_TRUSTED_PR_LABEL = getEnvVar('AIO_TRUSTED_PR_LABEL');
const AIO_UPLOAD_HOSTNAME = getEnvVar('AIO_UPLOAD_HOSTNAME');
const AIO_UPLOAD_PORT = +getEnvVar('AIO_UPLOAD_PORT');
// Run
_main();
// Functions
function _main() {
uploadServerFactory.
create({
buildsDir: AIO_BUILDS_DIR,
domainName: AIO_DOMAIN_NAME,
githubOrganization: AIO_GITHUB_ORGANIZATION,
githubTeamSlugs: AIO_GITHUB_TEAM_SLUGS.split(','),
githubToken: AIO_GITHUB_TOKEN,
repoSlug: AIO_REPO_SLUG,
secret: AIO_PREVIEW_DEPLOYMENT_TOKEN,
trustedPrLabel: AIO_TRUSTED_PR_LABEL,
}).
listen(AIO_UPLOAD_PORT, AIO_UPLOAD_HOSTNAME);
}

View File

@ -0,0 +1,8 @@
// Classes
export class UploadError extends Error {
// Constructor
constructor(public status: number = 500, message?: string) {
super(message);
Object.setPrototypeOf(this, UploadError.prototype);
}
}

View File

@ -0,0 +1,153 @@
// Imports
import * as bodyParser from 'body-parser';
import * as express from 'express';
import * as http from 'http';
import {GithubPullRequests} from '../common/github-pull-requests';
import {assertNotMissingOrEmpty} from '../common/utils';
import {BuildCreator} from './build-creator';
import {ChangedPrVisibilityEvent, CreatedBuildEvent} from './build-events';
import {BUILD_VERIFICATION_STATUS, BuildVerifier} from './build-verifier';
import {UploadError} from './upload-error';
// Constants
const AUTHORIZATION_HEADER = 'AUTHORIZATION';
const X_FILE_HEADER = 'X-FILE';
// Interfaces - Types
interface UploadServerConfig {
buildsDir: string;
domainName: string;
githubOrganization: string;
githubTeamSlugs: string[];
githubToken: string;
repoSlug: string;
secret: string;
trustedPrLabel: string;
}
// Classes
class UploadServerFactory {
// Methods - Public
public create({
buildsDir,
domainName,
githubOrganization,
githubTeamSlugs,
githubToken,
repoSlug,
secret,
trustedPrLabel,
}: UploadServerConfig): http.Server {
assertNotMissingOrEmpty('domainName', domainName);
const buildVerifier = new BuildVerifier(secret, githubToken, repoSlug, githubOrganization, githubTeamSlugs,
trustedPrLabel);
const buildCreator = this.createBuildCreator(buildsDir, githubToken, repoSlug, domainName);
const middleware = this.createMiddleware(buildVerifier, buildCreator);
const httpServer = http.createServer(middleware as any);
httpServer.on('listening', () => {
const info = httpServer.address();
console.info(`Up and running (and listening on ${info.address}:${info.port})...`);
});
return httpServer;
}
// Methods - Protected
protected createBuildCreator(buildsDir: string, githubToken: string, repoSlug: string,
domainName: string): BuildCreator {
const buildCreator = new BuildCreator(buildsDir);
const githubPullRequests = new GithubPullRequests(githubToken, repoSlug);
const postPreviewsComment = (pr: number, shas: string[]) => {
const body = shas.
map(sha => `You can preview ${sha} at https://pr${pr}-${sha}.${domainName}/.`).
join('\n');
return githubPullRequests.addComment(pr, body);
};
buildCreator.on(CreatedBuildEvent.type, ({pr, sha, isPublic}: CreatedBuildEvent) => {
if (isPublic) {
postPreviewsComment(pr, [sha]);
}
});
buildCreator.on(ChangedPrVisibilityEvent.type, ({pr, shas, isPublic}: ChangedPrVisibilityEvent) => {
if (isPublic && shas.length) {
postPreviewsComment(pr, shas);
}
});
return buildCreator;
}
protected createMiddleware(buildVerifier: BuildVerifier, buildCreator: BuildCreator): express.Express {
const middleware = express();
const jsonParser = bodyParser.json();
middleware.get(/^\/create-build\/([1-9][0-9]*)\/([0-9a-f]{40})\/?$/, (req, res) => {
const pr = req.params[0];
const sha = req.params[1];
const archive = req.header(X_FILE_HEADER);
const authHeader = req.header(AUTHORIZATION_HEADER);
if (!authHeader) {
this.throwRequestError(401, `Missing or empty '${AUTHORIZATION_HEADER}' header`, req);
} else if (!archive) {
this.throwRequestError(400, `Missing or empty '${X_FILE_HEADER}' header`, req);
} else {
Promise.resolve().
then(() => buildVerifier.verify(+pr, authHeader)).
then(verStatus => verStatus === BUILD_VERIFICATION_STATUS.verifiedAndTrusted).
then(isPublic => buildCreator.create(pr, sha, archive, isPublic).
then(() => res.sendStatus(isPublic ? 201 : 202))).
catch(err => this.respondWithError(res, err));
}
});
middleware.get(/^\/health-check\/?$/, (_req, res) => res.sendStatus(200));
middleware.post(/^\/pr-updated\/?$/, jsonParser, (req, res) => {
const {action, number: prNo}: {action?: string, number?: number} = req.body;
const visMayHaveChanged = !action || (action === 'labeled') || (action === 'unlabeled');
if (!visMayHaveChanged) {
res.sendStatus(200);
} else if (!prNo) {
this.throwRequestError(400, `Missing or empty 'number' field`, req);
} else {
Promise.resolve().
then(() => buildVerifier.getPrIsTrusted(prNo)).
then(isPublic => buildCreator.updatePrVisibility(String(prNo), isPublic)).
then(() => res.sendStatus(200)).
catch(err => this.respondWithError(res, err));
}
});
middleware.all('*', req => this.throwRequestError(404, 'Unknown resource', req));
middleware.use((err: any, _req: any, res: express.Response, _next: any) => this.respondWithError(res, err));
return middleware;
}
protected respondWithError(res: express.Response, err: any) {
if (!(err instanceof UploadError)) {
err = new UploadError(500, String((err && err.message) || err));
}
const statusText = http.STATUS_CODES[err.status] || '???';
console.error(`Upload error: ${err.status} - ${statusText}`);
console.error(err.message);
res.status(err.status).end(err.message);
}
protected throwRequestError(status: number, error: string, req: express.Request) {
const message = `${error} in request: ${req.method} ${req.originalUrl}` +
(!req.body ? '' : ` ${JSON.stringify(req.body)}`);
throw new UploadError(status, message);
}
}
// Exports
export const uploadServerFactory = new UploadServerFactory();

View File

@ -0,0 +1,16 @@
// Using the values below, we can fake the response of the corresponding methods in tests. This is
// necessary, because the test upload-server will be running as a separate node process, so we will
// not have direct access to the code (e.g. for mocking).
// (See also 'lib/verify-setup/start-test-upload-server.ts'.)
/* tslint:disable: variable-name */
// Special values to be used as `authHeader` in `BuildVerifier#verify()`.
export const BV_verify_error = 'FAKE_VERIFICATION_ERROR';
export const BV_verify_verifiedNotTrusted = 'FAKE_VERIFIED_NOT_TRUSTED';
// Special values to be used as `pr` in `BuildVerifier#getPrIsTrusted()`.
export const BV_getPrIsTrusted_error = 32203;
export const BV_getPrIsTrusted_notTrusted = 72457;
/* tslint:enable: variable-name */

View File

@ -0,0 +1,215 @@
// Imports
import * as cp from 'child_process';
import * as fs from 'fs';
import * as http from 'http';
import * as path from 'path';
import * as shell from 'shelljs';
import {HIDDEN_DIR_PREFIX, SHORT_SHA_LEN} from '../common/constants';
import {getEnvVar} from '../common/utils';
// Constans
const TEST_AIO_BUILDS_DIR = getEnvVar('TEST_AIO_BUILDS_DIR');
const TEST_AIO_NGINX_HOSTNAME = getEnvVar('TEST_AIO_NGINX_HOSTNAME');
const TEST_AIO_NGINX_PORT_HTTP = +getEnvVar('TEST_AIO_NGINX_PORT_HTTP');
const TEST_AIO_NGINX_PORT_HTTPS = +getEnvVar('TEST_AIO_NGINX_PORT_HTTPS');
const TEST_AIO_UPLOAD_HOSTNAME = getEnvVar('TEST_AIO_UPLOAD_HOSTNAME');
const TEST_AIO_UPLOAD_MAX_SIZE = +getEnvVar('TEST_AIO_UPLOAD_MAX_SIZE');
const TEST_AIO_UPLOAD_PORT = +getEnvVar('TEST_AIO_UPLOAD_PORT');
const WWW_USER = getEnvVar('AIO_WWW_USER');
// Interfaces - Types
export interface CmdResult { success: boolean; err: Error | null; stdout: string; stderr: string; }
export interface FileSpecs { content?: string; size?: number; }
export type CleanUpFn = () => void;
export type TestSuiteFactory = (scheme: string, port: number) => void;
export type VerifyCmdResultFn = (result: CmdResult) => void;
// Classes
class Helper {
// Properties - Public
public get buildsDir() { return TEST_AIO_BUILDS_DIR; }
public get nginxHostname() { return TEST_AIO_NGINX_HOSTNAME; }
public get nginxPortHttp() { return TEST_AIO_NGINX_PORT_HTTP; }
public get nginxPortHttps() { return TEST_AIO_NGINX_PORT_HTTPS; }
public get uploadHostname() { return TEST_AIO_UPLOAD_HOSTNAME; }
public get uploadPort() { return TEST_AIO_UPLOAD_PORT; }
public get uploadMaxSize() { return TEST_AIO_UPLOAD_MAX_SIZE; }
public get wwwUser() { return WWW_USER; }
// Properties - Protected
protected cleanUpFns: CleanUpFn[] = [];
protected portPerScheme: {[scheme: string]: number} = {
http: this.nginxPortHttp,
https: this.nginxPortHttps,
};
// Constructor
constructor() {
shell.mkdir('-p', this.buildsDir);
shell.exec(`chown -R ${this.wwwUser} ${this.buildsDir}`);
}
// Methods - Public
public buildExists(pr: string, sha = '', isPublic = true, legacy = false): boolean {
const prDir = this.getPrDir(pr, isPublic);
const dir = !sha ? prDir : this.getShaDir(prDir, sha, legacy);
return fs.existsSync(dir);
}
public cleanUp() {
while (this.cleanUpFns.length) {
// Clean-up fns remove themselves from the list.
this.cleanUpFns[0]();
}
if (fs.readdirSync(this.buildsDir).length) {
throw new Error(`Directory '${this.buildsDir}' is not empty after clean-up.`);
}
}
public createDummyArchive(pr: string, sha: string, archivePath: string): CleanUpFn {
const inputDir = this.getShaDir(this.getPrDir(`uploaded/${pr}`, true), sha);
const cmd1 = `tar --create --gzip --directory "${inputDir}" --file "${archivePath}" .`;
const cmd2 = `chown ${this.wwwUser} ${archivePath}`;
const cleanUpTemp = this.createDummyBuild(`uploaded/${pr}`, sha, true, true);
shell.exec(cmd1);
shell.exec(cmd2);
cleanUpTemp();
return this.createCleanUpFn(() => shell.rm('-rf', archivePath));
}
public createDummyBuild(pr: string, sha: string, isPublic = true, force = false, legacy = false): CleanUpFn {
const prDir = this.getPrDir(pr, isPublic);
const shaDir = this.getShaDir(prDir, sha, legacy);
const idxPath = path.join(shaDir, 'index.html');
const barPath = path.join(shaDir, 'foo', 'bar.js');
this.writeFile(idxPath, {content: `PR: ${pr} | SHA: ${sha} | File: /index.html`}, force);
this.writeFile(barPath, {content: `PR: ${pr} | SHA: ${sha} | File: /foo/bar.js`}, force);
shell.exec(`chown -R ${this.wwwUser} ${prDir}`);
return this.createCleanUpFn(() => shell.rm('-rf', prDir));
}
public deletePrDir(pr: string, isPublic = true) {
const prDir = this.getPrDir(pr, isPublic);
if (fs.existsSync(prDir)) {
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
(shell as any).chmod('-R', 'a+w', prDir);
shell.rm('-rf', prDir);
}
}
public getPrDir(pr: string, isPublic: boolean): string {
const prDirName = isPublic ? pr : HIDDEN_DIR_PREFIX + pr;
return path.join(this.buildsDir, prDirName);
}
public getShaDir(prDir: string, sha: string, legacy = false): string {
return path.join(prDir, legacy ? sha : this.getShordSha(sha));
}
public getShordSha(sha: string): string {
return sha.substr(0, SHORT_SHA_LEN);
}
public readBuildFile(pr: string, sha: string, relFilePath: string, isPublic = true, legacy = false): string {
const shaDir = this.getShaDir(this.getPrDir(pr, isPublic), sha, legacy);
const absFilePath = path.join(shaDir, relFilePath);
return fs.readFileSync(absFilePath, 'utf8');
}
public runCmd(cmd: string, opts: cp.ExecFileOptions = {}): Promise<CmdResult> {
return new Promise(resolve => {
const proc = cp.exec(cmd, opts, (err, stdout, stderr) => resolve({success: !err, err, stdout, stderr}));
this.createCleanUpFn(() => proc.kill());
});
}
public runForAllSupportedSchemes(suiteFactory: TestSuiteFactory) {
Object.keys(this.portPerScheme).forEach(scheme => suiteFactory(scheme, this.portPerScheme[scheme]));
}
public verifyResponse(status: number | [number, string], regex = /^/): VerifyCmdResultFn {
let statusCode: number;
let statusText: string;
if (Array.isArray(status)) {
statusCode = status[0];
statusText = status[1];
} else {
statusCode = status;
statusText = http.STATUS_CODES[statusCode] || 'UNKNOWN_STATUS_CODE';
}
return (result: CmdResult) => {
const [headers, body] = result.stdout.
split(/(?:\r?\n){2,}/).
map(s => s.trim()).
slice(-2); // In case of redirect, discard the previous headers.
// Only keep the last to sections (final headers and body).
if (!result.success) {
console.log('Stdout:', result.stdout);
console.log('Stderr:', result.stderr);
console.log('Error:', result.err);
}
expect(result.success).toBe(true);
expect(headers).toContain(`${statusCode} ${statusText}`);
expect(body).toMatch(regex);
};
}
public writeBuildFile(pr: string, sha: string, relFilePath: string, content: string, isPublic = true,
legacy = false): CleanUpFn {
const shaDir = this.getShaDir(this.getPrDir(pr, isPublic), sha, legacy);
const absFilePath = path.join(shaDir, relFilePath);
return this.writeFile(absFilePath, {content}, true);
}
public writeFile(filePath: string, {content, size}: FileSpecs, force = false): CleanUpFn {
if (!force && fs.existsSync(filePath)) {
throw new Error(`Refusing to overwrite existing file '${filePath}'.`);
}
let cleanUpTarget = filePath;
while (!fs.existsSync(path.dirname(cleanUpTarget))) {
cleanUpTarget = path.dirname(cleanUpTarget);
}
shell.mkdir('-p', path.dirname(filePath));
if (size) {
// Create a file of the specified size.
cp.execSync(`fallocate -l ${size} ${filePath}`);
} else {
// Create a file with the specified content.
fs.writeFileSync(filePath, content || '');
}
shell.exec(`chown ${this.wwwUser} ${filePath}`);
return this.createCleanUpFn(() => shell.rm('-rf', cleanUpTarget));
}
// Methods - Protected
protected createCleanUpFn(fn: () => void): CleanUpFn {
const cleanUpFn = () => {
const idx = this.cleanUpFns.indexOf(cleanUpFn);
if (idx !== -1) {
this.cleanUpFns.splice(idx, 1);
fn();
}
};
this.cleanUpFns.push(cleanUpFn);
return cleanUpFn;
}
}
// Exports
export const helper = new Helper();

View File

@ -0,0 +1,6 @@
// Imports
import {runTests} from '../common/run-tests';
// Run
const specFiles = [`${__dirname}/**/*.e2e.js`];
runTests(specFiles);

View File

@ -0,0 +1,389 @@
// Imports
import * as path from 'path';
import {helper as h} from './helper';
// Tests
describe(`nginx`, () => {
beforeEach(() => jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000);
afterEach(() => h.cleanUp());
it('should redirect HTTP to HTTPS', done => {
const httpHost = `${h.nginxHostname}:${h.nginxPortHttp}`;
const httpsHost = `${h.nginxHostname}:${h.nginxPortHttps}`;
const urlMap = {
[`http://${httpHost}/`]: `https://${httpsHost}/`,
[`http://${httpHost}/foo`]: `https://${httpsHost}/foo`,
[`http://foo.${httpHost}/`]: `https://foo.${httpsHost}/`,
};
const verifyRedirection = (httpUrl: string) => h.runCmd(`curl -i ${httpUrl}`).then(result => {
h.verifyResponse(307)(result);
const headers = result.stdout.split(/(?:\r?\n){2,}/)[0];
expect(headers).toContain(`Location: ${urlMap[httpUrl]}`);
});
Promise.
all(Object.keys(urlMap).map(verifyRedirection)).
then(done);
});
h.runForAllSupportedSchemes((scheme, port) => describe(`(on ${scheme.toUpperCase()})`, () => {
const hostname = h.nginxHostname;
const host = `${hostname}:${port}`;
const pr = '9';
const sha9 = '9'.repeat(40);
const sha0 = '0'.repeat(40);
const shortSha9 = h.getShordSha(sha9);
const shortSha0 = h.getShordSha(sha0);
describe(`pr<pr>-<sha>.${host}/*`, () => {
describe('(for public builds)', () => {
beforeEach(() => {
h.createDummyBuild(pr, sha9);
h.createDummyBuild(pr, sha0);
});
it('should return /index.html', done => {
const origin = `${scheme}://pr${pr}-${shortSha9}.${host}`;
const bodyRegex = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /index\\.html$`);
Promise.all([
h.runCmd(`curl -iL ${origin}/index.html`).then(h.verifyResponse(200, bodyRegex)),
h.runCmd(`curl -iL ${origin}/`).then(h.verifyResponse(200, bodyRegex)),
h.runCmd(`curl -iL ${origin}`).then(h.verifyResponse(200, bodyRegex)),
]).then(done);
});
it('should return /index.html (for legacy builds)', done => {
const origin = `${scheme}://pr${pr}-${sha9}.${host}`;
const bodyRegex = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /index\\.html$`);
h.createDummyBuild(pr, sha9, true, false, true);
Promise.all([
h.runCmd(`curl -iL ${origin}/index.html`).then(h.verifyResponse(200, bodyRegex)),
h.runCmd(`curl -iL ${origin}/`).then(h.verifyResponse(200, bodyRegex)),
h.runCmd(`curl -iL ${origin}`).then(h.verifyResponse(200, bodyRegex)),
]).then(done);
});
it('should return /foo/bar.js', done => {
const bodyRegex = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /foo/bar\\.js$`);
h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo/bar.js`).
then(h.verifyResponse(200, bodyRegex)).
then(done);
});
it('should return /foo/bar.js (for legacy builds)', done => {
const origin = `${scheme}://pr${pr}-${sha9}.${host}`;
const bodyRegex = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /foo/bar\\.js$`);
h.createDummyBuild(pr, sha9, true, false, true);
h.runCmd(`curl -iL ${origin}/foo/bar.js`).
then(h.verifyResponse(200, bodyRegex)).
then(done);
});
it('should respond with 403 for directories', done => {
Promise.all([
h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo/`).then(h.verifyResponse(403)),
h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo`).then(h.verifyResponse(403)),
]).then(done);
});
it('should respond with 404 for unknown paths to files', done => {
h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}/foo/baz.css`).
then(h.verifyResponse(404)).
then(done);
});
it('should rewrite to \'index.html\' for unknown paths that don\'t look like files', done => {
const origin = `${scheme}://pr${pr}-${shortSha9}.${host}`;
const bodyRegex = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /index\\.html$`);
Promise.all([
h.runCmd(`curl -iL ${origin}/foo/baz`).then(h.verifyResponse(200, bodyRegex)),
h.runCmd(`curl -iL ${origin}/foo/baz/`).then(h.verifyResponse(200, bodyRegex)),
]).then(done);
});
it('should respond with 404 for unknown PRs/SHAs', done => {
const otherPr = 54321;
const otherShortSha = h.getShordSha('8'.repeat(40));
Promise.all([
h.runCmd(`curl -iL ${scheme}://pr${pr}9-${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://pr${otherPr}-${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}9.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://pr${pr}-${otherShortSha}.${host}`).then(h.verifyResponse(404)),
]).then(done);
});
it('should respond with 404 if the subdomain format is wrong', done => {
Promise.all([
h.runCmd(`curl -iL ${scheme}://xpr${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://prx${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://xx${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://p${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://r${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${pr}-${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://pr${pr}${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://pr${pr}_${shortSha9}.${host}`).then(h.verifyResponse(404)),
]).then(done);
});
it('should reject PRs with leading zeros', done => {
h.runCmd(`curl -iL ${scheme}://pr0${pr}-${shortSha9}.${host}`).
then(h.verifyResponse(404)).
then(done);
});
it('should accept SHAs with leading zeros (but not trim the zeros)', done => {
const bodyRegex9 = new RegExp(`^PR: ${pr} | SHA: ${sha9} | File: /index\\.html$`);
const bodyRegex0 = new RegExp(`^PR: ${pr} | SHA: ${sha0} | File: /index\\.html$`);
Promise.all([
h.runCmd(`curl -iL ${scheme}://pr${pr}-0${shortSha9}.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha9}.${host}`).then(h.verifyResponse(200, bodyRegex9)),
h.runCmd(`curl -iL ${scheme}://pr${pr}-${shortSha0}.${host}`).then(h.verifyResponse(200, bodyRegex0)),
]).then(done);
});
});
describe('(for hidden builds)', () => {
it('should respond with 404 for any file or directory', done => {
const origin = `${scheme}://pr${pr}-${shortSha9}.${host}`;
const assert404 = h.verifyResponse(404);
h.createDummyBuild(pr, sha9, false);
expect(h.buildExists(pr, sha9, false)).toBe(true);
Promise.all([
h.runCmd(`curl -iL ${origin}/index.html`).then(assert404),
h.runCmd(`curl -iL ${origin}/`).then(assert404),
h.runCmd(`curl -iL ${origin}`).then(assert404),
h.runCmd(`curl -iL ${origin}/foo/bar.js`).then(assert404),
h.runCmd(`curl -iL ${origin}/foo/`).then(assert404),
h.runCmd(`curl -iL ${origin}/foo`).then(assert404),
]).then(done);
});
it('should respond with 404 for any file or directory (for legacy builds)', done => {
const origin = `${scheme}://pr${pr}-${sha9}.${host}`;
const assert404 = h.verifyResponse(404);
h.createDummyBuild(pr, sha9, false, false, true);
expect(h.buildExists(pr, sha9, false, true)).toBe(true);
Promise.all([
h.runCmd(`curl -iL ${origin}/index.html`).then(assert404),
h.runCmd(`curl -iL ${origin}/`).then(assert404),
h.runCmd(`curl -iL ${origin}`).then(assert404),
h.runCmd(`curl -iL ${origin}/foo/bar.js`).then(assert404),
h.runCmd(`curl -iL ${origin}/foo/`).then(assert404),
h.runCmd(`curl -iL ${origin}/foo`).then(assert404),
]).then(done);
});
});
});
describe(`${host}/health-check`, () => {
it('should respond with 200', done => {
Promise.all([
h.runCmd(`curl -iL ${scheme}://${host}/health-check`).then(h.verifyResponse(200)),
h.runCmd(`curl -iL ${scheme}://${host}/health-check/`).then(h.verifyResponse(200)),
]).then(done);
});
it('should respond with 404 if the path does not match exactly', done => {
Promise.all([
h.runCmd(`curl -iL ${scheme}://${host}/health-check/foo`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}/health-check-foo`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}/health-checknfoo`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}/foo/health-check`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}/foo-health-check`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}/foonhealth-check`).then(h.verifyResponse(404)),
]).then(done);
});
});
describe(`${host}/create-build/<pr>/<sha>`, () => {
it('should disallow non-POST requests', done => {
const url = `${scheme}://${host}/create-build/${pr}/${sha9}`;
Promise.all([
h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
]).then(done);
});
it(`should reject files larger than ${h.uploadMaxSize}B (according to header)`, done => {
const headers = `--header "Content-Length: ${1.5 * h.uploadMaxSize}"`;
const url = `${scheme}://${host}/create-build/${pr}/${sha9}`;
h.runCmd(`curl -iLX POST ${headers} ${url}`).
then(h.verifyResponse([413, 'Request Entity Too Large'])).
then(done);
});
it(`should reject files larger than ${h.uploadMaxSize}B (without header)`, done => {
const filePath = path.join(h.buildsDir, 'snapshot.tar.gz');
const url = `${scheme}://${host}/create-build/${pr}/${sha9}`;
h.writeFile(filePath, {size: 1.5 * h.uploadMaxSize});
h.runCmd(`curl -iLX POST --data-binary "@${filePath}" ${url}`).
then(h.verifyResponse([413, 'Request Entity Too Large'])).
then(done);
});
it('should pass requests through to the upload server', done => {
h.runCmd(`curl -iLX POST ${scheme}://${host}/create-build/${pr}/${sha9}`).
then(h.verifyResponse(401, /Missing or empty 'AUTHORIZATION' header/)).
then(done);
});
it('should respond with 404 for unknown paths', done => {
const cmdPrefix = `curl -iLX POST ${scheme}://${host}`;
Promise.all([
h.runCmd(`${cmdPrefix}/foo/create-build/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/foo-create-build/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/fooncreate-build/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-build/foo/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-build-foo/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-buildnfoo/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-build/pr${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-build/${pr}/${sha9}42`).then(h.verifyResponse(404)),
]).then(done);
});
it('should reject PRs with leading zeros', done => {
h.runCmd(`curl -iLX POST ${scheme}://${host}/create-build/0${pr}/${sha9}`).
then(h.verifyResponse(404)).
then(done);
});
it('should accept SHAs with leading zeros (but not trim the zeros)', done => {
const cmdPrefix = `curl -iLX POST ${scheme}://${host}/create-build/${pr}`;
const bodyRegex = /Missing or empty 'AUTHORIZATION' header/;
Promise.all([
h.runCmd(`${cmdPrefix}/0${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/${sha0}`).then(h.verifyResponse(401, bodyRegex)),
]).then(done);
});
});
describe(`${host}/pr-updated`, () => {
const url = `${scheme}://${host}/pr-updated`;
it('should disallow non-POST requests', done => {
Promise.all([
h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
]).then(done);
});
it('should pass requests through to the upload server', done => {
const cmdPrefix = `curl -iLX POST --header "Content-Type: application/json"`;
const cmd1 = `${cmdPrefix} ${url}`;
const cmd2 = `${cmdPrefix} --data '{"number":${pr}}' ${url}`;
const cmd3 = `${cmdPrefix} --data '{"number":${pr},"action":"foo"}' ${url}`;
Promise.all([
h.runCmd(cmd1).then(h.verifyResponse(400, /Missing or empty 'number' field/)),
h.runCmd(cmd2).then(h.verifyResponse(200)),
h.runCmd(cmd3).then(h.verifyResponse(200)),
]).then(done);
});
it('should respond with 404 for unknown paths', done => {
const cmdPrefix = `curl -iLX POST ${scheme}://${host}`;
Promise.all([
h.runCmd(`${cmdPrefix}/foo/pr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/foo-pr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/foonpr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updated/foo`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updated-foo`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updatednfoo`).then(h.verifyResponse(404)),
]).then(done);
});
});
describe(`${host}/*`, () => {
it('should respond with 404 for unknown URLs (even if the resource exists)', done => {
['index.html', 'foo.js', 'foo/index.html'].forEach(relFilePath => {
const absFilePath = path.join(h.buildsDir, relFilePath);
h.writeFile(absFilePath, {content: `File: /${relFilePath}`});
});
Promise.all([
h.runCmd(`curl -iL ${scheme}://${host}/index.html`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}/`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://foo.${host}/index.html`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://foo.${host}/`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://foo.${host}`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}/foo.js`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL ${scheme}://${host}/foo/index.html`).then(h.verifyResponse(404)),
]).then(done);
});
});
}));
});

View File

@ -0,0 +1,319 @@
// Imports
import * as path from 'path';
import * as c from './constants';
import {helper as h} from './helper';
// Tests
h.runForAllSupportedSchemes((scheme, port) => describe(`integration (on ${scheme.toUpperCase()})`, () => {
const hostname = h.nginxHostname;
const host = `${hostname}:${port}`;
const pr9 = '9';
const sha9 = '9'.repeat(40);
const sha0 = '0'.repeat(40);
const archivePath = path.join(h.buildsDir, 'snapshot.tar.gz');
const getFile = (pr: string, sha: string, file: string) =>
h.runCmd(`curl -iL ${scheme}://pr${pr}-${h.getShordSha(sha)}.${host}/${file}`);
const uploadBuild = (pr: string, sha: string, archive: string, authHeader = 'Token FOO') => {
const curlPost = `curl -iLX POST --header "Authorization: ${authHeader}"`;
return h.runCmd(`${curlPost} --data-binary "@${archive}" ${scheme}://${host}/create-build/${pr}/${sha}`);
};
const prUpdated = (pr: number, action?: string) => {
const url = `${scheme}://${host}/pr-updated`;
const payloadStr = JSON.stringify({number: pr, action});
return h.runCmd(`curl -iLX POST --header "Content-Type: application/json" --data '${payloadStr}' ${url}`);
};
beforeEach(() => jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000);
afterEach(() => {
h.deletePrDir(pr9);
h.deletePrDir(pr9, false);
h.cleanUp();
});
describe('for a new/non-existing PR', () => {
it('should be able to upload and serve a public build', done => {
const regexPrefix9 = `^PR: uploaded\\/${pr9} \\| SHA: ${sha9} \\| File:`;
const idxContentRegex9 = new RegExp(`${regexPrefix9} \\/index\\.html$`);
const barContentRegex9 = new RegExp(`${regexPrefix9} \\/foo\\/bar\\.js$`);
h.createDummyArchive(pr9, sha9, archivePath);
uploadBuild(pr9, sha9, archivePath).
then(() => Promise.all([
getFile(pr9, sha9, 'index.html').then(h.verifyResponse(200, idxContentRegex9)),
getFile(pr9, sha9, 'foo/bar.js').then(h.verifyResponse(200, barContentRegex9)),
])).
then(done);
});
it('should be able to upload but not serve a hidden build', done => {
const regexPrefix9 = `^PR: uploaded\\/${pr9} \\| SHA: ${sha9} \\| File:`;
const idxContentRegex9 = new RegExp(`${regexPrefix9} \\/index\\.html$`);
const barContentRegex9 = new RegExp(`${regexPrefix9} \\/foo\\/bar\\.js$`);
h.createDummyArchive(pr9, sha9, archivePath);
uploadBuild(pr9, sha9, archivePath, c.BV_verify_verifiedNotTrusted).
then(() => Promise.all([
getFile(pr9, sha9, 'index.html').then(h.verifyResponse(404)),
getFile(pr9, sha9, 'foo/bar.js').then(h.verifyResponse(404)),
])).
then(() => {
expect(h.buildExists(pr9, sha9)).toBe(false);
expect(h.buildExists(pr9, sha9, false)).toBe(true);
expect(h.readBuildFile(pr9, sha9, 'index.html', false)).toMatch(idxContentRegex9);
expect(h.readBuildFile(pr9, sha9, 'foo/bar.js', false)).toMatch(barContentRegex9);
}).
then(done);
});
it('should reject an upload if verification fails', done => {
const errorRegex9 = new RegExp(`Error while verifying upload for PR ${pr9}: Test`);
h.createDummyArchive(pr9, sha9, archivePath);
uploadBuild(pr9, sha9, archivePath, c.BV_verify_error).
then(h.verifyResponse(403, errorRegex9)).
then(() => {
expect(h.buildExists(pr9)).toBe(false);
expect(h.buildExists(pr9, '', false)).toBe(false);
}).
then(done);
});
it('should be able to notify that a PR has been updated (and do nothing)', done => {
prUpdated(+pr9).
then(h.verifyResponse(200)).
then(() => {
// The PR should still not exist.
expect(h.buildExists(pr9, '', false)).toBe(false);
expect(h.buildExists(pr9, '', true)).toBe(false);
}).
then(done);
});
});
describe('for an existing PR', () => {
it('should be able to upload and serve a public build', done => {
const regexPrefix0 = `^PR: ${pr9} \\| SHA: ${sha0} \\| File:`;
const idxContentRegex0 = new RegExp(`${regexPrefix0} \\/index\\.html$`);
const barContentRegex0 = new RegExp(`${regexPrefix0} \\/foo\\/bar\\.js$`);
const regexPrefix9 = `^PR: uploaded\\/${pr9} \\| SHA: ${sha9} \\| File:`;
const idxContentRegex9 = new RegExp(`${regexPrefix9} \\/index\\.html$`);
const barContentRegex9 = new RegExp(`${regexPrefix9} \\/foo\\/bar\\.js$`);
h.createDummyBuild(pr9, sha0);
h.createDummyArchive(pr9, sha9, archivePath);
uploadBuild(pr9, sha9, archivePath).
then(() => Promise.all([
getFile(pr9, sha0, 'index.html').then(h.verifyResponse(200, idxContentRegex0)),
getFile(pr9, sha0, 'foo/bar.js').then(h.verifyResponse(200, barContentRegex0)),
getFile(pr9, sha9, 'index.html').then(h.verifyResponse(200, idxContentRegex9)),
getFile(pr9, sha9, 'foo/bar.js').then(h.verifyResponse(200, barContentRegex9)),
])).
then(done);
});
it('should be able to upload but not serve a hidden build', done => {
const regexPrefix0 = `^PR: ${pr9} \\| SHA: ${sha0} \\| File:`;
const idxContentRegex0 = new RegExp(`${regexPrefix0} \\/index\\.html$`);
const barContentRegex0 = new RegExp(`${regexPrefix0} \\/foo\\/bar\\.js$`);
const regexPrefix9 = `^PR: uploaded\\/${pr9} \\| SHA: ${sha9} \\| File:`;
const idxContentRegex9 = new RegExp(`${regexPrefix9} \\/index\\.html$`);
const barContentRegex9 = new RegExp(`${regexPrefix9} \\/foo\\/bar\\.js$`);
h.createDummyBuild(pr9, sha0, false);
h.createDummyArchive(pr9, sha9, archivePath);
uploadBuild(pr9, sha9, archivePath, c.BV_verify_verifiedNotTrusted).
then(() => Promise.all([
getFile(pr9, sha0, 'index.html').then(h.verifyResponse(404)),
getFile(pr9, sha0, 'foo/bar.js').then(h.verifyResponse(404)),
getFile(pr9, sha9, 'index.html').then(h.verifyResponse(404)),
getFile(pr9, sha9, 'foo/bar.js').then(h.verifyResponse(404)),
])).
then(() => {
expect(h.buildExists(pr9, sha9)).toBe(false);
expect(h.buildExists(pr9, sha9, false)).toBe(true);
expect(h.readBuildFile(pr9, sha0, 'index.html', false)).toMatch(idxContentRegex0);
expect(h.readBuildFile(pr9, sha0, 'foo/bar.js', false)).toMatch(barContentRegex0);
expect(h.readBuildFile(pr9, sha9, 'index.html', false)).toMatch(idxContentRegex9);
expect(h.readBuildFile(pr9, sha9, 'foo/bar.js', false)).toMatch(barContentRegex9);
}).
then(done);
});
it('should reject an upload if verification fails', done => {
const errorRegex9 = new RegExp(`Error while verifying upload for PR ${pr9}: Test`);
h.createDummyBuild(pr9, sha0);
h.createDummyArchive(pr9, sha9, archivePath);
uploadBuild(pr9, sha9, archivePath, c.BV_verify_error).
then(h.verifyResponse(403, errorRegex9)).
then(() => {
expect(h.buildExists(pr9)).toBe(true);
expect(h.buildExists(pr9, sha0)).toBe(true);
expect(h.buildExists(pr9, sha9)).toBe(false);
}).
then(done);
});
it('should not be able to overwrite an existing public build', done => {
const regexPrefix9 = `^PR: ${pr9} \\| SHA: ${sha9} \\| File:`;
const idxContentRegex9 = new RegExp(`${regexPrefix9} \\/index\\.html$`);
const barContentRegex9 = new RegExp(`${regexPrefix9} \\/foo\\/bar\\.js$`);
h.createDummyBuild(pr9, sha9);
h.createDummyArchive(pr9, sha9, archivePath);
uploadBuild(pr9, sha9, archivePath).
then(h.verifyResponse(409)).
then(() => Promise.all([
getFile(pr9, sha9, 'index.html').then(h.verifyResponse(200, idxContentRegex9)),
getFile(pr9, sha9, 'foo/bar.js').then(h.verifyResponse(200, barContentRegex9)),
])).
then(done);
});
it('should not be able to overwrite an existing hidden build', done => {
const regexPrefix9 = `^PR: ${pr9} \\| SHA: ${sha9} \\| File:`;
const idxContentRegex9 = new RegExp(`${regexPrefix9} \\/index\\.html$`);
const barContentRegex9 = new RegExp(`${regexPrefix9} \\/foo\\/bar\\.js$`);
h.createDummyBuild(pr9, sha9, false);
h.createDummyArchive(pr9, sha9, archivePath);
uploadBuild(pr9, sha9, archivePath, c.BV_verify_verifiedNotTrusted).
then(h.verifyResponse(409)).
then(() => {
expect(h.readBuildFile(pr9, sha9, 'index.html', false)).toMatch(idxContentRegex9);
expect(h.readBuildFile(pr9, sha9, 'foo/bar.js', false)).toMatch(barContentRegex9);
}).
then(done);
});
it('should be able to request re-checking visibility (if outdated)', done => {
const publicPr = pr9;
const hiddenPr = String(c.BV_getPrIsTrusted_notTrusted);
h.createDummyBuild(publicPr, sha9, false);
h.createDummyBuild(hiddenPr, sha9, true);
// PR visibilities are outdated (i.e. the opposte of what the should).
expect(h.buildExists(publicPr, '', false)).toBe(true);
expect(h.buildExists(publicPr, '', true)).toBe(false);
expect(h.buildExists(hiddenPr, '', false)).toBe(false);
expect(h.buildExists(hiddenPr, '', true)).toBe(true);
Promise.
all([
prUpdated(+publicPr).then(h.verifyResponse(200)),
prUpdated(+hiddenPr).then(h.verifyResponse(200)),
]).
then(() => {
// PR visibilities should have been updated.
expect(h.buildExists(publicPr, '', false)).toBe(false);
expect(h.buildExists(publicPr, '', true)).toBe(true);
expect(h.buildExists(hiddenPr, '', false)).toBe(true);
expect(h.buildExists(hiddenPr, '', true)).toBe(false);
}).
then(() => {
h.deletePrDir(publicPr, true);
h.deletePrDir(hiddenPr, false);
}).
then(done);
});
it('should be able to request re-checking visibility (if up-to-date)', done => {
const publicPr = pr9;
const hiddenPr = String(c.BV_getPrIsTrusted_notTrusted);
h.createDummyBuild(publicPr, sha9, true);
h.createDummyBuild(hiddenPr, sha9, false);
// PR visibilities are already up-to-date.
expect(h.buildExists(publicPr, '', false)).toBe(false);
expect(h.buildExists(publicPr, '', true)).toBe(true);
expect(h.buildExists(hiddenPr, '', false)).toBe(true);
expect(h.buildExists(hiddenPr, '', true)).toBe(false);
Promise.
all([
prUpdated(+publicPr).then(h.verifyResponse(200)),
prUpdated(+hiddenPr).then(h.verifyResponse(200)),
]).
then(() => {
// PR visibilities are still up-to-date.
expect(h.buildExists(publicPr, '', false)).toBe(false);
expect(h.buildExists(publicPr, '', true)).toBe(true);
expect(h.buildExists(hiddenPr, '', false)).toBe(true);
expect(h.buildExists(hiddenPr, '', true)).toBe(false);
}).
then(done);
});
it('should reject a request if re-checking visibility fails', done => {
const errorPr = String(c.BV_getPrIsTrusted_error);
h.createDummyBuild(errorPr, sha9, true);
expect(h.buildExists(errorPr, '', false)).toBe(false);
expect(h.buildExists(errorPr, '', true)).toBe(true);
prUpdated(+errorPr).
then(h.verifyResponse(500, /Test/)).
then(() => {
// PR visibility should not have been updated.
expect(h.buildExists(errorPr, '', false)).toBe(false);
expect(h.buildExists(errorPr, '', true)).toBe(true);
}).
then(done);
});
it('should reject a request if updating visibility fails', done => {
// One way to cause an error is to have both a public and a hidden directory for the same PR.
h.createDummyBuild(pr9, sha9, false);
h.createDummyBuild(pr9, sha9, true);
const hiddenPrDir = h.getPrDir(pr9, false);
const publicPrDir = h.getPrDir(pr9, true);
const bodyRegex = new RegExp(`Request to move '${hiddenPrDir}' to existing directory '${publicPrDir}'`);
expect(h.buildExists(pr9, '', false)).toBe(true);
expect(h.buildExists(pr9, '', true)).toBe(true);
prUpdated(+pr9).
then(h.verifyResponse(409, bodyRegex)).
then(() => {
// PR visibility should not have been updated.
expect(h.buildExists(pr9, '', false)).toBe(true);
expect(h.buildExists(pr9, '', true)).toBe(true);
}).
then(done);
});
});
}));

View File

@ -0,0 +1,38 @@
// Imports
import {GithubPullRequests} from '../common/github-pull-requests';
import {BUILD_VERIFICATION_STATUS, BuildVerifier} from '../upload-server/build-verifier';
import {UploadError} from '../upload-server/upload-error';
import * as c from './constants';
// Run
// TODO(gkalpak): Add e2e tests to cover these interactions as well.
GithubPullRequests.prototype.addComment = () => Promise.resolve();
BuildVerifier.prototype.getPrIsTrusted = (pr: number) => {
switch (pr) {
case c.BV_getPrIsTrusted_error:
// For e2e tests, fake an error.
return Promise.reject('Test');
case c.BV_getPrIsTrusted_notTrusted:
// For e2e tests, fake an untrusted PR (`false`).
return Promise.resolve(false);
default:
// For e2e tests, default to trusted PRs (`true`).
return Promise.resolve(true);
}
};
BuildVerifier.prototype.verify = (expectedPr: number, authHeader: string) => {
switch (authHeader) {
case c.BV_verify_error:
// For e2e tests, fake a verification error.
return Promise.reject(new UploadError(403, `Error while verifying upload for PR ${expectedPr}: Test`));
case c.BV_verify_verifiedNotTrusted:
// For e2e tests, fake a `verifiedNotTrusted` verification status.
return Promise.resolve(BUILD_VERIFICATION_STATUS.verifiedNotTrusted);
default:
// For e2e tests, default to `verifiedAndTrusted` verification status.
return Promise.resolve(BUILD_VERIFICATION_STATUS.verifiedAndTrusted);
}
};
// tslint:disable-next-line: no-var-requires
require('../upload-server/index');

View File

@ -0,0 +1,571 @@
// Imports
import * as fs from 'fs';
import * as path from 'path';
import * as c from './constants';
import {CmdResult, helper as h} from './helper';
// Tests
describe('upload-server (on HTTP)', () => {
const hostname = h.uploadHostname;
const port = h.uploadPort;
const host = `${hostname}:${port}`;
const pr = '9';
const sha9 = '9'.repeat(40);
const sha0 = '0'.repeat(40);
beforeEach(() => jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000);
afterEach(() => h.cleanUp());
describe(`${host}/create-build/<pr>/<sha>`, () => {
const authorizationHeader = `--header "Authorization: Token FOO"`;
const xFileHeader = `--header "X-File: ${h.buildsDir}/snapshot.tar.gz"`;
const defaultHeaders = `${authorizationHeader} ${xFileHeader}`;
const curl = (url: string, headers = defaultHeaders) => `curl -iL ${headers} ${url}`;
it('should disallow non-GET requests', done => {
const url = `http://${host}/create-build/${pr}/${sha9}`;
const bodyRegex = /^Unknown resource/;
Promise.all([
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX POST ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse(404, bodyRegex)),
]).then(done);
});
it('should reject requests without an \'AUTHORIZATION\' header', done => {
const headers1 = '';
const headers2 = '--header "AUTHORIXATION: "';
const url = `http://${host}/create-build/${pr}/${sha9}`;
const bodyRegex = /^Missing or empty 'AUTHORIZATION' header/;
Promise.all([
h.runCmd(curl(url, headers1)).then(h.verifyResponse(401, bodyRegex)),
h.runCmd(curl(url, headers2)).then(h.verifyResponse(401, bodyRegex)),
]).then(done);
});
it('should reject requests without an \'X-FILE\' header', done => {
const headers1 = authorizationHeader;
const headers2 = `${authorizationHeader} --header "X-FILE: "`;
const url = `http://${host}/create-build/${pr}/${sha9}`;
const bodyRegex = /^Missing or empty 'X-FILE' header/;
Promise.all([
h.runCmd(curl(url, headers1)).then(h.verifyResponse(400, bodyRegex)),
h.runCmd(curl(url, headers2)).then(h.verifyResponse(400, bodyRegex)),
]).then(done);
});
it('should reject requests for which the PR verification fails', done => {
const headers = `--header "Authorization: ${c.BV_verify_error}" ${xFileHeader}`;
const url = `http://${host}/create-build/${pr}/${sha9}`;
const bodyRegex = new RegExp(`Error while verifying upload for PR ${pr}: Test`);
h.runCmd(curl(url, headers)).
then(h.verifyResponse(403, bodyRegex)).
then(done);
});
it('should respond with 404 for unknown paths', done => {
const cmdPrefix = curl(`http://${host}`);
Promise.all([
h.runCmd(`${cmdPrefix}/foo/create-build/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/foo-create-build/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/fooncreate-build/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-build/foo/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-build-foo/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-buildnfoo/${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-build/pr${pr}/${sha9}`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/create-build/${pr}/${sha9}42`).then(h.verifyResponse(404)),
]).then(done);
});
it('should reject PRs with leading zeros', done => {
h.runCmd(curl(`http://${host}/create-build/0${pr}/${sha9}`)).
then(h.verifyResponse(404)).
then(done);
});
it('should accept SHAs with leading zeros (but not trim the zeros)', done => {
Promise.all([
h.runCmd(curl(`http://${host}/create-build/${pr}/0${sha9}`)).then(h.verifyResponse(404)),
h.runCmd(curl(`http://${host}/create-build/${pr}/${sha9}`)).then(h.verifyResponse(500)),
h.runCmd(curl(`http://${host}/create-build/${pr}/${sha0}`)).then(h.verifyResponse(500)),
]).then(done);
});
[true, false].forEach(isPublic => describe(`(for ${isPublic ? 'public' : 'hidden'} builds)`, () => {
const authorizationHeader2 = isPublic ?
authorizationHeader : `--header "Authorization: ${c.BV_verify_verifiedNotTrusted}"`;
const cmdPrefix = curl('', `${authorizationHeader2} ${xFileHeader}`);
const overwriteRe = RegExp(`^Request to overwrite existing ${isPublic ? 'public' : 'non-public'} directory`);
it('should not overwrite existing builds', done => {
h.createDummyBuild(pr, sha9, isPublic);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toContain('index.html');
h.writeBuildFile(pr, sha9, 'index.html', 'My content', isPublic);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toBe('My content');
h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha9}`).
then(h.verifyResponse(409, overwriteRe)).
then(() => expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toBe('My content')).
then(done);
});
it('should not overwrite existing builds (even if the SHA is different)', done => {
// Since only the first few characters of the SHA are used, it is possible for two different
// SHAs to correspond to the same directory. In that case, we don't want the second SHA to
// overwrite the first.
const sha9Almost = sha9.replace(/.$/, '8');
expect(sha9Almost).not.toBe(sha9);
h.createDummyBuild(pr, sha9, isPublic);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toContain('index.html');
h.writeBuildFile(pr, sha9, 'index.html', 'My content', isPublic);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toBe('My content');
h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha9Almost}`).
then(h.verifyResponse(409, overwriteRe)).
then(() => expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toBe('My content')).
then(done);
});
it('should delete the PR directory on error (for new PR)', done => {
h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha9}`).
then(h.verifyResponse(500)).
then(() => expect(h.buildExists(pr, '', isPublic)).toBe(false)).
then(done);
});
it('should only delete the SHA directory on error (for existing PR)', done => {
h.createDummyBuild(pr, sha0, isPublic);
h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha9}`).
then(h.verifyResponse(500)).
then(() => {
expect(h.buildExists(pr, sha9, isPublic)).toBe(false);
expect(h.buildExists(pr, '', isPublic)).toBe(true);
}).
then(done);
});
describe('on successful upload', () => {
const archivePath = path.join(h.buildsDir, 'snapshot.tar.gz');
const statusCode = isPublic ? 201 : 202;
let uploadPromise: Promise<CmdResult>;
beforeEach(() => {
h.createDummyArchive(pr, sha9, archivePath);
uploadPromise = h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha9}`);
});
afterEach(() => h.deletePrDir(pr, isPublic));
it(`should respond with ${statusCode}`, done => {
uploadPromise.then(h.verifyResponse(statusCode)).then(done);
});
it('should extract the contents of the uploaded file', done => {
uploadPromise.
then(() => {
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toContain(`uploaded/${pr}`);
expect(h.readBuildFile(pr, sha9, 'foo/bar.js', isPublic)).toContain(`uploaded/${pr}`);
}).
then(done);
});
it(`should create files/directories owned by '${h.wwwUser}'`, done => {
const prDir = h.getPrDir(pr, isPublic);
const shaDir = h.getShaDir(prDir, sha9);
const idxPath = path.join(shaDir, 'index.html');
const barPath = path.join(shaDir, 'foo', 'bar.js');
uploadPromise.
then(() => Promise.all([
h.runCmd(`find ${shaDir}`),
h.runCmd(`find ${shaDir} -user ${h.wwwUser}`),
])).
then(([{stdout: allFiles}, {stdout: userFiles}]) => {
expect(userFiles).toBe(allFiles);
expect(userFiles).toContain(shaDir);
expect(userFiles).toContain(idxPath);
expect(userFiles).toContain(barPath);
}).
then(done);
});
it('should delete the uploaded file', done => {
expect(fs.existsSync(archivePath)).toBe(true);
uploadPromise.
then(() => expect(fs.existsSync(archivePath)).toBe(false)).
then(done);
});
it('should make the build directory non-writable', done => {
const prDir = h.getPrDir(pr, isPublic);
const shaDir = h.getShaDir(prDir, sha9);
const idxPath = path.join(shaDir, 'index.html');
const barPath = path.join(shaDir, 'foo', 'bar.js');
// See https://github.com/nodejs/node-v0.x-archive/issues/3045#issuecomment-4862588.
const isNotWritable = (fileOrDir: string) => {
const mode = fs.statSync(fileOrDir).mode;
// tslint:disable-next-line: no-bitwise
return !(mode & parseInt('222', 8));
};
uploadPromise.
then(() => {
expect(isNotWritable(shaDir)).toBe(true);
expect(isNotWritable(idxPath)).toBe(true);
expect(isNotWritable(barPath)).toBe(true);
}).
then(done);
});
it('should ignore a legacy 40-chars long build directory (even if it starts with the same chars)', done => {
// It is possible that 40-chars long build directories exist, if they had been deployed
// before implementing the shorter build directory names. In that case, we don't want the
// second (shorter) name to be considered the same as the old one (even if they originate
// from the same SHA).
h.createDummyBuild(pr, sha9, isPublic, false, true);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic, true)).toContain('index.html');
h.writeBuildFile(pr, sha9, 'index.html', 'My content', isPublic, true);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic, true)).toBe('My content');
h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha9}`).
then(h.verifyResponse(statusCode)).
then(() => {
expect(h.buildExists(pr, sha9, isPublic)).toBe(true);
expect(h.buildExists(pr, sha9, isPublic, true)).toBe(true);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toContain('index.html');
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic, true)).toBe('My content');
}).
then(done);
});
});
describe('when the PR\'s visibility has changed', () => {
const archivePath = path.join(h.buildsDir, 'snapshot.tar.gz');
const statusCode = isPublic ? 201 : 202;
const checkPrVisibility = (isPublic2: boolean) => {
expect(h.buildExists(pr, '', isPublic2)).toBe(true);
expect(h.buildExists(pr, '', !isPublic2)).toBe(false);
expect(h.buildExists(pr, sha0, isPublic2)).toBe(true);
expect(h.buildExists(pr, sha0, !isPublic2)).toBe(false);
};
const uploadBuild = (sha: string) => h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha}`);
beforeEach(() => {
h.createDummyBuild(pr, sha0, !isPublic);
h.createDummyArchive(pr, sha9, archivePath);
checkPrVisibility(!isPublic);
});
afterEach(() => h.deletePrDir(pr, isPublic));
it('should update the PR\'s visibility', done => {
uploadBuild(sha9).
then(h.verifyResponse(statusCode)).
then(() => {
checkPrVisibility(isPublic);
expect(h.buildExists(pr, sha9, isPublic)).toBe(true);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toContain(`uploaded/${pr}`);
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toContain(sha9);
}).
then(done);
});
it('should not overwrite existing builds (but keep the updated visibility)', done => {
expect(h.buildExists(pr, sha0, isPublic)).toBe(false);
uploadBuild(sha0).
then(h.verifyResponse(409, overwriteRe)).
then(() => {
checkPrVisibility(isPublic);
expect(h.readBuildFile(pr, sha0, 'index.html', isPublic)).toContain(pr);
expect(h.readBuildFile(pr, sha0, 'index.html', isPublic)).not.toContain(`uploaded/${pr}`);
expect(h.readBuildFile(pr, sha0, 'index.html', isPublic)).toContain(sha0);
expect(h.readBuildFile(pr, sha0, 'index.html', isPublic)).not.toContain(sha9);
}).
then(done);
});
it('should reject the request if it fails to update the PR\'s visibility', done => {
// One way to cause an error is to have both a public and a hidden directory for the same PR.
h.createDummyBuild(pr, sha0, isPublic);
expect(h.buildExists(pr, sha0, isPublic)).toBe(true);
expect(h.buildExists(pr, sha0, !isPublic)).toBe(true);
const errorRegex = new RegExp(`^Request to move '${h.getPrDir(pr, !isPublic)}' ` +
`to existing directory '${h.getPrDir(pr, isPublic)}'.`);
uploadBuild(sha9).
then(h.verifyResponse(409, errorRegex)).
then(() => {
expect(h.buildExists(pr, sha0, isPublic)).toBe(true);
expect(h.buildExists(pr, sha0, !isPublic)).toBe(true);
expect(h.buildExists(pr, sha9, isPublic)).toBe(false);
expect(h.buildExists(pr, sha9, !isPublic)).toBe(false);
}).
then(done);
});
});
}));
});
describe(`${host}/health-check`, () => {
it('should respond with 200', done => {
Promise.all([
h.runCmd(`curl -iL http://${host}/health-check`).then(h.verifyResponse(200)),
h.runCmd(`curl -iL http://${host}/health-check/`).then(h.verifyResponse(200)),
]).then(done);
});
it('should respond with 404 if the path does not match exactly', done => {
Promise.all([
h.runCmd(`curl -iL http://${host}/health-check/foo`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL http://${host}/health-check-foo`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL http://${host}/health-checknfoo`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL http://${host}/foo/health-check`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL http://${host}/foo-health-check`).then(h.verifyResponse(404)),
h.runCmd(`curl -iL http://${host}/foonhealth-check`).then(h.verifyResponse(404)),
]).then(done);
});
});
describe(`${host}/pr-updated`, () => {
const url = `http://${host}/pr-updated`;
// Helpers
const curl = (payload?: {number: number, action?: string}) => {
const payloadStr = payload && JSON.stringify(payload) || '';
return `curl -iLX POST --header "Content-Type: application/json" --data '${payloadStr}' ${url}`;
};
it('should disallow non-POST requests', done => {
const bodyRegex = /^Unknown resource in request/;
Promise.all([
h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse(404, bodyRegex)),
]).then(done);
});
it('should respond with 400 for requests without a payload', done => {
const bodyRegex = /^Missing or empty 'number' field in request/;
h.runCmd(curl()).
then(h.verifyResponse(400, bodyRegex)).
then(done);
});
it('should respond with 400 for requests without a \'number\' field', done => {
const bodyRegex = /^Missing or empty 'number' field in request/;
Promise.all([
h.runCmd(curl({} as any)).then(h.verifyResponse(400, bodyRegex)),
h.runCmd(curl({number: null} as any)).then(h.verifyResponse(400, bodyRegex)),
]).then(done);
});
it('should reject requests for which checking the PR visibility fails', done => {
h.runCmd(curl({number: c.BV_getPrIsTrusted_error})).
then(h.verifyResponse(500, /Test/)).
then(done);
});
it('should respond with 404 for unknown paths', done => {
const mockPayload = JSON.stringify({number: +pr});
const cmdPrefix = `curl -iLX POST --data "${mockPayload}" http://${host}`;
Promise.all([
h.runCmd(`${cmdPrefix}/foo/pr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/foo-pr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/foonpr-updated`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updated/foo`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updated-foo`).then(h.verifyResponse(404)),
h.runCmd(`${cmdPrefix}/pr-updatednfoo`).then(h.verifyResponse(404)),
]).then(done);
});
it('should do nothing if PR\'s visibility is already up-to-date', done => {
const publicPr = pr;
const hiddenPr = String(c.BV_getPrIsTrusted_notTrusted);
const checkVisibilities = () => {
// Public build is already public.
expect(h.buildExists(publicPr, '', false)).toBe(false);
expect(h.buildExists(publicPr, '', true)).toBe(true);
// Hidden build is already hidden.
expect(h.buildExists(hiddenPr, '', false)).toBe(true);
expect(h.buildExists(hiddenPr, '', true)).toBe(false);
};
h.createDummyBuild(publicPr, sha9, true);
h.createDummyBuild(hiddenPr, sha9, false);
checkVisibilities();
Promise.
all([
h.runCmd(curl({number: +publicPr, action: 'foo'})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr, action: 'foo'})).then(h.verifyResponse(200)),
]).
// Visibilities should not have changed, because the specified action could not have triggered a change.
then(checkVisibilities).
then(done);
});
it('should do nothing if \'action\' implies no visibility change', done => {
const publicPr = pr;
const hiddenPr = String(c.BV_getPrIsTrusted_notTrusted);
const checkVisibilities = () => {
// Public build is hidden atm.
expect(h.buildExists(publicPr, '', false)).toBe(true);
expect(h.buildExists(publicPr, '', true)).toBe(false);
// Hidden build is public atm.
expect(h.buildExists(hiddenPr, '', false)).toBe(false);
expect(h.buildExists(hiddenPr, '', true)).toBe(true);
};
h.createDummyBuild(publicPr, sha9, false);
h.createDummyBuild(hiddenPr, sha9, true);
checkVisibilities();
Promise.
all([
h.runCmd(curl({number: +publicPr, action: 'foo'})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr, action: 'foo'})).then(h.verifyResponse(200)),
]).
// Visibilities should not have changed, because the specified action could not have triggered a change.
then(checkVisibilities).
then(done);
});
describe('when the visiblity has changed', () => {
const publicPr = pr;
const hiddenPr = String(c.BV_getPrIsTrusted_notTrusted);
beforeEach(() => {
// Create initial PR builds with opposite visibilities as the ones that will be reported:
// - The now public PR was previously hidden.
// - The now hidden PR was previously public.
h.createDummyBuild(publicPr, sha9, false);
h.createDummyBuild(hiddenPr, sha9, true);
expect(h.buildExists(publicPr, '', false)).toBe(true);
expect(h.buildExists(publicPr, '', true)).toBe(false);
expect(h.buildExists(hiddenPr, '', false)).toBe(false);
expect(h.buildExists(hiddenPr, '', true)).toBe(true);
});
afterEach(() => {
// Expect PRs' visibility to have been updated:
// - The public PR should be actually public (previously it was hidden).
// - The hidden PR should be actually hidden (previously it was public).
expect(h.buildExists(publicPr, '', false)).toBe(false);
expect(h.buildExists(publicPr, '', true)).toBe(true);
expect(h.buildExists(hiddenPr, '', false)).toBe(true);
expect(h.buildExists(hiddenPr, '', true)).toBe(false);
h.deletePrDir(publicPr, true);
h.deletePrDir(hiddenPr, false);
});
it('should update the PR\'s visibility (action: undefined)', done => {
Promise.all([
h.runCmd(curl({number: +publicPr})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr})).then(h.verifyResponse(200)),
]).then(done);
});
it('should update the PR\'s visibility (action: labeled)', done => {
Promise.all([
h.runCmd(curl({number: +publicPr, action: 'labeled'})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr, action: 'labeled'})).then(h.verifyResponse(200)),
]).then(done);
});
it('should update the PR\'s visibility (action: unlabeled)', done => {
Promise.all([
h.runCmd(curl({number: +publicPr, action: 'unlabeled'})).then(h.verifyResponse(200)),
h.runCmd(curl({number: +hiddenPr, action: 'unlabeled'})).then(h.verifyResponse(200)),
]).then(done);
});
});
});
describe(`${host}/*`, () => {
it('should respond with 404 for requests to unknown URLs', done => {
const bodyRegex = /^Unknown resource/;
Promise.all([
h.runCmd(`curl -iL http://${host}/index.html`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iL http://${host}/`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iL http://${host}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX PUT http://${host}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX POST http://${host}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX PATCH http://${host}`).then(h.verifyResponse(404, bodyRegex)),
h.runCmd(`curl -iLX DELETE http://${host}`).then(h.verifyResponse(404, bodyRegex)),
]).then(done);
});
});
});

View File

@ -0,0 +1,45 @@
{
"name": "aio-scripts-js",
"version": "1.0.0",
"description": "Performing various tasks on PR build artifacts for angular.io.",
"repository": "https://github.com/angular/angular.git",
"author": "Angular",
"license": "MIT",
"scripts": {
"prebuild": "yarn clean-dist",
"build": "tsc",
"build-watch": "yarn tsc --watch",
"clean-dist": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
"dev": "concurrently --kill-others --raw --success first \"yarn build-watch\" \"yarn test-watch\"",
"lint": "tslint --project tsconfig.json",
"pre~~test-only": "yarn lint",
"~~test-only": "node dist/test",
"pretest": "yarn build",
"test": "yarn ~~test-only",
"pretest-watch": "yarn build",
"test-watch": "nodemon --exec \"yarn ~~test-only\" --watch dist"
},
"dependencies": {
"body-parser": "^1.18.2",
"express": "^4.15.4",
"jasmine": "^2.8.0",
"jsonwebtoken": "^8.0.1",
"shelljs": "^0.7.8",
"tslib": "^1.7.1"
},
"devDependencies": {
"@types/body-parser": "^1.16.5",
"@types/express": "^4.0.37",
"@types/jasmine": "^2.6.0",
"@types/jsonwebtoken": "^7.2.3",
"@types/node": "^8.0.30",
"@types/shelljs": "^0.7.4",
"@types/supertest": "^2.0.3",
"concurrently": "^3.5.0",
"nodemon": "^1.12.1",
"supertest": "^3.0.0",
"tslint": "^5.7.0",
"tslint-jasmine-noSkipOrFocus": "^1.0.8",
"typescript": "^2.5.2"
}
}

View File

@ -0,0 +1,360 @@
// Imports
import * as fs from 'fs';
import * as path from 'path';
import * as shell from 'shelljs';
import {BuildCleaner} from '../../lib/clean-up/build-cleaner';
import {HIDDEN_DIR_PREFIX} from '../../lib/common/constants';
import {GithubPullRequests} from '../../lib/common/github-pull-requests';
// Tests
describe('BuildCleaner', () => {
let cleaner: BuildCleaner;
beforeEach(() => cleaner = new BuildCleaner('/foo/bar', 'baz/qux', '12345'));
describe('constructor()', () => {
it('should throw if \'buildsDir\' is empty', () => {
expect(() => new BuildCleaner('', '/baz/qux', '12345')).
toThrowError('Missing or empty required parameter \'buildsDir\'!');
});
it('should throw if \'repoSlug\' is empty', () => {
expect(() => new BuildCleaner('/foo/bar', '', '12345')).
toThrowError('Missing or empty required parameter \'repoSlug\'!');
});
it('should throw if \'githubToken\' is empty', () => {
expect(() => new BuildCleaner('/foo/bar', 'baz/qux', '')).
toThrowError('Missing or empty required parameter \'githubToken\'!');
});
});
describe('cleanUp()', () => {
let cleanerGetExistingBuildNumbersSpy: jasmine.Spy;
let cleanerGetOpenPrNumbersSpy: jasmine.Spy;
let cleanerRemoveUnnecessaryBuildsSpy: jasmine.Spy;
let existingBuildsDeferred: {resolve: (v?: any) => void, reject: (e?: any) => void};
let openPrsDeferred: {resolve: (v?: any) => void, reject: (e?: any) => void};
let promise: Promise<void>;
beforeEach(() => {
cleanerGetExistingBuildNumbersSpy = spyOn(cleaner as any, 'getExistingBuildNumbers').and.callFake(() => {
return new Promise((resolve, reject) => existingBuildsDeferred = {resolve, reject});
});
cleanerGetOpenPrNumbersSpy = spyOn(cleaner as any, 'getOpenPrNumbers').and.callFake(() => {
return new Promise((resolve, reject) => openPrsDeferred = {resolve, reject});
});
cleanerRemoveUnnecessaryBuildsSpy = spyOn(cleaner as any, 'removeUnnecessaryBuilds');
promise = cleaner.cleanUp();
});
it('should return a promise', () => {
expect(promise).toEqual(jasmine.any(Promise));
});
it('should get the existing builds', () => {
expect(cleanerGetExistingBuildNumbersSpy).toHaveBeenCalled();
});
it('should get the open PRs', () => {
expect(cleanerGetOpenPrNumbersSpy).toHaveBeenCalled();
});
it('should reject if \'getExistingBuildNumbers()\' rejects', done => {
promise.catch(err => {
expect(err).toBe('Test');
done();
});
existingBuildsDeferred.reject('Test');
});
it('should reject if \'getOpenPrNumbers()\' rejects', done => {
promise.catch(err => {
expect(err).toBe('Test');
done();
});
openPrsDeferred.reject('Test');
});
it('should reject if \'removeUnnecessaryBuilds()\' rejects', done => {
promise.catch(err => {
expect(err).toBe('Test');
done();
});
cleanerRemoveUnnecessaryBuildsSpy.and.returnValue(Promise.reject('Test'));
existingBuildsDeferred.resolve();
openPrsDeferred.resolve();
});
it('should pass existing builds and open PRs to \'removeUnnecessaryBuilds()\'', done => {
promise.then(() => {
expect(cleanerRemoveUnnecessaryBuildsSpy).toHaveBeenCalledWith('foo', 'bar');
done();
});
existingBuildsDeferred.resolve('foo');
openPrsDeferred.resolve('bar');
});
it('should resolve with the value returned by \'removeUnnecessaryBuilds()\'', done => {
promise.then(result => {
expect(result as any).toBe('Test');
done();
});
cleanerRemoveUnnecessaryBuildsSpy.and.returnValue(Promise.resolve('Test'));
existingBuildsDeferred.resolve();
openPrsDeferred.resolve();
});
});
// Protected methods
describe('getExistingBuildNumbers()', () => {
let fsReaddirSpy: jasmine.Spy;
let readdirCb: (err: any, files?: string[]) => void;
let promise: Promise<number[]>;
beforeEach(() => {
fsReaddirSpy = spyOn(fs, 'readdir').and.callFake((_: string, cb: typeof readdirCb) => readdirCb = cb);
promise = (cleaner as any).getExistingBuildNumbers();
});
it('should return a promise', () => {
expect(promise).toEqual(jasmine.any(Promise));
});
it('should get the contents of the builds directory', () => {
expect(fsReaddirSpy).toHaveBeenCalled();
expect(fsReaddirSpy.calls.argsFor(0)[0]).toBe('/foo/bar');
});
it('should reject if an error occurs while getting the files', done => {
promise.catch(err => {
expect(err).toBe('Test');
done();
});
readdirCb('Test');
});
it('should resolve with the returned files (as numbers)', done => {
promise.then(result => {
expect(result).toEqual([12, 34, 56]);
done();
});
readdirCb(null, ['12', '34', '56']);
});
it('should remove `HIDDEN_DIR_PREFIX` from the filenames', done => {
promise.then(result => {
expect(result).toEqual([12, 34, 56]);
done();
});
readdirCb(null, [`${HIDDEN_DIR_PREFIX}12`, '34', `${HIDDEN_DIR_PREFIX}56`]);
});
it('should ignore files with non-numeric (or zero) names', done => {
promise.then(result => {
expect(result).toEqual([12, 34, 56]);
done();
});
readdirCb(null, ['12', 'foo', '34', 'bar', '56', '000']);
});
});
describe('getOpenPrNumbers()', () => {
let prDeferred: {resolve: (v: any) => void, reject: (v: any) => void};
let promise: Promise<number[]>;
beforeEach(() => {
spyOn(GithubPullRequests.prototype, 'fetchAll').and.callFake(() => {
return new Promise((resolve, reject) => prDeferred = {resolve, reject});
});
promise = (cleaner as any).getOpenPrNumbers();
});
it('should return a promise', () => {
expect(promise).toEqual(jasmine.any(Promise));
});
it('should fetch open PRs via \'GithubPullRequests\'', () => {
expect(GithubPullRequests.prototype.fetchAll).toHaveBeenCalledWith('open');
});
it('should reject if an error occurs while fetching PRs', done => {
promise.catch(err => {
expect(err).toBe('Test');
done();
});
prDeferred.reject('Test');
});
it('should resolve with the numbers of the fetched PRs', done => {
promise.then(prNumbers => {
expect(prNumbers).toEqual([1, 2, 3]);
done();
});
prDeferred.resolve([{id: 0, number: 1}, {id: 1, number: 2}, {id: 2, number: 3}]);
});
});
describe('removeDir()', () => {
let shellChmodSpy: jasmine.Spy;
let shellRmSpy: jasmine.Spy;
let shellTestSpy: jasmine.Spy;
beforeEach(() => {
shellChmodSpy = spyOn(shell, 'chmod');
shellRmSpy = spyOn(shell, 'rm');
shellTestSpy = spyOn(shell, 'test').and.returnValue(true);
});
it('should test if the directory exists (and return if is does not)', () => {
shellTestSpy.and.returnValue(false);
(cleaner as any).removeDir('/foo/bar');
expect(shellTestSpy).toHaveBeenCalledWith('-d', '/foo/bar');
expect(shellChmodSpy).not.toHaveBeenCalled();
expect(shellRmSpy).not.toHaveBeenCalled();
});
it('should remove the specified directory and its content', () => {
(cleaner as any).removeDir('/foo/bar');
expect(shellRmSpy).toHaveBeenCalledWith('-rf', '/foo/bar');
});
it('should make the directory and its content writable before removing', () => {
shellRmSpy.and.callFake(() => expect(shellChmodSpy).toHaveBeenCalledWith('-R', 'a+w', '/foo/bar'));
(cleaner as any).removeDir('/foo/bar');
expect(shellRmSpy).toHaveBeenCalled();
});
it('should catch errors and log them', () => {
const consoleErrorSpy = spyOn(console, 'error');
shellRmSpy.and.callFake(() => {
// tslint:disable-next-line: no-string-throw
throw 'Test';
});
(cleaner as any).removeDir('/foo/bar');
expect(consoleErrorSpy).toHaveBeenCalled();
expect(consoleErrorSpy.calls.argsFor(0)[0]).toContain('Unable to remove \'/foo/bar\'');
expect(consoleErrorSpy.calls.argsFor(0)[1]).toBe('Test');
});
});
describe('removeUnnecessaryBuilds()', () => {
let consoleLogSpy: jasmine.Spy;
let cleanerRemoveDirSpy: jasmine.Spy;
beforeEach(() => {
consoleLogSpy = spyOn(console, 'log');
cleanerRemoveDirSpy = spyOn(cleaner as any, 'removeDir');
});
it('should log the number of existing builds, open PRs and builds to be removed', () => {
(cleaner as any).removeUnnecessaryBuilds([1, 2, 3], [3, 4, 5, 6]);
expect(console.log).toHaveBeenCalledWith('Existing builds: 3');
expect(console.log).toHaveBeenCalledWith('Open pull requests: 4');
expect(console.log).toHaveBeenCalledWith('Removing 2 build(s): 1, 2');
});
it('should construct full paths to directories (by prepending \'buildsDir\')', () => {
(cleaner as any).removeUnnecessaryBuilds([1, 2, 3], []);
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/1'));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/2'));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/3'));
});
it('should try removing hidden directories as well', () => {
(cleaner as any).removeUnnecessaryBuilds([1, 2, 3], []);
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}1`));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}2`));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}3`));
});
it('should remove the builds that do not correspond to open PRs', () => {
(cleaner as any).removeUnnecessaryBuilds([1, 2, 3, 4], [2, 4]);
expect(cleanerRemoveDirSpy).toHaveBeenCalledTimes(4);
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/1'));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/3'));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}1`));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}3`));
cleanerRemoveDirSpy.calls.reset();
(cleaner as any).removeUnnecessaryBuilds([1, 2, 3, 4], [1, 2, 3, 4]);
expect(cleanerRemoveDirSpy).toHaveBeenCalledTimes(0);
cleanerRemoveDirSpy.calls.reset();
(cleaner as any).removeUnnecessaryBuilds([1, 2, 3, 4], []);
expect(cleanerRemoveDirSpy).toHaveBeenCalledTimes(8);
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/1'));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/2'));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/3'));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize('/foo/bar/4'));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}1`));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}2`));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}3`));
expect(cleanerRemoveDirSpy).toHaveBeenCalledWith(path.normalize(`/foo/bar/${HIDDEN_DIR_PREFIX}4`));
cleanerRemoveDirSpy.calls.reset();
});
});
});

View File

@ -0,0 +1,410 @@
// Imports
import {EventEmitter} from 'events';
import {ClientRequest, IncomingMessage} from 'http';
import * as https from 'https';
import {GithubApi} from '../../lib/common/github-api';
// Tests
describe('GithubApi', () => {
let api: GithubApi;
beforeEach(() => api = new GithubApi('12345'));
describe('constructor()', () => {
it('should throw if \'githubToken\' is missing or empty', () => {
expect(() => new GithubApi('')).toThrowError('Missing or empty required parameter \'githubToken\'!');
});
});
describe('get()', () => {
let apiBuildPathSpy: jasmine.Spy;
let apiRequestSpy: jasmine.Spy;
beforeEach(() => {
apiBuildPathSpy = spyOn(api as any, 'buildPath');
apiRequestSpy = spyOn(api as any, 'request');
});
it('should call \'buildPath()\' with the pathname and params', () => {
api.get('/foo', {bar: 'baz'});
expect(apiBuildPathSpy).toHaveBeenCalled();
expect(apiBuildPathSpy.calls.argsFor(0)).toEqual(['/foo', {bar: 'baz'}]);
});
it('should call \'request()\' with the correct method', () => {
api.get('/foo');
expect(apiRequestSpy).toHaveBeenCalled();
expect(apiRequestSpy.calls.argsFor(0)[0]).toBe('get');
});
it('should call \'request()\' with the correct path', () => {
apiBuildPathSpy.and.returnValue('/foo/bar');
api.get('foo');
expect(apiRequestSpy).toHaveBeenCalled();
expect(apiRequestSpy.calls.argsFor(0)[1]).toBe('/foo/bar');
});
it('should not pass data to \'request()\'', () => {
(api.get as any)('foo', {}, {});
expect(apiRequestSpy).toHaveBeenCalled();
expect(apiRequestSpy.calls.argsFor(0)[2]).toBeUndefined();
});
});
describe('post()', () => {
let apiBuildPathSpy: jasmine.Spy;
let apiRequestSpy: jasmine.Spy;
beforeEach(() => {
apiBuildPathSpy = spyOn(api as any, 'buildPath');
apiRequestSpy = spyOn(api as any, 'request');
});
it('should call \'buildPath()\' with the pathname and params', () => {
api.post('/foo', {bar: 'baz'});
expect(apiBuildPathSpy).toHaveBeenCalled();
expect(apiBuildPathSpy.calls.argsFor(0)).toEqual(['/foo', {bar: 'baz'}]);
});
it('should call \'request()\' with the correct method', () => {
api.post('/foo');
expect(apiRequestSpy).toHaveBeenCalled();
expect(apiRequestSpy.calls.argsFor(0)[0]).toBe('post');
});
it('should call \'request()\' with the correct path', () => {
apiBuildPathSpy.and.returnValue('/foo/bar');
api.post('/foo');
expect(apiRequestSpy).toHaveBeenCalled();
expect(apiRequestSpy.calls.argsFor(0)[1]).toBe('/foo/bar');
});
it('should pass the data to \'request()\'', () => {
api.post('/foo', {}, {bar: 'baz'});
expect(apiRequestSpy).toHaveBeenCalled();
expect(apiRequestSpy.calls.argsFor(0)[2]).toEqual({bar: 'baz'});
});
});
// Protected methods
describe('buildPath()', () => {
it('should return the pathname if no params', () => {
expect((api as any).buildPath('/foo')).toBe('/foo');
expect((api as any).buildPath('/foo', undefined)).toBe('/foo');
expect((api as any).buildPath('/foo', null)).toBe('/foo');
});
it('should append the params to the pathname', () => {
expect((api as any).buildPath('/foo', {bar: 'baz'})).toBe('/foo?bar=baz');
});
it('should join the params with \'&\'', () => {
expect((api as any).buildPath('/foo', {bar: 1, baz: 2})).toBe('/foo?bar=1&baz=2');
});
it('should ignore undefined/null params', () => {
expect((api as any).buildPath('/foo', {bar: undefined, baz: null})).toBe('/foo');
});
it('should encode param values as URI components', () => {
expect((api as any).buildPath('/foo', {bar: 'b a&z'})).toBe('/foo?bar=b%20a%26z');
});
});
describe('getPaginated()', () => {
let deferreds: {resolve: (v: any) => void, reject: (v: any) => void}[];
beforeEach(() => {
deferreds = [];
spyOn(api, 'get').and.callFake(() => new Promise((resolve, reject) => deferreds.push({resolve, reject})));
});
it('should return a promise', () => {
expect((api as any).getPaginated()).toEqual(jasmine.any(Promise));
});
it('should call \'get()\' with the correct pathname and params', () => {
(api as any).getPaginated('/foo/bar');
(api as any).getPaginated('/foo/bar', {baz: 'qux'});
expect(api.get).toHaveBeenCalledWith('/foo/bar', {page: 0, per_page: 100});
expect(api.get).toHaveBeenCalledWith('/foo/bar', {baz: 'qux', page: 0, per_page: 100});
});
it('should reject if the request fails', done => {
(api as any).getPaginated('/foo/bar').catch((err: any) => {
expect(err).toBe('Test');
done();
});
deferreds[0].reject('Test');
});
it('should resolve with the returned items', done => {
const items = [{id: 1}, {id: 2}];
(api as any).getPaginated('/foo/bar').then((data: any) => {
expect(data).toEqual(items);
done();
});
deferreds[0].resolve(items);
});
it('should iteratively call \'get()\' to fetch all items', done => {
// Create an array or 250 objects.
const allItems = '.'.repeat(250).split('').map((_, i) => ({id: i}));
const apiGetSpy = api.get as jasmine.Spy;
(api as any).getPaginated('/foo/bar', {baz: 'qux'}).then((data: any) => {
const paramsForPage = (page: number) => ({baz: 'qux', page, per_page: 100});
expect(apiGetSpy).toHaveBeenCalledTimes(3);
expect(apiGetSpy.calls.argsFor(0)).toEqual(['/foo/bar', paramsForPage(0)]);
expect(apiGetSpy.calls.argsFor(1)).toEqual(['/foo/bar', paramsForPage(1)]);
expect(apiGetSpy.calls.argsFor(2)).toEqual(['/foo/bar', paramsForPage(2)]);
expect(data).toEqual(allItems);
done();
});
deferreds[0].resolve(allItems.slice(0, 100));
setTimeout(() => {
deferreds[1].resolve(allItems.slice(100, 200));
setTimeout(() => {
deferreds[2].resolve(allItems.slice(200));
}, 0);
}, 0);
});
});
describe('request()', () => {
let httpsRequestSpy: jasmine.Spy;
let latestRequest: ClientRequest;
beforeEach(() => {
const originalRequest = https.request;
httpsRequestSpy = spyOn(https, 'request').and.callFake((...args: any[]) => {
latestRequest = originalRequest.apply(https, args);
spyOn(latestRequest, 'on').and.callThrough();
spyOn(latestRequest, 'end');
return latestRequest;
});
});
it('should return a promise', () => {
expect((api as any).request()).toEqual(jasmine.any(Promise));
});
it('should call \'https.request()\' with the correct options', () => {
(api as any).request('method', 'path');
expect(httpsRequestSpy).toHaveBeenCalled();
expect(httpsRequestSpy.calls.argsFor(0)[0]).toEqual(jasmine.objectContaining({
headers: jasmine.objectContaining({
'User-Agent': `Node/${process.versions.node}`,
}),
host: 'api.github.com',
method: 'method',
path: 'path',
}));
});
it('should call specify an \'Authorization\' header if \'githubToken\' is present', () => {
(api as any).request('method', 'path');
expect(httpsRequestSpy).toHaveBeenCalled();
expect(httpsRequestSpy.calls.argsFor(0)[0].headers).toEqual(jasmine.objectContaining({
Authorization: 'token 12345',
}));
});
it('should reject on request error', done => {
(api as any).request('method', 'path').catch((err: any) => {
expect(err).toBe('Test');
done();
});
latestRequest.emit('error', 'Test');
});
it('should send the request (i.e. call \'end()\')', () => {
(api as any).request('method', 'path');
expect(latestRequest.end).toHaveBeenCalled();
});
it('should \'JSON.stringify\' and send the data along with the request', () => {
(api as any).request('method', 'path');
expect(latestRequest.end).toHaveBeenCalledWith(null);
(api as any).request('method', 'path', {key: 'value'});
expect(latestRequest.end).toHaveBeenCalledWith('{"key":"value"}');
});
describe('onResponse', () => {
let promise: Promise<object>;
let respond: (statusCode: number) => IncomingMessage;
beforeEach(() => {
promise = (api as any).request('method', 'path');
respond = (statusCode: number) => {
const mockResponse = new EventEmitter() as IncomingMessage;
mockResponse.statusCode = statusCode;
const onResponse = httpsRequestSpy.calls.argsFor(0)[1];
onResponse(mockResponse);
return mockResponse;
};
});
it('should reject on response error', done => {
promise.catch(err => {
expect(err).toBe('Test');
done();
});
const res = respond(200);
res.emit('error', 'Test');
});
it('should reject if returned statusCode is <200', done => {
promise.catch(err => {
expect(err).toContain('failed');
expect(err).toContain('status: 199');
done();
});
const res = respond(199);
res.emit('end');
});
it('should reject if returned statusCode is >=400', done => {
promise.catch(err => {
expect(err).toContain('failed');
expect(err).toContain('status: 400');
done();
});
const res = respond(400);
res.emit('end');
});
it('should include the response text in the rejection message', done => {
promise.catch(err => {
expect(err).toContain('Test');
done();
});
const res = respond(500);
res.emit('data', 'Test');
res.emit('end');
});
it('should resolve if returned statusCode is <=200 <400', done => {
promise.then(done);
const res = respond(200);
res.emit('data', '{}');
res.emit('end');
});
it('should resolve with the response text \'JSON.parsed\'', done => {
promise.then(data => {
expect(data).toEqual({foo: 'bar'});
done();
});
const res = respond(300);
res.emit('data', '{"foo":"bar"}');
res.emit('end');
});
it('should collect and concatenate the whole response text', done => {
promise.then(data => {
expect(data).toEqual({foo: 'bar', baz: 'qux'});
done();
});
const res = respond(300);
res.emit('data', '{"foo":');
res.emit('data', '"bar","baz"');
res.emit('data', ':"qux"}');
res.emit('end');
});
it('should reject if the response text is malformed JSON', done => {
promise.catch(err => {
expect(err).toEqual(jasmine.any(SyntaxError));
done();
});
const res = respond(300);
res.emit('data', '}');
res.emit('end');
});
});
});
});

View File

@ -0,0 +1,141 @@
// Imports
import {GithubPullRequests} from '../../lib/common/github-pull-requests';
// Tests
describe('GithubPullRequests', () => {
describe('constructor()', () => {
it('should throw if \'githubToken\' is missing or empty', () => {
expect(() => new GithubPullRequests('', 'foo/bar')).
toThrowError('Missing or empty required parameter \'githubToken\'!');
});
it('should throw if \'repoSlug\' is missing or empty', () => {
expect(() => new GithubPullRequests('12345', '')).
toThrowError('Missing or empty required parameter \'repoSlug\'!');
});
});
describe('addComment()', () => {
let prs: GithubPullRequests;
let deferred: {resolve: (v: any) => void, reject: (v: any) => void};
beforeEach(() => {
prs = new GithubPullRequests('12345', 'foo/bar');
spyOn(prs, 'post').and.callFake(() => new Promise((resolve, reject) => deferred = {resolve, reject}));
});
it('should return a promise', () => {
expect(prs.addComment(42, 'body')).toEqual(jasmine.any(Promise));
});
it('should throw if the PR number is invalid', () => {
expect(() => prs.addComment(-1337, 'body')).toThrowError(`Invalid PR number: -1337`);
expect(() => prs.addComment(NaN, 'body')).toThrowError(`Invalid PR number: NaN`);
});
it('should throw if the comment body is invalid or empty', () => {
expect(() => prs.addComment(42, '')).toThrowError(`Invalid or empty comment body: `);
});
it('should call \'post()\' with the correct pathname, params and data', () => {
prs.addComment(42, 'body');
expect(prs.post).toHaveBeenCalledWith('/repos/foo/bar/issues/42/comments', null, {body: 'body'});
});
it('should reject if the request fails', done => {
prs.addComment(42, 'body').catch(err => {
expect(err).toBe('Test');
done();
});
deferred.reject('Test');
});
it('should resolve with the returned response', done => {
prs.addComment(42, 'body').then(data => {
expect(data as any).toBe('Test');
done();
});
deferred.resolve('Test');
});
});
describe('fetch()', () => {
let prs: GithubPullRequests;
let prsGetSpy: jasmine.Spy;
beforeEach(() => {
prs = new GithubPullRequests('12345', 'foo/bar');
prsGetSpy = spyOn(prs as any, 'get');
});
it('should call \'get()\' with the correct pathname', () => {
prs.fetch(42);
expect(prsGetSpy).toHaveBeenCalledWith('/repos/foo/bar/issues/42');
});
it('should forward the value returned by \'get()\'', () => {
prsGetSpy.and.returnValue('Test');
expect(prs.fetch(42) as any).toBe('Test');
});
});
describe('fetchAll()', () => {
let prs: GithubPullRequests;
let prsGetPaginatedSpy: jasmine.Spy;
beforeEach(() => {
prs = new GithubPullRequests('12345', 'foo/bar');
prsGetPaginatedSpy = spyOn(prs as any, 'getPaginated');
spyOn(console, 'log');
});
it('should call \'getPaginated()\' with the correct pathname and params', () => {
const expectedPathname = '/repos/foo/bar/pulls';
prs.fetchAll('all');
prs.fetchAll('closed');
prs.fetchAll('open');
expect(prsGetPaginatedSpy).toHaveBeenCalledTimes(3);
expect(prsGetPaginatedSpy.calls.argsFor(0)).toEqual([expectedPathname, {state: 'all'}]);
expect(prsGetPaginatedSpy.calls.argsFor(1)).toEqual([expectedPathname, {state: 'closed'}]);
expect(prsGetPaginatedSpy.calls.argsFor(2)).toEqual([expectedPathname, {state: 'open'}]);
});
it('should default to \'all\' if no state is specified', () => {
prs.fetchAll();
expect(prsGetPaginatedSpy).toHaveBeenCalledWith('/repos/foo/bar/pulls', {state: 'all'});
});
it('should forward the value returned by \'getPaginated()\'', () => {
prsGetPaginatedSpy.and.returnValue('Test');
expect(prs.fetchAll() as any).toBe('Test');
});
});
});

View File

@ -0,0 +1,235 @@
// Imports
import {GithubTeams} from '../../lib/common/github-teams';
// Tests
describe('GithubTeams', () => {
describe('constructor()', () => {
it('should throw if \'githubToken\' is missing or empty', () => {
expect(() => new GithubTeams('', 'org')).
toThrowError('Missing or empty required parameter \'githubToken\'!');
});
it('should throw if \'organization\' is missing or empty', () => {
expect(() => new GithubTeams('12345', '')).
toThrowError('Missing or empty required parameter \'organization\'!');
});
});
describe('fetchAll()', () => {
let teams: GithubTeams;
let teamsGetPaginatedSpy: jasmine.Spy;
beforeEach(() => {
teams = new GithubTeams('12345', 'foo');
teamsGetPaginatedSpy = spyOn(teams as any, 'getPaginated');
});
it('should call \'getPaginated()\' with the correct pathname and params', () => {
teams.fetchAll();
expect(teamsGetPaginatedSpy).toHaveBeenCalledWith('/orgs/foo/teams');
});
it('should forward the value returned by \'getPaginated()\'', () => {
teamsGetPaginatedSpy.and.returnValue('Test');
expect(teams.fetchAll() as any).toBe('Test');
});
});
describe('isMemberById()', () => {
let teams: GithubTeams;
let teamsGetSpy: jasmine.Spy;
beforeEach(() => {
teams = new GithubTeams('12345', 'foo');
teamsGetSpy = spyOn(teams, 'get').and.returnValue(Promise.resolve(null));
});
it('should return a promise', done => {
const promise = teams.isMemberById('user', [1]);
promise.then(done); // Do not complete the test (and release the spies) synchronously
// to avoid running the actual `get()`.
expect(promise).toEqual(jasmine.any(Promise));
});
it('should resolve with false if called with an empty array', done => {
teams.isMemberById('user', []).then(isMember => {
expect(isMember).toBe(false);
expect(teamsGetSpy).not.toHaveBeenCalled();
done();
});
});
it('should call \'get()\' with the correct pathname', done => {
teams.isMemberById('user', [1]).then(() => {
expect(teamsGetSpy).toHaveBeenCalledWith('/teams/1/memberships/user');
done();
});
});
it('should resolve with false if \'get()\' rejects', done => {
teamsGetSpy.and.returnValue(Promise.reject(null));
teams.isMemberById('user', [1]).then(isMember => {
expect(isMember).toBe(false);
expect(teamsGetSpy).toHaveBeenCalled();
done();
});
});
it('should resolve with false if the membership is not active', done => {
teamsGetSpy.and.returnValue(Promise.resolve({state: 'pending'}));
teams.isMemberById('user', [1]).then(isMember => {
expect(isMember).toBe(false);
expect(teamsGetSpy).toHaveBeenCalled();
done();
});
});
it('should resolve with true if the membership is active', done => {
teamsGetSpy.and.returnValue(Promise.resolve({state: 'active'}));
teams.isMemberById('user', [1]).then(isMember => {
expect(isMember).toBe(true);
done();
});
});
it('should sequentially call \'get()\' until an active membership is found', done => {
const trainedResponses: {[pathname: string]: Promise<{state: string}>} = {
'/teams/1/memberships/user': Promise.resolve({state: 'pending'}),
'/teams/2/memberships/user': Promise.reject(null),
'/teams/3/memberships/user': Promise.resolve({state: 'active'}),
};
teamsGetSpy.and.callFake((pathname: string) => trainedResponses[pathname]);
teams.isMemberById('user', [1, 2, 3, 4]).then(isMember => {
expect(isMember).toBe(true);
expect(teamsGetSpy).toHaveBeenCalledTimes(3);
expect(teamsGetSpy.calls.argsFor(0)[0]).toBe('/teams/1/memberships/user');
expect(teamsGetSpy.calls.argsFor(1)[0]).toBe('/teams/2/memberships/user');
expect(teamsGetSpy.calls.argsFor(2)[0]).toBe('/teams/3/memberships/user');
done();
});
});
it('should resolve with false if no active membership is found', done => {
const trainedResponses: {[pathname: string]: Promise<{state: string}>} = {
'/teams/1/memberships/user': Promise.resolve({state: 'pending'}),
'/teams/2/memberships/user': Promise.reject(null),
'/teams/3/memberships/user': Promise.resolve({state: 'not active'}),
'/teams/4/memberships/user': Promise.reject(null),
};
teamsGetSpy.and.callFake((pathname: string) => trainedResponses[pathname]);
teams.isMemberById('user', [1, 2, 3, 4]).then(isMember => {
expect(isMember).toBe(false);
expect(teamsGetSpy).toHaveBeenCalledTimes(4);
expect(teamsGetSpy.calls.argsFor(0)[0]).toBe('/teams/1/memberships/user');
expect(teamsGetSpy.calls.argsFor(1)[0]).toBe('/teams/2/memberships/user');
expect(teamsGetSpy.calls.argsFor(2)[0]).toBe('/teams/3/memberships/user');
expect(teamsGetSpy.calls.argsFor(3)[0]).toBe('/teams/4/memberships/user');
done();
});
});
});
describe('isMemberBySlug()', () => {
let teams: GithubTeams;
let teamsFetchAllSpy: jasmine.Spy;
let teamsIsMemberByIdSpy: jasmine.Spy;
beforeEach(() => {
teams = new GithubTeams('12345', 'foo');
const mockResponse = Promise.resolve([{id: 1, slug: 'team1'}, {id: 2, slug: 'team2'}]);
teamsFetchAllSpy = spyOn(teams, 'fetchAll').and.returnValue(mockResponse);
teamsIsMemberByIdSpy = spyOn(teams, 'isMemberById');
});
it('should return a promise', () => {
expect(teams.isMemberBySlug('user', ['team-slug'])).toEqual(jasmine.any(Promise));
});
it('should call \'fetchAll()\'', () => {
teams.isMemberBySlug('user', ['team-slug']);
expect(teamsFetchAllSpy).toHaveBeenCalled();
});
it('should resolve with false if \'fetchAll()\' rejects', done => {
teamsFetchAllSpy.and.returnValue(Promise.reject(null));
teams.isMemberBySlug('user', ['team-slug']).then(isMember => {
expect(isMember).toBe(false);
done();
});
});
it('should call \'isMemberById()\' with the correct params if no team is found', done => {
teams.isMemberBySlug('user', ['no-match']).then(() => {
expect(teamsIsMemberByIdSpy).toHaveBeenCalledWith('user', []);
done();
});
});
it('should call \'isMemberById()\' with the correct params if teams are found', done => {
const spy = teamsIsMemberByIdSpy;
Promise.all([
teams.isMemberBySlug('user', ['team1']).then(() => expect(spy).toHaveBeenCalledWith('user', [1])),
teams.isMemberBySlug('user', ['team2']).then(() => expect(spy).toHaveBeenCalledWith('user', [2])),
teams.isMemberBySlug('user', ['team1', 'team2']).then(() => expect(spy).toHaveBeenCalledWith('user', [1, 2])),
]).then(done);
});
it('should resolve with false if \'isMemberById()\' rejects', done => {
teamsIsMemberByIdSpy.and.returnValue(Promise.reject(null));
teams.isMemberBySlug('user', ['team1']).then(isMember => {
expect(isMember).toBe(false);
expect(teamsIsMemberByIdSpy).toHaveBeenCalled();
done();
});
});
it('should resolve with the value \'isMemberById()\' resolves with', done => {
teamsIsMemberByIdSpy.and.returnValues(Promise.resolve(false), Promise.resolve(true));
Promise.all([
teams.isMemberBySlug('user', ['team1']).then(isMember => expect(isMember).toBe(false)),
teams.isMemberBySlug('user', ['team1']).then(isMember => expect(isMember).toBe(true)),
]).then(() => {
expect(teamsIsMemberByIdSpy).toHaveBeenCalledTimes(2);
done();
});
});
});
});

View File

@ -0,0 +1,81 @@
// Imports
import {assertNotMissingOrEmpty, getEnvVar} from '../../lib/common/utils';
// Tests
describe('utils', () => {
describe('assertNotMissingOrEmpty()', () => {
it('should throw if passed an empty value', () => {
expect(() => assertNotMissingOrEmpty('foo', undefined)).
toThrowError('Missing or empty required parameter \'foo\'!');
expect(() => assertNotMissingOrEmpty('bar', null)).toThrowError('Missing or empty required parameter \'bar\'!');
expect(() => assertNotMissingOrEmpty('baz', '')).toThrowError('Missing or empty required parameter \'baz\'!');
});
it('should not throw if passed a non-empty value', () => {
expect(() => assertNotMissingOrEmpty('foo', ' ')).not.toThrow();
expect(() => assertNotMissingOrEmpty('bar', 'bar')).not.toThrow();
expect(() => assertNotMissingOrEmpty('baz', 'b a z')).not.toThrow();
});
});
describe('getEnvVar()', () => {
const emptyVar = '$$test_utils_getEnvVar_empty$$';
const nonEmptyVar = '$$test_utils_getEnvVar_nonEmpty$$';
const undefinedVar = '$$test_utils_getEnvVar_undefined$$';
beforeEach(() => {
process.env[emptyVar] = '';
process.env[nonEmptyVar] = 'foo';
});
afterEach(() => {
delete process.env[emptyVar];
delete process.env[nonEmptyVar];
});
it('should return an environment variable', () => {
expect(getEnvVar(nonEmptyVar)).toBe('foo');
});
it('should exit with an error if the environment variable is not defined', () => {
const consoleErrorSpy = spyOn(console, 'error');
const processExitSpy = spyOn(process, 'exit');
getEnvVar(undefinedVar);
expect(consoleErrorSpy).toHaveBeenCalled();
expect(consoleErrorSpy.calls.argsFor(0)[0]).toContain(undefinedVar);
expect(processExitSpy).toHaveBeenCalledWith(1);
});
it('should exit with an error if the environment variable is empty', () => {
const consoleErrorSpy = spyOn(console, 'error');
const processExitSpy = spyOn(process, 'exit');
getEnvVar(emptyVar);
expect(consoleErrorSpy).toHaveBeenCalled();
expect(consoleErrorSpy.calls.argsFor(0)[0]).toContain(emptyVar);
expect(processExitSpy).toHaveBeenCalledWith(1);
});
it('should return an empty string if an undefined variable is optional', () => {
expect(getEnvVar(undefinedVar, true)).toBe('');
});
it('should return an empty string if an empty variable is optional', () => {
expect(getEnvVar(emptyVar, true)).toBe('');
});
});
});

View File

@ -0,0 +1,6 @@
declare namespace jasmine {
export interface DoneFn extends Function {
(): void;
fail: (message: Error | string) => void;
}
}

View File

@ -0,0 +1,7 @@
// Imports
import {runTests} from '../lib/common/run-tests';
// Run
const specFiles = [`${__dirname}/**/*.spec.js`];
const helpers = [`${__dirname}/helpers.js`];
runTests(specFiles, helpers);

View File

@ -0,0 +1,687 @@
// Imports
import * as cp from 'child_process';
import {EventEmitter} from 'events';
import * as fs from 'fs';
import * as path from 'path';
import * as shell from 'shelljs';
import {SHORT_SHA_LEN} from '../../lib/common/constants';
import {BuildCreator} from '../../lib/upload-server/build-creator';
import {ChangedPrVisibilityEvent, CreatedBuildEvent} from '../../lib/upload-server/build-events';
import {UploadError} from '../../lib/upload-server/upload-error';
import {expectToBeUploadError} from './helpers';
// Tests
describe('BuildCreator', () => {
const pr = '9';
const sha = '9'.repeat(40);
const shortSha = sha.substr(0, SHORT_SHA_LEN);
const archive = 'snapshot.tar.gz';
const buildsDir = 'builds/dir';
const hiddenPrDir = path.join(buildsDir, `hidden--${pr}`);
const publicPrDir = path.join(buildsDir, pr);
const hiddenShaDir = path.join(hiddenPrDir, shortSha);
const publicShaDir = path.join(publicPrDir, shortSha);
let bc: BuildCreator;
beforeEach(() => bc = new BuildCreator(buildsDir));
describe('constructor()', () => {
it('should throw if \'buildsDir\' is missing or empty', () => {
expect(() => new BuildCreator('')).toThrowError('Missing or empty required parameter \'buildsDir\'!');
});
it('should extend EventEmitter', () => {
expect(bc).toEqual(jasmine.any(BuildCreator));
expect(bc).toEqual(jasmine.any(EventEmitter));
expect(Object.getPrototypeOf(bc)).toBe(BuildCreator.prototype);
});
});
describe('create()', () => {
let bcEmitSpy: jasmine.Spy;
let bcExistsSpy: jasmine.Spy;
let bcExtractArchiveSpy: jasmine.Spy;
let bcUpdatePrVisibilitySpy: jasmine.Spy;
let shellMkdirSpy: jasmine.Spy;
let shellRmSpy: jasmine.Spy;
beforeEach(() => {
bcEmitSpy = spyOn(bc, 'emit');
bcExistsSpy = spyOn(bc as any, 'exists');
bcExtractArchiveSpy = spyOn(bc as any, 'extractArchive');
bcUpdatePrVisibilitySpy = spyOn(bc, 'updatePrVisibility');
shellMkdirSpy = spyOn(shell, 'mkdir');
shellRmSpy = spyOn(shell, 'rm');
});
[true, false].forEach(isPublic => {
const prDir = isPublic ? publicPrDir : hiddenPrDir;
const shaDir = isPublic ? publicShaDir : hiddenShaDir;
it('should return a promise', done => {
const promise = bc.create(pr, sha, archive, isPublic);
promise.then(done); // Do not complete the test (and release the spies) synchronously
// to avoid running the actual `extractArchive()`.
expect(promise).toEqual(jasmine.any(Promise));
});
it('should update the PR\'s visibility first if necessary', done => {
bcUpdatePrVisibilitySpy.and.callFake(() => expect(shellMkdirSpy).not.toHaveBeenCalled());
bc.create(pr, sha, archive, isPublic).
then(() => {
expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledWith(pr, isPublic);
expect(shellMkdirSpy).toHaveBeenCalled();
}).
then(done);
});
it('should create the build directory (and any parent directories)', done => {
bc.create(pr, sha, archive, isPublic).
then(() => expect(shellMkdirSpy).toHaveBeenCalledWith('-p', shaDir)).
then(done);
});
it('should extract the archive contents into the build directory', done => {
bc.create(pr, sha, archive, isPublic).
then(() => expect(bcExtractArchiveSpy).toHaveBeenCalledWith(archive, shaDir)).
then(done);
});
it('should emit a CreatedBuildEvent on success', done => {
let emitted = false;
bcEmitSpy.and.callFake((type: string, evt: CreatedBuildEvent) => {
expect(type).toBe(CreatedBuildEvent.type);
expect(evt).toEqual(jasmine.any(CreatedBuildEvent));
expect(evt.pr).toBe(+pr);
expect(evt.sha).toBe(shortSha);
expect(evt.isPublic).toBe(isPublic);
emitted = true;
});
bc.create(pr, sha, archive, isPublic).
then(() => expect(emitted).toBe(true)).
then(done);
});
describe('on error', () => {
let existsValues: {[dir: string]: boolean};
beforeEach(() => {
existsValues = {
[prDir]: false,
[shaDir]: false,
};
bcExistsSpy.and.callFake((dir: string) => existsValues[dir]);
});
it('should abort and skip further operations if changing the PR\'s visibility fails', done => {
const mockError = new UploadError(543, 'Test');
bcUpdatePrVisibilitySpy.and.returnValue(Promise.reject(mockError));
bc.create(pr, sha, archive, isPublic).catch(err => {
expect(err).toBe(mockError);
expect(bcExistsSpy).not.toHaveBeenCalled();
expect(shellMkdirSpy).not.toHaveBeenCalled();
expect(bcExtractArchiveSpy).not.toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
done();
});
});
it('should abort and skip further operations if the build does already exist', done => {
existsValues[shaDir] = true;
bc.create(pr, sha, archive, isPublic).catch(err => {
const publicOrNot = isPublic ? 'public' : 'non-public';
expectToBeUploadError(err, 409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`);
expect(shellMkdirSpy).not.toHaveBeenCalled();
expect(bcExtractArchiveSpy).not.toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
done();
});
});
it('should detect existing build directory after visibility change', done => {
bcUpdatePrVisibilitySpy.and.callFake(() => existsValues[prDir] = existsValues[shaDir] = true);
expect(bcExistsSpy(prDir)).toBe(false);
expect(bcExistsSpy(shaDir)).toBe(false);
bc.create(pr, sha, archive, isPublic).catch(err => {
const publicOrNot = isPublic ? 'public' : 'non-public';
expectToBeUploadError(err, 409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`);
expect(shellMkdirSpy).not.toHaveBeenCalled();
expect(bcExtractArchiveSpy).not.toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
done();
});
});
it('should abort and skip further operations if it fails to create the directories', done => {
shellMkdirSpy.and.throwError('');
bc.create(pr, sha, archive, isPublic).catch(() => {
expect(shellMkdirSpy).toHaveBeenCalled();
expect(bcExtractArchiveSpy).not.toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
done();
});
});
it('should abort and skip further operations if it fails to extract the archive', done => {
bcExtractArchiveSpy.and.throwError('');
bc.create(pr, sha, archive, isPublic).catch(() => {
expect(shellMkdirSpy).toHaveBeenCalled();
expect(bcExtractArchiveSpy).toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
done();
});
});
it('should delete the PR directory (for new PR)', done => {
bcExtractArchiveSpy.and.throwError('');
bc.create(pr, sha, archive, isPublic).catch(() => {
expect(shellRmSpy).toHaveBeenCalledWith('-rf', prDir);
done();
});
});
it('should delete the SHA directory (for existing PR)', done => {
existsValues[prDir] = true;
bcExtractArchiveSpy.and.throwError('');
bc.create(pr, sha, archive, isPublic).catch(() => {
expect(shellRmSpy).toHaveBeenCalledWith('-rf', shaDir);
done();
});
});
it('should reject with an UploadError', done => {
// tslint:disable-next-line: no-string-throw
shellMkdirSpy.and.callFake(() => { throw 'Test'; });
bc.create(pr, sha, archive, isPublic).catch(err => {
expectToBeUploadError(err, 500, `Error while uploading to directory: ${shaDir}\nTest`);
done();
});
});
it('should pass UploadError instances unmodified', done => {
shellMkdirSpy.and.callFake(() => { throw new UploadError(543, 'Test'); });
bc.create(pr, sha, archive, isPublic).catch(err => {
expectToBeUploadError(err, 543, 'Test');
done();
});
});
});
});
});
describe('updatePrVisibility()', () => {
let bcEmitSpy: jasmine.Spy;
let bcExistsSpy: jasmine.Spy;
let bcListShasByDate: jasmine.Spy;
let shellMvSpy: jasmine.Spy;
beforeEach(() => {
bcEmitSpy = spyOn(bc, 'emit');
bcExistsSpy = spyOn(bc as any, 'exists');
bcListShasByDate = spyOn(bc as any, 'listShasByDate');
shellMvSpy = spyOn(shell, 'mv');
bcExistsSpy.and.returnValues(Promise.resolve(true), Promise.resolve(false));
bcListShasByDate.and.returnValue([]);
});
it('should return a promise', done => {
const promise = bc.updatePrVisibility(pr, true);
promise.then(done); // Do not complete the test (and release the spies) synchronously
// to avoid running the actual `extractArchive()`.
expect(promise).toEqual(jasmine.any(Promise));
});
[true, false].forEach(makePublic => {
const oldPrDir = makePublic ? hiddenPrDir : publicPrDir;
const newPrDir = makePublic ? publicPrDir : hiddenPrDir;
it('should rename the directory', done => {
bc.updatePrVisibility(pr, makePublic).
then(() => expect(shellMvSpy).toHaveBeenCalledWith(oldPrDir, newPrDir)).
then(done);
});
describe('when the visibility is updated', () => {
it('should resolve to true', done => {
bc.updatePrVisibility(pr, makePublic).
then(result => expect(result).toBe(true)).
then(done);
});
it('should rename the directory', done => {
bc.updatePrVisibility(pr, makePublic).
then(() => expect(shellMvSpy).toHaveBeenCalledWith(oldPrDir, newPrDir)).
then(done);
});
it('should emit a ChangedPrVisibilityEvent on success', done => {
let emitted = false;
bcEmitSpy.and.callFake((type: string, evt: ChangedPrVisibilityEvent) => {
expect(type).toBe(ChangedPrVisibilityEvent.type);
expect(evt).toEqual(jasmine.any(ChangedPrVisibilityEvent));
expect(evt.pr).toBe(+pr);
expect(evt.shas).toEqual(jasmine.any(Array));
expect(evt.isPublic).toBe(makePublic);
emitted = true;
});
bc.updatePrVisibility(pr, makePublic).
then(() => expect(emitted).toBe(true)).
then(done);
});
it('should include all shas in the emitted event', done => {
const shas = ['foo', 'bar', 'baz'];
let emitted = false;
bcListShasByDate.and.returnValue(Promise.resolve(shas));
bcEmitSpy.and.callFake((type: string, evt: ChangedPrVisibilityEvent) => {
expect(bcListShasByDate).toHaveBeenCalledWith(newPrDir);
expect(type).toBe(ChangedPrVisibilityEvent.type);
expect(evt).toEqual(jasmine.any(ChangedPrVisibilityEvent));
expect(evt.pr).toBe(+pr);
expect(evt.shas).toBe(shas);
expect(evt.isPublic).toBe(makePublic);
emitted = true;
});
bc.updatePrVisibility(pr, makePublic).
then(() => expect(emitted).toBe(true)).
then(done);
});
});
it('should do nothing if the visibility is already up-to-date', done => {
bcExistsSpy.and.callFake((dir: string) => dir === newPrDir);
bc.updatePrVisibility(pr, makePublic).
then(result => {
expect(result).toBe(false);
expect(shellMvSpy).not.toHaveBeenCalled();
expect(bcListShasByDate).not.toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
}).
then(done);
});
it('should do nothing if the PR directory does not exist', done => {
bcExistsSpy.and.returnValue(false);
bc.updatePrVisibility(pr, makePublic).
then(result => {
expect(result).toBe(false);
expect(shellMvSpy).not.toHaveBeenCalled();
expect(bcListShasByDate).not.toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
}).
then(done);
});
describe('on error', () => {
it('should abort and skip further operations if both directories exist', done => {
bcExistsSpy.and.returnValue(true);
bc.updatePrVisibility(pr, makePublic).catch(err => {
expectToBeUploadError(err, 409, `Request to move '${oldPrDir}' to existing directory '${newPrDir}'.`);
expect(shellMvSpy).not.toHaveBeenCalled();
expect(bcListShasByDate).not.toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
done();
});
});
it('should abort and skip further operations if it fails to rename the directory', done => {
shellMvSpy.and.throwError('');
bc.updatePrVisibility(pr, makePublic).catch(() => {
expect(shellMvSpy).toHaveBeenCalled();
expect(bcListShasByDate).not.toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
done();
});
});
it('should abort and skip further operations if it fails to list the SHAs', done => {
bcListShasByDate.and.throwError('');
bc.updatePrVisibility(pr, makePublic).catch(() => {
expect(shellMvSpy).toHaveBeenCalled();
expect(bcListShasByDate).toHaveBeenCalled();
expect(bcEmitSpy).not.toHaveBeenCalled();
done();
});
});
it('should reject with an UploadError', done => {
// tslint:disable-next-line: no-string-throw
shellMvSpy.and.callFake(() => { throw 'Test'; });
bc.updatePrVisibility(pr, makePublic).catch(err => {
expectToBeUploadError(err, 500, `Error while making PR ${pr} ${makePublic ? 'public' : 'hidden'}.\nTest`);
done();
});
});
it('should pass UploadError instances unmodified', done => {
shellMvSpy.and.callFake(() => { throw new UploadError(543, 'Test'); });
bc.updatePrVisibility(pr, makePublic).catch(err => {
expectToBeUploadError(err, 543, 'Test');
done();
});
});
});
});
});
// Protected methods
describe('exists()', () => {
let fsAccessSpy: jasmine.Spy;
let fsAccessCbs: ((v?: any) => void)[];
beforeEach(() => {
fsAccessCbs = [];
fsAccessSpy = spyOn(fs, 'access').and.callFake((_: string, cb: (v?: any) => void) => fsAccessCbs.push(cb));
});
it('should return a promise', () => {
expect((bc as any).exists('foo')).toEqual(jasmine.any(Promise));
});
it('should call \'fs.access()\' with the specified argument', () => {
(bc as any).exists('foo');
expect(fs.access).toHaveBeenCalledWith('foo', jasmine.any(Function));
});
it('should resolve with \'true\' if \'fs.access()\' succeeds', done => {
Promise.
all([(bc as any).exists('foo'), (bc as any).exists('bar')]).
then(results => expect(results).toEqual([true, true])).
then(done);
fsAccessCbs[0]();
fsAccessCbs[1](null);
});
it('should resolve with \'false\' if \'fs.access()\' errors', done => {
Promise.
all([(bc as any).exists('foo'), (bc as any).exists('bar')]).
then(results => expect(results).toEqual([false, false])).
then(done);
fsAccessCbs[0]('Error');
fsAccessCbs[1](new Error());
});
});
describe('extractArchive()', () => {
let consoleWarnSpy: jasmine.Spy;
let shellChmodSpy: jasmine.Spy;
let shellRmSpy: jasmine.Spy;
let cpExecSpy: jasmine.Spy;
let cpExecCbs: ((...args: any[]) => void)[];
beforeEach(() => {
cpExecCbs = [];
consoleWarnSpy = spyOn(console, 'warn');
shellChmodSpy = spyOn(shell, 'chmod');
shellRmSpy = spyOn(shell, 'rm');
cpExecSpy = spyOn(cp, 'exec').and.callFake((_: string, cb: (...args: any[]) => void) => cpExecCbs.push(cb));
});
it('should return a promise', () => {
expect((bc as any).extractArchive('foo', 'bar')).toEqual(jasmine.any(Promise));
});
it('should "gunzip" and "untar" the input file into the output directory', () => {
const cmd = 'tar --extract --gzip --directory "output/dir" --file "input/file"';
(bc as any).extractArchive('input/file', 'output/dir');
expect(cpExecSpy).toHaveBeenCalledWith(cmd, jasmine.any(Function));
});
it('should log (as a warning) any stderr output if extracting succeeded', done => {
(bc as any).extractArchive('foo', 'bar').
then(() => expect(consoleWarnSpy).toHaveBeenCalledWith('This is stderr')).
then(done);
cpExecCbs[0](null, 'This is stdout', 'This is stderr');
});
it('should make the build directory non-writable', done => {
(bc as any).extractArchive('foo', 'bar').
then(() => expect(shellChmodSpy).toHaveBeenCalledWith('-R', 'a-w', 'bar')).
then(done);
cpExecCbs[0]();
});
it('should delete the uploaded file on success', done => {
(bc as any).extractArchive('input/file', 'output/dir').
then(() => expect(shellRmSpy).toHaveBeenCalledWith('-f', 'input/file')).
then(done);
cpExecCbs[0]();
});
describe('on error', () => {
it('should abort and skip further operations if it fails to extract the archive', done => {
(bc as any).extractArchive('foo', 'bar').catch((err: any) => {
expect(shellChmodSpy).not.toHaveBeenCalled();
expect(shellRmSpy).not.toHaveBeenCalled();
expect(err).toBe('Test');
done();
});
cpExecCbs[0]('Test');
});
it('should abort and skip further operations if it fails to make non-writable', done => {
(bc as any).extractArchive('foo', 'bar').catch((err: any) => {
expect(shellChmodSpy).toHaveBeenCalled();
expect(shellRmSpy).not.toHaveBeenCalled();
expect(err).toBe('Test');
done();
});
shellChmodSpy.and.callFake(() => {
// tslint:disable-next-line: no-string-throw
throw 'Test';
});
cpExecCbs[0]();
});
it('should abort and reject if it fails to remove the uploaded file', done => {
(bc as any).extractArchive('foo', 'bar').catch((err: any) => {
expect(shellChmodSpy).toHaveBeenCalled();
expect(shellRmSpy).toHaveBeenCalled();
expect(err).toBe('Test');
done();
});
shellRmSpy.and.callFake(() => {
// tslint:disable-next-line: no-string-throw
throw 'Test';
});
cpExecCbs[0]();
});
});
});
describe('listShasByDate()', () => {
let shellLsSpy: jasmine.Spy;
const lsResult = (name: string, mtimeMs: number, isDirectory = true) => ({
isDirectory: () => isDirectory,
mtime: new Date(mtimeMs),
name,
});
beforeEach(() => {
shellLsSpy = spyOn(shell, 'ls').and.returnValue([]);
});
it('should return a promise', done => {
const promise = (bc as any).listShasByDate('input/dir');
promise.then(done); // Do not complete the test (and release the spies) synchronously
// to avoid running the actual `ls()`.
expect(promise).toEqual(jasmine.any(Promise));
});
it('should `ls()` files with their metadata', done => {
(bc as any).listShasByDate('input/dir').
then(() => expect(shellLsSpy).toHaveBeenCalledWith('-l', 'input/dir')).
then(done);
});
it('should reject if listing files fails', done => {
shellLsSpy.and.returnValue(Promise.reject('Test'));
(bc as any).listShasByDate('input/dir').catch((err: string) => {
expect(err).toBe('Test');
done();
});
});
it('should return the filenames', done => {
shellLsSpy.and.returnValue(Promise.resolve([
lsResult('foo', 100),
lsResult('bar', 200),
lsResult('baz', 300),
]));
(bc as any).listShasByDate('input/dir').
then((shas: string[]) => expect(shas).toEqual(['foo', 'bar', 'baz'])).
then(done);
});
it('should sort by date', done => {
shellLsSpy.and.returnValue(Promise.resolve([
lsResult('foo', 300),
lsResult('bar', 100),
lsResult('baz', 200),
]));
(bc as any).listShasByDate('input/dir').
then((shas: string[]) => expect(shas).toEqual(['bar', 'baz', 'foo'])).
then(done);
});
it('should not break with ShellJS\' custom `sort()` method', done => {
const mockArray = [
lsResult('foo', 300),
lsResult('bar', 100),
lsResult('baz', 200),
];
mockArray.sort = jasmine.createSpy('sort');
shellLsSpy.and.returnValue(Promise.resolve(mockArray));
(bc as any).listShasByDate('input/dir').
then((shas: string[]) => {
expect(shas).toEqual(['bar', 'baz', 'foo']);
expect(mockArray.sort).not.toHaveBeenCalled();
}).
then(done);
});
it('should only include directories', done => {
shellLsSpy.and.returnValue(Promise.resolve([
lsResult('foo', 100),
lsResult('bar', 200, false),
lsResult('baz', 300),
]));
(bc as any).listShasByDate('input/dir').
then((shas: string[]) => expect(shas).toEqual(['foo', 'baz'])).
then(done);
});
});
});

View File

@ -0,0 +1,58 @@
// Imports
import {ChangedPrVisibilityEvent, CreatedBuildEvent} from '../../lib/upload-server/build-events';
// Tests
describe('ChangedPrVisibilityEvent', () => {
let evt: ChangedPrVisibilityEvent;
beforeEach(() => evt = new ChangedPrVisibilityEvent(42, ['foo', 'bar'], true));
it('should have a static \'type\' property', () => {
expect(ChangedPrVisibilityEvent.type).toBe('pr.changedVisibility');
});
it('should have a \'pr\' property', () => {
expect(evt.pr).toBe(42);
});
it('should have a \'shas\' property', () => {
expect(evt.shas).toEqual(['foo', 'bar']);
});
it('should have an \'isPublic\' property', () => {
expect(evt.isPublic).toBe(true);
});
});
describe('CreatedBuildEvent', () => {
let evt: CreatedBuildEvent;
beforeEach(() => evt = new CreatedBuildEvent(42, 'bar', true));
it('should have a static \'type\' property', () => {
expect(CreatedBuildEvent.type).toBe('build.created');
});
it('should have a \'pr\' property', () => {
expect(evt.pr).toBe(42);
});
it('should have a \'sha\' property', () => {
expect(evt.sha).toBe('bar');
});
it('should have an \'isPublic\' property', () => {
expect(evt.isPublic).toBe(true);
});
});

View File

@ -0,0 +1,303 @@
// Imports
import * as jwt from 'jsonwebtoken';
import {GithubPullRequests, PullRequest} from '../../lib/common/github-pull-requests';
import {GithubTeams} from '../../lib/common/github-teams';
import {BUILD_VERIFICATION_STATUS, BuildVerifier} from '../../lib/upload-server/build-verifier';
import {expectToBeUploadError} from './helpers';
// Tests
describe('BuildVerifier', () => {
const defaultConfig = {
allowedTeamSlugs: ['team1', 'team2'],
githubToken: 'githubToken',
organization: 'organization',
repoSlug: 'repo/slug',
secret: 'secret',
trustedPrLabel: 'trusted: pr-label',
};
let bv: BuildVerifier;
// Helpers
const createBuildVerifier = (partialConfig: Partial<typeof defaultConfig> = {}) => {
const cfg = {...defaultConfig, ...partialConfig} as typeof defaultConfig;
return new BuildVerifier(cfg.secret, cfg.githubToken, cfg.repoSlug, cfg.organization,
cfg.allowedTeamSlugs, cfg.trustedPrLabel);
};
beforeEach(() => bv = createBuildVerifier());
describe('constructor()', () => {
['secret', 'githubToken', 'repoSlug', 'organization', 'allowedTeamSlugs', 'trustedPrLabel'].
forEach(param => {
it(`should throw if '${param}' is missing or empty`, () => {
expect(() => createBuildVerifier({[param]: ''})).
toThrowError(`Missing or empty required parameter '${param}'!`);
});
});
it('should throw if \'allowedTeamSlugs\' is an empty array', () => {
expect(() => createBuildVerifier({allowedTeamSlugs: []})).
toThrowError('Missing or empty required parameter \'allowedTeamSlugs\'!');
});
});
describe('getPrIsTrusted()', () => {
const pr = 9;
let mockPrInfo: PullRequest;
let prsFetchSpy: jasmine.Spy;
let teamsIsMemberBySlugSpy: jasmine.Spy;
beforeEach(() => {
mockPrInfo = {
labels: [
{name: 'foo'},
{name: 'bar'},
],
number: 9,
user: {login: 'username'},
};
prsFetchSpy = spyOn(GithubPullRequests.prototype, 'fetch').
and.returnValue(Promise.resolve(mockPrInfo));
teamsIsMemberBySlugSpy = spyOn(GithubTeams.prototype, 'isMemberBySlug').
and.returnValue(Promise.resolve(true));
});
it('should return a promise', done => {
const promise = bv.getPrIsTrusted(pr);
promise.then(done); // Do not complete the test (and release the spies) synchronously
// to avoid running the actual `GithubTeams#isMemberBySlug()`.
expect(promise).toEqual(jasmine.any(Promise));
});
it('should fetch the corresponding PR', done => {
bv.getPrIsTrusted(pr).then(() => {
expect(prsFetchSpy).toHaveBeenCalledWith(pr);
done();
});
});
it('should fail if fetching the PR errors', done => {
prsFetchSpy.and.callFake(() => Promise.reject('Test'));
bv.getPrIsTrusted(pr).catch(err => {
expect(err).toBe('Test');
done();
});
});
describe('when the PR has the "trusted PR" label', () => {
beforeEach(() => mockPrInfo.labels.push({name: 'trusted: pr-label'}));
it('should resolve to true', done => {
bv.getPrIsTrusted(pr).then(isTrusted => {
expect(isTrusted).toBe(true);
done();
});
});
it('should not try to verify the author\'s membership status', done => {
bv.getPrIsTrusted(pr).then(() => {
expect(teamsIsMemberBySlugSpy).not.toHaveBeenCalled();
done();
});
});
});
describe('when the PR does not have the "trusted PR" label', () => {
it('should verify the PR author\'s membership in the specified teams', done => {
bv.getPrIsTrusted(pr).then(() => {
expect(teamsIsMemberBySlugSpy).toHaveBeenCalledWith('username', ['team1', 'team2']);
done();
});
});
it('should fail if verifying membership errors', done => {
teamsIsMemberBySlugSpy.and.callFake(() => Promise.reject('Test'));
bv.getPrIsTrusted(pr).catch(err => {
expect(err).toBe('Test');
done();
});
});
it('should resolve to true if the PR\'s author is a member', done => {
teamsIsMemberBySlugSpy.and.returnValue(Promise.resolve(true));
bv.getPrIsTrusted(pr).then(isTrusted => {
expect(isTrusted).toBe(true);
done();
});
});
it('should resolve to false if the PR\'s author is not a member', done => {
teamsIsMemberBySlugSpy.and.returnValue(Promise.resolve(false));
bv.getPrIsTrusted(pr).then(isTrusted => {
expect(isTrusted).toBe(false);
done();
});
});
});
});
describe('verify()', () => {
const pr = 9;
const defaultJwt = {
'exp': Math.floor(Date.now() / 1000) + 30,
'iat': Math.floor(Date.now() / 1000) - 30,
'iss': 'Travis CI, GmbH',
'pull-request': pr,
'slug': defaultConfig.repoSlug,
};
let bvGetPrIsTrusted: jasmine.Spy;
// Heleprs
const createAuthHeader = (partialJwt: Partial<typeof defaultJwt> = {}, secret: string = defaultConfig.secret) =>
`Token ${jwt.sign({...defaultJwt, ...partialJwt}, secret)}`;
beforeEach(() => {
bvGetPrIsTrusted = spyOn(bv, 'getPrIsTrusted').and.returnValue(Promise.resolve(true));
});
it('should return a promise', done => {
const promise = bv.verify(pr, createAuthHeader());
promise.then(done); // Do not complete the test (and release the spies) synchronously
// to avoid running the actual `bvGetPrIsTrusted()`.
expect(promise).toEqual(jasmine.any(Promise));
});
it('should fail if the authorization header is invalid', done => {
bv.verify(pr, 'foo').catch(err => {
const errorMessage = 'Error while verifying upload for PR 9: jwt malformed';
expectToBeUploadError(err, 403, errorMessage);
done();
});
});
it('should fail if the secret is invalid', done => {
bv.verify(pr, createAuthHeader({}, 'foo')).catch(err => {
const errorMessage = 'Error while verifying upload for PR 9: invalid signature';
expectToBeUploadError(err, 403, errorMessage);
done();
});
});
it('should fail if the issuer is invalid', done => {
bv.verify(pr, createAuthHeader({iss: 'not valid'})).catch(err => {
const errorMessage = 'Error while verifying upload for PR 9: ' +
`jwt issuer invalid. expected: ${defaultJwt.iss}`;
expectToBeUploadError(err, 403, errorMessage);
done();
});
});
it('should fail if the token has expired', done => {
bv.verify(pr, createAuthHeader({exp: 0})).catch(err => {
const errorMessage = 'Error while verifying upload for PR 9: jwt expired';
expectToBeUploadError(err, 403, errorMessage);
done();
});
});
it('should fail if the repo slug does not match', done => {
bv.verify(pr, createAuthHeader({slug: 'foo/bar'})).catch(err => {
const errorMessage = 'Error while verifying upload for PR 9: ' +
`jwt slug invalid. expected: ${defaultConfig.repoSlug}`;
expectToBeUploadError(err, 403, errorMessage);
done();
});
});
it('should fail if the PR does not match', done => {
bv.verify(pr, createAuthHeader({'pull-request': 1337})).catch(err => {
const errorMessage = 'Error while verifying upload for PR 9: ' +
`jwt pull-request invalid. expected: ${pr}`;
expectToBeUploadError(err, 403, errorMessage);
done();
});
});
it('should not fail if the token is valid', done => {
bv.verify(pr, createAuthHeader()).then(done);
});
it('should not fail even if the token has been issued in the future', done => {
const in30s = Math.floor(Date.now() / 1000) + 30;
bv.verify(pr, createAuthHeader({iat: in30s})).then(done);
});
it('should call \'getPrIsTrusted()\' if the token is valid', done => {
bv.verify(pr, createAuthHeader()).then(() => {
expect(bvGetPrIsTrusted).toHaveBeenCalledWith(pr);
done();
});
});
it('should fail if \'getPrIsTrusted()\' rejects', done => {
bvGetPrIsTrusted.and.callFake(() => Promise.reject('Test'));
bv.verify(pr, createAuthHeader()).catch(err => {
expectToBeUploadError(err, 403, `Error while verifying upload for PR ${pr}: Test`);
done();
});
});
it('should resolve to `verifiedNotTrusted` if \'getPrIsTrusted()\' returns false', done => {
bvGetPrIsTrusted.and.returnValue(Promise.resolve(false));
bv.verify(pr, createAuthHeader()).then(value => {
expect(value).toBe(BUILD_VERIFICATION_STATUS.verifiedNotTrusted);
done();
});
});
it('should resolve to `verifiedAndTrusted` if \'getPrIsTrusted()\' returns true', done => {
bv.verify(pr, createAuthHeader()).then(value => {
expect(value).toBe(BUILD_VERIFICATION_STATUS.verifiedAndTrusted);
done();
});
});
});
});

View File

@ -0,0 +1,11 @@
import {UploadError} from '../../lib/upload-server/upload-error';
export const expectToBeUploadError = (actual: UploadError, status?: number, message?: string) => {
expect(actual).toEqual(jasmine.any(UploadError));
if (status != null) {
expect(actual.status).toBe(status);
}
if (message != null) {
expect(actual.message).toBe(message);
}
};

View File

@ -0,0 +1,39 @@
// Imports
import {UploadError} from '../../lib/upload-server/upload-error';
// Tests
describe('UploadError', () => {
let err: UploadError;
beforeEach(() => err = new UploadError(999, 'message'));
it('should extend Error', () => {
expect(err).toEqual(jasmine.any(UploadError));
expect(err).toEqual(jasmine.any(Error));
expect(Object.getPrototypeOf(err)).toBe(UploadError.prototype);
});
it('should have a \'status\' property', () => {
expect(err.status).toBe(999);
});
it('should have a \'message\' property', () => {
expect(err.message).toBe('message');
});
it('should have a 500 \'status\' by default', () => {
expect(new UploadError().status).toBe(500);
});
it('should have an empty \'message\' by default', () => {
expect(new UploadError().message).toBe('');
expect(new UploadError(999).message).toBe('');
});
});

View File

@ -0,0 +1,603 @@
// Imports
import * as express from 'express';
import * as http from 'http';
import * as supertest from 'supertest';
import {GithubPullRequests} from '../../lib/common/github-pull-requests';
import {BuildCreator} from '../../lib/upload-server/build-creator';
import {ChangedPrVisibilityEvent, CreatedBuildEvent} from '../../lib/upload-server/build-events';
import {BUILD_VERIFICATION_STATUS, BuildVerifier} from '../../lib/upload-server/build-verifier';
import {uploadServerFactory as usf} from '../../lib/upload-server/upload-server-factory';
// Tests
describe('uploadServerFactory', () => {
const defaultConfig = {
buildsDir: 'builds/dir',
domainName: 'domain.name',
githubOrganization: 'organization',
githubTeamSlugs: ['team1', 'team2'],
githubToken: '12345',
repoSlug: 'repo/slug',
secret: 'secret',
trustedPrLabel: 'trusted: pr-label',
};
// Helpers
const createUploadServer = (partialConfig: Partial<typeof defaultConfig> = {}) =>
usf.create({...defaultConfig, ...partialConfig} as typeof defaultConfig);
describe('create()', () => {
let usfCreateMiddlewareSpy: jasmine.Spy;
beforeEach(() => {
usfCreateMiddlewareSpy = spyOn(usf as any, 'createMiddleware').and.callThrough();
});
it('should throw if \'buildsDir\' is missing or empty', () => {
expect(() => createUploadServer({buildsDir: ''})).
toThrowError('Missing or empty required parameter \'buildsDir\'!');
});
it('should throw if \'domainName\' is missing or empty', () => {
expect(() => createUploadServer({domainName: ''})).
toThrowError('Missing or empty required parameter \'domainName\'!');
});
it('should throw if \'githubToken\' is missing or empty', () => {
expect(() => createUploadServer({githubToken: ''})).
toThrowError('Missing or empty required parameter \'githubToken\'!');
});
it('should throw if \'githubOrganization\' is missing or empty', () => {
expect(() => createUploadServer({githubOrganization: ''})).
toThrowError('Missing or empty required parameter \'organization\'!');
});
it('should throw if \'githubTeamSlugs\' is missing or empty', () => {
expect(() => createUploadServer({githubTeamSlugs: []})).
toThrowError('Missing or empty required parameter \'allowedTeamSlugs\'!');
});
it('should throw if \'repoSlug\' is missing or empty', () => {
expect(() => createUploadServer({repoSlug: ''})).
toThrowError('Missing or empty required parameter \'repoSlug\'!');
});
it('should throw if \'secret\' is missing or empty', () => {
expect(() => createUploadServer({secret: ''})).
toThrowError('Missing or empty required parameter \'secret\'!');
});
it('should throw if \'trustedPrLabel\' is missing or empty', () => {
expect(() => createUploadServer({trustedPrLabel: ''})).
toThrowError('Missing or empty required parameter \'trustedPrLabel\'!');
});
it('should return an http.Server', () => {
const httpCreateServerSpy = spyOn(http, 'createServer').and.callThrough();
const server = createUploadServer();
expect(server).toBe(httpCreateServerSpy.calls.mostRecent().returnValue);
});
it('should create and use an appropriate BuildCreator', () => {
const usfCreateBuildCreatorSpy = spyOn(usf as any, 'createBuildCreator').and.callThrough();
createUploadServer();
const buildCreator: BuildCreator = usfCreateBuildCreatorSpy.calls.mostRecent().returnValue;
expect(usfCreateMiddlewareSpy).toHaveBeenCalledWith(jasmine.any(BuildVerifier), buildCreator);
expect(usfCreateBuildCreatorSpy).toHaveBeenCalledWith('builds/dir', '12345', 'repo/slug', 'domain.name');
});
it('should create and use an appropriate middleware', () => {
const httpCreateServerSpy = spyOn(http, 'createServer').and.callThrough();
createUploadServer();
const middleware: express.Express = usfCreateMiddlewareSpy.calls.mostRecent().returnValue;
const buildVerifier = jasmine.any(BuildVerifier);
const buildCreator = jasmine.any(BuildCreator);
expect(httpCreateServerSpy).toHaveBeenCalledWith(middleware);
expect(usfCreateMiddlewareSpy).toHaveBeenCalledWith(buildVerifier, buildCreator);
});
it('should log the server address info on \'listening\'', () => {
const consoleInfoSpy = spyOn(console, 'info');
const server = createUploadServer();
server.address = () => ({address: 'foo', family: '', port: 1337});
expect(consoleInfoSpy).not.toHaveBeenCalled();
server.emit('listening');
expect(consoleInfoSpy).toHaveBeenCalledWith('Up and running (and listening on foo:1337)...');
});
});
// Protected methods
describe('createBuildCreator()', () => {
let buildCreator: BuildCreator;
beforeEach(() => {
buildCreator = (usf as any).createBuildCreator(
defaultConfig.buildsDir,
defaultConfig.githubToken,
defaultConfig.repoSlug,
defaultConfig.domainName,
);
});
it('should pass the \'buildsDir\' to the BuildCreator', () => {
expect((buildCreator as any).buildsDir).toBe('builds/dir');
});
describe('on \'build.created\'', () => {
let prsAddCommentSpy: jasmine.Spy;
beforeEach(() => prsAddCommentSpy = spyOn(GithubPullRequests.prototype, 'addComment'));
it('should post a comment on GitHub for public previews', () => {
const commentBody = 'You can preview 1234567890 at https://pr42-1234567890.domain.name/.';
buildCreator.emit(CreatedBuildEvent.type, {pr: 42, sha: '1234567890', isPublic: true});
expect(prsAddCommentSpy).toHaveBeenCalledWith(42, commentBody);
});
it('should not post a comment on GitHub for non-public previews', () => {
buildCreator.emit(CreatedBuildEvent.type, {pr: 42, sha: '1234567890', isPublic: false});
expect(prsAddCommentSpy).not.toHaveBeenCalled();
});
});
describe('on \'pr.changedVisibility\'', () => {
let prsAddCommentSpy: jasmine.Spy;
beforeEach(() => prsAddCommentSpy = spyOn(GithubPullRequests.prototype, 'addComment'));
it('should post a comment on GitHub (for all SHAs) for PRs made public', () => {
const commentBody = 'You can preview 12345 at https://pr42-12345.domain.name/.\n' +
'You can preview 67890 at https://pr42-67890.domain.name/.';
buildCreator.emit(ChangedPrVisibilityEvent.type, {pr: 42, shas: ['12345', '67890'], isPublic: true});
expect(prsAddCommentSpy).toHaveBeenCalledWith(42, commentBody);
});
it('should not post a comment on GitHub if no SHAs were affected', () => {
buildCreator.emit(ChangedPrVisibilityEvent.type, {pr: 42, shas: [], isPublic: true});
expect(prsAddCommentSpy).not.toHaveBeenCalled();
});
it('should not post a comment on GitHub for PRs made non-public', () => {
buildCreator.emit(ChangedPrVisibilityEvent.type, {pr: 42, shas: ['12345', '67890'], isPublic: false});
expect(prsAddCommentSpy).not.toHaveBeenCalled();
});
});
it('should pass the correct \'githubToken\' and \'repoSlug\' to GithubPullRequests', () => {
const prsAddCommentSpy = spyOn(GithubPullRequests.prototype, 'addComment');
buildCreator.emit(CreatedBuildEvent.type, {pr: 42, sha: '1234567890', isPublic: true});
buildCreator.emit(ChangedPrVisibilityEvent.type, {pr: 42, shas: ['12345', '67890'], isPublic: true});
const allCalls = prsAddCommentSpy.calls.all();
const prs = allCalls[0].object;
expect(prsAddCommentSpy).toHaveBeenCalledTimes(2);
expect(prs).toBe(allCalls[1].object);
expect(prs).toEqual(jasmine.any(GithubPullRequests));
expect(prs.repoSlug).toBe('repo/slug');
expect(prs.requestHeaders.Authorization).toContain('12345');
});
});
describe('createMiddleware()', () => {
let buildVerifier: BuildVerifier;
let buildCreator: BuildCreator;
let agent: supertest.SuperTest<supertest.Test>;
// Helpers
const promisifyRequest = (req: supertest.Request) =>
new Promise((resolve, reject) => req.end(err => err ? reject(err) : resolve()));
const verifyRequests = (reqs: supertest.Request[], done: jasmine.DoneFn) =>
Promise.all(reqs.map(promisifyRequest)).then(done, done.fail);
beforeEach(() => {
buildVerifier = new BuildVerifier(
defaultConfig.secret,
defaultConfig.githubToken,
defaultConfig.repoSlug,
defaultConfig.githubOrganization,
defaultConfig.githubTeamSlugs,
defaultConfig.trustedPrLabel,
);
buildCreator = new BuildCreator(defaultConfig.buildsDir);
agent = supertest.agent((usf as any).createMiddleware(buildVerifier, buildCreator));
spyOn(console, 'error');
});
describe('GET /create-build/<pr>/<sha>', () => {
const pr = '9';
const sha = '9'.repeat(40);
let buildVerifierVerifySpy: jasmine.Spy;
let buildCreatorCreateSpy: jasmine.Spy;
beforeEach(() => {
const verStatus = BUILD_VERIFICATION_STATUS.verifiedAndTrusted;
buildVerifierVerifySpy = spyOn(buildVerifier, 'verify').and.returnValue(Promise.resolve(verStatus));
buildCreatorCreateSpy = spyOn(buildCreator, 'create').and.returnValue(Promise.resolve());
});
it('should respond with 404 for non-GET requests', done => {
verifyRequests([
agent.put(`/create-build/${pr}/${sha}`).expect(404),
agent.post(`/create-build/${pr}/${sha}`).expect(404),
agent.patch(`/create-build/${pr}/${sha}`).expect(404),
agent.delete(`/create-build/${pr}/${sha}`).expect(404),
], done);
});
it('should respond with 401 for requests without an \'AUTHORIZATION\' header', done => {
const url = `/create-build/${pr}/${sha}`;
const responseBody = `Missing or empty 'AUTHORIZATION' header in request: GET ${url}`;
verifyRequests([
agent.get(url).expect(401, responseBody),
agent.get(url).set('AUTHORIZATION', '').expect(401, responseBody),
], done);
});
it('should respond with 400 for requests without an \'X-FILE\' header', done => {
const url = `/create-build/${pr}/${sha}`;
const responseBody = `Missing or empty 'X-FILE' header in request: GET ${url}`;
const request1 = agent.get(url).set('AUTHORIZATION', 'foo');
const request2 = agent.get(url).set('AUTHORIZATION', 'foo').set('X-FILE', '');
verifyRequests([
request1.expect(400, responseBody),
request2.expect(400, responseBody),
], done);
});
it('should respond with 404 for unknown paths', done => {
verifyRequests([
agent.get(`/foo/create-build/${pr}/${sha}`).expect(404),
agent.get(`/foo-create-build/${pr}/${sha}`).expect(404),
agent.get(`/fooncreate-build/${pr}/${sha}`).expect(404),
agent.get(`/create-build/foo/${pr}/${sha}`).expect(404),
agent.get(`/create-build-foo/${pr}/${sha}`).expect(404),
agent.get(`/create-buildnfoo/${pr}/${sha}`).expect(404),
agent.get(`/create-build/pr${pr}/${sha}`).expect(404),
agent.get(`/create-build/${pr}/${sha}42`).expect(404),
], done);
});
it('should call \'BuildVerifier#verify()\' with the correct arguments', done => {
const req = agent.
get(`/create-build/${pr}/${sha}`).
set('AUTHORIZATION', 'foo').
set('X-FILE', 'bar');
promisifyRequest(req).
then(() => expect(buildVerifierVerifySpy).toHaveBeenCalledWith(9, 'foo')).
then(done, done.fail);
});
it('should propagate errors from BuildVerifier', done => {
buildVerifierVerifySpy.and.callFake(() => Promise.reject('Test'));
const req = agent.
get(`/create-build/${pr}/${sha}`).
set('AUTHORIZATION', 'foo').
set('X-FILE', 'bar').
expect(500, 'Test');
promisifyRequest(req).
then(() => {
expect(buildVerifierVerifySpy).toHaveBeenCalledWith(9, 'foo');
expect(buildCreatorCreateSpy).not.toHaveBeenCalled();
}).
then(done, done.fail);
});
it('should call \'BuildCreator#create()\' with the correct arguments', done => {
buildVerifierVerifySpy.and.returnValues(
Promise.resolve(BUILD_VERIFICATION_STATUS.verifiedAndTrusted),
Promise.resolve(BUILD_VERIFICATION_STATUS.verifiedNotTrusted));
const req1 = agent.get(`/create-build/${pr}/${sha}`).set('AUTHORIZATION', 'foo').set('X-FILE', 'bar');
const req2 = agent.get(`/create-build/${pr}/${sha}`).set('AUTHORIZATION', 'foo').set('X-FILE', 'bar');
Promise.all([
promisifyRequest(req1).then(() => expect(buildCreatorCreateSpy).toHaveBeenCalledWith(pr, sha, 'bar', true)),
promisifyRequest(req2).then(() => expect(buildCreatorCreateSpy).toHaveBeenCalledWith(pr, sha, 'bar', false)),
]).then(done, done.fail);
});
it('should propagate errors from BuildCreator', done => {
buildCreatorCreateSpy.and.callFake(() => Promise.reject('Test'));
const req = agent.
get(`/create-build/${pr}/${sha}`).
set('AUTHORIZATION', 'foo').
set('X-FILE', 'bar').
expect(500, 'Test');
verifyRequests([req], done);
});
it('should respond with 201 on successful upload (for public builds)', done => {
const req = agent.
get(`/create-build/${pr}/${sha}`).
set('AUTHORIZATION', 'foo').
set('X-FILE', 'bar').
expect(201, http.STATUS_CODES[201]);
verifyRequests([req], done);
});
it('should respond with 202 on successful upload (for hidden builds)', done => {
buildVerifierVerifySpy.and.returnValue(Promise.resolve(BUILD_VERIFICATION_STATUS.verifiedNotTrusted));
const req = agent.
get(`/create-build/${pr}/${sha}`).
set('AUTHORIZATION', 'foo').
set('X-FILE', 'bar').
expect(202, http.STATUS_CODES[202]);
verifyRequests([req], done);
});
it('should reject PRs with leading zeros', done => {
verifyRequests([agent.get(`/create-build/0${pr}/${sha}`).expect(404)], done);
});
it('should accept SHAs with leading zeros (but not trim the zeros)', done => {
const sha40 = '0'.repeat(40);
const sha41 = `0${sha40}`;
const request40 = agent.get(`/create-build/${pr}/${sha40}`).set('AUTHORIZATION', 'foo').set('X-FILE', 'bar');
const request41 = agent.get(`/create-build/${pr}/${sha41}`).set('AUTHORIZATION', 'baz').set('X-FILE', 'qux');
Promise.all([
promisifyRequest(request40.expect(201)),
promisifyRequest(request41.expect(404)),
]).then(done, done.fail);
});
});
describe('GET /health-check', () => {
it('should respond with 200', done => {
verifyRequests([
agent.get('/health-check').expect(200),
agent.get('/health-check/').expect(200),
], done);
});
it('should respond with 404 for non-GET requests', done => {
verifyRequests([
agent.put('/health-check').expect(404),
agent.post('/health-check').expect(404),
agent.patch('/health-check').expect(404),
agent.delete('/health-check').expect(404),
], done);
});
it('should respond with 404 if the path does not match exactly', done => {
verifyRequests([
agent.get('/health-check/foo').expect(404),
agent.get('/health-check-foo').expect(404),
agent.get('/health-checknfoo').expect(404),
agent.get('/foo/health-check').expect(404),
agent.get('/foo-health-check').expect(404),
agent.get('/foonhealth-check').expect(404),
], done);
});
});
describe('POST /pr-updated', () => {
const pr = '9';
const url = '/pr-updated';
let bvGetPrIsTrustedSpy: jasmine.Spy;
let bcUpdatePrVisibilitySpy: jasmine.Spy;
// Helpers
const createRequest = (num: number, action?: string) =>
agent.post(url).send({number: num, action});
beforeEach(() => {
bvGetPrIsTrustedSpy = spyOn(buildVerifier, 'getPrIsTrusted');
bcUpdatePrVisibilitySpy = spyOn(buildCreator, 'updatePrVisibility');
});
it('should respond with 404 for non-POST requests', done => {
verifyRequests([
agent.get(url).expect(404),
agent.put(url).expect(404),
agent.patch(url).expect(404),
agent.delete(url).expect(404),
], done);
});
it('should respond with 400 for requests without a payload', done => {
const responseBody = `Missing or empty 'number' field in request: POST ${url} {}`;
const request1 = agent.post(url);
const request2 = agent.post(url).send();
verifyRequests([
request1.expect(400, responseBody),
request2.expect(400, responseBody),
], done);
});
it('should respond with 400 for requests without a \'number\' field', done => {
const responseBodyPrefix = `Missing or empty 'number' field in request: POST ${url}`;
const request1 = agent.post(url).send({});
const request2 = agent.post(url).send({number: null});
verifyRequests([
request1.expect(400, `${responseBodyPrefix} {}`),
request2.expect(400, `${responseBodyPrefix} {"number":null}`),
], done);
});
it('should call \'BuildVerifier#gtPrIsTrusted()\' with the correct arguments', done => {
const req = createRequest(+pr);
promisifyRequest(req).
then(() => expect(bvGetPrIsTrustedSpy).toHaveBeenCalledWith(9)).
then(done, done.fail);
});
it('should propagate errors from BuildVerifier', done => {
bvGetPrIsTrustedSpy.and.callFake(() => Promise.reject('Test'));
const req = createRequest(+pr).expect(500, 'Test');
promisifyRequest(req).
then(() => {
expect(bvGetPrIsTrustedSpy).toHaveBeenCalledWith(9);
expect(bcUpdatePrVisibilitySpy).not.toHaveBeenCalled();
}).
then(done, done.fail);
});
it('should call \'BuildCreator#updatePrVisibility()\' with the correct arguments', done => {
bvGetPrIsTrustedSpy.and.callFake((pr2: number) => Promise.resolve(pr2 === 42));
const req1 = createRequest(24);
const req2 = createRequest(42);
Promise.all([
promisifyRequest(req1).then(() => expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledWith('24', false)),
promisifyRequest(req2).then(() => expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledWith('42', true)),
]).then(done, done.fail);
});
it('should propagate errors from BuildCreator', done => {
bcUpdatePrVisibilitySpy.and.callFake(() => Promise.reject('Test'));
const req = createRequest(+pr).expect(500, 'Test');
verifyRequests([req], done);
});
describe('on success', () => {
it('should respond with 200 (action: undefined)', done => {
bvGetPrIsTrustedSpy.and.returnValues(Promise.resolve(true), Promise.resolve(false));
const reqs = [4, 2].map(num => createRequest(num).expect(200, http.STATUS_CODES[200]));
verifyRequests(reqs, done);
});
it('should respond with 200 (action: labeled)', done => {
bvGetPrIsTrustedSpy.and.returnValues(Promise.resolve(true), Promise.resolve(false));
const reqs = [4, 2].map(num => createRequest(num, 'labeled').expect(200, http.STATUS_CODES[200]));
verifyRequests(reqs, done);
});
it('should respond with 200 (action: unlabeled)', done => {
bvGetPrIsTrustedSpy.and.returnValues(Promise.resolve(true), Promise.resolve(false));
const reqs = [4, 2].map(num => createRequest(num, 'unlabeled').expect(200, http.STATUS_CODES[200]));
verifyRequests(reqs, done);
});
it('should respond with 200 (and do nothing) if \'action\' implies no visibility change', done => {
const promises = ['foo', 'notlabeled'].
map(action => createRequest(+pr, action).expect(200, http.STATUS_CODES[200])).
map(promisifyRequest);
Promise.all(promises).
then(() => {
expect(bvGetPrIsTrustedSpy).not.toHaveBeenCalled();
expect(bcUpdatePrVisibilitySpy).not.toHaveBeenCalled();
}).
then(done, done.fail);
});
});
});
describe('ALL *', () => {
it('should respond with 404', done => {
const responseFor = (method: string) => `Unknown resource in request: ${method.toUpperCase()} /some/url`;
verifyRequests([
agent.get('/some/url').expect(404, responseFor('get')),
agent.put('/some/url').expect(404, responseFor('put')),
agent.post('/some/url').expect(404, responseFor('post')),
agent.patch('/some/url').expect(404, responseFor('patch')),
agent.delete('/some/url').expect(404, responseFor('delete')),
], done);
});
});
});
});

View File

@ -0,0 +1,69 @@
{
"compilerOptions": {
/* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": [
"es2015",
"es2016.array.include"
], /* Specify library files to be included in the compilation: */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "dist", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
"importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
"typeRoots": [
"node_modules/@types"
], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
/* Source Map Options */
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
"inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Other */
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
"newLine": "LF", /* Use the specified end of line sequence to be used when emitting files: "crlf" (windows) or "lf" (unix). */
"pretty": true, /* Stylize errors and messages using color and context. */
"skipLibCheck": true /* Skip type checking of all declaration files (*.d.ts). */
},
"include": [
"lib/**/*",
"test/**/*"
]
}

View File

@ -0,0 +1,24 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {},
"rules": {
"array-type": [true, "array"],
"arrow-parens": [true, "ban-single-arg-parens"],
"interface-name": [true, "never-prefix"],
"max-classes-per-file": [true, 4],
"no-consecutive-blank-lines": [true, 2],
"no-console": [false],
"no-focused-test": true,
"no-namespace": [true, "allow-declarations"],
"no-skipped-test": true,
"no-string-literal": false,
"quotemark": [true, "single"],
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"]
},
"rulesDirectory": [
"node_modules/tslint-jasmine-noSkipOrFocus"
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
#!/bin/bash
set -eu -o pipefail
# Set up env variables
export AIO_GITHUB_TOKEN=$(head -c -1 /aio-secrets/GITHUB_TOKEN 2>/dev/null)
# Run the clean-up
node $AIO_SCRIPTS_JS_DIR/dist/lib/clean-up >> /var/log/aio/clean-up.log 2>&1

View File

@ -0,0 +1,54 @@
#!/bin/bash
# Using `+e` so that all checks are run and we get a complete report (even if some checks failed).
set +e -u -o pipefail
# Variables
exitCode=0
# Helpers
function reportStatus {
local lastExitCode=$?
echo "$1: $([[ $lastExitCode -eq 0 ]] && echo OK || echo NOT OK)"
[[ $lastExitCode -eq 0 ]] || exitCode=1
}
# Check services
services=(
rsyslog
cron
nginx
pm2-root
)
for s in ${services[@]}; do
service $s status > /dev/null
reportStatus "Service '$s'"
done
# Check servers
origins=(
http://$AIO_UPLOAD_HOSTNAME:$AIO_UPLOAD_PORT
http://$AIO_NGINX_HOSTNAME:$AIO_NGINX_PORT_HTTP
https://$AIO_NGINX_HOSTNAME:$AIO_NGINX_PORT_HTTPS
)
for o in ${origins[@]}; do
curl --fail --silent $o/health-check > /dev/null
reportStatus "Server '$o'"
done
# Check resolution of external URLs
origins=(
https://google.com
)
for o in ${origins[@]}; do
curl --fail --silent $o > /dev/null
reportStatus "External URL '$o'"
done
# Exit
exit $exitCode

View File

@ -0,0 +1,18 @@
#!/bin/bash
set -eu -o pipefail
exec >> /var/log/aio/init.log
exec 2>&1
# Start the services
echo [`date`] - Starting services...
mkdir -p $AIO_NGINX_LOGS_DIR
mkdir -p $TEST_AIO_NGINX_LOGS_DIR
service rsyslog start
service cron start
service dnsmasq start
service nginx start
service pm2-root start
aio-upload-server-prod start
echo [`date`] - Services started successfully.

View File

@ -0,0 +1,14 @@
#!/bin/bash
set -eu -o pipefail
# Set up env variables for production
export AIO_GITHUB_TOKEN=$(head -c -1 /aio-secrets/GITHUB_TOKEN 2>/dev/null || echo "MISSING_GITHUB_TOKEN")
export AIO_PREVIEW_DEPLOYMENT_TOKEN=$(head -c -1 /aio-secrets/PREVIEW_DEPLOYMENT_TOKEN 2>/dev/null || echo "MISSING_PREVIEW_DEPLOYMENT_TOKEN")
# Start the upload-server instance
action=$([ "$1" == "stop" ] && echo "stop" || echo "start")
pm2 $action $AIO_SCRIPTS_JS_DIR/dist/lib/upload-server \
--uid $AIO_WWW_USER \
--log /var/log/aio/upload-server-prod.log \
--name aio-upload-server-prod \
${@:2}

View File

@ -0,0 +1,28 @@
#!/bin/bash
set -eu -o pipefail
# Set up env variables for testing
export AIO_BUILDS_DIR=$TEST_AIO_BUILDS_DIR
export AIO_DOMAIN_NAME=$TEST_AIO_DOMAIN_NAME
export AIO_GITHUB_ORGANIZATION=$TEST_AIO_GITHUB_ORGANIZATION
export AIO_GITHUB_TEAM_SLUGS=$TEST_AIO_GITHUB_TEAM_SLUGS
export AIO_REPO_SLUG=$TEST_AIO_REPO_SLUG
export AIO_TRUSTED_PR_LABEL=$TEST_AIO_TRUSTED_PR_LABEL
export AIO_UPLOAD_HOSTNAME=$TEST_AIO_UPLOAD_HOSTNAME
export AIO_UPLOAD_PORT=$TEST_AIO_UPLOAD_PORT
export AIO_GITHUB_TOKEN=$(head -c -1 /aio-secrets/TEST_GITHUB_TOKEN 2>/dev/null || echo "TEST_GITHUB_TOKEN")
export AIO_PREVIEW_DEPLOYMENT_TOKEN=$(head -c -1 /aio-secrets/TEST_PREVIEW_DEPLOYMENT_TOKEN 2>/dev/null || echo "TEST_PREVIEW_DEPLOYMENT_TOKEN")
# Start the upload-server instance
appName=aio-upload-server-test
if [[ "$1" == "stop" ]]; then
pm2 delete $appName
else
pm2 start $AIO_SCRIPTS_JS_DIR/dist/lib/verify-setup/start-test-upload-server.js \
--uid $AIO_WWW_USER \
--log /var/log/aio/upload-server-test.log \
--name $appName \
--no-autorestart \
${@:2}
fi

View File

@ -0,0 +1,40 @@
#!/bin/bash
set -eu -o pipefail
logFile=/var/log/aio/verify-setup.log
uploadServerLogFile=/var/log/aio/upload-server-verify-setup.log
exec 3>&1
exec >> $logFile
exec 2>&1
echo "[`date`] - Starting verification..."
# Helpers
function countdown {
message=$1
secs=$2
while [ $secs -gt 0 ]; do
echo -ne "$message in $secs...\033[0K\r"
sleep 1
: $((secs--))
done
echo -ne "\033[0K\r"
}
function onExit {
aio-upload-server-test stop
echo -e "Full logs in '$logFile'.\n" > /dev/fd/3
}
# Setup EXIT trap
trap 'onExit' EXIT
# Start an upload-server instance for testing
aio-upload-server-test start --log $uploadServerLogFile
# Give the upload-server some time to start :(
countdown "Starting" 5 > /dev/fd/3
# Run the tests
node $AIO_SCRIPTS_JS_DIR/dist/lib/verify-setup | tee /dev/fd/3

View File

@ -0,0 +1,33 @@
# VM Setup Instructions
## Overview
- [General overview](overview--general.md)
- [Security model](overview--security-model.md)
- [Available scripts and commands](overview--scripts-and-commands.md)
- [HTTP status codes](overview--http-status-codes.md)
## Setting up the VM
- [Set up secrets](vm-setup--set-up-secrets.md)
- [Set up docker](vm-setup--set-up-docker.md)
- [Attach persistent disk](vm-setup--attach-persistent-disk.md)
- [Create host directories and files](vm-setup--create-host-dirs-and-files.md)
- [Create docker image](vm-setup--create-docker-image.md)
## Configuring the docker image
- [Available environment variables](image-config--environment-variables.md)
## Starting the docker container
- [Start docker container](vm-setup--start-docker-container.md)
## Updating the docker container
- [Update docker container](vm-setup--update-docker-container.md)
## Miscellaneous
- [Debug docker container](misc--debug-docker-container.md)
- [Integrate with CI](misc--integrate-with-ci.md)

View File

@ -0,0 +1,57 @@
# Image config - Environment variables
Below is a list of environment variables that can be configured when creating the docker image (as
described [here](vm-setup--create-docker-image.md)). An up-to-date list of the configurable
environment variables and their default values can be found in the
[Dockerfile](../dockerbuild/Dockerfile).
**Note:**
Each variable has a `TEST_` prefixed counterpart, which is used for testing purposes. In most cases
you don't need to specify values for those.
- `AIO_BUILDS_DIR`:
The directory (inside the container) where the uploaded build artifacts are kept.
- `AIO_DOMAIN_NAME`:
The domain name of the server.
- `AIO_GITHUB_ORGANIZATION`:
The GitHub organization whose teams are whitelisted for accepting uploads.
See also `AIO_GITHUB_TEAM_SLUGS`.
- `AIO_GITHUB_TEAM_SLUGS`:
A comma-separated list of teams, whose authors are allowed to upload PRs.
See also `AIO_GITHUB_ORGANIZATION`.
- `AIO_NGINX_HOSTNAME`:
The internal hostname for accessing the nginx server. This is mostly used for performing a
periodic health-check.
- `AIO_NGINX_PORT_HTTP`:
The port number on which nginx listens for HTTP connections. This should be mapped to the
corresponding port on the host VM (as described [here](vm-setup--start-docker-container.md)).
- `AIO_NGINX_PORT_HTTPS`:
The port number on which nginx listens for HTTPS connections. This should be mapped to the
corresponding port on the host VM (as described [here](vm-setup--start-docker-container.md)).
- `AIO_REPO_SLUG`:
The repository slug (in the form `<user>/<repo>`) for which PRs will be uploaded.
- `AIO_TRUSTED_PR_LABEL`:
The PR whose presence indicates the PR has been manually verified and is allowed to have its
build artifacts publicly served. This is useful for enabling previews for any PR (not only those
from trusted authors).
- `AIO_UPLOAD_HOSTNAME`:
The internal hostname for accessing the Node.js upload-server. This is used by nginx for
delegating upload requests and also for performing a periodic health-check.
- `AIO_UPLOAD_MAX_SIZE`:
The maximum allowed size for the uploaded gzip archive containing the build artifacts. Files
larger than this will be rejected.
- `AIO_UPLOAD_PORT`:
The port number on which the Node.js upload-server listens for HTTP connections. This is used by
nginx for delegating upload requests and also for performing a periodic health-check.

View File

@ -0,0 +1,12 @@
# Miscellaneous - Debug docker container
TODO (gkalpak): Add docs. Mention:
- `aio-health-check`
- `aio-verify-setup`
- Test nginx accessible at:
- `http://$TEST_AIO_NGINX_HOTNAME:$TEST_AIO_NGINX_PORT_HTTP`
- `https://$TEST_AIO_NGINX_HOTNAME:$TEST_AIO_NGINX_PORT_HTTPS`
- Test upload-server accessible at:
- `http://$TEST_AIO_UPLOAD_HOTNAME:$TEST_AIO_UPLOAD_PORT`
- Local DNS (via dnsmasq) maps the above hostnames to 127.0.0.1

View File

@ -0,0 +1,11 @@
# Miscellaneous - Integrate with CI
TODO (gkalpak): Add docs. Mention:
- Travis' JWT addon (+ limitations).
Relevant files: `.travis.yml`, `scripts/ci/env.sh`
- Testing on CI.
Relevant files: `scripts/ci/test-aio.sh`, `aio/aio-builds-setup/scripts/test.sh`
- Deploying from CI.
Relevant files: `scripts/ci/deploy.sh`, `aio/scripts/deploy-preview.sh`,
`aio/scripts/deploy-to-firebase.sh`

View File

@ -0,0 +1,120 @@
# Overview - General
## Objective
Whenever a PR job is run on Travis, we want to build `angular.io` and upload the build artifacts to
a publicly accessible server so that collaborators (developers, designers, authors, etc) can preview
the changes without having to checkout and build the app locally.
## Source code
In order to make it easier to administer the server and version-control the setup, we are using
[docker](https://www.docker.com) to run a container on a VM. The Dockerfile and all other files
necessary for creating the docker container are stored (and versioned) along with the angular.io
project's source code (currently part of the angular/angular repo) in the `aio-builds-setup/`
directory.
## Setup
The VM is hosted on [Google Compute Engine](https://cloud.google.com/compute/). The host OS is
debian:jessie. For more info how to set up the host VM take a look at the "Setting up the VM"
section in [TOC](_TOC.md).
## Security model
Since we are managing a public server, it is important to take appropriate measures in order to
prevent abuse. For more details on the challenges and the chosen approach take a look at the
[security model](overview--security-model.md).
## The 10000 feet view
This section gives a brief summary of the several operations performed on CI and by the docker
container:
### On CI (Travis)
- Build job completes successfully.
- The CI script checks whether the build job was initiated by a PR against the angular/angular
master branch.
- The CI script checks whether the PR has touched any files that might affect the angular.io app
(currently the `aio/` or `packages/` directories, ignoring spec files).
- Optionally, the CI script can check whether the PR can be automatically verified (i.e. if the
author of the PR is a member of one of the whitelisted GitHub teams or the PR has the specified
"trusted PR" label).
**Note:**
For security reasons, the same checks will be performed on the server as well. This is an optional
step that can be used in case one wants to apply special logic depending on the outcome of the
pre-verification. For example:
1. One might want to deploy automatically verified PRs only. In that case, the pre-verification
helps avoid the wasted overhead associated with uploads that are going to be rejected (e.g.
building the artifacts, sending them to the server, running checks on the server, detecting the
reasons of deployment failure and whether to fail the build, etc).
2. One might want to apply additional logic (e.g. different tests) depending on whether the PR is
automatically verified or not).
- The CI script gzips and uploads the build artifacts to the server.
More info on how to set things up on CI can be found [here](misc--integrate-with-ci.md).
### Uploading build artifacts
- nginx receives the upload request.
- nginx checks that the uploaded gzip archive does not exceed the specified max file size, stores it
in a temporary location and passes the filepath to the Node.js upload-server.
- The upload-server runs several checks to determine whether the request should be accepted and
whether it should be publicly accessible or stored for later verification (more details can be
found [here](overview--security-model.md)).
- The upload-server changes the "visibility" of the associated PR, if necessary. For example, if
builds for the same PR had been previously deployed as non-public and the current build has been
automatically verified, all previous builds are made public as well.
If the PR transitions from "non-public" to "public", the upload-server posts a comment on the
corresponding PR on GitHub mentioning the SHAs and the links where the previews can be found.
- The upload-server verifies that the uploaded file is not trying to overwrite an existing build.
- The upload-server deploys the artifacts to a sub-directory named after the PR number and the first
few characters of the SHA: `<PR>/<SHA>/`
(Non-publicly accessible PRs will be stored in a different location, but again derived from the PR
number and SHA.)
- If the PR is publicly accessible, the upload-server posts a comment on the corresponding PR on
GitHub mentioning the SHA and the link where the preview can be found.
More info on the possible HTTP status codes and their meaning can be found
[here](overview--http-status-codes.md).
### Updating PR visibility
- nginx receives a natification that a PR has been updated and passes it through to the
upload-server. This could, for example, be sent by a GitHub webhook every time a PR's labels
change.
E.g.: `ngbuilds.io/pr-updated` (payload: `{"number":<PR>,"action":"labeled"}`)
- The request contains the PR number (as `number`) and optionally the action that triggered the
request (as `action`) in the payload.
- The upload-server verifies the payload and determines whether the `action` (if specified) could
have led to PR visibility changes. Only requests that omit the `action` field altogether or
specify an action that can affect visibility are further processed.
(Currently, the only actions that are considered capable of affecting visibility are `labeled` and
`unlabeled`.)
- The upload-server re-checks and if necessary updates the PR's visibility.
More info on the possible HTTP status codes and their meaning can be found
[here](overview--http-status-codes.md).
### Serving build artifacts
- nginx receives a request for an uploaded resource on a subdomain corresponding to the PR and SHA.
E.g.: `pr<PR>-<SHA>.ngbuilds.io/path/to/resource`
- nginx maps the subdomain to the correct sub-directory and serves the resource.
E.g.: `/<PR>/<SHA>/path/to/resource`
More info on the possible HTTP status codes and their meaning can be found
[here](overview--http-status-codes.md).
### Removing obsolete artifacts
In order to avoid flooding the disk with unnecessary build artifacts, there is a cronjob that runs a
clean-up tasks once a day. The task retrieves all open PRs from GitHub and removes all directories
that do not correspond with an open PR.
### Health-check
The docker service runs a periodic health-check that verifies the running conditions of the
container. This includes verifying the status of specific system services, the responsiveness of
nginx and the upload-server and internet connectivity.

View File

@ -0,0 +1,85 @@
# Overview - HTTP Status Codes
This is a list of all the possible HTTP status codes returned by the nginx anf upload servers, along
with a bried explanation of what they mean:
## `http://*.ngbuilds.io/*`
- **307 (Temporary Redirect)**:
All non-HTTPS requests. 308 (Permanent Redirect) would be more appropriate, but is not supported
by all agents (e.g. cURL).
## `https://pr<pr>-<sha>.ngbuilds.io/*`
- **200 (OK)**:
File was found or URL was rewritten to `/index.html` (i.e. all paths that have no `.` in final
segment).
- **403 (Forbidden)**:
Trying to access a sub-directory.
- **404 (Not Found)**:
File not found.
## `https://ngbuilds.io/create-build/<pr>/<sha>`
- **201 (Created)**:
Build deployed successfully and is publicly available.
- **202 (Accepted)**:
Build not automatically verifiable. Stored for later deployment (after re-verification).
- **400 (Bad Request)**:
No payload.
- **401 (Unauthorized)**:
No `AUTHORIZATION` header.
- **403 (Forbidden)**:
Unable to verify build (e.g. invalid JWT token, or unable to talk to 3rd-party APIs, etc).
- **405 (Method Not Allowed)**:
Request method other than POST.
- **409 (Conflict)**:
Request to overwrite existing (public or non-public) directory (e.g. deploy existing build or
change PR visibility when the destination directory does already exist).
- **413 (Payload Too Large)**:
Payload larger than size specified in `AIO_UPLOAD_MAX_SIZE`.
## `https://ngbuilds.io/health-check`
- **200 (OK)**:
The server is healthy (i.e. up and running and processing requests).
## `https://ngbuilds.io/pr-updated`
- **200 (OK)**:
Request processed successfully. Processing may or may not have resulted in further actions.
- **400 (Bad Request)**:
No payload or no `number` field in payload.
- **405 (Method Not Allowed)**:
Request method other than POST.
- **409 (Conflict)**:
Request to overwrite existing (public or non-public) directory (i.e. directories for both
visibilities exist).
(Normally, this should not happen.)
## `https://*.ngbuilds.io/*`
- **404 (Not Found)**:
Request not matched by the above rules.
- **500 (Internal Server Error)**:
Error while processing a request matched by the above rules.

View File

@ -0,0 +1,53 @@
# Overview - Scripts and Commands
This is an overview of the available scripts and commands.
## Scripts
The scripts are located inside `<aio-builds-setup-dir>/scripts/`. The following scripts are
available:
- `create-image.sh`:
Can be used for creating a preconfigured docker image.
See [here](vm-setup--create-docker-image.md) for more info.
- `test.sh`:
Can be used for running the tests for `<aio-builds-setup-dir>/dockerbuild/scripts-js/`. This is
useful for CI integration. See [here](misc--integrate-with-ci.md) for more info.
- `update-preview-server.sh`:
Can be used for updating the docker container (and image) based on the latest changes checked out
from a git repository. See [here](vm-setup--update-docker-container.md) for more info.
## Commands
The following commands are available globally from inside the docker container. They are either used
by the container to perform its various operations or can be used ad-hoc, mainly for testing
purposes. Each command is backed by a corresponding script inside
`<aio-builds-setup-dir>/dockerbuild/scripts-sh/`.
- `aio-clean-up`:
Cleans up the builds directory by removing the artifacts that do not correspond to an open PR.
_It is run as a daily cronjob._
- `aio-health-check`:
Runs a basic health-check, verifying that the necessary services are running, the servers are
responding and there is a working internet connection.
_It is used periodically by docker for determining the container's health status._
- `aio-init`:
Initializes the container (mainly by starting the necessary services).
_It is run (by default) when starting the container._
- `aio-upload-server-prod`:
Spins up a Node.js upload-server instance.
_It is used in `aio-init` (see above) during initialization._
- `aio-upload-server-test`:
Spins up a Node.js upload-server instance for tests.
_It is used in `aio-verify-setup` (see below) for running tests._
- `aio-verify-setup`:
Runs a suite of e2e-like tests, mainly verifying the correct (inter)operation of nginx and the
Node.js upload-server.

View File

@ -0,0 +1,138 @@
# Overview - Security model
Whenever a PR job is run on Travis, we want to build `angular.io` and upload the build artifacts to
a publicly accessible server so that collaborators (developers, designers, authors, etc) can preview
the changes without having to checkout and build the app locally.
This document discusses the security considerations associated with uploading build artifacts as
part of the CI setup and serving them publicly.
## Security objectives
- **Prevent uploading arbitrary content to our servers.**
Since there is no restriction on who can submit a PR, we cannot allow any PR's build artifacts to
be uploaded.
- **Prevent overwriting other peoples uploaded content.**
There needs to be a mechanism in place to ensure that the uploaded content does indeed correspond
to the PR indicated by its URL.
- **Prevent arbitrary access on the server.**
Since the PR author has full access over the build artifacts that would be uploaded, we must
ensure that the uploaded files will not enable arbitrary access to the server or expose sensitive
info.
## Issues / Caveats
- Because the PR author can change the scripts run on CI, any security mechanisms must be immune to
such changes.
- For security reasons, encrypted Travis variables are not available to PRs, so we can't rely on
them to implement security.
## Implemented approach
### In a nutshell
The implemented approach can be broken up to the following sub-tasks:
1. Verify which PR the uploaded artifacts correspond to.
2. Fetch the PR's metadata, including author and labels.
3. Check whether the PR can be automatically verified as "trusted" (based on its author or labels).
4. If necessary, update the corresponding PR's verification status.
5. Deploy the artifacts to the corresponding PR's directory.
6. Prevent overwriting previously deployed artifacts (which ensures that the guarantees established
during deployment will remain valid until the artifacts are removed).
7. Prevent uploaded files from accessing anything outside their directory.
### Implementation details
This section describes how each of the aforementioned sub-tasks is accomplished:
1. **Verify which PR the uploaded artifacts correspond to.**
We are taking advantage of Travis' [JWT addon](https://docs.travis-ci.com/user/jwt). By sharing
a secret between Travis (which keeps it private but uses it to sign a JWT) and the server (which
uses it to verify the authenticity of the JWT), we can accomplish the following:
a. Verify that the upload request comes from Travis.
b. Determine the PR that these artifacts correspond to (since Travis puts that information into
the JWT, without the PR author being able to modify it).
_Note:_
_There are currently certain limitation in the implementation of the JWT addon._
_See the next section for more details._
2. **Fetch the PR's metadata, including author and labels**.
Once we have securely associated the uploaded artifacts to a PR, we retrieve the PR's metadata -
including the author's username and the labels - using the
[GitHub API](https://developer.github.com/v3/).
To avoid rate-limit restrictions, we use a Personal Access Token (issued by
[@mary-poppins](https://github.com/mary-poppins)).
3. **Check whether the PR can be automatically verified as "trusted"**.
"Trusted" means that we are confident that the build artifacts are suitable for being deployed
and publicly accessible on the preview server. There are two ways to check that:
1. We can verify that the PR has a pre-determined label, which marks it as "safe for preview".
Such a label can only have been added by a maintainer (with the necessary rights) and
designates that they have manually verified the PR contents.
2. We can verify (again using the GitHub API) the author's membership in one of the
whitelisted/trusted GitHub teams. For this operation, we need a Personal Access Token with the
`read:org` scope issued by a user that can "see" the specified GitHub organization.
Here too, we use the token by @mary-poppins.
4. **If necessary update the corresponding PR's verification status**.
Once we have determined whether the PR is considered "trusted", we update its "visibility" (i.e.
whether it is publicly accessible or not), based on the new verification status. For example, if
a PR was initially considered "not trusted" but the check triggered by a new build determined
otherwise, the PR (and all the previously uploaded previews) are made public. It works the same
way if a PR has gone from "trusted" to "not trusted".
5. **Deploy the artifacts to the corresponding PR's directory.**
With the preceding steps, we have verified that the uploaded artifacts have been uploaded by
Travis. Additionally, we have determined whether the PR can be trusted to have its previews
publicly accessible or whether further verification is necessary. The artifacts will be stored to
the PR's directory, but will not be publicly accessible unless the PR has been verified.
Essentially, as long as sub-tasks 1, 2 and 3 can be securely accomplished, it is possible to
"project" the trust we have in a team's members through the PR and Travis to the build artifacts.
6. **Prevent overwriting previously deployed artifacts**.
In order to enforce this restriction (and ensure that the deployed artifacts' validity is
preserved throughout their "lifetime"), the server that handles the upload (currently a Node.js
Express server) rejects uploads that target an existing directory.
_Note: A PR can contain multiple uploads; one for each SHA that was built on Travis._
7. **Prevent uploaded files from accessing anything outside their directory.**
Nginx (which is used to serve the uploaded artifacts) has been configured to not follow symlinks
outside of the directory where the build artifacts are stored.
## Assumptions / Things to keep in mind
- Each trusted PR author has full control over the content that is uploaded for their PRs. Part of
the security model relies on the trustworthiness of these authors.
- Adding the specified label on a PR and marking it as trusted, gives the author full control over
the content that is uploaded for the specific PR (e.g. by pushing more commits to it). The user
adding the label is responsible for ensuring that this control is not abused and that the PR is
either closed (one way of another) or the access is revoked.
- If anyone gets access to the `PREVIEW_DEPLOYMENT_TOKEN` (a.k.a. `NGBUILDS_IO_KEY` on
angular/angular) variable generated for each Travis job, they will be able to impersonate the
corresponding PR's author on the preview server for as long as the token is valid (currently 90
mins). Because of this, the value of the `PREVIEW_DEPLOYMENT_TOKEN` should not be made publicly
accessible (e.g. by printing it on the Travis job log).
- Travis does only allow specific whitelisted property names to be used with the JWT addon. The only
known such property at the time is `SAUCE_ACCESS_KEY` (used for integration with SauceLabs). In
order to be able to actually use the JWT addon we had to name the encrypted variable
`SAUCE_ACCESS_KEY` (which we later re-assign to `NGBUILDS_IO_KEY`).

View File

@ -0,0 +1,20 @@
# VM setup - Attach persistent disk
## Create `aio-builds` persistent disk (if not already exists)
- Follow instructions [here](https://cloud.google.com/compute/docs/disks/add-persistent-disk#create_disk).
- `sudo mkfs.ext4 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/disk/by-id/google-aio-builds`
## Mount disk
- `sudo mkdir -p /mnt/disks/aio-builds`
- `sudo mount -o discard,defaults /dev/disk/by-id/google-aio-builds /mnt/disks/aio-builds`
- `sudo chmod a+w /mnt/disks/aio-builds`
## Mount disk on boot
- Run:
```
echo UUID=`sudo blkid -s UUID -o value /dev/disk/by-id/google-aio-builds` \
/mnt/disks/aio-builds ext4 discard,defaults,nofail 0 2 | sudo tee -a /etc/fstab
```

View File

@ -0,0 +1,32 @@
# VM setup - Create docker image
## Checkout repository
- `git clone <repo-url>`
## Build docker image
- `<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
`--build-arg`.
**Note:** The script has to execute docker commands with `sudo`.
## Example
The following commands would create a docker image from GitHub repo `foo/bar` to be deployed on the
`foobar-builds.io` domain and accepting PR deployments from authors that are members of the
`bar-core` and `bar-docs-authors` teams of organization `foo`:
- `git clone https://github.com/foo/bar.git foobar`
- Run:
```
./foobar/aio-builds-setup/scripts/build.sh foobar-builds \
--build-arg AIO_REPO_SLUG=foo/bar \
--build-arg AIO_DOMAIN_NAME=foobar-builds.io \
--build-arg AIO_GITHUB_ORGANIZATION=foo \
--build-arg AIO_GITHUB_TEAM_SLUGS=bar-core,bar-docs-authors
```
A full list of the available environment variables can be found
[here](image-config--environment-variables.md).

View File

@ -0,0 +1,75 @@
# VM setup - Create host directories and files
## Create directory with secrets
For security reasons, sensitive info (such as tokens and passwords) are not hardcoded into the
docker image, nor passed as environment variables at runtime. They are passed to the docker
container from the host VM as files inside a directory. Each file's name is the name of the variable
and the file content is the value. These are read from inside the running container when necessary.
More info on how to create `secrets` directory and files can be found
[here](vm-setup--set-up-secrets.md).
## Create directory for build artifacts
The uploaded build artifacts should be kept on a directory outside the docker container, so it is
easier to replace the container without losing the uploaded builds. For portability across VMs a
persistent disk can be used (as described [here](vm-setup--attach-persistent-disk.md)).
**Note:** The directories created inside that directory will be owned by user `www-data`.
## Create SSL certificates (Optional for dev)
The host VM can attach a directory containing the SSL certificate and key to be used by the nginx
server for serving the uploaded build artifacts. More info on how to attach the directory when
starting the container can be found [here](vm-setup--start-docker-container.md).
In order for the container to be able to find the certificate and key, they should be named
`<DOMAIN_NAME>.crt` and `<DOMAIN_NAME>.key` respectively. For example, for a domain name
`ngbuild.io`, nginx will look for files `ngbuilds.io.crt` and `ngbuilds.io.key`. More info on how to
specify the domain name see [here](vm-setup--create-docker-image.md).
If no directory is attached, nginx will use an internal self-signed certificate. This is convenient
during development, but is not suitable for production.
**Note:**
Since nginx needs to be able to serve requests for both the main domain as well as any subdomain
(e.g. `ngbuilds.io/` and `foo-bar.ngbuilds.io/`), the provided certificate needs to be a wildcard
certificate covering both the domain and subdomains.
## Create directory for logs (Optional)
Optionally, a logs directory can pe passed to the docker container for storing non-system-related
logs. If not provided, the logs are kept locally on the container and will be lost whenever the
container is replaced (e.g. when updating to use a newer version of the docker image). Log files are
rotated and retained for 6 months.
The following log files are kept in this directory:
- `clean-up.log`:
Output of the `aio-clean-up` command, run as a cronjob for cleaning up the build artifacts of
closed PRs.
- `init.log`:
Output of the `aio-init` command, run (by default) when starting the container.
- `nginx/{access,error}.log`:
The access and error logs produced by the nginx server while serving "production" files.
- `nginx-test/{access,error}.log`:
The access and error logs produced by the nginx server while serving "test" files. This is only
used when running tests locally from inside the container, e.g. with the `aio-verify-setup`
command. (See [here](overview--scripts-and-commands.md) for more info.)
- `upload-server-{prod,test,verify-setup}-*.log`:
The logs produced by the Node.js upload-server while serving either:
- `-prod`: "Production" files (g.g during normal operation).
- `-test`: "Test" files (e.g. when a test instance is started with the `aio-upload-server-test`
command).
- `-verify-setup`: "Test" files, but while running `aio-verify-setup`.
(See [here](overview--scripts-and-commands.md) for more info the commands mentioned above.)
- `verify-setup.log`:
The output of the `aio-verify-setup` command (e.g. Jasmine output), except for upload-server
output which is logged to `upload-server-verify-setup-*.log` (see above).

View File

@ -0,0 +1,35 @@
# VM Setup - Set up docker
## Install docker
_Debian (jessie):_
- `sudo apt-get update`
- `sudo apt-get install -y apt-transport-https ca-certificates curl git software-properties-common`
- `curl -fsSL https://apt.dockerproject.org/gpg | sudo apt-key add -`
- `apt-key fingerprint 58118E89F3A912897C070ADBF76221572C52609D`
- `sudo add-apt-repository "deb https://apt.dockerproject.org/repo/ debian-$(lsb_release -cs) main"`
- `sudo apt-get update`
- `sudo apt-get -y install docker-engine`
_Ubuntu (16.04):_
- `sudo apt-get update`
- `sudo apt-get install -y curl git linux-image-extra-$(uname -r) linux-image-extra-virtual`
- `sudo apt-get install -y apt-transport-https ca-certificates`
- `curl -fsSL https://yum.dockerproject.org/gpg | sudo apt-key add -`
- `apt-key fingerprint 58118E89F3A912897C070ADBF76221572C52609D`
- `sudo add-apt-repository "deb https://apt.dockerproject.org/repo/ ubuntu-$(lsb_release -cs) main"`
- `sudo apt-get update`
- `sudo apt-get -y install docker-engine`
## Start the docker
- `sudo service docker start`
## Test docker
- `sudo docker run hello-world`
## Start docker on boot
- `sudo systemctl enable docker`

View File

@ -0,0 +1,52 @@
# VM Setup - Set up secrets
## Overview
Necessary secrets:
1. `GITHUB_TOKEN`
- Used for:
- Retrieving open PRs without rate-limiting.
- Retrieving PR author.
- Retrieving members of the `angular-core` team.
- Posting comments with preview links on PRs.
2. `PREVIEW_DEPLOYMENT_TOKEN`
- Used for:
- Decoding the JWT tokens received with `/create-build` requests.
**Note:**
`TEST_GITHUB_TOKEN` and `TEST_PREVIEW_DEPLOYMENT_TOKEN` can also be created similar to their
non-TEST counterparts and they will be loaded when running `aio-verify-setup`, but it is currently
not clear if/how they can be used in tests.
## Create secrets
1. `GITHUB_TOKEN`
- Visit https://github.com/settings/tokens.
- Generate new token with the `public_repo` scope.
2. `PREVIEW_DEPLOYMENT_TOKEN`
- Just generate a hard-to-guess character sequence.
- Add it to `.travis.yml` under `addons -> jwt -> secure`.
Can be added automatically with: `travis encrypt --add addons.jwt PREVIEW_DEPLOYMENT_TOKEN=<access-key>`
**Note:**
Due to [travis-ci/travis-ci#7223](https://github.com/travis-ci/travis-ci/issues/7223) it is not
currently possible to use the JWT addon (as described above) for anything other than the
`SAUCE_ACCESS_KEY` variable. You can get creative, though...
**WARNING**
TO avoid arbitrary uploads, make sure the `PREVIEW_DEPLOYMENT_TOKEN` is NOT printed in the Travis log.
## Save secrets on the VM
- `sudo mkdir /aio-secrets`
- `sudo touch /aio-secrets/GITHUB_TOKEN`
- Insert `<github-token>` into `/aio-secrets/GITHUB_TOKEN`.
- `sudo touch /aio-secrets/PREVIEW_DEPLOYMENT_TOKEN`
- Insert `<access-token>` into `/aio-secrets/PREVIEW_DEPLOYMENT_TOKEN`.
- `sudo chmod 400 /aio-secrets/*`

View File

@ -0,0 +1,92 @@
# VM setup - Start docker container
## The `docker run` command
Once everything has been setup and configured, a docker container can be started with the following
command:
```
sudo docker run \
--detach \
--dns 127.0.0.1 \
--name <instance-name> \
--publish 80:80 \
--publish 443:443 \
--restart unless-stopped \
[--volume <host-cert-dir>:/etc/ssl/localcerts:ro] \
--volume <host-secrets-dir>:/aio-secrets:ro \
--volume <host-builds-dir>:/var/www/aio-builds \
[--volume <host-logs-dir>:/var/log/aio] \
<name>[:<tag>]
```
Below is the same command with inline comments explaining each option. The aPI docs for `docker run`
can be found [here](https://docs.docker.com/engine/reference/run/).
```
sudo docker run \
# Start as a daemon.
--detach \
# Use the local DNS server.
# (This is necessary for mapping internal URLs, e.g. for the Node.js upload-server.)
--dns 127.0.0.1 \
# USe `<instance-name>` as an alias for the container.
# Useful for running `docker` commands, e.g.: `docker stop <instance-name>`
--name <instance-name> \
# Map ports of the host VM (left) to ports of the docker container (right)
--publish 80:80 \
--publish 443:443 \
# Automatically restart the container (unless it was explicitly stopped by the user).
# (This ensures that the container will be automatically started on boot.)
--restart unless-stopped \
# The directory the contains the SSL certificates.
# (See [here](vm-setup--create-host-dirs-and-files.md) for more info.)
# If not provided, the container will use self-signed certificates.
[--volume <host-cert-dir>:/etc/ssl/localcerts:ro] \
# The directory the contains the secrets (e.g. GitHub token, JWT secret, etc).
# (See [here](vm-setup--set-up-secrets.md) for more info.)
--volume <host-secrets-dir>:/aio-secrets:ro \
# The uploaded build artifacts will stored to and served from this directory.
# (If you are using a persistent disk - as described [here](vm-setup--attach-persistent-disk.md) -
# this will be a directory inside the disk.)
--volume <host-builds-dir>:/var/www/aio-builds \
# The directory where the logs are being kept.
# (See [here](vm-setup--create-host-dirs-and-files.md) for more info.)
# If not provided, the logs will be kept inside the container, which means they will be lost
# whenever a new container is created.
[--volume <host-logs-dir>:/var/log/aio] \
# 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.)
<name>[:<tag>]
```
## Example
The following command would start a docker container based on the previously created `foobar-builds`
docker image, alias it as 'foobar-builds-1' and map predefined directories on the host VM to be used
by the container for accesing secrets and SSL certificates and keeping the build artifacts and logs.
```
sudo docker run \
--detach \
--dns 127.0.0.1 \
--name foobar-builds-1 \
--publish 80:80 \
--publish 443:443 \
--restart unless-stopped \
--volume /etc/ssl/localcerts:/etc/ssl/localcerts:ro \
--volume /foobar-secrets:/aio-secrets:ro \
--volume /mnt/disks/foobar-builds:/var/www/aio-builds \
--volume /foobar-logs:/var/log/aio \
foobar-builds
```

View File

@ -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 a new container based on the new image and start it.
The script assumes that the preview server source code is in the repository's
`aio/aio-builds-setup/` directory and expects the following inputs:
- **$1**: `HOST_REPO_DIR`
- **$2**: `HOST_LOCALCERTS_DIR`
- **$3**: `HOST_SECRETS_DIR`
- **$4**: `HOST_BUILDS_DIR`
- **$5**: `HOST_LOGS_DIR`
See [here](vm-setup--create-host-dirs-and-files.md) for more info on what each input directory is
used for.
**Note 1:** The script has to execute docker commands with `sudo`.
**Note 2:** Make sure the user that executes the script has access to update the repository
## Run the script manually
You may choose to manually run the script, when necessary. Example:
```
update-preview-server.sh \
/path/to/repo \
/path/to/localcerts \
/path/to/secrets \
/path/to/builds \
/path/to/logs
```
## Run the script automatically
You may choose to automatically trigger the script, e.g. using a cronjob. For example, the following
cronjob entry would run the script every hour and update the preview server (assuming the user has
the necessary permissions):
```
# Periodically check for changes and update the preview server (if necessary)
*/30 * * * * /path/to/update-preview-server.sh /path/to/repo /path/to/localcerts /path/to/secrets /path/to/builds /path/to/logs
```

View File

@ -0,0 +1,5 @@
#!/bin/bash
readonly THIS_DIR=$(cd $(dirname $0); pwd)
readonly DOCKERBUILD_DIR="$THIS_DIR/../dockerbuild"
readonly SCRIPTS_JS_DIR="$DOCKERBUILD_DIR/scripts-js"

View File

@ -0,0 +1,18 @@
#!/bin/bash
set -eux -o pipefail
# Set up env
source "`dirname $0`/_env.sh"
readonly defaultImageNameAndTag="aio-builds:latest"
# Build `scripts-js/`
# (Necessary, because only `scripts-js/dist/` is copied to the docker image.)
(
cd "$SCRIPTS_JS_DIR"
yarn install --freeze-lockfile --non-interactive
yarn build
)
# Create docker image
readonly nameAndOptionalTag=${1:-$defaultImageNameAndTag}
sudo docker build --tag $nameAndOptionalTag ${@:2} $DOCKERBUILD_DIR

View File

@ -0,0 +1,12 @@
#!/bin/bash
set -eux -o pipefail
# Set up env
source "`dirname $0`/_env.sh"
# Test `scripts-js/`
(
cd "$SCRIPTS_JS_DIR"
yarn install --freeze-lockfile --non-interactive
yarn test
)

View 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."
)

66
aio/content/examples/.gitignore vendored Normal file
View File

@ -0,0 +1,66 @@
# boilerplate files
**/src/styles.css
**/src/systemjs-angular-loader.js
**/src/systemjs.config.js
**/src/tsconfig.json
**/bs-config.e2e.json
**/bs-config.json
**/package.json
**/tslint.json
**/karma.conf.js
**/karma-test-shim.js
**/browser-test-shim.js
**/node_modules
# built files
*.map
_test-output
protractor-helpers.js
*/e2e-spec.js
**/*.js
**/ts/**/*.js
**/js-es6*/**/*.js
dist/
# special
!/*
!*.1.*
!*.2.*
!*.3.*
*.1.js
*.2.js
*.3.js
*.1.js.map
*.2.js.map
*.3.js.map
!systemjs.config.*.js
!karma-test-shim.*.js
!copy-dist-files.js
# AngularJS files
!**/*.ajs.js
**/app/**/*.ajs.js
# aot
*/aot/**/*
!*/aot/bs-config.json
!*/aot/index.html
!rollup-config.js
# i18n
!i18n/src/systemjs-text-plugin.js
# testing
!testing/src/browser-test-shim.js
!testing/karma*.js
# webpack
!webpack/**/config/*.js
!webpack/**/*webpack*.js
# styleguide
!styleguide/src/systemjs.custom.js
# plunkers
*plnkr.no-link.html

View File

@ -0,0 +1,115 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('AngularJS to Angular Quick Reference Tests', function () {
beforeAll(function () {
browser.get('');
});
it('should display no poster images after bootstrap', function () {
testImagesAreDisplayed(false);
});
it('should display proper movie data', function () {
// We check only a few samples
let expectedSamples: any[] = [
{row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true},
{row: 0, column: 2, value: 'Celeritas'},
{row: 1, column: 3, matches: /Dec 1[678], 2015/}, // absorb timezone dif; we care about date format
{row: 1, column: 5, value: '$14.95'},
{row: 2, column: 4, value: 'PG-13'},
{row: 2, column: 7, value: '100%'},
{row: 2, column: 0, element: 'img', attr: 'src', value: 'images/ng-logo.png', contains: true},
];
// Go through the samples
let movieRows = getMovieRows();
for (let i = 0; i < expectedSamples.length; i++) {
let sample = expectedSamples[i];
let tableCell = movieRows.get(sample.row)
.all(by.tagName('td')).get(sample.column);
// Check the cell or its nested element
let elementToCheck = sample.element
? tableCell.element(by.tagName(sample.element))
: tableCell;
// Check element attribute or text
let valueToCheck = sample.attr
? elementToCheck.getAttribute(sample.attr)
: elementToCheck.getText();
// Test for equals/contains/match
if (sample.contains) {
expect(valueToCheck).toContain(sample.value);
} else if (sample.matches) {
expect(valueToCheck).toMatch(sample.matches);
} else {
expect(valueToCheck).toEqual(sample.value);
}
}
});
it('should display images after Show Poster', function () {
testPosterButtonClick('Show Poster', true);
});
it('should hide images after Hide Poster', function () {
testPosterButtonClick('Hide Poster', false);
});
it('should display no movie when no favorite hero is specified', function () {
testFavoriteHero(null, 'Please enter your favorite hero.');
});
it('should display no movie for Magneta', function () {
testFavoriteHero('Magneta', 'No movie, sorry!');
});
it('should display a movie for Mr. Nice', function () {
testFavoriteHero('Mr. Nice', 'Excellent choice!');
});
function testImagesAreDisplayed(isDisplayed: boolean) {
let expectedMovieCount = 3;
let movieRows = getMovieRows();
expect(movieRows.count()).toBe(expectedMovieCount);
for (let i = 0; i < expectedMovieCount; i++) {
let movieImage = movieRows.get(i).element(by.css('td > img'));
expect(movieImage.isDisplayed()).toBe(isDisplayed);
}
}
function testPosterButtonClick(expectedButtonText: string, isDisplayed: boolean) {
let posterButton = element(by.css('movie-list tr > th > button'));
expect(posterButton.getText()).toBe(expectedButtonText);
posterButton.click().then(function () {
testImagesAreDisplayed(isDisplayed);
});
}
function getMovieRows() {
return element.all(by.css('movie-list tbody > tr'));
}
function testFavoriteHero(heroName: string, expectedLabel: string) {
let movieListComp = element(by.tagName('movie-list'));
let heroInput = movieListComp.element(by.tagName('input'));
let favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
let resultLabel = movieListComp.element(by.css('span > p'));
heroInput.clear().then(function () {
heroInput.sendKeys(heroName || '');
expect(resultLabel.getText()).toBe(expectedLabel);
if (heroName) {
expect(favoriteHeroLabel.isDisplayed()).toBe(true);
expect(favoriteHeroLabel.getText()).toContain(heroName);
} else {
expect(favoriteHeroLabel.isDisplayed()).toBe(false);
}
});
}
});

View File

@ -0,0 +1,10 @@
{
"description": "AngularJS to Angular Quick Reference",
"basePath": "src/",
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[1].*"
],
"tags":["cookbook", "angularjs"]
}

View File

@ -0,0 +1,16 @@
// #docregion
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MovieListComponent } from './movie-list.component';
const routes: Routes = [
{ path: '', redirectTo: '/movies', pathMatch: 'full' },
{ path: 'movies', component: MovieListComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}

View File

@ -0,0 +1,9 @@
.active {font-style: italic;}
.shazam {font-weight: bold;}
img {height: 100px;}
table td {
padding: 4px;
border: 1px solid #e0e0e0;
}

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