Submit: Differentiate between conflicts and server errors
If a change cannot be submitted we currently always throw an IntegrationException that is mapped to ResouceConflictException, which the calling user sees as '409 Conflict'. IntegrationException is thrown in 2 cases: 1. the change cannot be submitted due to conflicts 2. the change cannot be submitted due to an error in Gerrit For 2. we should not return '409 Conflict' but rather '500 Internal Server Error'. Returning '409 Conflict' for server errors is bad because our metric and alerting system is not seeing them as errors and we do leak internal messages to the calling user. To fix this we introduce an IntegrateConflictException as subclass of ResourceConflictException that is thrown if there is a conflict on merge and the user should get a '409 Conflict' response. In case of internal server errors we throw StorageException now. Since StorageException is a RuntimeException this cleans up our method signatures quite a bit. We do have some places now that catch StorageException and then throw a new StorageException. I left this in place because I think the message of the newly thrown StorageException is of value. SubmoduleException is still mapped to '409 Conflict', but for this exception we have the same issue. This will be addressed in a follow-up change. Signed-off-by: Edwin Kempin <ekempin@google.com> Change-Id: Ifdc9d122b54f190ac37a0c3e8e10f9a6b0ec4139
This commit is contained in:
@@ -56,7 +56,6 @@ import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.submit.ChangeAlreadyMergedException;
|
||||
import com.google.gerrit.server.submit.CommitMergeStatus;
|
||||
import com.google.gerrit.server.submit.IntegrationException;
|
||||
import com.google.gerrit.server.submit.MergeIdenticalTreeException;
|
||||
import com.google.gerrit.server.submit.MergeSorter;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
@@ -185,8 +184,7 @@ public class MergeUtil {
|
||||
}
|
||||
|
||||
public CodeReviewCommit getFirstFastForward(
|
||||
CodeReviewCommit mergeTip, RevWalk rw, List<CodeReviewCommit> toMerge)
|
||||
throws IntegrationException {
|
||||
CodeReviewCommit mergeTip, RevWalk rw, List<CodeReviewCommit> toMerge) {
|
||||
for (Iterator<CodeReviewCommit> i = toMerge.iterator(); i.hasNext(); ) {
|
||||
try {
|
||||
final CodeReviewCommit n = i.next();
|
||||
@@ -195,19 +193,19 @@ public class MergeUtil {
|
||||
return n;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Cannot fast-forward test during merge", e);
|
||||
throw new StorageException("Cannot fast-forward test during merge", e);
|
||||
}
|
||||
}
|
||||
return mergeTip;
|
||||
}
|
||||
|
||||
public List<CodeReviewCommit> reduceToMinimalMerge(
|
||||
MergeSorter mergeSorter, Collection<CodeReviewCommit> toSort) throws IntegrationException {
|
||||
MergeSorter mergeSorter, Collection<CodeReviewCommit> toSort) {
|
||||
List<CodeReviewCommit> result = new ArrayList<>();
|
||||
try {
|
||||
result.addAll(mergeSorter.sort(toSort));
|
||||
} catch (IOException | StorageException e) {
|
||||
throw new IntegrationException("Branch head sorting failed", e);
|
||||
throw new StorageException("Branch head sorting failed", e);
|
||||
}
|
||||
result.sort(CodeReviewCommit.ORDER);
|
||||
return result;
|
||||
@@ -673,8 +671,10 @@ public class MergeUtil {
|
||||
}
|
||||
|
||||
public boolean canMerge(
|
||||
MergeSorter mergeSorter, Repository repo, CodeReviewCommit mergeTip, CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
MergeSorter mergeSorter,
|
||||
Repository repo,
|
||||
CodeReviewCommit mergeTip,
|
||||
CodeReviewCommit toMerge) {
|
||||
if (hasMissingDependencies(mergeSorter, toMerge)) {
|
||||
return false;
|
||||
}
|
||||
@@ -687,7 +687,7 @@ public class MergeUtil {
|
||||
} catch (NoMergeBaseException e) {
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Cannot merge " + toMerge.name(), e);
|
||||
throw new StorageException("Cannot merge " + toMerge.name(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,8 +695,7 @@ public class MergeUtil {
|
||||
MergeSorter mergeSorter,
|
||||
CodeReviewCommit mergeTip,
|
||||
CodeReviewRevWalk rw,
|
||||
CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
CodeReviewCommit toMerge) {
|
||||
if (hasMissingDependencies(mergeSorter, toMerge)) {
|
||||
return false;
|
||||
}
|
||||
@@ -706,7 +705,7 @@ public class MergeUtil {
|
||||
|| rw.isMergedInto(mergeTip, toMerge)
|
||||
|| rw.isMergedInto(toMerge, mergeTip);
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Cannot fast-forward test during merge", e);
|
||||
throw new StorageException("Cannot fast-forward test during merge", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,8 +714,7 @@ public class MergeUtil {
|
||||
Repository repo,
|
||||
CodeReviewCommit mergeTip,
|
||||
CodeReviewRevWalk rw,
|
||||
CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
CodeReviewCommit toMerge) {
|
||||
if (mergeTip == null) {
|
||||
// The branch is unborn. Fast-forward is possible.
|
||||
//
|
||||
@@ -740,7 +738,7 @@ public class MergeUtil {
|
||||
m.setBase(toMerge.getParent(0));
|
||||
return m.merge(mergeTip, toMerge);
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException(
|
||||
throw new StorageException(
|
||||
String.format(
|
||||
"Cannot merge commit %s with mergetip %s", toMerge.name(), mergeTip.name()),
|
||||
e);
|
||||
@@ -757,12 +755,11 @@ public class MergeUtil {
|
||||
|| canMerge(mergeSorter, repo, mergeTip, toMerge);
|
||||
}
|
||||
|
||||
public boolean hasMissingDependencies(MergeSorter mergeSorter, CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
public boolean hasMissingDependencies(MergeSorter mergeSorter, CodeReviewCommit toMerge) {
|
||||
try {
|
||||
return !mergeSorter.sort(Collections.singleton(toMerge)).contains(toMerge);
|
||||
} catch (IOException | StorageException e) {
|
||||
throw new IntegrationException("Branch head sorting failed", e);
|
||||
throw new StorageException("Branch head sorting failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,7 +772,7 @@ public class MergeUtil {
|
||||
BranchNameKey destBranch,
|
||||
CodeReviewCommit mergeTip,
|
||||
CodeReviewCommit n)
|
||||
throws IntegrationException, InvalidMergeStrategyException {
|
||||
throws InvalidMergeStrategyException {
|
||||
ThreeWayMerger m = newThreeWayMerger(inserter, repoConfig);
|
||||
try {
|
||||
if (m.merge(mergeTip, n)) {
|
||||
@@ -788,10 +785,10 @@ public class MergeUtil {
|
||||
failed(rw, mergeTip, n, getCommitMergeStatus(e.getReason()));
|
||||
} catch (IOException e2) {
|
||||
logger.atSevere().withCause(e2).log("Failed to set merge failure status for " + n.name());
|
||||
throw new IntegrationException("Cannot merge " + n.name(), e);
|
||||
throw new StorageException("Cannot merge " + n.name(), e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Cannot merge " + n.name(), e);
|
||||
throw new StorageException("Cannot merge " + n.name(), e);
|
||||
}
|
||||
return mergeTip;
|
||||
}
|
||||
@@ -964,8 +961,7 @@ public class MergeUtil {
|
||||
}
|
||||
|
||||
public void markCleanMerges(
|
||||
RevWalk rw, RevFlag canMergeFlag, CodeReviewCommit mergeTip, Set<RevCommit> alreadyAccepted)
|
||||
throws IntegrationException {
|
||||
RevWalk rw, RevFlag canMergeFlag, CodeReviewCommit mergeTip, Set<RevCommit> alreadyAccepted) {
|
||||
if (mergeTip == null) {
|
||||
// If mergeTip is null here, branchTip was null, indicating a new branch
|
||||
// at the start of the merge process. We also elected to merge nothing,
|
||||
@@ -993,7 +989,7 @@ public class MergeUtil {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Cannot mark clean merges", e);
|
||||
throw new StorageException("Cannot mark clean merges", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1003,8 +999,7 @@ public class MergeUtil {
|
||||
RevFlag canMergeFlag,
|
||||
CodeReviewCommit oldTip,
|
||||
CodeReviewCommit mergeTip,
|
||||
Iterable<Change.Id> alreadyMerged)
|
||||
throws IntegrationException {
|
||||
Iterable<Change.Id> alreadyMerged) {
|
||||
if (mergeTip == null) {
|
||||
return expected;
|
||||
}
|
||||
@@ -1035,7 +1030,7 @@ public class MergeUtil {
|
||||
}
|
||||
return Sets.difference(expected, found);
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Cannot check if changes were merged", e);
|
||||
throw new StorageException("Cannot check if changes were merged", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ package com.google.gerrit.server.git.validators;
|
||||
import com.google.gerrit.entities.Project;
|
||||
import com.google.gerrit.server.git.validators.OnSubmitValidationListener.Arguments;
|
||||
import com.google.gerrit.server.plugincontext.PluginSetContext;
|
||||
import com.google.gerrit.server.submit.IntegrationException;
|
||||
import com.google.gerrit.server.submit.IntegrationConflictException;
|
||||
import com.google.gerrit.server.update.ChainedReceiveCommands;
|
||||
import com.google.gerrit.server.validators.ValidationException;
|
||||
import com.google.inject.Inject;
|
||||
@@ -38,12 +38,12 @@ public class OnSubmitValidators {
|
||||
|
||||
public void validate(
|
||||
Project.NameKey project, ObjectReader objectReader, ChainedReceiveCommands commands)
|
||||
throws IntegrationException {
|
||||
throws IntegrationConflictException {
|
||||
try (RevWalk rw = new RevWalk(objectReader)) {
|
||||
Arguments args = new Arguments(project, rw, commands);
|
||||
listeners.runEach(l -> l.preBranchUpdate(args), ValidationException.class);
|
||||
} catch (ValidationException e) {
|
||||
throw new IntegrationException(e.getMessage(), e);
|
||||
throw new IntegrationConflictException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
|
||||
import com.google.gerrit.server.submit.IntegrationException;
|
||||
import com.google.gerrit.server.submit.SubmitDryRun;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -163,7 +162,7 @@ public class ConflictsPredicate {
|
||||
args.conflictsCache.put(conflictsKey, conflicts);
|
||||
return conflicts;
|
||||
}
|
||||
} catch (IntegrationException | NoSuchProjectException | StorageException | IOException e) {
|
||||
} catch (NoSuchProjectException | StorageException | IOException e) {
|
||||
ObjectId finalOther = other;
|
||||
warnWithOccasionalStackTrace(
|
||||
e,
|
||||
@@ -181,8 +180,7 @@ public class ConflictsPredicate {
|
||||
return 5;
|
||||
}
|
||||
|
||||
private Set<RevCommit> getAlreadyAccepted(Repository repo, RevWalk rw)
|
||||
throws IntegrationException {
|
||||
private Set<RevCommit> getAlreadyAccepted(Repository repo, RevWalk rw) {
|
||||
try {
|
||||
Set<RevCommit> accepted = new HashSet<>();
|
||||
SubmitDryRun.addCommits(changeDataCache.getAlreadyAccepted(repo), rw, accepted);
|
||||
@@ -192,7 +190,7 @@ public class ConflictsPredicate {
|
||||
}
|
||||
return accepted;
|
||||
} catch (StorageException | IOException e) {
|
||||
throw new IntegrationException("Failed to determine already accepted commits.", e);
|
||||
throw new StorageException("Failed to determine already accepted commits.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.submit.IntegrationException;
|
||||
import com.google.gerrit.server.update.UpdateException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
@@ -103,7 +102,7 @@ public class CherryPick
|
||||
return Response.ok(changeInfo);
|
||||
} catch (InvalidChangeOperationException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
} catch (IntegrationException | NoSuchChangeException e) {
|
||||
} catch (NoSuchChangeException e) {
|
||||
throw new ResourceConflictException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||
import com.google.gerrit.server.submit.IntegrationException;
|
||||
import com.google.gerrit.server.submit.IntegrationConflictException;
|
||||
import com.google.gerrit.server.submit.MergeIdenticalTreeException;
|
||||
import com.google.gerrit.server.update.BatchUpdate;
|
||||
import com.google.gerrit.server.update.UpdateException;
|
||||
@@ -155,15 +155,14 @@ public class CherryPickChange {
|
||||
* @throws IOException Unable to open repository or read from the database.
|
||||
* @throws InvalidChangeOperationException Parent or branch don't exist, or two changes with same
|
||||
* key exist in the branch.
|
||||
* @throws IntegrationException Merge conflict or trees are identical after cherry pick.
|
||||
* @throws UpdateException Problem updating the database using batchUpdateFactory.
|
||||
* @throws RestApiException Error such as invalid SHA1
|
||||
* @throws ConfigInvalidException Can't find account to notify.
|
||||
* @throws NoSuchProjectException Can't find project state.
|
||||
*/
|
||||
public Result cherryPick(Change change, PatchSet patch, CherryPickInput input, BranchNameKey dest)
|
||||
throws IOException, InvalidChangeOperationException, IntegrationException, UpdateException,
|
||||
RestApiException, ConfigInvalidException, NoSuchProjectException {
|
||||
throws IOException, InvalidChangeOperationException, UpdateException, RestApiException,
|
||||
ConfigInvalidException, NoSuchProjectException {
|
||||
return cherryPick(
|
||||
change,
|
||||
change.getProject(),
|
||||
@@ -193,7 +192,6 @@ public class CherryPickChange {
|
||||
* @throws IOException Unable to open repository or read from the database.
|
||||
* @throws InvalidChangeOperationException Parent or branch don't exist, or two changes with same
|
||||
* key exist in the branch.
|
||||
* @throws IntegrationException Merge conflict or trees are identical after cherry pick.
|
||||
* @throws UpdateException Problem updating the database using batchUpdateFactory.
|
||||
* @throws RestApiException Error such as invalid SHA1
|
||||
* @throws ConfigInvalidException Can't find account to notify.
|
||||
@@ -205,8 +203,8 @@ public class CherryPickChange {
|
||||
ObjectId sourceCommit,
|
||||
CherryPickInput input,
|
||||
BranchNameKey dest)
|
||||
throws IOException, InvalidChangeOperationException, IntegrationException, UpdateException,
|
||||
RestApiException, ConfigInvalidException, NoSuchProjectException {
|
||||
throws IOException, InvalidChangeOperationException, UpdateException, RestApiException,
|
||||
ConfigInvalidException, NoSuchProjectException {
|
||||
return cherryPick(
|
||||
sourceChange,
|
||||
project,
|
||||
@@ -251,7 +249,6 @@ public class CherryPickChange {
|
||||
* @throws InvalidChangeOperationException Parent or branch don't exist, or two changes with same
|
||||
* key exist in the branch. Also thrown when idForNewChange is not null but cherry-pick only
|
||||
* creates a new patchset rather than a new change.
|
||||
* @throws IntegrationException Merge conflict or trees are identical after cherry pick.
|
||||
* @throws UpdateException Problem updating the database using batchUpdateFactory.
|
||||
* @throws RestApiException Error such as invalid SHA1
|
||||
* @throws ConfigInvalidException Can't find account to notify.
|
||||
@@ -270,8 +267,8 @@ public class CherryPickChange {
|
||||
@Nullable ObjectId changeIdForNewChange,
|
||||
@Nullable Change.Id idForNewChange,
|
||||
@Nullable String groupName)
|
||||
throws IOException, InvalidChangeOperationException, IntegrationException, UpdateException,
|
||||
RestApiException, ConfigInvalidException, NoSuchProjectException {
|
||||
throws IOException, InvalidChangeOperationException, UpdateException, RestApiException,
|
||||
ConfigInvalidException, NoSuchProjectException {
|
||||
|
||||
IdentifiedUser identifiedUser = user.get();
|
||||
try (Repository git = gitManager.openRepository(project);
|
||||
@@ -408,7 +405,7 @@ public class CherryPickChange {
|
||||
return Result.create(changeId, cherryPickCommit.getFilesWithGitConflicts());
|
||||
}
|
||||
} catch (MergeIdenticalTreeException | MergeConflictException e) {
|
||||
throw new IntegrationException("Cherry pick failed: " + e.getMessage());
|
||||
throw new IntegrationConflictException("Cherry pick failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.google.gerrit.entities.RefNames;
|
||||
import com.google.gerrit.extensions.api.changes.CherryPickInput;
|
||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||
@@ -34,7 +33,6 @@ import com.google.gerrit.server.project.CommitResource;
|
||||
import com.google.gerrit.server.project.ContributorAgreementsChecker;
|
||||
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.submit.IntegrationException;
|
||||
import com.google.gerrit.server.update.UpdateException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
@@ -99,8 +97,6 @@ public class CherryPickCommit implements RestModifyView<CommitResource, CherryPi
|
||||
return Response.ok(changeInfo);
|
||||
} catch (InvalidChangeOperationException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
} catch (IntegrationException e) {
|
||||
throw new ResourceConflictException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,7 @@ public class CherryPick extends SubmitStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge)
|
||||
throws IntegrationException {
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge) {
|
||||
List<CodeReviewCommit> sorted = CodeReviewCommit.ORDER.sortedCopy(toMerge);
|
||||
List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
|
||||
boolean first = true;
|
||||
@@ -90,7 +89,7 @@ public class CherryPick extends SubmitStrategy {
|
||||
|
||||
@Override
|
||||
protected void updateRepoImpl(RepoContext ctx)
|
||||
throws IntegrationException, IOException, MethodNotAllowedException {
|
||||
throws IntegrationConflictException, IOException, MethodNotAllowedException {
|
||||
// If there is only one parent, a cherry-pick can be done by taking the
|
||||
// delta relative to that one parent and redoing that on the current merge
|
||||
// tip.
|
||||
@@ -181,7 +180,7 @@ public class CherryPick extends SubmitStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRepoImpl(RepoContext ctx) throws IntegrationException, IOException {
|
||||
public void updateRepoImpl(RepoContext ctx) throws IntegrationConflictException, IOException {
|
||||
if (args.mergeUtil.hasMissingDependencies(args.mergeSorter, toMerge)) {
|
||||
// One or more dependencies were not met. The status was already marked
|
||||
// on the commit so we have nothing further to perform at this time.
|
||||
@@ -217,8 +216,7 @@ public class CherryPick extends SubmitStrategy {
|
||||
}
|
||||
|
||||
static boolean dryRun(
|
||||
SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge) {
|
||||
return args.mergeUtil.canCherryPick(args.mergeSorter, args.repo, mergeTip, args.rw, toMerge);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,7 @@ public class FastForwardOnly extends SubmitStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge)
|
||||
throws IntegrationException {
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge) {
|
||||
List<CodeReviewCommit> sorted = args.mergeUtil.reduceToMinimalMerge(args.mergeSorter, toMerge);
|
||||
List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
|
||||
CodeReviewCommit newTipCommit =
|
||||
@@ -53,8 +52,7 @@ public class FastForwardOnly extends SubmitStrategy {
|
||||
}
|
||||
|
||||
static boolean dryRun(
|
||||
SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge) {
|
||||
return args.mergeUtil.canFastForward(args.mergeSorter, mergeTip, args.rw, toMerge);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class FastForwardOp extends SubmitStrategyOp {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRepoImpl(RepoContext ctx) throws IntegrationException {
|
||||
protected void updateRepoImpl(RepoContext ctx) {
|
||||
if (args.project.is(BooleanProjectConfig.REJECT_EMPTY_COMMIT)
|
||||
&& toMerge.getParentCount() > 0
|
||||
&& toMerge.getTree().equals(toMerge.getParent(0).getTree())) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2008 The Android Open Source Project
|
||||
// Copyright (C) 2020 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -14,19 +14,23 @@
|
||||
|
||||
package com.google.gerrit.server.submit;
|
||||
|
||||
/** Indicates an integration operation (see {@link MergeOp}) failed. */
|
||||
public class IntegrationException extends Exception {
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
|
||||
/**
|
||||
* Exception to be thrown if integrating (aka merging) a change into the destination branch is not
|
||||
* possible due to conflicts.
|
||||
*
|
||||
* <p>Throwing this exception results in a {@code 409 Conflict} response to the calling user. The
|
||||
* exception message is returned as error message to the user.
|
||||
*/
|
||||
public class IntegrationConflictException extends ResourceConflictException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public IntegrationException(String msg) {
|
||||
public IntegrationConflictException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public IntegrationException(Throwable why) {
|
||||
super(why);
|
||||
}
|
||||
|
||||
public IntegrationException(String msg, Throwable why) {
|
||||
public IntegrationConflictException(String msg, Throwable why) {
|
||||
super(msg, why);
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,7 @@ public class MergeAlways extends SubmitStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge)
|
||||
throws IntegrationException {
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge) {
|
||||
List<CodeReviewCommit> sorted = args.mergeUtil.reduceToMinimalMerge(args.mergeSorter, toMerge);
|
||||
List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
|
||||
if (args.mergeTip.getInitialTip() == null && !sorted.isEmpty()) {
|
||||
@@ -43,8 +42,7 @@ public class MergeAlways extends SubmitStrategy {
|
||||
}
|
||||
|
||||
static boolean dryRun(
|
||||
SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge) {
|
||||
return args.mergeUtil.canMerge(args.mergeSorter, args.repo, mergeTip, toMerge);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ public class MergeIfNecessary extends SubmitStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge)
|
||||
throws IntegrationException {
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge) {
|
||||
List<CodeReviewCommit> sorted = args.mergeUtil.reduceToMinimalMerge(args.mergeSorter, toMerge);
|
||||
List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
|
||||
|
||||
@@ -48,8 +47,7 @@ public class MergeIfNecessary extends SubmitStrategy {
|
||||
}
|
||||
|
||||
static boolean dryRun(
|
||||
SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
SubmitDryRun.Arguments args, CodeReviewCommit mergeTip, CodeReviewCommit toMerge) {
|
||||
return args.mergeUtil.canFastForward(args.mergeSorter, mergeTip, args.rw, toMerge)
|
||||
|| args.mergeUtil.canMerge(args.mergeSorter, args.repo, mergeTip, toMerge);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class MergeOneOp extends SubmitStrategyOp {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRepoImpl(RepoContext ctx) throws IntegrationException, IOException {
|
||||
public void updateRepoImpl(RepoContext ctx) throws IntegrationConflictException, IOException {
|
||||
PersonIdent caller =
|
||||
ctx.getIdentifiedUser()
|
||||
.newCommitterIdent(args.serverIdent.getWhen(), args.serverIdent.getTimeZone());
|
||||
|
||||
@@ -506,12 +506,7 @@ public class MergeOp implements AutoCloseable {
|
||||
logger.atFine().log("Bypassing submit rules");
|
||||
bypassSubmitRules(cs, isRetry);
|
||||
}
|
||||
try {
|
||||
integrateIntoHistory(cs);
|
||||
} catch (IntegrationException e) {
|
||||
logger.atWarning().withCause(e).log("Error from integrateIntoHistory");
|
||||
throw new ResourceConflictException(e.getMessage(), e);
|
||||
}
|
||||
integrateIntoHistory(cs);
|
||||
return null;
|
||||
})
|
||||
.listener(retryTracker)
|
||||
@@ -585,8 +580,7 @@ public class MergeOp implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
private void integrateIntoHistory(ChangeSet cs)
|
||||
throws IntegrationException, RestApiException, UpdateException {
|
||||
private void integrateIntoHistory(ChangeSet cs) throws RestApiException, UpdateException {
|
||||
checkArgument(!cs.furtherHiddenChanges(), "cannot integrate hidden changes into history");
|
||||
logger.atFine().log("Beginning merge attempt on %s", cs);
|
||||
Map<BranchNameKey, BranchBatch> toSubmit = new HashMap<>();
|
||||
@@ -595,7 +589,7 @@ public class MergeOp implements AutoCloseable {
|
||||
try {
|
||||
cbb = cs.changesByBranch();
|
||||
} catch (StorageException e) {
|
||||
throw new IntegrationException("Error reading changes to submit", e);
|
||||
throw new StorageException("Error reading changes to submit", e);
|
||||
}
|
||||
Set<BranchNameKey> branches = cbb.keySet();
|
||||
|
||||
@@ -626,8 +620,10 @@ public class MergeOp implements AutoCloseable {
|
||||
}
|
||||
} catch (NoSuchProjectException e) {
|
||||
throw new ResourceNotFoundException(e.getMessage());
|
||||
} catch (IOException | SubmoduleException e) {
|
||||
throw new IntegrationException(e);
|
||||
} catch (IOException e) {
|
||||
throw new StorageException(e);
|
||||
} catch (SubmoduleException e) {
|
||||
throw new IntegrationConflictException(e.getMessage(), e);
|
||||
} catch (UpdateException e) {
|
||||
if (e.getCause() instanceof LockFailureException) {
|
||||
// Lock failures are a special case: RetryHelper depends on this specific causal chain in
|
||||
@@ -645,13 +641,10 @@ public class MergeOp implements AutoCloseable {
|
||||
//
|
||||
// If you happen across one of these, the correct fix is to convert the
|
||||
// inner IntegrationException to a ResourceConflictException.
|
||||
String msg;
|
||||
if (e.getCause() instanceof IntegrationException) {
|
||||
msg = e.getCause().getMessage();
|
||||
} else {
|
||||
msg = genericMergeError(cs);
|
||||
if (e.getCause() instanceof IntegrationConflictException) {
|
||||
throw (IntegrationConflictException) e.getCause();
|
||||
}
|
||||
throw new IntegrationException(msg, e);
|
||||
throw new StorageException(genericMergeError(cs), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,7 +658,7 @@ public class MergeOp implements AutoCloseable {
|
||||
|
||||
private List<SubmitStrategy> getSubmitStrategies(
|
||||
Map<BranchNameKey, BranchBatch> toSubmit, SubmoduleOp submoduleOp, boolean dryrun)
|
||||
throws IntegrationException, NoSuchProjectException, IOException {
|
||||
throws IntegrationConflictException, NoSuchProjectException, IOException {
|
||||
List<SubmitStrategy> strategies = new ArrayList<>();
|
||||
Set<BranchNameKey> allBranches = submoduleOp.getBranchesInOrder();
|
||||
Set<CodeReviewCommit> allCommits =
|
||||
@@ -711,8 +704,7 @@ public class MergeOp implements AutoCloseable {
|
||||
return strategies;
|
||||
}
|
||||
|
||||
private Set<RevCommit> getAlreadyAccepted(OpenRepo or, CodeReviewCommit branchTip)
|
||||
throws IntegrationException {
|
||||
private Set<RevCommit> getAlreadyAccepted(OpenRepo or, CodeReviewCommit branchTip) {
|
||||
Set<RevCommit> alreadyAccepted = new HashSet<>();
|
||||
|
||||
if (branchTip != null) {
|
||||
@@ -731,7 +723,7 @@ public class MergeOp implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Failed to determine already accepted commits.", e);
|
||||
throw new StorageException("Failed to determine already accepted commits.", e);
|
||||
}
|
||||
|
||||
logger.atFine().log("Found %d existing heads: %s", alreadyAccepted.size(), alreadyAccepted);
|
||||
@@ -746,8 +738,7 @@ public class MergeOp implements AutoCloseable {
|
||||
abstract Set<CodeReviewCommit> commits();
|
||||
}
|
||||
|
||||
private BranchBatch validateChangeList(OpenRepo or, Collection<ChangeData> submitted)
|
||||
throws IntegrationException {
|
||||
private BranchBatch validateChangeList(OpenRepo or, Collection<ChangeData> submitted) {
|
||||
logger.atFine().log("Validating %d changes", submitted.size());
|
||||
Set<CodeReviewCommit> toSubmit = new LinkedHashSet<>(submitted.size());
|
||||
SetMultimap<ObjectId, PatchSet.Id> revisions = getRevisions(or, submitted);
|
||||
@@ -862,8 +853,7 @@ public class MergeOp implements AutoCloseable {
|
||||
return new AutoValue_MergeOp_BranchBatch(submitType, toSubmit);
|
||||
}
|
||||
|
||||
private SetMultimap<ObjectId, PatchSet.Id> getRevisions(OpenRepo or, Collection<ChangeData> cds)
|
||||
throws IntegrationException {
|
||||
private SetMultimap<ObjectId, PatchSet.Id> getRevisions(OpenRepo or, Collection<ChangeData> cds) {
|
||||
try {
|
||||
List<String> refNames = new ArrayList<>(cds.size());
|
||||
for (ChangeData cd : cds) {
|
||||
@@ -883,7 +873,7 @@ public class MergeOp implements AutoCloseable {
|
||||
}
|
||||
return revisions;
|
||||
} catch (IOException | StorageException e) {
|
||||
throw new IntegrationException("Failed to validate changes", e);
|
||||
throw new StorageException("Failed to validate changes", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -892,14 +882,14 @@ public class MergeOp implements AutoCloseable {
|
||||
return str.isOk() ? str.type : null;
|
||||
}
|
||||
|
||||
private OpenRepo openRepo(Project.NameKey project) throws IntegrationException {
|
||||
private OpenRepo openRepo(Project.NameKey project) {
|
||||
try {
|
||||
return orm.getRepo(project);
|
||||
} catch (NoSuchProjectException e) {
|
||||
logger.atWarning().log("Project %s no longer exists, abandoning open changes.", project);
|
||||
abandonAllOpenChangeForDeletedProject(project);
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Error opening project " + project, e);
|
||||
throw new StorageException("Error opening project " + project, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.entities.BranchNameKey;
|
||||
import com.google.gerrit.entities.Project;
|
||||
import com.google.gerrit.entities.RefNames;
|
||||
import com.google.gerrit.exceptions.StorageException;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.change.NotifyResolver;
|
||||
import com.google.gerrit.server.git.CodeReviewCommit;
|
||||
@@ -84,7 +85,7 @@ public class MergeOpRepoManager implements AutoCloseable {
|
||||
branches = Maps.newHashMapWithExpectedSize(1);
|
||||
}
|
||||
|
||||
OpenBranch getBranch(BranchNameKey branch) throws IntegrationException {
|
||||
OpenBranch getBranch(BranchNameKey branch) throws IntegrationConflictException {
|
||||
OpenBranch ob = branches.get(branch);
|
||||
if (ob == null) {
|
||||
ob = new OpenBranch(this, branch);
|
||||
@@ -133,7 +134,7 @@ public class MergeOpRepoManager implements AutoCloseable {
|
||||
final CodeReviewCommit oldTip;
|
||||
MergeTip mergeTip;
|
||||
|
||||
OpenBranch(OpenRepo or, BranchNameKey name) throws IntegrationException {
|
||||
OpenBranch(OpenRepo or, BranchNameKey name) throws IntegrationConflictException {
|
||||
try {
|
||||
Ref ref = or.getRepo().exactRef(name.branch());
|
||||
if (ref != null) {
|
||||
@@ -142,11 +143,11 @@ public class MergeOpRepoManager implements AutoCloseable {
|
||||
|| Objects.equals(RefNames.REFS_CONFIG, name.branch())) {
|
||||
oldTip = null;
|
||||
} else {
|
||||
throw new IntegrationException(
|
||||
throw new IntegrationConflictException(
|
||||
"The destination branch " + name + " does not exist anymore.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IntegrationException("Cannot open branch " + name, e);
|
||||
throw new StorageException("Cannot open branch " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,13 +54,12 @@ public class RebaseSubmitStrategy extends SubmitStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge)
|
||||
throws IntegrationException {
|
||||
public List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge) {
|
||||
List<CodeReviewCommit> sorted;
|
||||
try {
|
||||
sorted = args.rebaseSorter.sort(toMerge);
|
||||
} catch (IOException | StorageException e) {
|
||||
throw new IntegrationException("Commit sorting failed", e);
|
||||
throw new StorageException("Commit sorting failed", e);
|
||||
}
|
||||
List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
|
||||
boolean first = true;
|
||||
@@ -118,7 +117,7 @@ public class RebaseSubmitStrategy extends SubmitStrategy {
|
||||
|
||||
@Override
|
||||
public void updateRepoImpl(RepoContext ctx)
|
||||
throws IntegrationException, InvalidChangeOperationException, RestApiException, IOException,
|
||||
throws InvalidChangeOperationException, RestApiException, IOException,
|
||||
PermissionBackendException {
|
||||
if (args.mergeUtil.canFastForward(
|
||||
args.mergeSorter, args.mergeTip.getCurrentTip(), args.rw, toMerge)) {
|
||||
@@ -193,7 +192,7 @@ public class RebaseSubmitStrategy extends SubmitStrategy {
|
||||
rebaseOp.updateRepo(ctx);
|
||||
} catch (MergeConflictException | NoSuchChangeException e) {
|
||||
toMerge.setStatusCode(CommitMergeStatus.REBASE_MERGE_CONFLICT);
|
||||
throw new IntegrationException(
|
||||
throw new IntegrationConflictException(
|
||||
"Cannot rebase " + toMerge.name() + ": " + e.getMessage(), e);
|
||||
}
|
||||
newCommit = args.rw.parseCommit(rebaseOp.getRebasedCommit());
|
||||
@@ -260,7 +259,7 @@ public class RebaseSubmitStrategy extends SubmitStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRepoImpl(RepoContext ctx) throws IntegrationException, IOException {
|
||||
public void updateRepoImpl(RepoContext ctx) throws IntegrationConflictException, IOException {
|
||||
// There are multiple parents, so this is a merge commit. We don't want
|
||||
// to rebase the merge as clients can't easily rebase their history with
|
||||
// that merge present and replaced by an equivalent merge with a different
|
||||
@@ -306,8 +305,7 @@ public class RebaseSubmitStrategy extends SubmitStrategy {
|
||||
SubmitDryRun.Arguments args,
|
||||
Repository repo,
|
||||
CodeReviewCommit mergeTip,
|
||||
CodeReviewCommit toMerge)
|
||||
throws IntegrationException {
|
||||
CodeReviewCommit toMerge) {
|
||||
// Test for merge instead of cherry pick to avoid false negatives
|
||||
// on commit chains.
|
||||
return args.mergeUtil.canMerge(args.mergeSorter, repo, mergeTip, toMerge);
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.entities.BranchNameKey;
|
||||
import com.google.gerrit.exceptions.StorageException;
|
||||
import com.google.gerrit.extensions.client.SubmitType;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.git.CodeReviewCommit;
|
||||
@@ -117,7 +118,7 @@ public class SubmitDryRun {
|
||||
ObjectId tip,
|
||||
ObjectId toMerge,
|
||||
Set<RevCommit> alreadyAccepted)
|
||||
throws IntegrationException, NoSuchProjectException, IOException {
|
||||
throws NoSuchProjectException, IOException {
|
||||
CodeReviewCommit tipCommit = rw.parseCommit(tip);
|
||||
CodeReviewCommit toMergeCommit = rw.parseCommit(toMerge);
|
||||
RevFlag canMerge = rw.newFlag("CAN_MERGE");
|
||||
@@ -152,7 +153,7 @@ public class SubmitDryRun {
|
||||
default:
|
||||
String errorMsg = "No submit strategy for: " + submitType;
|
||||
logger.atSevere().log(errorMsg);
|
||||
throw new IntegrationException(errorMsg);
|
||||
throw new StorageException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -249,12 +249,8 @@ public abstract class SubmitStrategy {
|
||||
* @param toMerge the set of submitted commits that should be merged using this submit strategy.
|
||||
* Implementations are responsible for ordering of commits, and will not modify the input in
|
||||
* place.
|
||||
* @throws IntegrationException if an error occurred initializing the operations (as opposed to an
|
||||
* error during execution, which will be reported only when the batch update executes the
|
||||
* operations).
|
||||
*/
|
||||
public final void addOps(BatchUpdate bu, Set<CodeReviewCommit> toMerge)
|
||||
throws IntegrationException {
|
||||
public final void addOps(BatchUpdate bu, Set<CodeReviewCommit> toMerge) {
|
||||
List<SubmitStrategyOp> ops = buildOps(toMerge);
|
||||
Set<CodeReviewCommit> added = Sets.newHashSetWithExpectedSize(ops.size());
|
||||
|
||||
@@ -289,6 +285,5 @@ public abstract class SubmitStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge)
|
||||
throws IntegrationException;
|
||||
protected abstract List<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.google.gerrit.server.submit;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gerrit.entities.BranchNameKey;
|
||||
import com.google.gerrit.entities.SubmissionId;
|
||||
import com.google.gerrit.exceptions.StorageException;
|
||||
import com.google.gerrit.extensions.api.changes.SubmitInput;
|
||||
import com.google.gerrit.extensions.client.SubmitType;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
@@ -55,8 +56,7 @@ public class SubmitStrategyFactory {
|
||||
SubmissionId submissionId,
|
||||
SubmitInput submitInput,
|
||||
SubmoduleOp submoduleOp,
|
||||
boolean dryrun)
|
||||
throws IntegrationException {
|
||||
boolean dryrun) {
|
||||
SubmitStrategy.Arguments args =
|
||||
argsFactory.create(
|
||||
submitType,
|
||||
@@ -89,7 +89,7 @@ public class SubmitStrategyFactory {
|
||||
default:
|
||||
String errorMsg = "No submit strategy for: " + submitType;
|
||||
logger.atSevere().log(errorMsg);
|
||||
throw new IntegrationException(errorMsg);
|
||||
throw new StorageException(errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,13 +50,9 @@ public class SubmitStrategyListener implements BatchUpdateListener {
|
||||
|
||||
@Override
|
||||
public void afterUpdateRepos() throws ResourceConflictException {
|
||||
try {
|
||||
markCleanMerges();
|
||||
List<Change.Id> alreadyMerged = checkCommitStatus();
|
||||
findUnmergedChanges(alreadyMerged);
|
||||
} catch (IntegrationException e) {
|
||||
throw new ResourceConflictException(e.getMessage(), e);
|
||||
}
|
||||
markCleanMerges();
|
||||
List<Change.Id> alreadyMerged = checkCommitStatus();
|
||||
findUnmergedChanges(alreadyMerged);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,8 +62,7 @@ public class SubmitStrategyListener implements BatchUpdateListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void findUnmergedChanges(List<Change.Id> alreadyMerged)
|
||||
throws ResourceConflictException, IntegrationException {
|
||||
private void findUnmergedChanges(List<Change.Id> alreadyMerged) throws ResourceConflictException {
|
||||
for (SubmitStrategy strategy : strategies) {
|
||||
if (strategy instanceof CherryPick) {
|
||||
// Can't do this sanity check for CherryPick since:
|
||||
@@ -91,7 +86,7 @@ public class SubmitStrategyListener implements BatchUpdateListener {
|
||||
commitStatus.maybeFailVerbose();
|
||||
}
|
||||
|
||||
private void markCleanMerges() throws IntegrationException {
|
||||
private void markCleanMerges() {
|
||||
for (SubmitStrategy strategy : strategies) {
|
||||
SubmitStrategy.Arguments args = strategy.args;
|
||||
RevCommit initialTip = args.mergeTip.getInitialTip();
|
||||
|
||||
@@ -138,8 +138,7 @@ abstract class SubmitStrategyOp implements BatchUpdateOp {
|
||||
args.submoduleOp.addBranchTip(getDest(), tipAfter);
|
||||
}
|
||||
|
||||
private void checkProjectConfig(RepoContext ctx, CodeReviewCommit commit)
|
||||
throws IntegrationException {
|
||||
private void checkProjectConfig(RepoContext ctx, CodeReviewCommit commit) {
|
||||
String refName = getDest().branch();
|
||||
if (RefNames.REFS_CONFIG.equals(refName)) {
|
||||
logger.atFine().log("Loading new configuration from %s", RefNames.REFS_CONFIG);
|
||||
@@ -147,7 +146,7 @@ abstract class SubmitStrategyOp implements BatchUpdateOp {
|
||||
ProjectConfig cfg = args.projectConfigFactory.create(getProject());
|
||||
cfg.load(ctx.getRevWalk(), commit);
|
||||
} catch (Exception e) {
|
||||
throw new IntegrationException(
|
||||
throw new StorageException(
|
||||
"Submit would store invalid"
|
||||
+ " project configuration "
|
||||
+ commit.name()
|
||||
@@ -542,7 +541,8 @@ abstract class SubmitStrategyOp implements BatchUpdateOp {
|
||||
*
|
||||
* @param commit
|
||||
*/
|
||||
protected CodeReviewCommit amendGitlink(CodeReviewCommit commit) throws IntegrationException {
|
||||
protected CodeReviewCommit amendGitlink(CodeReviewCommit commit)
|
||||
throws IntegrationConflictException {
|
||||
if (!args.submoduleOp.hasSubscription(args.destBranch)) {
|
||||
return commit;
|
||||
}
|
||||
@@ -550,8 +550,11 @@ abstract class SubmitStrategyOp implements BatchUpdateOp {
|
||||
// Modify the commit with gitlink update
|
||||
try {
|
||||
return args.submoduleOp.composeGitlinksCommit(args.destBranch, commit);
|
||||
} catch (SubmoduleException | IOException e) {
|
||||
throw new IntegrationException(
|
||||
} catch (IOException e) {
|
||||
throw new StorageException(
|
||||
"cannot update gitlink for the commit at branch: " + args.destBranch, e);
|
||||
} catch (SubmoduleException e) {
|
||||
throw new IntegrationConflictException(
|
||||
"cannot update gitlink for the commit at branch: " + args.destBranch, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ import com.google.gerrit.acceptance.TestProjectInput;
|
||||
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
|
||||
import com.google.gerrit.common.FooterConstants;
|
||||
import com.google.gerrit.entities.PatchSet;
|
||||
import com.google.gerrit.exceptions.StorageException;
|
||||
import com.google.gerrit.extensions.client.InheritableBoolean;
|
||||
import com.google.gerrit.extensions.client.SubmitType;
|
||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.server.config.UrlFormatter;
|
||||
import com.google.gerrit.server.git.ChangeMessageModifier;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
@@ -129,8 +129,7 @@ public class SubmitByRebaseAlwaysIT extends AbstractSubmitByRebase {
|
||||
ChangeMessageModifier modifier2 = (msg, orig, tip, dest) -> msg + "A-footer: value\n";
|
||||
try (Registration registration =
|
||||
extensionRegistry.newRegistration().add(modifier1).add(modifier2)) {
|
||||
ResourceConflictException thrown =
|
||||
assertThrows(ResourceConflictException.class, () -> submitWithRebase());
|
||||
StorageException thrown = assertThrows(StorageException.class, () -> submitWithRebase());
|
||||
Throwable cause = Throwables.getRootCause(thrown);
|
||||
assertThat(cause).isInstanceOf(RuntimeException.class);
|
||||
assertThat(cause).hasMessageThat().isEqualTo("boom");
|
||||
@@ -146,8 +145,7 @@ public class SubmitByRebaseAlwaysIT extends AbstractSubmitByRebase {
|
||||
.newRegistration()
|
||||
.add(modifier1, "modifier-1")
|
||||
.add(modifier2, "modifier-2")) {
|
||||
ResourceConflictException thrown =
|
||||
assertThrows(ResourceConflictException.class, () -> submitWithRebase());
|
||||
StorageException thrown = assertThrows(StorageException.class, () -> submitWithRebase());
|
||||
Throwable cause = Throwables.getRootCause(thrown);
|
||||
assertThat(cause).isInstanceOf(RuntimeException.class);
|
||||
assertThat(cause)
|
||||
|
||||
Reference in New Issue
Block a user