
These tags are preserved by the Closure compiler and vulcanize in order to serve the license notices embedded in the outputs. In a standalone Gerrit server, these license are also covered in the LICENSES.txt served with the documentation. When serving PG assets from a CDN, it's less obvious what the corresponding LICENSES.txt file is, since the CDN is not directly linked to a running Gerrit server. Safer to embed the licenses in the assets themselves. Change-Id: Id1add1451fad1baa7916882a6bda02c326ccc988
271 lines
9.3 KiB
HTML
271 lines
9.3 KiB
HTML
<!--
|
|
@license
|
|
Copyright (C) 2016 The Android Open Source Project
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
-->
|
|
<script>
|
|
(function(window) {
|
|
'use strict';
|
|
|
|
// Tags identifying ChangeMessages that move change into WIP state.
|
|
const WIP_TAGS = [
|
|
'autogenerated:gerrit:newWipPatchSet',
|
|
'autogenerated:gerrit:setWorkInProgress',
|
|
];
|
|
|
|
// Tags identifying ChangeMessages that move change out of WIP state.
|
|
const READY_TAGS = [
|
|
'autogenerated:gerrit:setReadyForReview',
|
|
];
|
|
|
|
window.Gerrit = window.Gerrit || {};
|
|
|
|
/** @polymerBehavior this */
|
|
Gerrit.PatchSetBehavior = {
|
|
EDIT_NAME: 'edit',
|
|
PARENT_NAME: 'PARENT',
|
|
|
|
/**
|
|
* As patchNum can be either a string (e.g. 'edit', 'PARENT') OR a number,
|
|
* this function checks for patchNum equality.
|
|
*
|
|
* @param {string|number} a
|
|
* @param {string|number|undefined} b Undefined sometimes because
|
|
* computeLatestPatchNum can return undefined.
|
|
* @return {boolean}
|
|
*/
|
|
patchNumEquals(a, b) {
|
|
return a + '' === b + '';
|
|
},
|
|
|
|
/**
|
|
* Whether the given patch is a numbered parent of a merge (i.e. a negative
|
|
* number).
|
|
* @param {string|number} n
|
|
* @return {Boolean}
|
|
*/
|
|
isMergeParent(n) {
|
|
return (n + '')[0] === '-';
|
|
},
|
|
|
|
/**
|
|
* Given an object of revisions, get a particular revision based on patch
|
|
* num.
|
|
*
|
|
* @param {Object} revisions The object of revisions given by the API
|
|
* @param {number|string} patchNum The number index of the revision
|
|
* @return {Object} The correspondent revision obj from {revisions}
|
|
*/
|
|
getRevisionByPatchNum(revisions, patchNum) {
|
|
for (const rev of Object.values(revisions || {})) {
|
|
if (Gerrit.PatchSetBehavior.patchNumEquals(rev._number, patchNum)) {
|
|
return rev;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Find change edit base revision if change edit exists.
|
|
*
|
|
* @param {!Array<!Object>} revisions The revisions array.
|
|
* @return {Object} change edit parent revision or null if change edit
|
|
* doesn't exist.
|
|
*/
|
|
findEditParentRevision(revisions) {
|
|
const editInfo =
|
|
revisions.find(info => info._number ===
|
|
Gerrit.PatchSetBehavior.EDIT_NAME);
|
|
|
|
if (!editInfo) { return null; }
|
|
|
|
return revisions.find(info => info._number === editInfo.basePatchNum) ||
|
|
null;
|
|
},
|
|
|
|
/**
|
|
* Find change edit base patch set number if change edit exists.
|
|
*
|
|
* @param {!Array<!Object>} revisions The revisions array.
|
|
* @return {number} Change edit patch set number or -1.
|
|
*/
|
|
findEditParentPatchNum(revisions) {
|
|
const revisionInfo =
|
|
Gerrit.PatchSetBehavior.findEditParentRevision(revisions);
|
|
return revisionInfo ? revisionInfo._number : -1;
|
|
},
|
|
|
|
/**
|
|
* Sort given revisions array according to the patch set number, in
|
|
* descending order.
|
|
* The sort algorithm is change edit aware. Change edit has patch set number
|
|
* equals 'edit', but must appear after the patch set it was based on.
|
|
* Example: change edit is based on patch set 2, and another patch set was
|
|
* uploaded after change edit creation, the sorted order should be:
|
|
* 3, edit, 2, 1.
|
|
*
|
|
* @param {!Array<!Object>} revisions The revisions array
|
|
* @return {!Array<!Object>} The sorted {revisions} array
|
|
*/
|
|
sortRevisions(revisions) {
|
|
const editParent =
|
|
Gerrit.PatchSetBehavior.findEditParentPatchNum(revisions);
|
|
// Map a normal patchNum to 2 * (patchNum - 1) + 1... I.e. 1 -> 1,
|
|
// 2 -> 3, 3 -> 5, etc.
|
|
// Map an edit to the patchNum of parent*2... I.e. edit on 2 -> 4.
|
|
const num = r => r._number === Gerrit.PatchSetBehavior.EDIT_NAME ?
|
|
2 * editParent :
|
|
2 * (r._number - 1) + 1;
|
|
return revisions.sort((a, b) => num(b) - num(a));
|
|
},
|
|
|
|
/**
|
|
* Construct a chronological list of patch sets derived from change details.
|
|
* Each element of this list is an object with the following properties:
|
|
*
|
|
* * num {number} The number identifying the patch set
|
|
* * desc {!string} Optional patch set description
|
|
* * wip {boolean} If true, this patch set was never subject to review.
|
|
*
|
|
* The wip property is determined by the change's current work_in_progress
|
|
* property and its log of change messages.
|
|
*
|
|
* @param {!Object} change The change details
|
|
* @return {!Array<!Object>} Sorted list of patch set objects, as described
|
|
* above
|
|
*/
|
|
computeAllPatchSets(change) {
|
|
if (!change) { return []; }
|
|
let patchNums = [];
|
|
if (change.revisions && Object.keys(change.revisions).length) {
|
|
patchNums =
|
|
Gerrit.PatchSetBehavior.sortRevisions(Object.values(change.revisions))
|
|
.map(e => {
|
|
// TODO(kaspern): Mark which patchset an edit was made on, if an
|
|
// edit exists -- perhaps with a temporary description.
|
|
return {
|
|
num: e._number,
|
|
desc: e.description,
|
|
};
|
|
});
|
|
}
|
|
return Gerrit.PatchSetBehavior._computeWipForPatchSets(change, patchNums);
|
|
},
|
|
|
|
/**
|
|
* Populate the wip properties of the given list of patch sets.
|
|
*
|
|
* @param {!Object} change The change details
|
|
* @param {!Array<!Object>} patchNums Sorted list of patch set objects, as
|
|
* generated by computeAllPatchSets
|
|
* @return {!Array<!Object>} The given list of patch set objects, with the
|
|
* wip property set on each of them
|
|
*/
|
|
_computeWipForPatchSets(change, patchNums) {
|
|
if (!change.messages || !change.messages.length) {
|
|
return patchNums;
|
|
}
|
|
const psWip = {};
|
|
let wip = change.work_in_progress;
|
|
for (let i = 0; i < change.messages.length; i++) {
|
|
const msg = change.messages[i];
|
|
if (WIP_TAGS.includes(msg.tag)) {
|
|
wip = true;
|
|
} else if (READY_TAGS.includes(msg.tag)) {
|
|
wip = false;
|
|
}
|
|
if (psWip[msg._revision_number] !== false) {
|
|
psWip[msg._revision_number] = wip;
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < patchNums.length; i++) {
|
|
patchNums[i].wip = psWip[patchNums[i].num];
|
|
}
|
|
return patchNums;
|
|
},
|
|
|
|
/** @return {number|undefined} */
|
|
computeLatestPatchNum(allPatchSets) {
|
|
if (!allPatchSets || !allPatchSets.length) { return undefined; }
|
|
if (allPatchSets[0].num === Gerrit.PatchSetBehavior.EDIT_NAME) {
|
|
return allPatchSets[1].num;
|
|
}
|
|
return allPatchSets[0].num;
|
|
},
|
|
|
|
/** @return {Boolean} */
|
|
hasEditBasedOnCurrentPatchSet(allPatchSets) {
|
|
if (!allPatchSets || allPatchSets.length < 2) { return false; }
|
|
return allPatchSets[0].num === Gerrit.PatchSetBehavior.EDIT_NAME;
|
|
},
|
|
|
|
/** @return {Boolean} */
|
|
hasEditPatchsetLoaded(patchRangeRecord) {
|
|
const patchRange = patchRangeRecord.base;
|
|
if (!patchRange) { return false; }
|
|
return patchRange.patchNum === Gerrit.PatchSetBehavior.EDIT_NAME ||
|
|
patchRange.basePatchNum === Gerrit.PatchSetBehavior.EDIT_NAME;
|
|
},
|
|
|
|
/**
|
|
* Check whether there is no newer patch than the latest patch that was
|
|
* available when this change was loaded.
|
|
*
|
|
* @return {Promise<!Object>} A promise that yields true if the latest patch
|
|
* has been loaded, and false if a newer patch has been uploaded in the
|
|
* meantime. The promise is rejected on network error.
|
|
*/
|
|
fetchChangeUpdates(change, restAPI) {
|
|
const knownLatest = Gerrit.PatchSetBehavior.computeLatestPatchNum(
|
|
Gerrit.PatchSetBehavior.computeAllPatchSets(change));
|
|
return restAPI.getChangeDetail(change._number)
|
|
.then(detail => {
|
|
if (!detail) {
|
|
return Promise.reject('Unable to check for latest patchset.');
|
|
}
|
|
const actualLatest = Gerrit.PatchSetBehavior.computeLatestPatchNum(
|
|
Gerrit.PatchSetBehavior.computeAllPatchSets(detail));
|
|
return {
|
|
isLatest: actualLatest <= knownLatest,
|
|
newStatus: change.status !== detail.status ? detail.status : null,
|
|
newMessages: change.messages.length < detail.messages.length,
|
|
};
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @param {number|string} patchNum
|
|
* @param {!Array<!Object>} revisions A sorted array of revisions.
|
|
*
|
|
* @return {number} The index of the revision with the given patchNum.
|
|
*/
|
|
findSortedIndex(patchNum, revisions) {
|
|
revisions = revisions || [];
|
|
const findNum = rev => rev._number + '' === patchNum + '';
|
|
return revisions.findIndex(findNum);
|
|
},
|
|
|
|
/**
|
|
* Convert parent indexes from patch range expressions to numbers.
|
|
* For example, in a patch range expression `"-3"` becomes `3`.
|
|
* @param {number|string} rangeBase
|
|
* @return {number}
|
|
*/
|
|
getParentIndex(rangeBase) {
|
|
return -parseInt(rangeBase + '', 10);
|
|
},
|
|
};
|
|
})(window);
|
|
</script>
|