Merge "Merge branch 'stable-2.15'"
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index ccad352..48f4b17 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -365,38 +365,25 @@
[[local-action-cache]]
-To accelerate builds, local action cache can be activated. Note, that this
-experimental feature is not activated per default and only available since
-Bazel version 0.7.
-
-To activate the local action cache, create accessible cache directory:
+To accelerate builds, local action cache can be activated.
+To activate the local action cache add these lines to your `~/.bazelrc` file:
----
- mkdir -p ~/.gerritcodereview/bazel-cache/cas
-----
-
-and add these lines to your `~/.bazelrc` file:
-
-----
-build --experimental_local_disk_cache_path=/home/<user>/.gerritcodereview/bazel-cache/cas
-build --experimental_local_disk_cache
+build --disk_cache=~/.gerritcodereview/bazel-cache/cas
build --experimental_strict_action_env
build --action_env=PATH
----
-[NOTE] `experimental_local_disk_cache_path` must be absolute path. Expansion of `~` is
-unfortunately not supported yet. This is also the reason why we can't activate this
-feature by default yet (by adjusting tools/bazel.rc file).
-
[[repository_cache]]
-To accelerate fetches, local repository cache can be activated. This cache is
-only used for rules_closure external repository and transitive dependendcies.
-That's because rules_closure uses standard Bazel download facility. For all
-other gerrit dependencies, the download_artifacts repository cache is used
+To accelerate fetches, local repository cache is activated per default in Bazel.
+This cache is only used for rules_closure external repository and transitive
+dependendcies. That's because rules_closure uses standard Bazel download facility.
+For all other gerrit dependencies, the download_artifacts repository cache is used
already.
-To activate the local repository cache, create accessible cache directory:
+To change the default local repository cache directry, create accessible cache
+directory:
----
mkdir -p ~/.gerritcodereview/bazel-cache/repository
@@ -405,12 +392,9 @@
and add this line to your `~/.bazelrc` file:
----
-build --experimental_repository_cache=/home/<user>/.gerritcodereview/bazel-cache/repository
+build --repository_cache=/home/<user>/.gerritcodereview/bazel-cache/repository
----
-[NOTE] `experimental_repository_cache` must be absolute path. Expansion of `~` is
-unfortunately not supported yet. This is also the reason why we can't activate this
-feature by default yet (by adjusting tools/bazel.rc file).
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index 1d3a020..eb24d8e 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -27,6 +27,7 @@
const SIZE_BAR_MIN_WIDTH = 1.5;
const RENDER_TIME = 'FileListRenderTime';
+ const RENDER_TIME_AVERAGE = 'FileListRenderTimePerFile';
const FileStatus = {
A: 'Added',
@@ -146,6 +147,13 @@
type: Array,
computed: '_computeFilesShown(numFilesShown, _files.*)',
},
+
+ /**
+ * The amount of files added to the shown files list the last time it was
+ * updated. This is used for reporting the average render time.
+ */
+ _reportinShownFilesIncrement: Number,
+
_expandedFilePaths: {
type: Array,
value() { return []; },
@@ -802,6 +810,9 @@
},
_computeFilesShown(numFilesShown, files) {
+ const previousNumFilesShown = this._shownFiles ?
+ this._shownFiles.length : 0;
+
const filesShown = files.base.slice(0, numFilesShown);
this.fire('files-shown-changed', {length: filesShown.length});
@@ -810,6 +821,10 @@
// dom-repeat binding.
this.$.reporting.time(RENDER_TIME);
+ // How many more files are being shown (if it's an increase).
+ this._reportinShownFilesIncrement =
+ Math.max(0, filesShown.length - previousNumFilesShown);
+
return filesShown;
},
@@ -1199,7 +1214,8 @@
_reportRenderedRow(index) {
if (index === this._shownFiles.length - 1) {
this.async(() => {
- this.$.reporting.timeEnd(RENDER_TIME);
+ this.$.reporting.timeEndWithAverage(RENDER_TIME, RENDER_TIME_AVERAGE,
+ this._reportinShownFilesIncrement);
}, 1);
}
return '';
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
index ae67dac..63808d1 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
@@ -295,6 +295,26 @@
delete this._baselines[name];
},
+ /**
+ * Reports just line timeEnd, but additionally reports an average given a
+ * denominator and a separate reporiting name for the average.
+ * @param {string} name Timing name.
+ * @param {string} averageName Average timing name.
+ * @param {number} denominator Number by which to divide the total to
+ * compute the average.
+ */
+ timeEndWithAverage(name, averageName, denominator) {
+ if (!this._baselines.hasOwnProperty(name)) { return; }
+ const baseTime = this._baselines[name];
+ this.timeEnd(name);
+
+ // Guard against division by zero.
+ if (!denominator) { return; }
+ const time = Math.round(this.now() - baseTime);
+ this.reporter(TIMING.TYPE, TIMING.CATEGORY, averageName,
+ Math.round(time / denominator));
+ },
+
reportInteraction(eventName, opt_msg) {
this.reporter(INTERACTION_TYPE, this.category, eventName, opt_msg);
},
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
index e2bb83d..5849042 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
@@ -166,6 +166,19 @@
));
});
+ test('timeEndWithAverage', () => {
+ const nowStub = sandbox.stub(element, 'now').returns(0);
+ nowStub.returns(1000);
+ element.time('foo');
+ nowStub.returns(1100);
+ element.timeEndWithAverage('foo', 'bar', 10);
+ assert.isTrue(element.reporter.calledTwice);
+ assert.isTrue(element.reporter.calledWithExactly(
+ 'timing-report', 'UI Latency', 'foo', 100));
+ assert.isTrue(element.reporter.calledWithExactly(
+ 'timing-report', 'UI Latency', 'bar', 10));
+ });
+
test('reportExtension', () => {
element.reportExtension('foo');
assert.isTrue(element.reporter.calledWithExactly(
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
index de92d8a..ef8c112 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
@@ -19,7 +19,6 @@
const HLJS_PATH = 'bower_components/highlightjs/highlight.min.js';
const DARK_THEME_PATH = 'styles/themes/dark-theme.html';
- const LIB_ROOT_PATTERN = /(.+\/)elements\/gr-app\.html/;
Polymer({
is: 'gr-lib-loader',
@@ -110,30 +109,11 @@
* @return {string}
*/
_getLibRoot() {
- // TODO(wyatta): Remove the remainder of this method logic once the
- // STATIC_RESOURCE_PATH variable is being provided generally.
if (window.STATIC_RESOURCE_PATH) {
return window.STATIC_RESOURCE_PATH + '/';
}
-
- if (this._cachedLibRoot) { return this._cachedLibRoot; }
-
- const appLink = document.head
- .querySelector('link[rel=import][href$="gr-app.html"]');
-
- if (!appLink) { throw new Error('Could not find application link'); }
-
- this._cachedLibRoot = appLink
- .href
- .match(LIB_ROOT_PATTERN)[1];
-
- if (!this._cachedLibRoot) {
- throw new Error('Could not extract lib root');
- }
-
- return this._cachedLibRoot;
+ return '/';
},
- _cachedLibRoot: null,
/**
* Load and execute a JS file from the lib root.
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index c081b30..ed4f528 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -138,16 +138,50 @@
JSON_PREFIX,
/**
+ * Wraps calls to the underlying authenticated fetch function (_auth.fetch)
+ * with timing and logging.
+ * @param {string} url
+ * @param {Object=} opt_fetchOptions
+ */
+ _fetch(url, opt_fetchOptions) {
+ const start = Date.now();
+ const xhr = this._auth.fetch(url, opt_fetchOptions);
+
+ // Log the call after it completes.
+ xhr.then(res => this._logCall(url, opt_fetchOptions, start, res.status));
+
+ // Return the XHR directly (without the log).
+ return xhr;
+ },
+
+ /**
+ * Log information about a REST call. Because the elapsed time is determined
+ * by this method, it should be called immediately after the request
+ * finishes.
+ * @param {string} url
+ * @param {Object|undefined} fetchOptions
+ * @param {number} startTime the time that the request was started.
+ * @param {number} status the HTTP status of the response. The status value
+ * is used here rather than the response object so there is no way this
+ * method can read the body stream.
+ */
+ _logCall(url, fetchOptions, startTime, status) {
+ const method = (fetchOptions && fetchOptions.method) ?
+ fetchOptions.method : 'GET';
+ const elapsed = (Date.now() - startTime) + 'ms';
+ console.log(['HTTP', status, method, elapsed, url].join(' '));
+ },
+
+ /**
* Fetch JSON from url provided.
* Returns a Promise that resolves to a native Response.
* Doesn't do error checking. Supports cancel condition. Performs auth.
* Validates auth expiry errors.
* @param {Defs.FetchJSONRequest} req
- * @return {Promise}
*/
_fetchRawJSON(req) {
const urlWithParams = this._urlWithParams(req.url, req.params);
- return this._auth.fetch(urlWithParams, req.fetchOptions).then(res => {
+ return this._fetch(urlWithParams, req.fetchOptions).then(res => {
if (req.cancelCondition && req.cancelCondition()) {
res.body.cancel();
return;
@@ -1607,7 +1641,7 @@
if (!url.startsWith('http')) {
url = this.getBaseUrl() + url;
}
- return this._auth.fetch(url, options).then(response => {
+ return this._fetch(url, options).then(response => {
if (!response.ok) {
if (opt_errFn) {
return opt_errFn.call(null, response);
@@ -1867,7 +1901,7 @@
},
_fetchB64File(url) {
- return this._auth.fetch(this.getBaseUrl() + url)
+ return this._fetch(this.getBaseUrl() + url)
.then(response => {
if (!response.ok) { return Promise.reject(response.statusText); }
const type = response.headers.get('X-FYI-Content-Type');
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index 7e71efa..0f1db03 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -1319,5 +1319,21 @@
});
});
});
+
+ test('_fetch forwards request and logs', () => {
+ const logStub = sandbox.stub(element, '_logCall');
+ const response = {status: 404, text: sinon.stub()};
+ const url = 'my url';
+ const fetchOptions = {method: 'DELETE'};
+ sandbox.stub(element._auth, 'fetch').returns(Promise.resolve(response));
+ const startTime = 123;
+ sandbox.stub(Date, 'now').returns(startTime);
+ return element._fetch(url, fetchOptions).then(() => {
+ assert.isTrue(logStub.calledOnce);
+ assert.isTrue(logStub.calledWith(
+ url, fetchOptions, startTime, response.status));
+ assert.isFalse(response.text.called);
+ });
+ });
});
</script>