Skip to content

Commit e8b5ec3

Browse files
committed
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 <[email protected]> Reviewed-by: Edward Welbourne <[email protected]> Reviewed-by: Lars Knoll <[email protected]>
1 parent f57831d commit e8b5ec3

File tree

8 files changed

+198
-102
lines changed

8 files changed

+198
-102
lines changed

src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCherryPickPatch.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ public CodeReviewCommit cherryPickPatch(
122122
RevCommit commit =
123123
QtUtil.merge(committerIdent, git, oi, revWalk, commitToCherryPick, baseCommit, true);
124124
cherryPickCommit = revWalk.parseCommit(commit);
125+
logger.atInfo().log("qtcodereview: %s merged as %s", commitToCherryPick, cherryPickCommit);
125126
}
126127
} else {
127128
String commitMessage =
@@ -138,14 +139,14 @@ public CodeReviewCommit cherryPickPatch(
138139
0,
139140
true, // ignoreIdenticalTree
140141
false); // allowConflicts
142+
boolean patchSetNotChanged = cherryPickCommit.equals(commitToCherryPick);
143+
if (!patchSetNotChanged) {
144+
logger.atInfo().log(
145+
"qtcodereview: %s cherrypicked as %s", commitToCherryPick, cherryPickCommit);
146+
oi.flush();
147+
}
141148
}
142149

