aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJukka Jokiniva <jukka.jokiniva@qt.io>2019-09-13 12:02:24 +0300
committerJukka Jokiniva <jukka.jokiniva@qt.io>2019-09-13 12:03:16 +0300
commit761f4f66c0b7a21cdac3cd7025a175fef25865fa (patch)
tree4d1258de57a3b28333d04d537a78e08911540752
parentbeb4572f62fb2d759dcb621410bfcb222e69d702 (diff)
parent143f1d30cc7f9d72d46c5992fc576573dba65d9c (diff)
Merge remote-tracking branch 'origin/v2.16.9-based' into v3.0-based
-rw-r--r--qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html179
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java76
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java68
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java2
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtDefer.java4
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpen.java2
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtStage.java4
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStage.java2
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java181
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java95
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java61
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java13
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandRebuildStagingIT.java12
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandStageIT.java2
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommitFooterIT.java8
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommonFlowsIT.java122
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtEmailSendingIT.java2
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpenIT.java6
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java72
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStageIT.java129
20 files changed, 612 insertions, 428 deletions
diff --git a/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html b/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
index 3bd29f6..9bedbb9 100644
--- a/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
+++ b/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
@@ -8,33 +8,16 @@
<script>
'use strict';
- var BUTTONS = {
- 'gerrit-plugin-qt-workflow~abandon' : {
- header: 'Abandon the change?',
- action_name: 'abandon'
- },
- 'gerrit-plugin-qt-workflow~defer' : {
- header: 'Defer the change?',
- action_name: 'defer'
- },
- 'gerrit-plugin-qt-workflow~reopen' : {
- header: 'Reopen the change?',
- action_name: 'reopen'
- },
- 'gerrit-plugin-qt-workflow~stage' : {
- header: 'Submit to staging?',
- action_name: 'stage'
- },
- 'gerrit-plugin-qt-workflow~unstage' : {
- header: 'Unstage the change?',
- action_name: 'unstage'
- }
- };
+ var BUTTONS = [
+ 'gerrit-plugin-qt-workflow~abandon',
+ 'gerrit-plugin-qt-workflow~defer',
+ 'gerrit-plugin-qt-workflow~reopen',
+ 'gerrit-plugin-qt-workflow~stage',
+ 'gerrit-plugin-qt-workflow~unstage'
+ ];
Gerrit.install(plugin => {
- plugin.custom_popup = null;
- plugin.custom_popup_promise = null;
plugin.buttons = null;
function htmlToElement(html) {
@@ -126,32 +109,28 @@
// Remove any existing buttons
if (plugin.buttons) {
- for (var key in BUTTONS) {
- if (BUTTONS.hasOwnProperty(key)) {
- if(typeof plugin.buttons[key] !== 'undefined' && plugin.buttons[key] !== null) {
- plugin.ca.removeTapListener(plugin.buttons[key], (param) => {} );
- plugin.ca.remove(plugin.buttons[key]);
- plugin.buttons[key] = null;
- }
+ BUTTONS.forEach((key) => {
+ if(typeof plugin.buttons[key] !== 'undefined' && plugin.buttons[key] !== null) {
+ plugin.ca.removeTapListener(plugin.buttons[key], (param) => {} );
+ plugin.ca.remove(plugin.buttons[key]);
+ plugin.buttons[key] = null;
}
- }
+ });
} else plugin.buttons = [];
// Add buttons based on server response
- for (var key in BUTTONS) {
- if (BUTTONS.hasOwnProperty(key)) {
- var action = plugin.ca.getActionDetails(key);
- if (action) {
- // hide dropdown action
- plugin.ca.setActionHidden(action.__type, action.__key, true);
-
- // add button
- plugin.buttons[key] = plugin.ca.add(action.__type, action.label);
- plugin.ca.setTitle(plugin.buttons[key], action.title);
- plugin.ca.addTapListener(plugin.buttons[key], buttonEventCallback);
- }
+ BUTTONS.forEach((key) => {
+ var action = plugin.ca.getActionDetails(key);
+ if (action) {
+ // hide dropdown action
+ plugin.ca.setActionHidden(action.__type, action.__key, true);
+
+ // add button
+ plugin.buttons[key] = plugin.ca.add(action.__type, action.label);
+ plugin.ca.setTitle(plugin.buttons[key], action.title);
+ plugin.ca.addTapListener(plugin.buttons[key], buttonEventCallback);
}
- }
+ });
function buttonEventCallback(event) {
var button_key = event.type.substring(0, event.type.indexOf('-tap'));
@@ -165,106 +144,22 @@
}
}
if (button_action) {
- plugin.popup('qt-gerrit-ui-confirm-dialog').then( (param) => {
- plugin.custom_popup_promise = param;
- plugin.custom_popup.set('header', BUTTONS[button_index].header);
- plugin.custom_popup.set('subject', changeInfo.subject);
- plugin.custom_popup.set('action_name', BUTTONS[button_index].action_name);
- plugin.custom_popup.set('api_url', button_action.__url);
- }).catch( (param) => { console.log('unexpected error: promise failed');});
+ const buttonEl = this.$$(`[data-action-key="${button_key}"]`);
+ buttonEl.setAttribute('loading', true);
+ buttonEl.disabled = true;
+ plugin.restApi().post(button_action.__url, {})
+ .then((ok_resp) => {
+ buttonEl.removeAttribute('loading');
+ buttonEl.disabled = false;
+ window.location.reload(true);
+ }).catch((failed_resp) => {
+ buttonEl.removeAttribute('loading');
+ buttonEl.disabled = false;
+ this.fire('show-alert', {message: 'FAILED: ' + failed_resp});
+ });
} else console.log('unexpected error: no action');
}
});
});
</script>
</dom-module>
-
-<dom-module id="qt-gerrit-ui-confirm-dialog">
- <template>
- <style include="shared-styles">
- #dialog {
- min-width: 40em;
- }
- p {
- margin-bottom: 1em;
- }
- @media screen and (max-width: 50em) {
- #dialog {
- min-width: inherit;
- width: 100%;
- }
- }
- </style>
- <gr-dialog
- id="dialog"
- confirm-label="Continue"
- confirm-on-enter
- on-cancel="_handleCancelTap"
- on-confirm="_handleConfirmTap">
- <div class="header" slot="header">[[header]]</div>
- <div class="main" slot="main">
- <p>Ready to [[action_name]] &ldquo;<strong>[[subject]]</strong>&rdquo;?</p>
- <p class="main" style="color: red;font-weight: bold;">[[errorMessage]]</p>
- </div>
- </gr-dialog>
- </template>
- <script>
- 'use strict';
-
- var qtgerrituiconfirmdialog = Polymer({
- is: 'qt-gerrit-ui-confirm-dialog',
-
- properties: {
- header: {
- type: String,
- value: '...wait...'
- },
- action_name: {
- type: String,
- value: ''
- },
- api_url: {
- type: String,
- value: ''
- },
- subject: {
- type: String,
- value: ''
- },
- errorMessage: {
- type: String,
- value: ''
- }
- },
-
- attached: function() {
- this.plugin.custom_popup = this;
- },
-
- resetFocus(e) {
- this.$.dialog.resetFocus();
- },
-
- _handleConfirmTap(e) {
- this.$.dialog.disabled = true;
- e.preventDefault();
- this.plugin.restApi().post(this.get('api_url'), {})
- .then((ok_resp) => {
- this.$.dialog.disabled = false;
- this.plugin.custom_popup_promise.close();
- this.plugin.custom_popup_promise = null;
- window.location.reload(true);
- }).catch((failed_resp) => {
- this.$.dialog.disabled = false;
- this.set('errorMessage', 'FAILED: ' + failed_resp);
- });
- },
-
- _handleCancelTap(e) {
- e.preventDefault();
- this.plugin.custom_popup_promise.close();
- this.plugin.custom_popup_promise = null;
- },
- });
- </script>
-</dom-module>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java
index 3ad64f4..ddbff1d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java
@@ -5,7 +5,6 @@
package com.googlesource.gerrit.plugins.qtcodereview;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.MergeConflictException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
@@ -13,15 +12,11 @@ import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.change.NotifyResolver;
-import com.google.gerrit.server.change.PatchSetInserter;
import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeUtil;
-import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.NoSuchRefException;
import com.google.gerrit.server.project.ProjectCache;
@@ -35,12 +30,10 @@ import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
-import java.io.IOException;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
-import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
@@ -56,7 +49,6 @@ public class QtCherryPickPatch {
private final BatchUpdate.Factory batchUpdateFactory;
private final GitRepositoryManager gitManager;
private final Provider<IdentifiedUser> user;
- private final PatchSetInserter.Factory patchSetInserterFactory;
private final MergeUtil.Factory mergeUtilFactory;
private final ProjectCache projectCache;
private final QtChangeUpdateOp.Factory qtUpdateFactory;
@@ -65,14 +57,12 @@ public class QtCherryPickPatch {
QtCherryPickPatch(BatchUpdate.Factory batchUpdateFactory,
GitRepositoryManager gitManager,
Provider<IdentifiedUser> user,
- PatchSetInserter.Factory patchSetInserterFactory,
MergeUtil.Factory mergeUtilFactory,
ProjectCache projectCache,
QtChangeUpdateOp.Factory qtUpdateFactory) {
this.batchUpdateFactory = batchUpdateFactory;
this.gitManager = gitManager;
this.user = user;
- this.patchSetInserterFactory = patchSetInserterFactory;
this.mergeUtilFactory = mergeUtilFactory;
this.projectCache = projectCache;
this.qtUpdateFactory = qtUpdateFactory;
@@ -114,7 +104,6 @@ public class QtCherryPickPatch {
commitToCherryPick.setNotes(changeData.notes());
CodeReviewCommit cherryPickCommit;
- boolean mergeCommit = false;
ProjectState projectState = projectCache.checkedGet(project);
if (projectState == null) throw new NoSuchProjectException(project);
@@ -123,14 +112,21 @@ public class QtCherryPickPatch {
if (commitToCherryPick.getParentCount() > 1) {
// Merge commit cannot be cherrypicked
logger.atInfo().log("qtcodereview: merge commit detected %s", commitToCherryPick);
- mergeCommit = true;
- RevCommit commit = QtUtil.merge(committerIdent,
- git, oi,
- revWalk,
- commitToCherryPick,
- baseCommit,
- true /* merge always */);
- cherryPickCommit = revWalk.parseCommit(commit);
+
+ if (commitToCherryPick.getParent(0).equals(baseCommit)) {
+ // allow fast forward, when parent index 0 is correct
+ logger.atInfo().log("qtcodereview: merge commit fast forwarded");
+ cherryPickCommit = commitToCherryPick;
+ } else {
+ logger.atInfo().log("qtcodereview: merge of merge created");
+ RevCommit commit = QtUtil.merge(committerIdent,
+ git, oi,
+ revWalk,
+ commitToCherryPick,
+ baseCommit,
+ true);
+ cherryPickCommit = revWalk.parseCommit(commit);
+ }
} else {
String commitMessage = mergeUtil.createCommitMessageOnSubmit(commitToCherryPick, baseCommit);
cherryPickCommit = mergeUtil.createCherryPickFromCommit(oi,
@@ -147,30 +143,17 @@ public class QtCherryPickPatch {
boolean patchSetNotChanged = cherryPickCommit.equals(commitToCherryPick);
if (!patchSetNotChanged) {
- logger.atInfo().log("qtcodereview: new patch %s -> %s", commitToCherryPick, cherryPickCommit);
+ logger.atInfo().log("qtcodereview: %s cherrypicked as %s", commitToCherryPick, cherryPickCommit);
oi.flush();
}
Timestamp commitTimestamp = new Timestamp(committerIdent.getWhen().getTime());
BatchUpdate bu = batchUpdateFactory.create(project, identifiedUser, commitTimestamp);
- bu.setRepository(git, revWalk, oi);
- if (!patchSetNotChanged && !mergeCommit) {
- Change.Id changeId = insertPatchSet(bu, git, changeData.notes(), cherryPickCommit);
- bu.addOp(changeData.getId(), qtUpdateFactory.create(newStatus,
- null,
- defaultMessage,
- inputMessage,
- tag,
- commitToCherryPick));
- logger.atInfo().log("qtcodereview: cherrypick new patch %s for %s", cherryPickCommit.toObjectId(), changeId);
- } else {
- bu.addOp(changeData.getId(), qtUpdateFactory.create(newStatus,
- null,
- defaultMessage,
- inputMessage,
- tag,
- null));
- }
-
+ bu.addOp(changeData.getId(), qtUpdateFactory.create(newStatus,
+ null,
+ defaultMessage,
+ inputMessage,
+ tag,
+ null));
bu.execute();
logger.atInfo().log("qtcodereview: cherrypick done %s", changeData.getId());
return cherryPickCommit;
@@ -179,19 +162,4 @@ public class QtCherryPickPatch {
}
}
- private Change.Id insertPatchSet(BatchUpdate bu,
- Repository git,
- ChangeNotes destNotes,
- CodeReviewCommit cherryPickCommit)
- throws IOException, BadRequestException, ConfigInvalidException {
- Change destChange = destNotes.getChange();
- PatchSet.Id psId = ChangeUtil.nextPatchSetId(git, destChange.currentPatchSetId());
- PatchSetInserter inserter = patchSetInserterFactory.create(destNotes, psId, cherryPickCommit);
- inserter.setAllowClosed(true);
- // .setCopyApprovals(true) doesn't work, so copying done in QtChangeUpdateOp
- bu.setNotify(NotifyResolver.Result.none());
- bu.addOp(destChange.getId(), inserter);
- return destChange.getId();
- }
-
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java
index 4979323..83fcb71 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java
@@ -5,6 +5,8 @@
package com.googlesource.gerrit.plugins.qtcodereview;
import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.extensions.api.changes.NotifyHandling;
+import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Branch;
@@ -12,11 +14,15 @@ import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.ChangeMessagesUtil;
+import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.change.PatchSetInserter;
import com.google.gerrit.server.extensions.events.ChangeMerged;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.mail.send.MergedSender;
+import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.ProjectPermission;
@@ -33,6 +39,7 @@ import com.google.gerrit.sshd.CommandMetaData;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.ObjectId;
@@ -81,6 +88,9 @@ class QtCommandBuildApprove extends SshCommand {
private BatchUpdate.Factory updateFactory;
@Inject
+ private PatchSetInserter.Factory patchSetInserterFactory;
+
+ @Inject
private GitReferenceUpdated referenceUpdated;
@Inject
@@ -185,7 +195,7 @@ class QtCommandBuildApprove extends SshCommand {
throw die("invalid branch " + e.getMessage());
} catch (NoSuchRefException e) {
throw die("invalid reference " + e.getMessage());
- } catch (UpdateException | RestApiException e) {
+ } catch (UpdateException | RestApiException | ConfigInvalidException e ) {
logger.atSevere().log("qtcodereview: staging-napprove failed to update change status %s", e);
throw die("Failed to update change status");
} catch (QtUtil.MergeConflictException e) {
@@ -198,12 +208,19 @@ class QtCommandBuildApprove extends SshCommand {
}
private void approveBuildChanges() throws QtUtil.MergeConflictException, NoSuchRefException,
- IOException, UpdateException, RestApiException {
+ IOException, UpdateException, RestApiException,
+ ConfigInvalidException {
if (message == null) message = String.format("Change merged into branch %s", destBranchKey);
ObjectId oldId = git.resolve(destBranchKey.get());
- QtUtil.mergeBranches(user.asIdentifiedUser(), git, buildBranchKey, destBranchKey);
+ Result result = QtUtil.mergeBranches(user.asIdentifiedUser(), git, buildBranchKey, destBranchKey);
+
+ if (result != Result.FAST_FORWARD) {
+ message = "Branch update failed, changed back to NEW. Either the destination branch was changed externally, or this is an issue in the Qt plugin.";
+ rejectBuildChanges();
+ return;
+ }
updateChanges(affectedChanges, Change.Status.MERGED, null,
message, ChangeMessagesUtil.TAG_MERGED, true);
@@ -219,7 +236,8 @@ class QtCommandBuildApprove extends SshCommand {
}
private void rejectBuildChanges() throws QtUtil.MergeConflictException, UpdateException,
- RestApiException {
+ RestApiException, IOException,
+ ConfigInvalidException {
if (message == null) message = String.format("Change rejected for branch %s", destBranchKey);
updateChanges(affectedChanges, Change.Status.NEW, Change.Status.INTEGRATING,
@@ -238,7 +256,8 @@ class QtCommandBuildApprove extends SshCommand {
String changeMessage,
String tag,
Boolean passed)
- throws UpdateException, RestApiException {
+ throws UpdateException, RestApiException,
+ IOException, ConfigInvalidException {
List<Entry<ChangeData,RevCommit>> emailingList = new ArrayList<Map.Entry<ChangeData, RevCommit>>();
@@ -246,10 +265,29 @@ class QtCommandBuildApprove extends SshCommand {
QtChangeUpdateOp op = qtUpdateFactory.create(status, oldStatus, changeMessage, null, tag, null);
try (BatchUpdate u = updateFactory.create(projectKey, user, TimeUtil.nowTs())) {
for (Entry<ChangeData,RevCommit> item : list) {
- Change change = item.getKey().change();
+ ChangeData cd = item.getKey();
+ Change change = cd.change();
if ((oldStatus == null || change.getStatus() == oldStatus)
&& change.getStatus() != Change.Status.MERGED) {
- u.addOp(change.getId(), op);
+ if (status == Change.Status.MERGED) {
+ ObjectId obj = git.resolve(cd.currentPatchSet().getRevision().get());
+ CodeReviewCommit currCommit = new CodeReviewCommit(obj);
+ currCommit.setPatchsetId(cd.currentPatchSet().getId());
+ CodeReviewCommit newCommit = new CodeReviewCommit(item.getValue());
+ Change.Id changeId = insertPatchSet(u, git, cd.notes(), newCommit);
+ if (!changeId.equals(cd.getId())) {
+ logger.atWarning().log("staging-approve wrong changeId for new patchSet %s != %s",
+ changeId, cd.getId());
+ }
+ u.addOp(changeId, qtUpdateFactory.create(status,
+ oldStatus,
+ changeMessage,
+ null,
+ tag,
+ currCommit));
+ } else {
+ u.addOp(change.getId(), op);
+ }
emailingList.add(item);
}
}
@@ -271,6 +309,22 @@ class QtCommandBuildApprove extends SshCommand {
change, destBranchKey);
}
}
+
+ }
+
+ private Change.Id insertPatchSet(BatchUpdate bu,
+ Repository git,
+ ChangeNotes destNotes,
+ CodeReviewCommit cherryPickCommit)
+ throws IOException, BadRequestException, ConfigInvalidException {
+ Change destChange = destNotes.getChange();
+ PatchSet.Id psId = ChangeUtil.nextPatchSetId(git, destChange.currentPatchSetId());
+ PatchSetInserter inserter = patchSetInserterFactory.create(destNotes, psId, cherryPickCommit);
+ inserter.setSendEmail(false)
+ .setAllowClosed(true);
+ // .setCopyApprovals(true) doesn't work, so copying done in QtChangeUpdateOp
+ bu.addOp(destChange.getId(), inserter);
+ return destChange.getId();
}
private void sendMergeEvent(ChangeData changeData) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java
index 4af35d3..881cdc7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java
@@ -122,7 +122,7 @@ class QtCommandNewBuild extends SshCommand {
throw die("No changes in staging branch. Not creating a build reference");
}
- QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.INTEGRATING, Change.Status.STAGED, message, null, null, null);
+ QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.INTEGRATING, Change.Status.STAGED, message, null, QtUtil.TAG_CI, null);
try (BatchUpdate u = updateFactory.create(projectKey, user, TimeUtil.nowTs())) {
for (Entry<ChangeData, RevCommit> item: openChanges) {
Change change = item.getKey().change();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtDefer.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtDefer.java
index a48110c..748b155 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtDefer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtDefer.java
@@ -26,6 +26,7 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.change.ChangeJson;
@@ -85,7 +86,8 @@ class QtDefer extends RetryingRestModifyView<ChangeResource, AbandonInput, Chang
throw new ResourceConflictException("change is " + ChangeUtil.status(change));
}
- QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.DEFERRED, null, "Deferred", input.message, null, null);
+
+ QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.DEFERRED, null, "Deferred", input.message, ChangeMessagesUtil.TAG_ABANDON, null);
try (BatchUpdate u = updateFactory.create(change.getProject(), rsrc.getUser(), TimeUtil.nowTs())) {
u.addOp(rsrc.getId(), op).execute();
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpen.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpen.java
index 205337a..0367e90 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpen.java
@@ -79,7 +79,7 @@ class QtReOpen extends RetryingRestModifyView<ChangeResource, RestoreInput, Chan
throw new ResourceConflictException("change is " + ChangeUtil.status(change));
}
- QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.NEW, Change.Status.DEFERRED, "Reopened", input.message, null, null);
+ QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.NEW, Change.Status.DEFERRED, "Reopened", input.message, QtUtil.TAG_REOPENED, null);
try (BatchUpdate u = updateFactory.create(change.getProject(), rsrc.getUser(), TimeUtil.nowTs())) {
u.addOp(rsrc.getId(), op).execute();
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtStage.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtStage.java
index bcee0f3..2dd1d97 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtStage.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtStage.java
@@ -116,7 +116,7 @@ public class QtStage implements RestModifyView<RevisionResource, SubmitInput>,
throws RestApiException, RepositoryNotFoundException, IOException,
PermissionBackendException, UpdateException, ConfigInvalidException {
- logger.atInfo().log("qtcodereview: submit %s to staging", rsrc.getChange().toString());
+ logger.atInfo().log("qtcodereview: stage %s", rsrc.getChange().toString());
IdentifiedUser submitter = rsrc.getUser().asIdentifiedUser();
change = rsrc.getChange();
@@ -181,7 +181,7 @@ public class QtStage implements RestModifyView<RevisionResource, SubmitInput>,
Change.Status.STAGED,
"Staged for CI", // defaultMessage
null, // inputMessage
- null // tag
+ QtUtil.TAG_CI // tag
);
Result result = qtUtil.updateRef(git, stagingBranchKey.get(), commit.toObjectId(), false);
referenceUpdated.fire(projectKey, stagingBranchKey.get(), destId, commit.toObjectId(), submitter.state());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStage.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStage.java
index b6d5f63..872edb5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStage.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStage.java
@@ -137,7 +137,7 @@ class QtUnStage implements RestModifyView<RevisionResource, SubmitInput>, UiActi
throw new ResourceConflictException("Invalid Revision: " + patchSet);
}
- QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.NEW, Change.Status.STAGED, "Unstaged", null, null, null);
+ QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.NEW, Change.Status.STAGED, "Unstaged", null, QtUtil.TAG_CI, null);
BatchUpdate u = updateFactory.create(projectKey, submitter, TimeUtil.nowTs());
u.addOp(rsrc.getChange().getId(), op).execute();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
index c8fd8e7..246a653 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
@@ -24,6 +24,7 @@ import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.project.NoSuchRefException;
@@ -74,6 +75,10 @@ public class QtUtil {
public static final String R_HEADS = "refs/heads/";
public static final String R_STAGING = "refs/staging/";
public static final String R_BUILDS = "refs/builds/";
+ public static final String TAG_CI = ChangeMessagesUtil.AUTOGENERATED_TAG_PREFIX + "qt:ci";
+ public static final String TAG_ADMINCHANGE = ChangeMessagesUtil.AUTOGENERATED_TAG_PREFIX + "qt:adminchange";
+ public static final String TAG_REOPENED = ChangeMessagesUtil.AUTOGENERATED_TAG_PREFIX + "qt:reopened";
+
private final Provider<InternalChangeQuery> queryProvider;
private final GitReferenceUpdated referenceUpdated;
@@ -282,6 +287,7 @@ public class QtUtil {
return null;
}
+ // Step backwards from the ref and return change list in the same order
private List<ChangeData> arrangeOrderLikeInRef(Repository git,
ObjectId refObj,
ObjectId tipObj,
@@ -307,6 +313,7 @@ public class QtUtil {
ChangeData change = findChangeFromList(changeId, changeList);
if (change != null) results.add(0, change);
+ // It can always be trusted that parent in index 0 is the correct one
commit = revWalk.parseCommit(commit.getParent(0));
}
} while (commit != null && !commit.equals(tipObj) && count < 100);
@@ -330,16 +337,76 @@ public class QtUtil {
projectKey,
srcId,
newId,
- true, // allowFastForward
+ false, // allowFastForward
null, // newStatus
null, // defaultMessage
null, // inputMessage
- null // tag
+ TAG_CI // tag
).toObjectId();
}
return newId;
}
+ // Step backwards from staging head and return 1st commit in integrating status
+ private ObjectId findIntegrationHead(Repository git,
+ ObjectId stagingHead,
+ ObjectId branchHead,
+ List<ChangeData> integratingChanges)
+ throws MissingObjectException, IOException {
+
+ if (stagingHead.equals(branchHead)) return branchHead;
+
+ RevWalk revWalk = new RevWalk(git);
+ RevCommit commit = revWalk.parseCommit(stagingHead);
+ int count = 0;
+ do {
+ count++;
+ String changeId = getChangeId(commit);
+ ChangeData change = findChangeFromList(changeId, integratingChanges);
+ if (change != null) return commit;
+
+ if (commit.getParentCount() > 0) {
+ // It can always be trusted that parent in index 0 is the correct one
+ commit = revWalk.parseCommit(commit.getParent(0));
+ } else commit = null;
+
+ } while (commit != null && !commit.equals(branchHead) && count < 100);
+
+ return branchHead;
+ }
+
+ // Step backwards from staging head and find commit that can be reused
+ private ObjectId findReusableStagingHead(Repository git,
+ ObjectId stagingHead,
+ ObjectId integrationHead,
+ List<ChangeData> stagedChanges)
+ throws MissingObjectException, IOException {
+
+ if (stagingHead.equals(integrationHead)) return integrationHead;
+
+ ObjectId reusableHead = null;
+ RevWalk revWalk = new RevWalk(git);
+ RevCommit commit = revWalk.parseCommit(stagingHead);
+ int count = 0;
+ do {
+ count++;
+ String changeId = getChangeId(commit);
+ ChangeData change = findChangeFromList(changeId, stagedChanges);
+ if (change != null) {
+ if (reusableHead == null) reusableHead = commit;
+ } else reusableHead = null;
+
+ if (commit.getParentCount() > 0) {
+ // It can always be trusted that parent in index 0 is the correct one
+ commit = revWalk.parseCommit(commit.getParent(0));
+ } else commit = null;
+
+ } while (commit != null && !commit.equals(integrationHead) && count < 100);
+
+ if (reusableHead == null) reusableHead = integrationHead;
+ return reusableHead;
+ }
+
public void rebuildStagingBranch(Repository git,
IdentifiedUser user,
final Project.NameKey projectKey,
@@ -349,87 +416,73 @@ public class QtUtil {
InternalChangeQuery query = null;
List<ChangeData> changes_integrating = null;
List<ChangeData> changes_staged = null;
- ObjectId oldStageRefObjId = null;
- ObjectId branchObjId = null;
- ObjectId newStageRefObjId = null;
- ObjectId newObjId = null;
- String branchName = null;
+ List<ChangeData> changes_to_cherrypick = null;
+ ObjectId oldStageRef = null;
+ ObjectId branchRef = null;
+ ObjectId newStageRef = null;
+ ObjectId integratingRef = null;
+ String stagingBranchName = null;
try {
- branchName = stagingBranchKey.get();
- oldStageRefObjId = git.resolve(branchName);
- branchObjId = git.resolve(destBranchShortKey.get());
+ stagingBranchName = stagingBranchKey.get();
+ oldStageRef = git.resolve(stagingBranchName);
+ branchRef = git.resolve(destBranchShortKey.get());
query = queryProvider.get();
- List<ChangeData> unsorted_list = query.byBranchStatus(destBranchShortKey, Change.Status.INTEGRATING);
- changes_integrating = arrangeOrderLikeInRef(git, oldStageRefObjId, branchObjId, unsorted_list);
+ changes_integrating = query.byBranchStatus(destBranchShortKey, Change.Status.INTEGRATING);
query = queryProvider.get();
- unsorted_list = query.byBranchStatus(destBranchShortKey, Change.Status.STAGED);
- changes_staged = arrangeOrderLikeInRef(git, oldStageRefObjId, branchObjId, unsorted_list);
+ changes_staged = query.byBranchStatus(destBranchShortKey, Change.Status.STAGED);
} catch (IOException e) {
- logger.atSevere().log("qtcodereview: rebuild staging ref %s db failed. IOException %s",
+ logger.atSevere().log("qtcodereview: rebuild staging ref %s db query failed. Exception %s",
stagingBranchKey, e);
- throw new MergeConflictException("fatal: IOException");
+ throw new MergeConflictException("fatal: " + e.getMessage());
}
try {
logger.atInfo().log("qtcodereview: rebuild staging ref reset %s back to %s",
stagingBranchKey, destBranchShortKey);
Result result = QtUtil.createStagingBranch(git, destBranchShortKey);
- if (result == null) throw new NoSuchRefException("Cannot create staging ref: " + branchName);
- logger.atInfo().log("qtcodereview: rebuild staging ref reset result %s", result);
- newStageRefObjId = git.resolve(branchName);
- } catch (NoSuchRefException e) {
- logger.atSevere().log("qtcodereview: rebuild staging ref reset %s failed. No such ref %s",
- stagingBranchKey, e);
- throw new MergeConflictException("fatal: NoSuchRefException");
- } catch (IOException e) {
- logger.atSevere().log("qtcodereview: rebuild staging ref reset %s failed. IOException %s",
- stagingBranchKey, e);
- throw new MergeConflictException("fatal: IOException");
+ if (result == null) throw new NoSuchRefException("Cannot create staging ref: " + stagingBranchName);
+ logger.atInfo().log("qtcodereview: rebuild staging ref reset to %s with result %s", branchRef, result);
+ integratingRef = findIntegrationHead(git, oldStageRef, branchRef, changes_integrating);
+ logger.atInfo().log("qtcodereview: rebuild staging integration ref is %s", integratingRef);
+ newStageRef = findReusableStagingHead(git, oldStageRef, integratingRef, changes_staged);
+ logger.atInfo().log("qtcodereview: rebuild staging reused staging ref is %s", newStageRef);
+ changes_to_cherrypick = arrangeOrderLikeInRef(git, oldStageRef, newStageRef, changes_staged);
+ } catch (NoSuchRefException | IOException e) {
+ logger.atSevere().log("qtcodereview: rebuild staging ref reset %s failed. Exception %s",
+ stagingBranchKey, e);
+ throw new MergeConflictException("fatal: " + e.getMessage());
}
try {
- newObjId = pickChangesToStagingRef(git, projectKey, changes_integrating, newStageRefObjId);
- newStageRefObjId = newObjId;
+ newStageRef = pickChangesToStagingRef(git, projectKey, changes_to_cherrypick, newStageRef);
} catch(Exception e) {
- logger.atSevere().log("qtcodereview: rebuild staging ref %s. failed to cherry pick integrating changes %s",
- stagingBranchKey, e);
- newObjId = null;
- }
-
- if (newObjId != null) {
- try {
- newObjId = pickChangesToStagingRef(git, projectKey, changes_staged, newObjId);
- newStageRefObjId = newObjId;
- } catch(Exception e) {
- newObjId = null;
- logger.atInfo().log("qtcodereview: rebuild staging ref %s merge conflict", stagingBranchKey);
- String message = "Merge conflict in staging branch. Status changed back to new. Please stage again.";
- QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.NEW, Change.Status.STAGED, message, null, null, null);
- try (BatchUpdate u = updateFactory.create(projectKey, user, TimeUtil.nowTs())) {
- for (ChangeData item: changes_staged) {
- Change change = item.change();
- logger.atInfo().log("qtcodereview: staging ref rebuild merge conflict. Change %s back to NEW", change);
- u.addOp(change.getId(), op);
- }
- u.execute();
- } catch (UpdateException | RestApiException ex) {
- logger.atSevere().log("qtcodereview: staging ref rebuild. Failed to update change status %s", ex);
+ logger.atInfo().log("qtcodereview: rebuild staging ref %s merge conflict", stagingBranchKey);
+ newStageRef = integratingRef;
+ String message = "Merge conflict in staging branch. Status changed back to new. Please stage again.";
+ QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.NEW, Change.Status.STAGED, message, null, null, null);
+ try (BatchUpdate u = updateFactory.create(projectKey, user, TimeUtil.nowTs())) {
+ for (ChangeData item: changes_staged) {
+ Change change = item.change();
+ logger.atInfo().log("qtcodereview: staging ref rebuild merge conflict. Change %s back to NEW", change);
+ u.addOp(change.getId(), op);
}
+ u.execute();
+ } catch (UpdateException | RestApiException ex) {
+ logger.atSevere().log("qtcodereview: staging ref rebuild. Failed to update change status %s", ex);
}
}
try {
- RefUpdate refUpdate = git.updateRef(branchName);
- refUpdate.setNewObjectId(newStageRefObjId);
+ RefUpdate refUpdate = git.updateRef(stagingBranchName);
+ refUpdate.setNewObjectId(newStageRef);
refUpdate.update();
// send ref updated event only if it changed
- if (!newStageRefObjId.equals(oldStageRefObjId)) {
- referenceUpdated.fire(projectKey, branchName, oldStageRefObjId,
- newStageRefObjId, user.state());
+ if (!newStageRef.equals(oldStageRef)) {
+ referenceUpdated.fire(projectKey, stagingBranchName, oldStageRef, newStageRef, user.state());
}
} catch (IOException e) {
logger.atSevere().log("qtcodereview: rebuild %s failed to update ref %s", stagingBranchKey, e);
@@ -468,7 +521,14 @@ public class QtUtil {
Iterator<RevCommit> i = revWalk.iterator();
while (i.hasNext()) {
RevCommit commit = i.next();
- List<ChangeData> changes = queryProvider.get().byBranchCommit(destination, commit.name());
+ String changeId = getChangeId(commit);
+ List<ChangeData> changes = null;
+
+ if (changeId != null) {
+ Change.Key key = new Change.Key(changeId);
+ changes = queryProvider.get().byBranchKey(destination, key);
+ }
+
if (changes != null && !changes.isEmpty()) {
if (changes.size() > 1) logger.atWarning().log("qtcodereview: commit belongs to multiple changes: %s", commit.name());
ChangeData cd = changes.get(0);
@@ -517,7 +577,7 @@ public class QtUtil {
final CommitBuilder mergeCommit = new CommitBuilder();
mergeCommit.setTreeId(merger.getResultTreeId());
- mergeCommit.setParentIds(mergeTip, toMerge);
+ mergeCommit.setParentIds(mergeTip, toMerge); // important: mergeTip must be parent index 0
mergeCommit.setAuthor(toMerge.getAuthorIdent());
mergeCommit.setCommitter(committerIdent);
mergeCommit.setMessage(message);
@@ -570,6 +630,9 @@ public class QtUtil {
RefUpdate refUpdate = git.updateRef(destination.get());
refUpdate.setNewObjectId(mergeCommit);
return refUpdate.update();
+ } catch (Exception e) {
+ logger.atWarning().log("qtcodereview: merge failed, %s", e);
+ return null;
} finally {
revWalk.dispose();
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java
index ec57b33..9c3be66 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java
@@ -14,8 +14,11 @@ import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.acceptance.TestPlugin;
import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.common.FooterConstants;
+import com.google.gerrit.extensions.client.ChangeStatus;
import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.LabelInfo;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
@@ -96,7 +99,10 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
RestResponse response = call_REST_API_Stage(c.getChangeId(), c.getCommit().getName());
response.assertOK();
Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(change);
+ String branch = getBranchNameFromRef(change.getDest().get());
+ RevCommit stagingHead = getRemoteHead(project, R_STAGING + branch);
+ assertReviewedByFooter(stagingHead, true);
resetEvents();
}
@@ -109,8 +115,7 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
protected void QtUnStage(PushOneCommit.Result c) throws Exception {
RestResponse response = call_REST_API_UnStage(c.getChangeId(), getCurrentPatchId(c));
response.assertOK();
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c.getChange().change());
}
protected RestResponse call_REST_API_UnStage(String changeId, String revisionId) throws Exception {
@@ -127,6 +132,8 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
commandStr += " --build-id " + buildId;
String resultStr = adminSshSession.exec(commandStr);
assertThat(adminSshSession.getError()).isNull();
+ RevCommit buildHead = getRemoteHead(project, R_BUILDS + buildId);
+ assertReviewedByFooter(buildHead, true);
resetEvents();
}
@@ -140,6 +147,8 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
commandStr += " --message " + BUILD_PASS_MESSAGE;
String resultStr = adminSshSession.exec(commandStr);
assertThat(adminSshSession.getError()).isNull();
+ RevCommit branchHead = getRemoteHead(project, R_HEADS + branch);
+ assertReviewedByFooter(branchHead, true);
}
protected void QtFailBuild(String branch, String buildId) throws Exception {
@@ -161,8 +170,7 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
throws Exception {
String pushRef = R_PUSH + branch;
PushOneCommit.Result c = createUserChange(pushRef, message, file, content);
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c.getChange().change());
return c;
}
@@ -185,32 +193,87 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
return result;
}
- protected void assertCherryPick(RevCommit head, RevCommit source, String cherrypickSHA) {
- assertThat(head.getName()).isEqualTo(cherrypickSHA);
+ protected void assertCherryPick(RevCommit head, RevCommit source, RevCommit base) {
assertThat(head).isNotEqualTo(source);
- assertThat(cherrypickSHA).isNotEqualTo(source.getName());
+ assertThat(head.getName()).isNotEqualTo(source.getName());
assertThat(head.getShortMessage()).isEqualTo(source.getShortMessage());
assertThat(head.getFooterLines("Change-Id")).isEqualTo(source.getFooterLines("Change-Id"));
assertThat(head.getParentCount()).isEqualTo(1);
+
+ if (base != null) assertThat(head.getParent(0)).isEqualTo(base);
}
- protected void assertApproval(String changeId, TestAccount user) throws Exception {
- ChangeInfo c = gApi.changes().id(changeId).get(DETAILED_LABELS, CURRENT_REVISION, CURRENT_COMMIT);
+ private void assertStatus(Change change, ChangeStatus status, boolean approved, boolean footer)
+ throws Exception {
+ ChangeInfo cf;
- String label = "Code-Review";
- int expectedVote = 2;
+ if (approved) {
+ cf = gApi.changes().id(change.getChangeId()).get(DETAILED_LABELS, CURRENT_REVISION, CURRENT_COMMIT);
+ Integer vote = getLabelValue(cf, "Code-Review", admin);
+ assertThat(vote).named("label = Code-Review").isEqualTo(2);
+ } else {
+ cf = gApi.changes().id(change.getChangeId()).get(CURRENT_REVISION, CURRENT_COMMIT);
+ }
+
+ assertThat(cf.status).isEqualTo(status);
+ String commitMsg = cf.revisions.get(cf.currentRevision).commit.message;
+
+ if (footer && cf.revisions.get(cf.currentRevision).commit.parents.size() == 1) {
+ assertThat(commitMsg).contains("Reviewed-by");
+ } else {
+ assertThat(commitMsg).doesNotContain("Reviewed-by");
+ }
+ }
+
+ protected void assertStatusNew(Change change) throws Exception {
+ assertStatus(change, ChangeStatus.NEW, false, false);
+ }
+
+ protected void assertStatusStaged(Change change) throws Exception {
+ assertStatus(change, ChangeStatus.STAGED, true, false);
+ }
+
+ protected void assertStatusIntegrating(Change change) throws Exception {
+ assertStatus(change, ChangeStatus.INTEGRATING, true, false);
+ }
+
+ protected void assertStatusMerged(Change change) throws Exception {
+ assertStatus(change, ChangeStatus.MERGED, true, true);
+ }
+
+ private Integer getLabelValue(ChangeInfo c, String label, TestAccount user) {
Integer vote = 0;
- if (c.labels.get(label) != null && c.labels.get(label).all != null) {
- for (ApprovalInfo approval : c.labels.get(label).all) {
+ LabelInfo labels = c.labels.get(label);
+
+ if (labels != null && labels.all != null) {
+ for (ApprovalInfo approval : labels.all) {
if (approval._accountId == user.id().get()) {
vote = approval.value;
break;
}
}
}
+ return vote;
+ }
+
+ protected void assertApproval(String changeId, TestAccount user) throws Exception {
+ ChangeInfo c = gApi.changes().id(changeId).get(DETAILED_LABELS, CURRENT_REVISION, CURRENT_COMMIT);
+
+ String label = "Code-Review";
+ int expectedVote = 2;
+ Integer vote = 0;
+
+ vote = getLabelValue(c, label, user);
+ assertThat(vote).named("label = " + label).isEqualTo(expectedVote);
+ }
+
+ protected void assertReviewedByFooter(RevCommit commit, boolean exists) {
+
+ // Skip initial commit and merge commits
+ if (commit.getParentCount() != 1) return;
- String name = "label = " + label;
- assertThat(vote).named(name).isEqualTo(expectedVote);
+ List<String> changeIds = commit.getFooterLines(FooterConstants.REVIEWED_BY);
+ assertThat(!changeIds.isEmpty()).isEqualTo(exists);
}
protected void assertRefUpdatedEvents(String refName, RevCommit ... expected) throws Exception {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java
index 1c35265..22b55cd 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java
@@ -71,10 +71,8 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
QtNewBuild("master", "test-build-101");
RevCommit updatedHead = qtApproveBuild("master", "test-build-101", c3, null);
- Change change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.MERGED);
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.MERGED);
+ assertStatusMerged(c1.getChange().change());
+ assertStatusMerged(c2.getChange().change());
}
@Test
@@ -108,10 +106,8 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
QtNewBuild("master", "test-build-201");
RevCommit updatedHead = qtFailBuild("master", "test-build-201", c3, initialHead);
- Change change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c1.getChange().change());
+ assertStatusNew(c2.getChange().change());
}
@Test
@@ -196,6 +192,44 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
}
@Test
+ public void errorApproveBuild_FastForwardFail() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c.getChangeId());
+ QtStage(c);
+ QtNewBuild("master", "test-build-605");
+
+ // direct push that causes fast forward failure
+ testRepo.reset(initialHead);
+ PushOneCommit.Result d = pushCommit("master", "commitmsg2", "file2", "content2");
+ approve(d.getChangeId());
+ gApi.changes().id(d.getChangeId()).current().submit();
+ RevCommit branchHead = getRemoteHead();
+
+
+ String stagingRef = R_STAGING + "master";
+ String branchRef = R_HEADS + "master";
+ String commandStr;
+ commandStr ="gerrit-plugin-qt-workflow staging-approve";
+ commandStr += " --project " + project.get();
+ commandStr += " --branch master";
+ commandStr += " --build-id test-build-605";
+ commandStr += " --result pass";
+ commandStr += " --message " + MERGED_MSG;
+ adminSshSession.exec(commandStr);
+ assertThat(adminSshSession.getError()).isNull();
+
+ RevCommit updatedHead = getRemoteHead(project, branchRef);
+ assertThat(updatedHead).isEqualTo(branchHead); // master is not updated
+ RevCommit stagingHead = getRemoteHead(project, stagingRef);
+ assertThat(stagingHead).isEqualTo(branchHead); // staging is updated to branch head
+
+ assertStatusNew(c.getChange().change());
+ Change change = d.getChange().change();
+ assertThat(change.getStatus()).isEqualTo(Change.Status.MERGED);
+ }
+
+ @Test
public void approveBuild_MultiLineMessage() throws Exception {
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
approve(c.getChangeId());
@@ -244,11 +278,12 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
RevCommit buildHead = getRemoteHead(project, buildRef);
assertThat(buildHead.getId()).isNotNull(); // build ref is still there
+ assertReviewedByFooter(buildHead, true);
RevCommit updatedHead = getRemoteHead(project, branchRef);
if (expectedContent != null && expectedHead == null) {
RevCommit commit = expectedContent.getCommit();
- assertCherryPick(updatedHead, commit, getCurrentPatchSHA(expectedContent));
+ assertCherryPick(updatedHead, commit, null);
expectedHead = updatedHead;
} else {
assertThat(updatedHead).isEqualTo(expectedHead); // master is updated
@@ -260,8 +295,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
assertRefUpdatedEvents(branchRef, initialHead, expectedHead);
resetEvents();
- Change change = expectedContent.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.MERGED);
+ assertStatusMerged(expectedContent.getChange().change());
ArrayList<ChangeMessage> messages = new ArrayList(expectedContent.getChange().messages());
assertThat(messages.get(messages.size()-1).getMessage()).isEqualTo(MERGED_MSG); // check last message
@@ -296,7 +330,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
if (c != null && expectedStagingHead == null) {
- assertCherryPick(stagingHead, c.getCommit(), getCurrentPatchSHA(c));
+ assertCherryPick(stagingHead, c.getCommit(), null);
expectedStagingHead = stagingHead;
}
assertThat(stagingHead).isEqualTo(expectedStagingHead); // staging is rebuild
@@ -306,8 +340,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
assertRefUpdatedEvents(stagingRef, stagingHeadOld, stagingHead); // staging is rebuild
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c.getChange().change());
ArrayList<ChangeMessage> messages = new ArrayList<ChangeMessage>(c.getChange().messages());
assertThat(messages.get(messages.size()-1).getMessage()).isEqualTo(FAILED_MSG); // check last message
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java
index f4d3efb..db07c8d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java
@@ -66,10 +66,8 @@ public class QtCommandNewBuildIT extends QtCodeReviewIT {
QtStage(c3);
RevCommit buildHead = qtNewBuild("master", "test-build-101", c3, null);
- Change change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+ assertStatusIntegrating(c1.getChange().change());
+ assertStatusIntegrating(c2.getChange().change());
}
@@ -184,18 +182,18 @@ public class QtCommandNewBuildIT extends QtCodeReviewIT {
assertThat(stagingHead.getId()).isNotEqualTo(initialHead.getId()); // staging is not master
if (expectedHead == null) {
- assertCherryPick(stagingHead, c.getCommit(), getCurrentPatchSHA(c));
+ assertCherryPick(stagingHead, c.getCommit(), null);
expectedHead = stagingHead;
}
RevCommit buildHead = getRemoteHead(project, buildRef);
assertThat(buildHead).isEqualTo(expectedHead); // build ref is updated
assertRefUpdatedEvents(buildRef, null, expectedHead);
+ assertReviewedByFooter(buildHead, true);
resetEvents();
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+ assertStatusIntegrating(c.getChange().change());
ArrayList<ChangeMessage> messages = new ArrayList(c.getChange().messages());
assertThat(messages.get(messages.size() - 1).getMessage()).contains(BUILDING_MSG + buildId); // check last message
@@ -227,5 +225,4 @@ public class QtCommandNewBuildIT extends QtCodeReviewIT {
return adminSshSession.getError();
}
-
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandRebuildStagingIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandRebuildStagingIT.java
index 233aa5b..637b9fa 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandRebuildStagingIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandRebuildStagingIT.java
@@ -51,8 +51,9 @@ public class QtCommandRebuildStagingIT extends QtCodeReviewIT {
QtStage(c1);
QtStage(c2);
QtStage(c3);
+ RevCommit stagingExpected = getRemoteHead(project, R_STAGING + "master");
- RevCommit stagingHead = qtRebuildStaging("master", c3, null);
+ RevCommit stagingHead = qtRebuildStaging("master", null, stagingExpected);
}
@Test
@@ -71,8 +72,9 @@ public class QtCommandRebuildStagingIT extends QtCodeReviewIT {
QtStage(c2);
QtNewBuild("master", "test-build-250");
QtStage(c3);
+ RevCommit stagingExpected = getRemoteHead(project, R_STAGING + "master");
- RevCommit stagingHead = qtRebuildStaging("master", c3, null);
+ RevCommit stagingHead = qtRebuildStaging("master", null, stagingExpected);
}
@Test
@@ -135,9 +137,11 @@ public class QtCommandRebuildStagingIT extends QtCodeReviewIT {
assertThat(updatedHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
+ assertReviewedByFooter(stagingHead, true);
- if (expectedStagingHead==null && expectedContent != null) {
- assertCherryPick(stagingHead, expectedContent.getCommit(), getCurrentPatchSHA(expectedContent));
+
+ if (expectedStagingHead == null && expectedContent != null) {
+ assertCherryPick(stagingHead, expectedContent.getCommit(), null);
expectedStagingHead = stagingHead;
} else {
assertThat(stagingHead).isEqualTo(expectedStagingHead); // staging is updated
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandStageIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandStageIT.java
index 8f0171f..a9e381b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandStageIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandStageIT.java
@@ -160,7 +160,7 @@ public class QtCommandStageIT extends QtCodeReviewIT {
Change change = c.getChange().change();
if (expectFail) assertThat(change.getStatus()).isNotEqualTo(Change.Status.STAGED);
- else assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ else assertStatusStaged(change);
return adminSshSession.getError();
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommitFooterIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommitFooterIT.java
index fda4ba1..952d170 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommitFooterIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommitFooterIT.java
@@ -3,8 +3,8 @@
package com.googlesource.gerrit.plugins.qtcodereview;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
-import static com.google.gerrit.extensions.client.ListChangesOption.COMMIT_FOOTERS;
+import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT;
+import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.server.project.testing.Util.category;
import static com.google.gerrit.server.project.testing.Util.value;
@@ -75,8 +75,8 @@ public class QtCommitFooterIT extends LightweightPluginDaemonTest {
requestScopeOperations.setApiUser(admin.id());
gApi.changes().id(change.getChangeId()).current().submit();
- ChangeInfo cf = gApi.changes().id(change.getChangeId()).get(ALL_REVISIONS, COMMIT_FOOTERS);
- String commitMsg = cf.revisions.get(cf.currentRevision).commitWithFooters;
+ ChangeInfo cf = gApi.changes().id(change.getChangeId()).get(CURRENT_REVISION, CURRENT_COMMIT);
+ String commitMsg = cf.revisions.get(cf.currentRevision).commit.message;
assertThat(commitMsg).contains("Reviewed-by");
assertThat(commitMsg).doesNotContain("Reviewed-on");
assertThat(commitMsg).doesNotContain("Sanity-Review");
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommonFlowsIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommonFlowsIT.java
index fd35c6a..da48465 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommonFlowsIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommonFlowsIT.java
@@ -55,17 +55,14 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
c = pushCommit("master", "no content", "afile", "");
approve(c.getChangeId());
QtStage(c);
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c.getChange().change());
RevCommit stagingHead = getRemoteHead(project, "refs/staging/master");
QtNewBuild("master", "master-build-000");
- change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+ assertStatusIntegrating(c.getChange().change());
QtApproveBuild("master", "master-build-000");
- change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.MERGED);
+ assertStatusMerged(c.getChange().change());
String gitLog = getRemoteLog("refs/staging/master").toString();
assertThat(gitLog).contains(stagingHead.getId().name());
@@ -96,16 +93,13 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
m.assertOkStatus();
approve(m.getChangeId());
QtStage(m);
- Change change = m.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(m.getChange().change());
QtNewBuild("master", "master-build-001");
- change = m.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+ assertStatusIntegrating(m.getChange().change());
QtApproveBuild("master", "master-build-001");
- change = m.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.MERGED);
+ assertStatusMerged(m.getChange().change());
// check that all commits are in staging ref
String gitLog = getRemoteLog("refs/heads/master").toString();
@@ -134,17 +128,13 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
QtStage(c3);
QtNewBuild("master", "master-build-100");
- Change change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusIntegrating(c1.getChange().change());
+ assertStatusStaged(c2.getChange().change());
QtNewBuild("5.12", "5.12-build-100");
QtApproveBuild("5.12", "5.12-build-100");
- change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
- change = c3.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+ assertStatusIntegrating(c1.getChange().change());
+ assertStatusIntegrating(c3.getChange().change());
QtApproveBuild("master", "master-build-100");
RevCommit branchHeadMaster = getRemoteHead(project, R_HEADS + "master");
@@ -170,17 +160,13 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
QtStage(c3);
QtNewBuild("5.12", "5.12-build-101");
- Change change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
- change = c3.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusIntegrating(c1.getChange().change());
+ assertStatusStaged(c3.getChange().change());
QtNewBuild("master", "master-build-101");
QtFailBuild("master", "master-build-101");
- change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
+ assertStatusIntegrating(c1.getChange().change());
+ assertStatusIntegrating(c2.getChange().change());
QtFailBuild("5.12", "5.12-build-101");
RevCommit branchHeadMaster = getRemoteHead(project, R_HEADS + "master");
@@ -202,8 +188,7 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
QtStage(c2);
QtUnStage(c1);
- Change change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c2.getChange().change());
QtUnStage(c2);
RevCommit stagingHeadMaster = getRemoteHead(project, R_STAGING + "master");
@@ -221,18 +206,15 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
approve(c2.getChangeId());
QtStage(c1);
- Change change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
QtNewBuild("master", "master-build-401");
RevCommit build1Head = getRemoteHead(project, R_BUILDS + "master-build-401");
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
QtStage(c2);
QtApproveBuild("master", "master-build-401");
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c2.getChange().change());
QtNewBuild("master", "master-build-402");
RevCommit build2Head = getRemoteHead(project, R_BUILDS + "master-build-402");
@@ -256,18 +238,15 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
approve(c2.getChangeId());
QtStage(c1);
- Change change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
QtNewBuild("master", "master-build-401");
RevCommit build1Head = getRemoteHead(project, R_BUILDS + "master-build-401");
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
QtStage(c2);
QtApproveBuild("master", "master-build-401");
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c2.getChange().change());
QtNewBuild("master", "master-build-402");
RevCommit build2Head = getRemoteHead(project, R_BUILDS + "master-build-402");
@@ -291,24 +270,20 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
approve(c2.getChangeId());
QtStage(c1);
- Change change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
QtNewBuild("master", "master-build-401");
RevCommit build1Head = getRemoteHead(project, R_BUILDS + "master-build-401");
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
QtStage(c2);
QtFailBuild("master", "master-build-401");
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c2.getChange().change());
QtNewBuild("master", "master-build-402");
RevCommit build2Head = getRemoteHead(project, R_BUILDS + "master-build-402");
QtApproveBuild("master", "master-build-402");
- change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c1.getChange().change());;
String gitLog = getRemoteLog("refs/heads/master").toString();
assertThat(gitLog).doesNotContain(build1Head.getId().name());
@@ -328,17 +303,14 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
approve(c2.getChangeId());
QtStage(c1);
- Change change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
QtNewBuild("master", "master-build-401");
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
QtStage(c2);
QtFailBuild("master", "master-build-401");
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c2.getChange().change());
QtNewBuild("master", "master-build-402");
QtFailBuild("master", "master-build-402");
@@ -348,6 +320,32 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
}
@Test
+ public void unStageWhileBuilding() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c1.getChangeId());
+ QtStage(c1);
+ QtNewBuild("master", "master-build-402");
+
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
+ approve(c2.getChangeId());
+ QtStage(c2);
+ RevCommit stagingExpected = getRemoteHead(project, R_STAGING + "master");
+
+ PushOneCommit.Result c3 = pushCommit("master", "commitmsg3", "file3", "content3");
+ approve(c3.getChangeId());
+ QtStage(c3);
+
+ QtUnStage(c3);
+ RevCommit stagingHead = getRemoteHead(project, R_STAGING + "master");
+ assertThat(stagingHead).isEqualTo(stagingExpected);
+
+ assertStatusIntegrating(c1.getChange().change());
+ assertStatusStaged(c2.getChange().change());
+ assertStatusNew(c3.getChange().change());
+ }
+
+ @Test
public void unStage_MergeConflict_While_Building() throws Exception {
RevCommit initialHead = getRemoteHead();
PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
@@ -371,14 +369,10 @@ public class QtCommonFlowsIT extends QtCodeReviewIT {
QtStage(c4);
QtUnStage(c3);
- Change change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.INTEGRATING);
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
- change = c3.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
- change = c4.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusIntegrating(c1.getChange().change());
+ assertStatusNew(c2.getChange().change());
+ assertStatusNew(c3.getChange().change());
+ assertStatusNew(c4.getChange().change());
RevCommit stagingHeadMaster = getRemoteHead(project, R_STAGING + "master");
assertThat(stagingHeadMaster.getId()).isEqualTo(stagingExpected.getId());
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtEmailSendingIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtEmailSendingIT.java
index b785c59..e4ef0f2 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtEmailSendingIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtEmailSendingIT.java
@@ -113,7 +113,7 @@ public class QtEmailSendingIT extends QtCodeReviewIT {
private void QtStageByAdmin(PushOneCommit.Result c) throws Exception {
RestResponse response = call_REST_API_Stage_By_Admin(c.getChangeId(), c.getCommit().getName());
response.assertOK();
- assertThat(c.getChange().change().getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c.getChange().change());
}
private RestResponse call_REST_API_Stage_By_Admin(String changeId, String revisionId) throws Exception {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpenIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpenIT.java
index 0a1710e..5b1ca54 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpenIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpenIT.java
@@ -60,8 +60,7 @@ public class QtReOpenIT extends QtCodeReviewIT {
String url = "/changes/" + changeId + "/gerrit-plugin-qt-workflow~reopen";
RestResponse response = adminRestSession.post(url, restoreInput);
response.assertOK();
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c.getChange().change());
}
@Test
@@ -100,8 +99,7 @@ public class QtReOpenIT extends QtCodeReviewIT {
assertRefUpdatedEvents(masterRef); // no events
assertRefUpdatedEvents(stagingRef); // no events
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c.getChange().change());
return masterHead;
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java
index 626032d..8e07afa 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java
@@ -73,8 +73,8 @@ public class QtStageIT extends QtCodeReviewIT {
approve(c3.getChangeId());
stagingHead = qtStage(c1);
- stagingHead = qtStage(c2);
- stagingHead = qtStage(c3);
+ stagingHead = qtStage(c2, stagingHead);
+ stagingHead = qtStage(c3, stagingHead);
}
@Test
@@ -101,7 +101,42 @@ public class QtStageIT extends QtCodeReviewIT {
PushOneCommit.Result m = mm.to("refs/for/master");
m.assertOkStatus();
approve(m.getChangeId());
- RevCommit stagingHead = qtStageExpectMerge(m);
+ RevCommit stagingHead = qtStageExpectMergeFastForward(m);
+
+ // check that all commits are in staging ref
+ String gitLog = getRemoteLog("refs/staging/master").toString();
+ assertThat(gitLog).contains(initialHead.getId().name());
+ assertThat(gitLog).contains(c1.getCommit().getId().name());
+ assertThat(gitLog).contains(f1.getCommit().getId().name());
+ assertThat(gitLog).contains(f2.getCommit().getId().name());
+ assertThat(gitLog).contains(m.getCommit().getId().name());
+ }
+
+ @Test
+ public void mergeCommit_Stage_ExpectMergeOfMerge() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+
+ // make changes on feature branch
+ PushOneCommit.Result f1 = pushCommit("feature", "commitmsg1", "file1", "content1");
+ PushOneCommit.Result f2 = pushCommit("feature", "commitmsg2", "file2", "content2");
+ approve(f1.getChangeId());
+ gApi.changes().id(f1.getChangeId()).current().submit();
+ approve(f2.getChangeId());
+ gApi.changes().id(f2.getChangeId()).current().submit();
+
+ // make a change on master branch
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg3", "file3", "content3");
+ approve(c1.getChangeId());
+ gApi.changes().id(c1.getChangeId()).current().submit();
+
+ // merge feature branch into master
+ PushOneCommit mm = pushFactory.create(admin.newIdent(), testRepo);
+ mm.setParents(ImmutableList.of(f2.getCommit(), c1.getCommit()));
+ PushOneCommit.Result m = mm.to("refs/for/master");
+ m.assertOkStatus();
+ approve(m.getChangeId());
+ RevCommit stagingHead = qtStageExpectMergeOfMerge(m);
// check that all commits are in staging ref
String gitLog = getRemoteLog("refs/staging/master").toString();
@@ -123,7 +158,7 @@ public class QtStageIT extends QtCodeReviewIT {
// no changes in this commit
c = pushCommit("master", "no content", "afile", "");
approve(c.getChangeId());
- stagingHead = qtStage(c);
+ stagingHead = qtStage(c, stagingHead);
assertApproval(c.getChangeId(), admin);
}
@@ -219,19 +254,26 @@ public class QtStageIT extends QtCodeReviewIT {
RestResponse response = qtStageExpectFail(c2, initialHead, stagingHead1, HttpStatus.SC_CONFLICT);
assertThat(response.getEntityContent()).contains("merge conflict");
- Change change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
}
private RevCommit qtStage(PushOneCommit.Result c) throws Exception {
- return qtStage(c, false);
+ return qtStage(c, false, false, null);
+ }
+
+ private RevCommit qtStage(PushOneCommit.Result c, RevCommit base) throws Exception {
+ return qtStage(c, false, false, base);
+ }
+
+ private RevCommit qtStageExpectMergeFastForward(PushOneCommit.Result c) throws Exception {
+ return qtStage(c, true, true, null);
}
- private RevCommit qtStageExpectMerge(PushOneCommit.Result c) throws Exception {
- return qtStage(c, true);
+ private RevCommit qtStageExpectMergeOfMerge(PushOneCommit.Result c) throws Exception {
+ return qtStage(c, true, false, null);
}
- private RevCommit qtStage(PushOneCommit.Result c, boolean merge) throws Exception {
+ private RevCommit qtStage(PushOneCommit.Result c, boolean merge, boolean fastForward, RevCommit base) throws Exception {
String branch = getBranchNameFromRef(c.getChange().change().getDest().get());
String stagingRef = R_STAGING + branch;
String branchRef = R_HEADS + branch;
@@ -247,19 +289,21 @@ public class QtStageIT extends QtCodeReviewIT {
assertThat(branchHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
+ assertReviewedByFooter(stagingHead, true);
- if (merge) {
+ if (fastForward) {
+ assertThat(stagingHead).isEqualTo(originalCommit);
+ } else if (merge) {
assertThat(stagingHead.getParentCount()).isEqualTo(2);
assertThat(stagingHead.getParent(1)).isEqualTo(originalCommit);
} else {
- assertCherryPick(stagingHead, originalCommit, getCurrentPatchSHA(c));
+ assertCherryPick(stagingHead, originalCommit, base);
}
assertThat(stagingHead.getParent(0)).isEqualTo(oldStagingHead);
assertRefUpdatedEvents(stagingRef, oldStagingHead, stagingHead);
resetEvents();
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c.getChange().change());
ArrayList<ChangeMessage> messages = new ArrayList(c.getChange().messages());
assertThat(messages.get(messages.size()-1).getMessage()).isEqualTo(STAGED_MSG); // check last message
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStageIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStageIT.java
index 4c09d65..291fb96 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStageIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtUnStageIT.java
@@ -54,6 +54,21 @@ public class QtUnStageIT extends QtCodeReviewIT {
}
@Test
+ public void multiChange_UnStage_NoFastForwardOnStagingRefRebuild() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c1.getChangeId());
+ QtStage(c1);
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
+ approve(c2.getChangeId());
+ QtStage(c2);
+
+ RevCommit stagingHead = qtUnStageExpectCherryPick(c1, c2);
+ }
+
+ @Test
public void multiChange_UnStage_First() throws Exception {
// Push 3 independent commits
RevCommit initialHead = getRemoteHead();
@@ -71,10 +86,8 @@ public class QtUnStageIT extends QtCodeReviewIT {
QtStage(c3);
RevCommit stagingHead = qtUnStageExpectCherryPick(c1, c3);
- Change change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
- change = c3.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c2.getChange().change());
+ assertStatusStaged(c3.getChange().change());
}
@Test
@@ -95,10 +108,8 @@ public class QtUnStageIT extends QtCodeReviewIT {
QtStage(c3);
RevCommit stagingHead = qtUnStageExpectCherryPick(c2, c3);
- Change change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
- change = c3.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c1.getChange().change());
+ assertStatusStaged(c3.getChange().change());
}
@Test
@@ -120,10 +131,8 @@ public class QtUnStageIT extends QtCodeReviewIT {
QtStage(c3);
RevCommit stagingHead = qtUnStageExpectCommit(c3, expectedFastForward);
- Change change = c1.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
- change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.STAGED);
+ assertStatusStaged(c1.getChange().change());
+ assertStatusStaged(c2.getChange().change());
}
@Test
@@ -143,6 +152,7 @@ public class QtUnStageIT extends QtCodeReviewIT {
PushOneCommit.Result c1 = pushCommit("master", "commitmsg3", "file3", "content3");
approve(c1.getChangeId());
gApi.changes().id(c1.getChangeId()).current().submit();
+ RevCommit stagingHead = getRemoteHead(project, R_HEADS + "master");
// merge feature branch into master
PushOneCommit mm = pushFactory.create(admin.newIdent(), testRepo);
@@ -158,7 +168,7 @@ public class QtUnStageIT extends QtCodeReviewIT {
approve(c2.getChangeId());
QtStage(c2);
- RevCommit stagingHead = qtUnStageExpectCherryPick(m, c2);
+ stagingHead = qtUnStageExpectCherryPick(m, c2, stagingHead);
String gitLog = getRemoteLog("refs/staging/master").toString();
assertThat(gitLog).contains(initialHead.getId().name());
assertThat(gitLog).contains(c1.getCommit().getId().name());
@@ -169,7 +179,7 @@ public class QtUnStageIT extends QtCodeReviewIT {
}
@Test
- public void multiChange_UnStage_Before_MergeCommit() throws Exception {
+ public void multiChange_UnStage_Before_MergeCommit_ExpectFastForward() throws Exception {
RevCommit initialHead = getRemoteHead();
// make changes on feature branch
@@ -197,10 +207,54 @@ public class QtUnStageIT extends QtCodeReviewIT {
mm.setParents(ImmutableList.of(c1.getCommit(), f2.getCommit()));
PushOneCommit.Result m = mm.to("refs/for/master");
m.assertOkStatus();
+ RevCommit originalMergeCommit = m.getCommit();
+ approve(m.getChangeId());
+ QtStage(m);
+
+ RevCommit stagingHead = qtUnStageExpectMergeFastForward(c2, originalMergeCommit);
+ String gitLog = getRemoteLog("refs/staging/master").toString();
+ assertThat(gitLog).contains(initialHead.getId().name());
+ assertThat(gitLog).contains(c1.getCommit().getId().name());
+ assertThat(gitLog).contains(stagingHead.getId().name());
+ assertThat(gitLog).contains(f1.getCommit().getId().name());
+ assertThat(gitLog).contains(f2.getCommit().getId().name());
+ assertThat(gitLog).contains(m.getCommit().getId().name());
+ assertThat(gitLog).doesNotContain(c2.getCommit().getId().name());
+ }
+
+ @Test
+ public void multiChange_UnStage_Before_MergeCommit_ExpectMergeOfMerge() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+
+ // make changes on feature branch
+ PushOneCommit.Result f1 = pushCommit("feature", "commitmsg1", "file1", "content1");
+ PushOneCommit.Result f2 = pushCommit("feature", "commitmsg2", "file2", "content2");
+ approve(f1.getChangeId());
+ gApi.changes().id(f1.getChangeId()).current().submit();
+ approve(f2.getChangeId());
+ gApi.changes().id(f2.getChangeId()).current().submit();
+
+ // make a change on master branch
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg3", "file3", "content3");
+ approve(c1.getChangeId());
+ gApi.changes().id(c1.getChangeId()).current().submit();
+
+ // Stage a change
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg4", "file4", "content4");
+ approve(c2.getChangeId());
+ QtStage(c2);
+
+ // merge feature branch and stage it on top
+ PushOneCommit mm = pushFactory.create(admin.newIdent(), testRepo);
+ mm.setParents(ImmutableList.of(f2.getCommit(),c1.getCommit()));
+ PushOneCommit.Result m = mm.to("refs/for/master");
+ m.assertOkStatus();
approve(m.getChangeId());
QtStage(m);
- RevCommit stagingHead = qtUnStageExpectMerge(c2, m);
+ RevCommit stagingHead = qtUnStageExpectMergeOfMerge(c2, m);
String gitLog = getRemoteLog("refs/staging/master").toString();
assertThat(gitLog).contains(initialHead.getId().name());
assertThat(gitLog).contains(c1.getCommit().getId().name());
@@ -228,10 +282,8 @@ public class QtUnStageIT extends QtCodeReviewIT {
QtStage(c3);
RevCommit stagingHead = qtUnStageExpectCommit(c1, initialHead);
- Change change = c2.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
- change = c3.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c2.getChange().change());
+ assertStatusNew(c3.getChange().change());
}
@Test
@@ -295,25 +347,40 @@ public class QtUnStageIT extends QtCodeReviewIT {
private RevCommit qtUnStageExpectCherryPick(PushOneCommit.Result c,
PushOneCommit.Result expectedContent)
throws Exception {
- return qtUnStage(c, null, expectedContent, false);
+ return qtUnStage(c, null, expectedContent, null, false, false);
+ }
+
+ private RevCommit qtUnStageExpectCherryPick(PushOneCommit.Result c,
+ PushOneCommit.Result expectedContent,
+ RevCommit base)
+ throws Exception {
+ return qtUnStage(c, null, expectedContent, base, false, false);
}
private RevCommit qtUnStageExpectCommit(PushOneCommit.Result c,
RevCommit expectedStagingHead)
throws Exception {
- return qtUnStage(c, expectedStagingHead, null, false);
+ return qtUnStage(c, expectedStagingHead, null, null, false, false);
}
- private RevCommit qtUnStageExpectMerge(PushOneCommit.Result c,
- PushOneCommit.Result expectedContent)
- throws Exception {
- return qtUnStage(c, null, expectedContent, true);
+ private RevCommit qtUnStageExpectMergeFastForward(PushOneCommit.Result c,
+ RevCommit expectedStagingHead)
+ throws Exception {
+ return qtUnStage(c, expectedStagingHead, null, null, true, true);
+ }
+
+ private RevCommit qtUnStageExpectMergeOfMerge(PushOneCommit.Result c,
+ PushOneCommit.Result expectedContent)
+ throws Exception {
+ return qtUnStage(c, null, expectedContent, null, true, false);
}
private RevCommit qtUnStage(PushOneCommit.Result c,
RevCommit expectedStagingHead,
PushOneCommit.Result expectedContent,
- boolean merge)
+ RevCommit base,
+ boolean merge,
+ boolean fastForward)
throws Exception {
String branch = getBranchNameFromRef(c.getChange().change().getDest().get());
String stagingRef = R_STAGING + branch;
@@ -331,13 +398,16 @@ public class QtUnStageIT extends QtCodeReviewIT {
RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
assertThat(stagingHead).isNotEqualTo(oldStagingHead);
+ assertReviewedByFooter(stagingHead, true);
- if (merge) {
+ if (fastForward) {
+ assertThat(stagingHead).isEqualTo(expectedStagingHead);
+ } else if (merge) {
assertThat(stagingHead.getParentCount()).isEqualTo(2);
assertThat(stagingHead.getParent(1)).isEqualTo(expectedContent.getCommit());
expectedStagingHead = stagingHead;
} else if (expectedStagingHead == null && expectedContent != null) {
- assertCherryPick(stagingHead, expectedContent.getCommit(), getCurrentPatchSHA(expectedContent));
+ assertCherryPick(stagingHead, expectedContent.getCommit(), base);
expectedStagingHead = stagingHead;
} else {
assertThat(stagingHead).isEqualTo(expectedStagingHead); // staging is updated
@@ -350,8 +420,7 @@ public class QtUnStageIT extends QtCodeReviewIT {
resetEvents();
}
- Change change = c.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.NEW);
+ assertStatusNew(c.getChange().change());
ArrayList<ChangeMessage> messages = new ArrayList(c.getChange().messages());
assertThat(messages.get(messages.size() - 1).getMessage()).isEqualTo(UNSTAGED_MSG);