Let users know which change prevents submit in case of MISSING_DEPENDENCY
If a change cannot be submitted because it depends on a commit that cannot be merged the user got the following message: Depends on change that was not submitted. Commit <commit> depends on commit <other-commit> which cannot be merged. To find the change to which <other-commit> belongs the user must do a change query. Do this for the user and return the change ID too. Now we return: Depends on change that was not submitted. Commit <commit> depends on commit <other-commit> of change <other-change> which cannot be merged. Returning the commit SHA1 of <other-commit> is still useful since the commit that prevents submit may be an outdated patch set and this can be found easier if the commit SHA1 is known. Change-Id: I1368af204702a06d01ee6f812a5da5ac419b89d7 Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -216,7 +216,7 @@ public class MergeUtil {
|
|||||||
List<CodeReviewCommit> result = new ArrayList<>();
|
List<CodeReviewCommit> result = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
result.addAll(mergeSorter.sort(toSort));
|
result.addAll(mergeSorter.sort(toSort));
|
||||||
} catch (IOException e) {
|
} catch (IOException | OrmException e) {
|
||||||
throw new IntegrationException("Branch head sorting failed", e);
|
throw new IntegrationException("Branch head sorting failed", e);
|
||||||
}
|
}
|
||||||
result.sort(CodeReviewCommit.ORDER);
|
result.sort(CodeReviewCommit.ORDER);
|
||||||
@@ -566,7 +566,7 @@ public class MergeUtil {
|
|||||||
throws IntegrationException {
|
throws IntegrationException {
|
||||||
try {
|
try {
|
||||||
return !mergeSorter.sort(Collections.singleton(toMerge)).contains(toMerge);
|
return !mergeSorter.sort(Collections.singleton(toMerge)).contains(toMerge);
|
||||||
} catch (IOException e) {
|
} catch (IOException | OrmException e) {
|
||||||
throw new IntegrationException("Branch head sorting failed", e);
|
throw new IntegrationException("Branch head sorting failed", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,14 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.submit;
|
package com.google.gerrit.server.submit;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toSet;
|
||||||
|
|
||||||
|
import com.google.gerrit.server.query.change.ChangeData;
|
||||||
|
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status codes set on {@link com.google.gerrit.server.git.CodeReviewCommit}s by {@link
|
* Status codes set on {@link com.google.gerrit.server.git.CodeReviewCommit}s by {@link
|
||||||
* SubmitStrategy} implementations.
|
* SubmitStrategy} implementations.
|
||||||
@@ -76,4 +84,23 @@ public enum CommitMergeStatus {
|
|||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String createMissingDependencyMessage(
|
||||||
|
Provider<InternalChangeQuery> queryProvider, String commit, String otherCommit)
|
||||||
|
throws OrmException {
|
||||||
|
List<ChangeData> changes = queryProvider.get().enforceVisibility(true).byCommit(otherCommit);
|
||||||
|
|
||||||
|
if (changes.isEmpty()) {
|
||||||
|
return String.format(
|
||||||
|
"Commit %s depends on commit %s which cannot be merged.", commit, otherCommit);
|
||||||
|
} else if (changes.size() == 1) {
|
||||||
|
return String.format(
|
||||||
|
"Commit %s depends on commit %s of change %d which cannot be merged.",
|
||||||
|
commit, otherCommit, changes.get(0).getId().get());
|
||||||
|
} else {
|
||||||
|
return String.format(
|
||||||
|
"Commit %s depends on commit %s of changes %s which cannot be merged.",
|
||||||
|
commit, otherCommit, changes.stream().map(cd -> cd.getId().get()).collect(toSet()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ package com.google.gerrit.server.submit;
|
|||||||
|
|
||||||
import com.google.gerrit.server.git.CodeReviewCommit;
|
import com.google.gerrit.server.git.CodeReviewCommit;
|
||||||
import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk;
|
import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk;
|
||||||
|
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
import com.google.inject.Provider;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -29,21 +32,24 @@ public class MergeSorter {
|
|||||||
private final CodeReviewRevWalk rw;
|
private final CodeReviewRevWalk rw;
|
||||||
private final RevFlag canMergeFlag;
|
private final RevFlag canMergeFlag;
|
||||||
private final Set<RevCommit> accepted;
|
private final Set<RevCommit> accepted;
|
||||||
|
private final Provider<InternalChangeQuery> queryProvider;
|
||||||
private final Set<CodeReviewCommit> incoming;
|
private final Set<CodeReviewCommit> incoming;
|
||||||
|
|
||||||
public MergeSorter(
|
public MergeSorter(
|
||||||
CodeReviewRevWalk rw,
|
CodeReviewRevWalk rw,
|
||||||
Set<RevCommit> alreadyAccepted,
|
Set<RevCommit> alreadyAccepted,
|
||||||
RevFlag canMergeFlag,
|
RevFlag canMergeFlag,
|
||||||
|
Provider<InternalChangeQuery> queryProvider,
|
||||||
Set<CodeReviewCommit> incoming) {
|
Set<CodeReviewCommit> incoming) {
|
||||||
this.rw = rw;
|
this.rw = rw;
|
||||||
this.canMergeFlag = canMergeFlag;
|
this.canMergeFlag = canMergeFlag;
|
||||||
this.accepted = alreadyAccepted;
|
this.accepted = alreadyAccepted;
|
||||||
|
this.queryProvider = queryProvider;
|
||||||
this.incoming = incoming;
|
this.incoming = incoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<CodeReviewCommit> sort(Collection<CodeReviewCommit> toMerge)
|
public Collection<CodeReviewCommit> sort(Collection<CodeReviewCommit> toMerge)
|
||||||
throws IOException {
|
throws IOException, OrmException {
|
||||||
final Set<CodeReviewCommit> heads = new HashSet<>();
|
final Set<CodeReviewCommit> heads = new HashSet<>();
|
||||||
final Set<CodeReviewCommit> sort = new HashSet<>(toMerge);
|
final Set<CodeReviewCommit> sort = new HashSet<>(toMerge);
|
||||||
while (!sort.isEmpty()) {
|
while (!sort.isEmpty()) {
|
||||||
@@ -64,8 +70,7 @@ public class MergeSorter {
|
|||||||
//
|
//
|
||||||
n.setStatusCode(CommitMergeStatus.MISSING_DEPENDENCY);
|
n.setStatusCode(CommitMergeStatus.MISSING_DEPENDENCY);
|
||||||
n.setStatusMessage(
|
n.setStatusMessage(
|
||||||
String.format(
|
CommitMergeStatus.createMissingDependencyMessage(queryProvider, n.name(), c.name()));
|
||||||
"Commit %s depends on commit %s which cannot be merged.", n.name(), c.name()));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
contents.add(c);
|
contents.add(c);
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ public class RebaseSorter {
|
|||||||
this.incoming = incoming;
|
this.incoming = incoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CodeReviewCommit> sort(Collection<CodeReviewCommit> toSort) throws IOException {
|
public List<CodeReviewCommit> sort(Collection<CodeReviewCommit> toSort)
|
||||||
|
throws IOException, OrmException {
|
||||||
final List<CodeReviewCommit> sorted = new ArrayList<>();
|
final List<CodeReviewCommit> sorted = new ArrayList<>();
|
||||||
final Set<CodeReviewCommit> sort = new HashSet<>(toSort);
|
final Set<CodeReviewCommit> sort = new HashSet<>(toSort);
|
||||||
while (!sort.isEmpty()) {
|
while (!sort.isEmpty()) {
|
||||||
@@ -83,8 +84,8 @@ public class RebaseSorter {
|
|||||||
//
|
//
|
||||||
n.setStatusCode(CommitMergeStatus.MISSING_DEPENDENCY);
|
n.setStatusCode(CommitMergeStatus.MISSING_DEPENDENCY);
|
||||||
n.setStatusMessage(
|
n.setStatusMessage(
|
||||||
String.format(
|
CommitMergeStatus.createMissingDependencyMessage(
|
||||||
"Commit %s depends on commit %s which cannot be merged.", n.name(), c.name()));
|
queryProvider, n.name(), c.name()));
|
||||||
}
|
}
|
||||||
// Stop RevWalk because c is either a merged commit or a missing
|
// Stop RevWalk because c is either a merged commit or a missing
|
||||||
// dependency. Not need to walk further.
|
// dependency. Not need to walk further.
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class RebaseSubmitStrategy extends SubmitStrategy {
|
|||||||
List<CodeReviewCommit> sorted;
|
List<CodeReviewCommit> sorted;
|
||||||
try {
|
try {
|
||||||
sorted = args.rebaseSorter.sort(toMerge);
|
sorted = args.rebaseSorter.sort(toMerge);
|
||||||
} catch (IOException e) {
|
} catch (IOException | OrmException e) {
|
||||||
throw new IntegrationException("Commit sorting failed", e);
|
throw new IntegrationException("Commit sorting failed", e);
|
||||||
}
|
}
|
||||||
List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
|
List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ import com.google.gerrit.server.git.MergeUtil;
|
|||||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||||
import com.google.gerrit.server.project.ProjectCache;
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
import com.google.gerrit.server.project.ProjectState;
|
import com.google.gerrit.server.project.ProjectState;
|
||||||
|
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -91,11 +93,16 @@ public class SubmitDryRun {
|
|||||||
|
|
||||||
private final ProjectCache projectCache;
|
private final ProjectCache projectCache;
|
||||||
private final MergeUtil.Factory mergeUtilFactory;
|
private final MergeUtil.Factory mergeUtilFactory;
|
||||||
|
private final Provider<InternalChangeQuery> queryProvider;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SubmitDryRun(ProjectCache projectCache, MergeUtil.Factory mergeUtilFactory) {
|
SubmitDryRun(
|
||||||
|
ProjectCache projectCache,
|
||||||
|
MergeUtil.Factory mergeUtilFactory,
|
||||||
|
Provider<InternalChangeQuery> queryProvider) {
|
||||||
this.projectCache = projectCache;
|
this.projectCache = projectCache;
|
||||||
this.mergeUtilFactory = mergeUtilFactory;
|
this.mergeUtilFactory = mergeUtilFactory;
|
||||||
|
this.queryProvider = queryProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean run(
|
public boolean run(
|
||||||
@@ -116,7 +123,8 @@ public class SubmitDryRun {
|
|||||||
repo,
|
repo,
|
||||||
rw,
|
rw,
|
||||||
mergeUtilFactory.create(getProject(destBranch)),
|
mergeUtilFactory.create(getProject(destBranch)),
|
||||||
new MergeSorter(rw, alreadyAccepted, canMerge, ImmutableSet.of(toMergeCommit)));
|
new MergeSorter(
|
||||||
|
rw, alreadyAccepted, canMerge, queryProvider, ImmutableSet.of(toMergeCommit)));
|
||||||
|
|
||||||
switch (submitType) {
|
switch (submitType) {
|
||||||
case CHERRY_PICK:
|
case CHERRY_PICK:
|
||||||
|
|||||||
@@ -204,7 +204,8 @@ public abstract class SubmitStrategy {
|
|||||||
projectCache.get(destBranch.getParentKey()),
|
projectCache.get(destBranch.getParentKey()),
|
||||||
"project not found: %s",
|
"project not found: %s",
|
||||||
destBranch.getParentKey());
|
destBranch.getParentKey());
|
||||||
this.mergeSorter = new MergeSorter(rw, alreadyAccepted, canMergeFlag, incoming);
|
this.mergeSorter =
|
||||||
|
new MergeSorter(rw, alreadyAccepted, canMergeFlag, queryProvider, incoming);
|
||||||
this.rebaseSorter =
|
this.rebaseSorter =
|
||||||
new RebaseSorter(
|
new RebaseSorter(
|
||||||
rw, mergeTip.getInitialTip(), alreadyAccepted, canMergeFlag, queryProvider, incoming);
|
rw, mergeTip.getInitialTip(), alreadyAccepted, canMergeFlag, queryProvider, incoming);
|
||||||
|
|||||||
@@ -408,6 +408,8 @@ public class SubmitByMergeIfNecessaryIT extends AbstractSubmitByMerge {
|
|||||||
+ change3a.getCommit().name()
|
+ change3a.getCommit().name()
|
||||||
+ " depends on commit "
|
+ " depends on commit "
|
||||||
+ change2.getCommit().name()
|
+ change2.getCommit().name()
|
||||||
|
+ " of change "
|
||||||
|
+ change2.getChange().getId()
|
||||||
+ " which cannot be merged.");
|
+ " which cannot be merged.");
|
||||||
|
|
||||||
RevCommit tipbranch = getRemoteLog(project, "branch").get(0);
|
RevCommit tipbranch = getRemoteLog(project, "branch").get(0);
|
||||||
@@ -511,6 +513,8 @@ public class SubmitByMergeIfNecessaryIT extends AbstractSubmitByMerge {
|
|||||||
+ change3.getCommit().name()
|
+ change3.getCommit().name()
|
||||||
+ " depends on commit "
|
+ " depends on commit "
|
||||||
+ change2result.getCommit().name()
|
+ change2result.getCommit().name()
|
||||||
|
+ " of change "
|
||||||
|
+ change2result.getChange().getId()
|
||||||
+ " which cannot be merged.");
|
+ " which cannot be merged.");
|
||||||
|
|
||||||
assertRefUpdatedEvents();
|
assertRefUpdatedEvents();
|
||||||
|
|||||||
Reference in New Issue
Block a user