143-
boolean patchSetNotChanged = cherryPickCommit.equals(commitToCherryPick);
144-
if (!patchSetNotChanged) {
145-
logger.atInfo().log(
146-
"qtcodereview: %s cherrypicked as %s", commitToCherryPick, cherryPickCommit);
147-
oi.flush();
148-
}
149150
Timestamp commitTimestamp = new Timestamp(committerIdent.getWhen().getTime());
150151
BatchUpdate bu = batchUpdateFactory.create(project, identifiedUser, commitTimestamp);
151152
bu.addOp(

src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApprove.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.util.List;
4141
import java.util.Map;
4242
import java.util.Map.Entry;
43+
import java.util.concurrent.locks.ReentrantLock;
4344
import org.eclipse.jgit.errors.ConfigInvalidException;
4445
import org.eclipse.jgit.errors.RepositoryNotFoundException;
4546
import org.eclipse.jgit.lib.ObjectId;
@@ -82,6 +83,8 @@ class QtCommandBuildApprove extends SshCommand {
8283

8384
@Inject private QtChangeUpdateOp.Factory qtUpdateFactory;
8485

86+
private final ReentrantLock buildApproveLock = new ReentrantLock();
87+
8588
@Option(
8689
name = "--project",
8790
aliases = {"-p"},
@@ -139,6 +142,15 @@ class QtCommandBuildApprove extends SshCommand {
139142

140143
@Override
141144
protected void run() throws UnloggedFailure {
145+
buildApproveLock.lock(); // block processing of parallel requests
146+
try {
147+
runBuildApprove();
148+
} finally {
149+
buildApproveLock.unlock();
150+
}
151+
}
152+
153+
private void runBuildApprove() throws UnloggedFailure {
142154
logger.atInfo().log(
143155
"qtcodereview: staging-approve -p %s -i %s -r %s -m %s -b %s",
144156
project, buildBranch, result, message, destBranch);
@@ -229,8 +241,10 @@ private void approveBuildChanges()
229241
QtUtil.mergeBranches(user.asIdentifiedUser(), git, buildBranchKey, destBranchKey);
230242

231243
if (result != Result.FAST_FORWARD) {
232-
message =
233-
"Branch update failed, changed back to NEW. Either the destination branch was changed externally, or this is an issue in the Qt plugin.";
244+
message = "Unable to merge this integration because another integration parallel to this one "
245+
+ "successfully merged first and created a conflict in one of the tested changes.\n"
246+
+ "Please review, resolve conflicts if necessary, and restage.";
247+
logger.atInfo().log(message);
234248
rejectBuildChanges();
235249
return;
236250
}
@@ -241,6 +255,10 @@ private void approveBuildChanges()
241255
logger.atInfo().log(
242256
"qtcodereview: staging-approve build %s merged into branch %s", buildBranch, destBranchKey);
243257

258+
// need to rebuild the staging ref to include recently merged changes
259+
qtUtil.rebuildStagingBranch(
260+
git, user.asIdentifiedUser(), projectKey, stagingBranchKey, destBranchShortKey);
261+
244262
ObjectId newId = git.resolve(destBranchKey.branch());
245263
// send ref updated event only if there are changes to build
246264
if (!newId.equals(oldId)) {
@@ -262,10 +280,6 @@ private void rejectBuildChanges()
262280
ChangeMessagesUtil.TAG_REVERT,
263281
false);
264282

265-
// need to rebuild the staging ref because the reject changes need to be removed from there
266-
qtUtil.rebuildStagingBranch(
267-
git, user.asIdentifiedUser(), projectKey, stagingBranchKey, destBranchShortKey);
268-
269283
logger.atInfo().log(
270284
"qtcodereview: staging-approve build %s rejected for branch %s",
271285
buildBranch, destBranchKey);

src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandNewBuild.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ protected void run() throws UnloggedFailure {
162162
}
163163
}
164164

165+
// reset staging ref back to branch head
166+
result = QtUtil.createStagingBranch(git, destBranchShortKey);
167+
165168
logger.atInfo().log(
166169
"qtcodereview: staging-new-build build %s for %s created", build, destBranchShortKey);
167170

src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -361,44 +361,15 @@ private ObjectId pickChangesToStagingRef(
361361
return newId;
362362
}
363363

364-
// Step backwards from staging head and return 1st commit in integrating status
365-
private ObjectId findIntegrationHead(
366-
Repository git,
367-
ObjectId stagingHead,
368-
ObjectId branchHead,
369-
List<ChangeData> integratingChanges)
370-
throws MissingObjectException, IOException {
371-
372-
if (stagingHead.equals(branchHead)) return branchHead;
373-
374-
RevWalk revWalk = new RevWalk(git);
375-
RevCommit commit = revWalk.parseCommit(stagingHead);
376-
int count = 0;
377-
do {
378-
count++;
379-
String changeId = getChangeId(commit);
380-
ChangeData change = findChangeFromList(changeId, integratingChanges);
381-
if (change != null) return commit;
382-
383-
if (commit.getParentCount() > 0) {
384-
// It can always be trusted that parent in index 0 is the correct one
385-
commit = revWalk.parseCommit(commit.getParent(0));
386-
} else commit = null;
387-
388-
} while (commit != null && !commit.equals(branchHead) && count < 100);
389-
390-
return branchHead;
391-
}
392-
393364
// Step backwards from staging head and find commit that can be reused
394365
private ObjectId findReusableStagingHead(
395366
Repository git,
396367
ObjectId stagingHead,
397-
ObjectId integrationHead,
368+
ObjectId branchHead,
398369
List<ChangeData> stagedChanges)
399370
throws MissingObjectException, IOException {
400371

401-
if (stagingHead.equals(integrationHead)) return integrationHead;
372+
if (stagingHead.equals(branchHead)) return branchHead;
402373

403374
ObjectId reusableHead = null;
404375
RevWalk revWalk = new RevWalk(git);
@@ -417,9 +388,9 @@ private ObjectId findReusableStagingHead(
417388
commit = revWalk.parseCommit(commit.getParent(0));
418389
} else commit = null;
419390

420-
} while (commit != null && !commit.equals(integrationHead) && count < 100);
391+
} while (commit != null && !commit.equals(branchHead) && count < 100);
421392

422-
if (reusableHead == null) reusableHead = integrationHead;
393+
if (reusableHead == null) reusableHead = branchHead;
423394
return reusableHead;
424395
}
425396

@@ -431,23 +402,18 @@ public void rebuildStagingBranch(
431402
final BranchNameKey destBranchShortKey)
432403
throws MergeConflictException {
433404
InternalChangeQuery query = null;
434-
List<ChangeData> changes_integrating = null;
435405
List<ChangeData> changes_staged = null;
436406
List<ChangeData> changes_to_cherrypick = null;
437407
ObjectId oldStageRef = null;
438408
ObjectId branchRef = null;
439409
ObjectId newStageRef = null;
440-
ObjectId integratingRef = null;
441410
String stagingBranchName = null;
442411

443412
try {
444413
stagingBranchName = stagingBranchKey.branch();
445414
oldStageRef = git.resolve(stagingBranchName);
446415
branchRef = git.resolve(destBranchShortKey.branch());
447416

448-
query = queryProvider.get();
449-
changes_integrating = query.byBranchStatus(destBranchShortKey, Change.Status.INTEGRATING);
450-
451417
query = queryProvider.get();
452418
changes_staged = query.byBranchStatus(destBranchShortKey, Change.Status.STAGED);
453419
} catch (IOException e) {
@@ -466,9 +432,7 @@ public void rebuildStagingBranch(
466432
throw new NoSuchRefException("Cannot create staging ref: " + stagingBranchName);
467433
logger.atInfo().log(
468434
"qtcodereview: rebuild staging ref reset to %s with result %s", branchRef, result);
469-
integratingRef = findIntegrationHead(git, oldStageRef, branchRef, changes_integrating);
470-
logger.atInfo().log("qtcodereview: rebuild staging integration ref is %s", integratingRef);
471-
newStageRef = findReusableStagingHead(git, oldStageRef, integratingRef, changes_staged);
435+
newStageRef = findReusableStagingHead(git, oldStageRef, branchRef, changes_staged);
472436
logger.atInfo().log("qtcodereview: rebuild staging reused staging ref is %s", newStageRef);
473437
changes_to_cherrypick = arrangeOrderLikeInRef(git, oldStageRef, newStageRef, changes_staged);
474438
} catch (NoSuchRefException | IOException e) {
@@ -481,7 +445,7 @@ public void rebuildStagingBranch(
481445
newStageRef = pickChangesToStagingRef(git, projectKey, changes_to_cherrypick, newStageRef);
482446
} catch (Exception e) {
483447
logger.atInfo().log("qtcodereview: rebuild staging ref %s merge conflict", stagingBranchKey);
484-
newStageRef = integratingRef;
448+
newStageRef = branchRef;
485449
String message =
486450
"Merge conflict in staging branch. Status changed back to new. Please stage again.";
487451
QtChangeUpdateOp op =
@@ -612,7 +576,9 @@ public static RevCommit merge(
612576
mergeCommit.setCommitter(committerIdent);
613577
mergeCommit.setMessage(message);
614578

615-
return revWalk.parseCommit(objInserter.insert(mergeCommit));
579+
ObjectId commit = objInserter.insert(mergeCommit);
580+
objInserter.flush();
581+
return revWalk.parseCommit(commit);
616582
}
617583

618584
public static RefUpdate.Result mergeBranches(
@@ -648,7 +614,6 @@ private static RefUpdate.Result mergeObjectToBranch(
648614
user.newCommitterIdent(new Timestamp(System.currentTimeMillis()), TimeZone.getDefault());
649615

650616
RevCommit mergeCommit = merge(committer, git, objInserter, revWalk, toMerge, mergeTip, false);
651-
objInserter.flush();
652617
logger.atInfo().log("qtcodereview: merge commit for %s added to %s", srcId, destination);
653618

654619
RefUpdate refUpdate = git.updateRef(destination.branch());

src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCodeReviewIT.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,13 @@ protected PushOneCommit.Result createUserChange(
209209
return result;
210210
}
211211

212-
protected void assertCherryPick(RevCommit head, RevCommit source, RevCommit base) {
212+
protected void assertCherryPick(RevCommit head, RevCommit source, RevCommit base) throws Exception {
213+
// Fetch all commit data
214+
Repository repo = repoManager.openRepository(project);
215+
RevWalk revWalk = new RevWalk(repo);
216+
source = revWalk.parseCommit(source);
217+
head = revWalk.parseCommit(head);
218+
213219
assertThat(head).isNotEqualTo(source);
214220
assertThat(head.getName()).isNotEqualTo(source.getName());
215221
assertThat(head.getShortMessage()).isEqualTo(source.getShortMessage());

0 commit comments

Comments
 (0)