Merge "MergeUtil#newMerger: Throw a specific exception for invalid strategy"
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 0535397..9c6637b 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -1670,18 +1670,37 @@
if (!res.isCommitted()) {
res.reset();
traceContext.getTraceId().ifPresent(traceId -> res.addHeader(X_GERRIT_TRACE, traceId));
- StringBuilder msg = new StringBuilder("Internal server error");
ImmutableList<String> userMessages =
globals.exceptionHooks.stream()
.map(h -> h.getUserMessage(err))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toImmutableList());
+
+ Optional<Integer> statusCode =
+ globals.exceptionHooks.stream()
+ .map(h -> h.getStatusCode(err))
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .findFirst();
+ if (statusCode.isPresent() && statusCode.get() < 400) {
+ StringBuilder msg = new StringBuilder();
+ if (userMessages.size() == 1) {
+ msg.append(userMessages.get(0));
+ } else {
+ userMessages.forEach(m -> msg.append("\n* ").append(m));
+ }
+
+ res.setStatus(statusCode.get());
+ logger.atFinest().withCause(err).log("REST call finished: %d", statusCode);
+ return replyText(req, res, true, msg.toString());
+ }
+
+ StringBuilder msg = new StringBuilder("Internal server error");
if (!userMessages.isEmpty()) {
- msg.append("\n");
userMessages.forEach(m -> msg.append("\n* ").append(m));
}
- return replyError(req, res, SC_INTERNAL_SERVER_ERROR, msg.toString(), err);
+ return replyError(req, res, statusCode.orElse(SC_INTERNAL_SERVER_ERROR), msg.toString(), err);
}
return 0;
}
diff --git a/java/com/google/gerrit/server/ExceptionHook.java b/java/com/google/gerrit/server/ExceptionHook.java
index db44b4b..a2bade0 100644
--- a/java/com/google/gerrit/server/ExceptionHook.java
+++ b/java/com/google/gerrit/server/ExceptionHook.java
@@ -55,7 +55,9 @@
}
/**
- * Returns an error message that should be returned to the user.
+ * Returns a message that should be returned to the user.
+ *
+ * <p>This message is included into the HTTP response that is sent to the user.
*
* @param throwable throwable that was thrown while executing an operation
* @return error message that should be returned to the user, {@link Optional#empty()} if no
@@ -64,4 +66,25 @@
default Optional<String> getUserMessage(Throwable throwable) {
return Optional.empty();
}
+
+ /**
+ * Returns the HTTP status code that should be returned to the user.
+ *
+ * <p>If no value is returned ({@link Optional#empty()}) the HTTP status code defaults to {@code
+ * 500 Internal Server Error}.
+ *
+ * <p>{@link #getUserMessage(Throwable)} allows to define which message should be included into
+ * the body of the HTTP response.
+ *
+ * <p>Implementors may use this method to change the status code for certain exceptions (e.g.
+ * using this method it would be possible to return {@code 409 Conflict} for {@link
+ * com.google.gerrit.git.LockFailureException}s instead of {@code 500 Internal Server Error}).
+ *
+ * @param throwable throwable that was thrown while executing an operation
+ * @return HTTP status code that should be returned to the user, {@link Optional#empty()} if the
+ * exception should result in {@code 500 Internal Server Error}
+ */
+ default Optional<Integer> getStatusCode(Throwable throwable) {
+ return Optional.empty();
+ }
}
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
index 6703651..0817762 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
@@ -269,25 +269,6 @@
Do you really want to delete the edit?
</div>
</gr-dialog>
- <gr-dialog
- id="showRevertSubmissionChangesDialog"
- class="confirmDialog"
- confirm-label="Close"
- cancel-label=''
- on-confirm="_handleShowRevertSubmissionChangesConfirm">
- <div class="header" slot="header">
- Reverted Changes
- </div>
- <div class="main" slot="main">
- <template is="dom-repeat" items="[[_revertChanges]]">
- <div>
- <a href$="[[item.link]]" target="_blank">
- Change [[item._number]]
- </a>
- </div>
- </template>
- </div>
- </gr-dialog>
</gr-overlay>
<gr-js-api-interface id="jsAPI"></gr-js-api-interface>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index 8ad2a06..9d2854a 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -420,10 +420,6 @@
type: Boolean,
value: true,
},
- _revertChanges: {
- type: Array,
- value: [],
- },
};
}
@@ -1262,7 +1258,6 @@
_handleResponse(action, response) {
if (!response) { return; }
return this.$.restAPI.getResponseObject(response).then(obj => {
- let revertChanges = [];
switch (action.__key) {
case ChangeActions.REVERT:
this._waitForChangeReachable(obj._number)
@@ -1288,27 +1283,11 @@
Gerrit.Nav.navigateToChange(this.change);
break;
case ChangeActions.REVERT_SUBMISSION:
- revertChanges = obj.revert_changes || [];
- revertChanges = revertChanges.map(change => {
- change.link = '/q/' + encodeURIComponent(change.change_id);
- return change;
- });
- // list of reverted changes can never be 0
- if (revertChanges.length === 1) {
- // redirect to the change if only 1 change is reverted
- const change = revertChanges[0];
- this._waitForChangeReachable(change._number).then(success => {
- if (success) {
- Gerrit.Nav.navigateToChange(change);
- } else {
- console.error('Change ' + change._number + ' not reachable');
- }
- });
- } else {
- // show multiple reverted changes in a dialog
- this._revertChanges = revertChanges;
- this._showActionDialog(this.$.showRevertSubmissionChangesDialog);
- }
+ if (!obj.revert_changes || !obj.revert_changes.length) return;
+ /* If there is only 1 change then gerrit will automatically
+ redirect to that change */
+ Gerrit.Nav.navigateToSearchQuery('topic: ' +
+ obj.revert_changes[0].topic);
break;
default:
this.dispatchEvent(new CustomEvent('reload-change',
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index d9b7986..50f6fb0 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -1446,7 +1446,6 @@
suite('happy path', () => {
let sendStub;
- let waitForChangeReachableStub;
setup(() => {
sandbox.stub(element, 'fetchChangeUpdates')
.returns(Promise.resolve({isLatest: true}));
@@ -1454,8 +1453,6 @@
.returns(Promise.resolve({}));
getResponseObjectStub = sandbox.stub(element.$.restAPI,
'getResponseObject');
- waitForChangeReachableStub = sandbox.stub(element,
- '_waitForChangeReachable').returns(Promise.resolve(true));
sandbox.stub(Gerrit.Nav,
'navigateToChange').returns(Promise.resolve(true));
});
@@ -1471,12 +1468,15 @@
});
suite('single changes revert', () => {
+ let navigateToSearchQueryStub;
setup(() => {
getResponseObjectStub
.returns(Promise.resolve({revert_changes: [
{change_id: 12345},
]}));
showActionDialogStub = sandbox.stub(element, '_showActionDialog');
+ navigateToSearchQueryStub = sandbox.stub(Gerrit.Nav,
+ 'navigateToSearchQuery');
});
test('revert submission single change', done => {
@@ -1484,7 +1484,7 @@
'/revert_submission', false, cleanup).then(res => {
element._handleResponse({__key: 'revert_submission'}, {}).
then(() => {
- assert.isTrue(waitForChangeReachableStub.called);
+ assert.isTrue(navigateToSearchQueryStub.called);
done();
});
});
@@ -1493,12 +1493,16 @@
suite('multiple changes revert', () => {
let showActionDialogStub;
+ let navigateToSearchQueryStub;
setup(() => {
getResponseObjectStub
.returns(Promise.resolve({revert_changes: [
- {change_id: 12345}, {change_id: 23456},
+ {change_id: 12345, topic: 'T'},
+ {change_id: 23456, topic: 'T'},
]}));
showActionDialogStub = sandbox.stub(element, '_showActionDialog');
+ navigateToSearchQueryStub = sandbox.stub(Gerrit.Nav,
+ 'navigateToSearchQuery');
});
test('revert submission multiple change', done => {
@@ -1506,7 +1510,9 @@
'/revert_submission', false, cleanup).then(res => {
element._handleResponse({__key: 'revert_submission'}, {}).then(
() => {
- assert.isTrue(showActionDialogStub.called);
+ assert.isFalse(showActionDialogStub.called);
+ assert.isTrue(navigateToSearchQueryStub.calledWith(
+ 'topic: T'));
done();
});
});