aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJukka Jokiniva <jukka.jokiniva@qt.io>2020-09-29 08:19:56 +0300
committerJukka Jokiniva <jukka.jokiniva@qt.io>2021-02-04 10:17:24 +0000
commite8b5ec34e8be5b78ac3c034605169358c597a872 (patch)
tree4009e14d2a416e1e2a2419ff908679cf8756ff49
parentf57831d8f6a1bd39c407c6af9982912f40d558b9 (diff)
Support for parallel builds
Staging ref is reset to branch head after new build command. Staging ref is rebuilt after successful build. Staging ref is not rebuilt after failed build. Staging ref rebuilt doesn't include integrating changes. Lock added to prevent parallel execution of build approve commands. Change-Id: I5707cf4d8b1c165dff78d6cc2b9356dfb31ad6c8 Reviewed-by: Daniel Smith <Daniel.Smith@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java13
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java26
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java3
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java53
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java8
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java152
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandListStagingIT.java4
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java41
8 files changed, 198 insertions, 102 deletions
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 f43de65..35407f1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java
@@ -122,6 +122,7 @@ public class QtCherryPickPatch {
RevCommit commit =
QtUtil.merge(committerIdent, git, oi, revWalk, commitToCherryPick, baseCommit, true);
cherryPickCommit = revWalk.parseCommit(commit);
+ logger.atInfo().log("qtcodereview: %s merged as %s", commitToCherryPick, cherryPickCommit);
}
} else {
String commitMessage =
@@ -138,14 +139,14 @@ public class QtCherryPickPatch {
0,
true, // ignoreIdenticalTree
false); // allowConflicts
+ boolean patchSetNotChanged = cherryPickCommit.equals(commitToCherryPick);
+ if (!patchSetNotChanged) {
+ logger.atInfo().log(
+ "qtcodereview: %s cherrypicked as %s", commitToCherryPick, cherryPickCommit);
+ oi.flush();
+ }
}
- boolean patchSetNotChanged = cherryPickCommit.equals(commitToCherryPick);
- if (!patchSetNotChanged) {
- 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.addOp(
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 33273cd..73d5b7c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java
@@ -40,6 +40,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.ObjectId;
@@ -82,6 +83,8 @@ class QtCommandBuildApprove extends SshCommand {
@Inject private QtChangeUpdateOp.Factory qtUpdateFactory;
+ private final ReentrantLock buildApproveLock = new ReentrantLock();
+
@Option(
name = "--project",
aliases = {"-p"},
@@ -139,6 +142,15 @@ class QtCommandBuildApprove extends SshCommand {
@Override
protected void run() throws UnloggedFailure {
+ buildApproveLock.lock(); // block processing of parallel requests
+ try {
+ runBuildApprove();
+ } finally {
+ buildApproveLock.unlock();
+ }
+ }
+
+ private void runBuildApprove() throws UnloggedFailure {
logger.atInfo().log(
"qtcodereview: staging-approve -p %s -i %s -r %s -m %s -b %s",
project, buildBranch, result, message, destBranch);
@@ -229,8 +241,10 @@ class QtCommandBuildApprove extends SshCommand {
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.";
+ message = "Unable to merge this integration because another integration parallel to this one "
+ + "successfully merged first and created a conflict in one of the tested changes.\n"
+ + "Please review, resolve conflicts if necessary, and restage.";
+ logger.atInfo().log(message);
rejectBuildChanges();
return;
}
@@ -241,6 +255,10 @@ class QtCommandBuildApprove extends SshCommand {
logger.atInfo().log(
"qtcodereview: staging-approve build %s merged into branch %s", buildBranch, destBranchKey);
+ // need to rebuild the staging ref to include recently merged changes
+ qtUtil.rebuildStagingBranch(
+ git, user.asIdentifiedUser(), projectKey, stagingBranchKey, destBranchShortKey);
+
ObjectId newId = git.resolve(destBranchKey.branch());
// send ref updated event only if there are changes to build
if (!newId.equals(oldId)) {
@@ -262,10 +280,6 @@ class QtCommandBuildApprove extends SshCommand {
ChangeMessagesUtil.TAG_REVERT,
false);
- // need to rebuild the staging ref because the reject changes need to be removed from there
- qtUtil.rebuildStagingBranch(
- git, user.asIdentifiedUser(), projectKey, stagingBranchKey, destBranchShortKey);
-
logger.atInfo().log(
"qtcodereview: staging-approve build %s rejected for branch %s",
buildBranch, destBranchKey);
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 0569099..7ef95f1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java
@@ -162,6 +162,9 @@ class QtCommandNewBuild extends SshCommand {
}
}
+ // reset staging ref back to branch head
+ result = QtUtil.createStagingBranch(git, destBranchShortKey);
+
logger.atInfo().log(
"qtcodereview: staging-new-build build %s for %s created", build, destBranchShortKey);
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 7d7efcd..fc09ac5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
@@ -361,44 +361,15 @@ public class QtUtil {
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,
+ ObjectId branchHead,
List<ChangeData> stagedChanges)
throws MissingObjectException, IOException {
- if (stagingHead.equals(integrationHead)) return integrationHead;
+ if (stagingHead.equals(branchHead)) return branchHead;
ObjectId reusableHead = null;
RevWalk revWalk = new RevWalk(git);
@@ -417,9 +388,9 @@ public class QtUtil {
commit = revWalk.parseCommit(commit.getParent(0));
} else commit = null;
- } while (commit != null && !commit.equals(integrationHead) && count < 100);
+ } while (commit != null && !commit.equals(branchHead) && count < 100);
- if (reusableHead == null) reusableHead = integrationHead;
+ if (reusableHead == null) reusableHead = branchHead;
return reusableHead;
}
@@ -431,13 +402,11 @@ public class QtUtil {
final BranchNameKey destBranchShortKey)
throws MergeConflictException {
InternalChangeQuery query = null;
- List<ChangeData> changes_integrating = null;
List<ChangeData> changes_staged = null;
List<ChangeData> changes_to_cherrypick = null;
ObjectId oldStageRef = null;
ObjectId branchRef = null;
ObjectId newStageRef = null;
- ObjectId integratingRef = null;
String stagingBranchName = null;
try {
@@ -446,9 +415,6 @@ public class QtUtil {
branchRef = git.resolve(destBranchShortKey.branch());
query = queryProvider.get();
- changes_integrating = query.byBranchStatus(destBranchShortKey, Change.Status.INTEGRATING);
-
- query = queryProvider.get();
changes_staged = query.byBranchStatus(destBranchShortKey, Change.Status.STAGED);
} catch (IOException e) {
logger.atSevere().log(
@@ -466,9 +432,7 @@ public class QtUtil {
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);
+ newStageRef = findReusableStagingHead(git, oldStageRef, branchRef, 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) {
@@ -481,7 +445,7 @@ public class QtUtil {
newStageRef = pickChangesToStagingRef(git, projectKey, changes_to_cherrypick, newStageRef);
} catch (Exception e) {
logger.atInfo().log("qtcodereview: rebuild staging ref %s merge conflict", stagingBranchKey);
- newStageRef = integratingRef;
+ newStageRef = branchRef;
String message =
"Merge conflict in staging branch. Status changed back to new. Please stage again.";
QtChangeUpdateOp op =
@@ -612,7 +576,9 @@ public class QtUtil {
mergeCommit.setCommitter(committerIdent);
mergeCommit.setMessage(message);
- return revWalk.parseCommit(objInserter.insert(mergeCommit));
+ ObjectId commit = objInserter.insert(mergeCommit);
+ objInserter.flush();
+ return revWalk.parseCommit(commit);
}
public static RefUpdate.Result mergeBranches(
@@ -648,7 +614,6 @@ public class QtUtil {
user.newCommitterIdent(new Timestamp(System.currentTimeMillis()), TimeZone.getDefault());
RevCommit mergeCommit = merge(committer, git, objInserter, revWalk, toMerge, mergeTip, false);
- objInserter.flush();
logger.atInfo().log("qtcodereview: merge commit for %s added to %s", srcId, destination);
RefUpdate refUpdate = git.updateRef(destination.branch());
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 1bd4ca7..9c4bec8 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java
@@ -209,7 +209,13 @@ public class QtCodeReviewIT extends LightweightPluginDaemonTest {
return result;
}
- protected void assertCherryPick(RevCommit head, RevCommit source, RevCommit base) {
+ protected void assertCherryPick(RevCommit head, RevCommit source, RevCommit base) throws Exception {
+ // Fetch all commit data
+ Repository repo = repoManager.openRepository(project);
+ RevWalk revWalk = new RevWalk(repo);
+ source = revWalk.parseCommit(source);
+ head = revWalk.parseCommit(head);
+
assertThat(head).isNotEqualTo(source);
assertThat(head.getName()).isNotEqualTo(source.getName());
assertThat(head.getShortMessage()).isEqualTo(source.getShortMessage());
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 c92b3d2..29f09da 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java
@@ -51,7 +51,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
QtStage(c);
QtNewBuild("master", "test-build-100");
- RevCommit updatedHead = qtApproveBuild("master", "test-build-100", c, null);
+ RevCommit updatedHead = qtApproveBuild("master", "test-build-100", c, false);
}
@Test
@@ -73,7 +73,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
QtNewBuild("master", "test-build-101");
- RevCommit updatedHead = qtApproveBuild("master", "test-build-101", c3, null);
+ RevCommit updatedHead = qtApproveBuild("master", "test-build-101", c3, false);
assertStatusMerged(c1.getChange().change());
assertStatusMerged(c2.getChange().change());
}
@@ -86,7 +86,98 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
QtStage(c);
QtNewBuild("master", "test-build-200");
- RevCommit updatedHead = qtFailBuild("master", "test-build-200", c, initialHead);
+ RevCommit updatedHead = qtFailBuild("master", "test-build-200", c);
+ }
+
+ @Test
+ public void RebuildStagingRefAfterPassingBuild() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c1.getChangeId());
+ QtStage(c1);
+ QtNewBuild("master", "test-build-parallel-1");
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
+ approve(c2.getChangeId());
+ QtStage(c2);
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c3 = pushCommit("master", "commitmsg3", "file3", "content3");
+ approve(c3.getChangeId());
+ QtStage(c3);
+
+ RevCommit updatedHead = qtApproveBuild("master", "test-build-parallel-1", c1, false);
+ assertStatusStaged(c2.getChange().change());
+ assertStatusStaged(c3.getChange().change());
+
+ // verify that staged changes are in the rebuilt staging ref
+ RevCommit stagingHead = getRemoteRefHead(project, R_STAGING + "master");
+ assertCherryPick(stagingHead, c3.getCommit(), null);
+ assertCherryPick(stagingHead.getParent(0), c2.getCommit(), updatedHead);
+ }
+
+ @Test
+ public void RebuildStagingRefFailsAfterPassingBuild() throws Exception {
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "thesamefile", "content1");
+ approve(c.getChangeId());
+ QtStage(c);
+ QtNewBuild("master", "test-build-201");
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result d1 = pushCommit("master", "commitmsg2", "file2", "content2");
+ approve(d1.getChangeId());
+ QtStage(d1);
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result d2 = pushCommit("master", "commitmsg3", "thesamefile", "content3");
+ approve(d2.getChangeId());
+ QtStage(d2);
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result d3 = pushCommit("master", "commitmsg4", "file4", "content4");
+ approve(d3.getChangeId());
+ QtStage(d3);
+
+ RevCommit updatedHead = qtApproveBuild("master", "test-build-201", c, false);
+
+ RevCommit stagingHead = getRemoteRefHead(project, R_STAGING + "master");
+ assertThat(stagingHead).isEqualTo(updatedHead); // staging is not updated
+ assertStatusMerged(c.getChange().change());
+ assertStatusNew(d1.getChange().change());
+ assertStatusNew(d2.getChange().change());
+ assertStatusNew(d3.getChange().change());
+ }
+
+ @Test
+ public void parallelBuilds_MergeCommitVerify() throws Exception {
+ // created 3 parallel builds
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c1.getChangeId());
+ QtStage(c1);
+ QtNewBuild("master", "test-build-parallel-1");
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
+ approve(c2.getChangeId());
+ QtStage(c2);
+ QtNewBuild("master", "test-build-parallel-2");
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c3 = pushCommit("master", "commitmsg3", "file3", "content3");
+ approve(c3.getChangeId());
+ QtStage(c3);
+ QtNewBuild("master", "test-build-parallel-3");
+
+ RevCommit updatedHead = qtApproveBuild("master", "test-build-parallel-1", c1, false);
+ updatedHead = qtApproveBuild("master", "test-build-parallel-2", c2, true);
+ updatedHead = qtApproveBuild("master", "test-build-parallel-3", c3, true);
+
+ assertStatusMerged(c1.getChange().change());
+ assertStatusMerged(c2.getChange().change());
+ assertStatusMerged(c3.getChange().change());
}
@Test
@@ -191,7 +282,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
QtNewBuild("master", "test-build-201");
- RevCommit updatedHead = qtFailBuild("master", "test-build-201", c3, initialHead);
+ RevCommit updatedHead = qtFailBuild("master", "test-build-201", c3);
assertStatusNew(c1.getChange().change());
assertStatusNew(c2.getChange().change());
}
@@ -249,7 +340,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
approve(c.getChangeId());
QtStage(c);
QtNewBuild("master", "test-build-602");
- RevCommit updatedHead = qtApproveBuild("master", "test-build-602", c, null);
+ RevCommit updatedHead = qtApproveBuild("master", "test-build-602", c, false);
String resultStr = qtApproveBuildExpectFail("pass", "master", "test-build-602");
assertThat(resultStr).contains("No open changes in the build branch");
@@ -278,22 +369,23 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
}
@Test
- public void errorApproveBuild_FastForwardFail() throws Exception {
+ public void errorApproveBuild_MergeFailInParallelBuilds() 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
+ // parallel change causing a merge conflict
testRepo.reset(initialHead);
- PushOneCommit.Result d = pushCommit("master", "commitmsg2", "file2", "content2");
+ PushOneCommit.Result d = pushCommit("master", "commitmsg2", "file1", "content2");
approve(d.getChangeId());
- gApi.changes().id(d.getChangeId()).current().submit();
+ QtStage(d);
+ QtNewBuild("master", "test-build-606");
+ QtApproveBuild("master", "test-build-606");
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();
@@ -304,14 +396,13 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
adminSshSession.exec(commandStr);
assertThat(adminSshSession.getError()).isNull();
- RevCommit updatedHead = getRemoteHead(project, branchRef);
+ RevCommit updatedHead = getRemoteHead();
assertThat(updatedHead).isEqualTo(branchHead); // master is not updated
- RevCommit stagingHead = getRemoteHead(project, stagingRef);
- assertThat(stagingHead).isEqualTo(branchHead); // staging is updated to branch head
+ RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
+ assertThat(stagingHead).isEqualTo(branchHead); // staging is not updated
assertStatusNew(c.getChange().change());
- Change change = d.getChange().change();
- assertThat(change.getStatus()).isEqualTo(Change.Status.MERGED);
+ assertStatusMerged(d.getChange().change());
}
@Test
@@ -319,13 +410,13 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
approve(c.getChangeId());
QtStage(c);
- QtNewBuild("master", "test-build-605");
+ QtNewBuild("master", "test-build-607");
String commandStr;
commandStr = "gerrit-plugin-qt-workflow staging-approve";
commandStr += " --project " + project.get();
commandStr += " --branch master";
- commandStr += " --build-id test-build-605";
+ commandStr += " --build-id test-build-607";
commandStr += " --result pass";
commandStr += " --message -";
String multiMessage = "the build\nwas\n\"approved\"\n";
@@ -341,7 +432,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
}
private RevCommit qtApproveBuild(
- String branch, String buildId, PushOneCommit.Result expectedContent, RevCommit expectedHead)
+ String branch, String buildId, PushOneCommit.Result expectedContent, boolean expectMerge)
throws Exception {
String stagingRef = R_STAGING + branch;
String branchRef = R_HEADS + branch;
@@ -365,18 +456,17 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
assertReviewedByFooter(buildHead, true);
RevCommit updatedHead = getRemoteHead(project, branchRef);
- if (expectedContent != null && expectedHead == null) {
- RevCommit commit = expectedContent.getCommit();
- assertCherryPick(updatedHead, commit, null);
- expectedHead = updatedHead;
+ if (expectMerge) {
+ assertThat(updatedHead.getParentCount()).isEqualTo(2);
+ assertCherryPick(updatedHead.getParent(1), expectedContent.getCommit(), null);
} else {
- assertThat(updatedHead).isEqualTo(expectedHead); // master is updated
+ assertCherryPick(updatedHead, expectedContent.getCommit(), null);
}
RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
- assertThat(stagingHead).isEqualTo(stagingHeadOld); // staging remains the same
+ assertThat(stagingHead).isNotEqualTo(stagingHeadOld); // staging is rebuilt
- assertRefUpdatedEvents(branchRef, initialHead, expectedHead);
+ assertRefUpdatedEvents(branchRef, initialHead, updatedHead);
resetEvents();
assertStatusMerged(expectedContent.getChange().change());
@@ -388,8 +478,7 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
return updatedHead;
}
- private RevCommit qtFailBuild(
- String branch, String buildId, PushOneCommit.Result c, RevCommit expectedStagingHead)
+ private RevCommit qtFailBuild(String branch, String buildId, PushOneCommit.Result c)
throws Exception {
String stagingRef = R_STAGING + branch;
String branchRef = R_HEADS + branch;
@@ -411,18 +500,11 @@ public class QtCommandBuildApproveIT extends QtCodeReviewIT {
assertThat(updatedHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
-
- if (c != null && expectedStagingHead == null) {
- assertCherryPick(stagingHead, c.getCommit(), null);
- expectedStagingHead = stagingHead;
- }
- assertThat(stagingHead).isEqualTo(expectedStagingHead); // staging is rebuild
+ assertThat(stagingHead).isEqualTo(stagingHeadOld); // staging ref remains the same
RevCommit buildHead = getRemoteHead(project, buildRef);
assertThat(buildHead.getId()).isNotNull(); // build ref is still there
- assertRefUpdatedEvents(stagingRef, stagingHeadOld, stagingHead); // staging is rebuild
-
assertStatusNew(c.getChange().change());
ArrayList<ChangeMessage> messages = new ArrayList<ChangeMessage>(c.getChange().messages());
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandListStagingIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandListStagingIT.java
index 34d0c28..c222853 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandListStagingIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandListStagingIT.java
@@ -57,9 +57,7 @@ public class QtCommandListStagingIT extends QtCodeReviewIT {
QtNewBuild("master", "test-build-251");
result = qtListStaging("refs/staging/master", "refs/heads/master");
- assertThat(result).contains(stagingHead1.getId().name());
- assertThat(result).contains(stagingHead2.getId().name());
- assertThat(result).contains(stagingHead3.getId().name());
+ assertThat(result).isEmpty();
result = qtListStaging("refs/builds/test-build-251", "master");
assertThat(result).contains(stagingHead1.getId().name());
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 cc6cb8a..96a8e48 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuildIT.java
@@ -63,6 +63,32 @@ public class QtCommandNewBuildIT extends QtCodeReviewIT {
}
@Test
+ public void parallelBuilds_New_Staged_Integrating() throws Exception {
+ // 3 parallel integrations
+ RevCommit initialHead = getRemoteHead();
+ PushOneCommit.Result c1 = pushCommit("master", "commitmsg1", "file1", "content1");
+ approve(c1.getChangeId());
+ QtStage(c1);
+ RevCommit buildHead1 = qtNewBuild("master", "test-build-paraller-1", c1, null);
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c2 = pushCommit("master", "commitmsg2", "file2", "content2");
+ approve(c2.getChangeId());
+ QtStage(c2);
+ RevCommit buildHead2 = qtNewBuild("master", "test-build-paraller-2", c2, null);
+
+ testRepo.reset(initialHead);
+ PushOneCommit.Result c3 = pushCommit("master", "commitmsg3", "file3", "content3");
+ approve(c3.getChangeId());
+ QtStage(c3);
+ RevCommit buildHead3 = qtNewBuild("master", "test-build-paraller-3", c3, null);
+
+ assertStatusIntegrating(c1.getChange().change());
+ assertStatusIntegrating(c2.getChange().change());
+ assertStatusIntegrating(c3.getChange().change());
+ }
+
+ @Test
public void errorNewBuild_NoPermission() throws Exception {
PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
approve(c.getChangeId());
@@ -156,6 +182,12 @@ public class QtCommandNewBuildIT extends QtCodeReviewIT {
String buildRef = R_BUILDS + buildId;
String commandStr;
RevCommit initialHead = getRemoteHead(project, branchRef);
+ RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
+
+ if (expectedHead == null) {
+ assertCherryPick(stagingHead, c.getCommit(), null);
+ expectedHead = stagingHead;
+ }
commandStr = "gerrit-plugin-qt-workflow staging-new-build";
commandStr += " --project " + project.get();
@@ -167,13 +199,8 @@ public class QtCommandNewBuildIT extends QtCodeReviewIT {
RevCommit updatedHead = getRemoteHead(project, branchRef);
assertThat(updatedHead.getId()).isEqualTo(initialHead.getId()); // master is not updated
- RevCommit stagingHead = getRemoteRefHead(project, stagingRef);
- assertThat(stagingHead.getId()).isNotEqualTo(initialHead.getId()); // staging is not master
-
- if (expectedHead == null) {
- assertCherryPick(stagingHead, c.getCommit(), null);
- expectedHead = stagingHead;
- }
+ stagingHead = getRemoteRefHead(project, stagingRef);
+ assertThat(stagingHead.getId()).isEqualTo(initialHead.getId()); // staging reset back to master
RevCommit buildHead = getRemoteHead(project, buildRef);
assertThat(buildHead).isEqualTo(expectedHead); // build ref is updated