Wait for revert or cherrypick changes to be reachable before redirecting

Bug: Issue 6969
Change-Id: I60c27dcf3446eec0afa07b2d5ef45cbfd080a3d7
This commit is contained in:
Wyatt Allen
2017-08-10 09:29:20 -07:00
parent 8ec31f97b7
commit 15ed72fe51
3 changed files with 83 additions and 9 deletions

View File

@@ -118,6 +118,9 @@
__type: 'revision', __type: 'revision',
}; };
const AWAIT_CHANGE_ATTEMPTS = 5;
const AWAIT_CHANGE_TIMEOUT_MS = 1000;
Polymer({ Polymer({
is: 'gr-change-actions', is: 'gr-change-actions',
@@ -824,10 +827,9 @@
// https://bugs.chromium.org/p/gerrit/issues/detail?id=4671 is resolved. // https://bugs.chromium.org/p/gerrit/issues/detail?id=4671 is resolved.
_setLabelValuesOnRevert(newChangeId) { _setLabelValuesOnRevert(newChangeId) {
const labels = this.$.jsAPI.getLabelValuesPostRevert(this.change); const labels = this.$.jsAPI.getLabelValuesPostRevert(this.change);
if (labels) { if (!labels) { return Promise.resolve(); }
this.$.restAPI.getChangeURLAndSend(newChangeId, return this.$.restAPI.getChangeURLAndSend(newChangeId,
this.actions.revert.method, 'current', '/review', {labels}); this.actions.revert.method, 'current', '/review', {labels});
}
}, },
_handleResponse(action, response) { _handleResponse(action, response) {
@@ -835,10 +837,16 @@
return this.$.restAPI.getResponseObject(response).then(obj => { return this.$.restAPI.getResponseObject(response).then(obj => {
switch (action.__key) { switch (action.__key) {
case ChangeActions.REVERT: case ChangeActions.REVERT:
this._setLabelValuesOnRevert(obj.change_id); this._waitForChangeReachable(obj._number)
/* falls through */ .then(() => this._setLabelValuesOnRevert(obj._number))
.then(() => {
Gerrit.Nav.navigateToChange(obj);
});
break;
case RevisionActions.CHERRYPICK: case RevisionActions.CHERRYPICK:
page.show(this.changePath(obj._number)); this._waitForChangeReachable(obj._number).then(() => {
Gerrit.Nav.navigateToChange(obj);
});
break; break;
case ChangeActions.DELETE: case ChangeActions.DELETE:
case RevisionActions.DELETE: case RevisionActions.DELETE:
@@ -1015,5 +1023,39 @@
}; };
}); });
}, },
/**
* Occasionally, a change created by a change action is not yet knwon to the
* API for a brief time. Wait for the given change number to be recognized.
*
* Returns a promise that resolves with true if a request is recognized, or
* false if the change was never recognized after all attempts.
*
* @param {number} changeNum
* @return {Promise<boolean>}
*/
_waitForChangeReachable(changeNum) {
let attempsRemaining = AWAIT_CHANGE_ATTEMPTS;
return new Promise(resolve => {
const check = () => {
attempsRemaining--;
// Pass a no-op error handler to avoid the "not found" error toast.
this.$.restAPI.getChange(changeNum, () => {}).then(response => {
// If the response is 404, the response will be undefined.
if (response) {
resolve(true);
return;
}
if (attempsRemaining) {
this.async(check, AWAIT_CHANGE_TIMEOUT_MS);
} else {
resolve(false);
}
});
};
check();
});
},
}); });
})(); })();

View File

@@ -1038,6 +1038,37 @@ limitations under the License.
assert.strictEqual( assert.strictEqual(
element.$.moreActions.items[4].id, 'submit-revision'); element.$.moreActions.items[4].id, 'submit-revision');
}); });
suite('_waitForChangeReachable', () => {
setup(() => {
sandbox.stub(element, 'async', fn => fn());
});
const makeGetChange = numTries => {
return () => {
if (numTries === 1) {
return Promise.resolve({_number: 123});
} else {
numTries--;
return Promise.resolve(undefined);
}
};
};
test('succeed', () => {
sandbox.stub(element.$.restAPI, 'getChange', makeGetChange(5));
return element._waitForChangeReachable(123).then(success => {
assert.isTrue(success);
});
});
test('fail', () => {
sandbox.stub(element.$.restAPI, 'getChange', makeGetChange(6));
return element._waitForChangeReachable(123).then(success => {
assert.isFalse(success);
});
});
});
}); });
}); });
</script> </script>

View File

@@ -1738,11 +1738,12 @@
* Given a changeNum, gets the change. * Given a changeNum, gets the change.
* *
* @param {number|string} changeNum * @param {number|string} changeNum
* @param {function(?Response, string=)=} opt_errFn
* @return {!Promise<?Object>} The change * @return {!Promise<?Object>} The change
*/ */
getChange(changeNum) { getChange(changeNum, opt_errFn) {
// Cannot use _changeBaseURL, as this function is used by _projectLookup. // Cannot use _changeBaseURL, as this function is used by _projectLookup.
return this.fetchJSON(`/changes/${changeNum}`); return this.fetchJSON(`/changes/${changeNum}`, opt_errFn);
}, },
/** /**