use of com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk in project gerrit by GerritCodeReview.
the class CherryPickChange method cherryPick.
public Change.Id cherryPick(BatchUpdate.Factory batchUpdateFactory, @Nullable Change.Id sourceChangeId, @Nullable PatchSet.Id sourcePatchId, @Nullable Branch.NameKey sourceBranch, @Nullable String sourceChangeTopic, Project.NameKey project, ObjectId sourceCommit, CherryPickInput input, String targetRef, RefControl targetRefControl) throws OrmException, IOException, InvalidChangeOperationException, IntegrationException, UpdateException, RestApiException {
if (Strings.isNullOrEmpty(targetRef)) {
throw new InvalidChangeOperationException("Cherry Pick: Destination branch cannot be null or empty");
}
String destinationBranch = RefNames.shortName(targetRef);
IdentifiedUser identifiedUser = user.get();
try (Repository git = gitManager.openRepository(project);
// before patch sets are updated.
ObjectInserter oi = git.newObjectInserter();
ObjectReader reader = oi.newReader();
CodeReviewRevWalk revWalk = CodeReviewCommit.newRevWalk(reader)) {
Ref destRef = git.getRefDatabase().exactRef(targetRef);
if (destRef == null) {
throw new InvalidChangeOperationException(String.format("Branch %s does not exist.", destinationBranch));
}
CodeReviewCommit mergeTip = revWalk.parseCommit(destRef.getObjectId());
CodeReviewCommit commitToCherryPick = revWalk.parseCommit(sourceCommit);
if (input.parent <= 0 || input.parent > commitToCherryPick.getParentCount()) {
throw new InvalidChangeOperationException(String.format("Cherry Pick: Parent %s does not exist. Please specify a parent in" + " range [1, %s].", input.parent, commitToCherryPick.getParentCount()));
}
Timestamp now = TimeUtil.nowTs();
PersonIdent committerIdent = identifiedUser.newCommitterIdent(now, serverTimeZone);
final ObjectId computedChangeId = ChangeIdUtil.computeChangeId(commitToCherryPick.getTree(), mergeTip, commitToCherryPick.getAuthorIdent(), committerIdent, input.message);
String commitMessage = ChangeIdUtil.insertId(input.message, computedChangeId).trim() + '\n';
CodeReviewCommit cherryPickCommit;
try {
ProjectState projectState = targetRefControl.getProjectControl().getProjectState();
cherryPickCommit = mergeUtilFactory.create(projectState).createCherryPickFromCommit(oi, git.getConfig(), mergeTip, commitToCherryPick, committerIdent, commitMessage, revWalk, input.parent - 1, false);
Change.Key changeKey;
final List<String> idList = cherryPickCommit.getFooterLines(FooterConstants.CHANGE_ID);
if (!idList.isEmpty()) {
final String idStr = idList.get(idList.size() - 1).trim();
changeKey = new Change.Key(idStr);
} else {
changeKey = new Change.Key("I" + computedChangeId.name());
}
Branch.NameKey newDest = new Branch.NameKey(project, destRef.getName());
List<ChangeData> destChanges = queryProvider.get().setLimit(2).byBranchKey(newDest, changeKey);
if (destChanges.size() > 1) {
throw new InvalidChangeOperationException("Several changes with key " + changeKey + " reside on the same branch. " + "Cannot create a new patch set.");
}
try (BatchUpdate bu = batchUpdateFactory.create(db.get(), project, identifiedUser, now)) {
bu.setRepository(git, revWalk, oi);
Change.Id result;
if (destChanges.size() == 1) {
// The change key exists on the destination branch. The cherry pick
// will be added as a new patch set.
ChangeControl destCtl = targetRefControl.getProjectControl().controlFor(destChanges.get(0).notes());
result = insertPatchSet(bu, git, destCtl, cherryPickCommit, input);
} else {
// Change key not found on destination branch. We can create a new
// change.
String newTopic = null;
if (!Strings.isNullOrEmpty(sourceChangeTopic)) {
newTopic = sourceChangeTopic + "-" + newDest.getShortName();
}
result = createNewChange(bu, cherryPickCommit, targetRefControl.getRefName(), newTopic, sourceBranch, sourceCommit, input);
if (sourceChangeId != null && sourcePatchId != null) {
bu.addOp(sourceChangeId, new AddMessageToSourceChangeOp(changeMessagesUtil, sourcePatchId, destinationBranch, cherryPickCommit));
}
}
bu.execute();
return result;
}
} catch (MergeIdenticalTreeException | MergeConflictException e) {
throw new IntegrationException("Cherry pick failed: " + e.getMessage());
}
}
}
use of com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk in project gerrit by GerritCodeReview.
the class MergeabilityCacheImpl method get.
@Override
public boolean get(ObjectId commit, Ref intoRef, SubmitType submitType, String mergeStrategy, Branch.NameKey dest, Repository repo) {
ObjectId into = intoRef != null ? intoRef.getObjectId() : ObjectId.zeroId();
EntryKey key = new EntryKey(commit, into, submitType, mergeStrategy);
try {
return cache.get(key, () -> {
if (key.into.equals(ObjectId.zeroId())) {
// Assume yes on new branch.
return true;
}
try (CodeReviewRevWalk rw = CodeReviewCommit.newRevWalk(repo)) {
Set<RevCommit> accepted = SubmitDryRun.getAlreadyAccepted(repo, rw);
accepted.add(rw.parseCommit(key.into));
accepted.addAll(Arrays.asList(rw.parseCommit(key.commit).getParents()));
return submitDryRun.run(key.submitType, repo, rw, dest, key.into, key.commit, accepted);
}
});
} catch (ExecutionException | UncheckedExecutionException e) {
log.error(String.format("Error checking mergeability of %s into %s (%s)", key.commit.name(), key.into.name(), key.submitType.name()), e.getCause());
return false;
}
}
use of com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk in project gerrit by GerritCodeReview.
the class SubmitStrategyOp method getAlreadyMergedCommit.
private CodeReviewCommit getAlreadyMergedCommit(RepoContext ctx) throws IOException {
CodeReviewCommit tip = args.mergeTip.getInitialTip();
if (tip == null) {
return null;
}
CodeReviewRevWalk rw = (CodeReviewRevWalk) ctx.getRevWalk();
Change.Id id = getId();
String refPrefix = id.toRefPrefix();
Map<String, ObjectId> refs = ctx.getRepoView().getRefs(refPrefix);
List<CodeReviewCommit> commits = new ArrayList<>(refs.size());
for (Map.Entry<String, ObjectId> e : refs.entrySet()) {
PatchSet.Id psId = PatchSet.Id.fromRef(refPrefix + e.getKey());
if (psId == null) {
continue;
}
try {
CodeReviewCommit c = rw.parseCommit(e.getValue());
c.setPatchsetId(psId);
commits.add(c);
} catch (MissingObjectException | IncorrectObjectTypeException ex) {
// Bogus ref, can't be merged into tip so we don't care.
continue;
}
}
Collections.sort(commits, ReviewDbUtil.intKeyOrdering().reverse().onResultOf(c -> c.getPatchsetId()));
CodeReviewCommit result = MergeUtil.findAnyMergedInto(rw, commits, tip);
if (result == null) {
return null;
}
// Some patch set of this change is actually merged into the target
// branch, most likely because a previous run of MergeOp failed after
// updateRepo, during updateChange.
//
// Do the best we can to clean this up: mark the change as merged and set
// the current patch set. Don't touch the dest branch at all. This can
// lead to some odd situations like another change in the set merging in
// a different patch set of this change, but that's unavoidable at this
// point. At least the change will end up in the right state.
//
// TODO(dborowitz): Consider deleting later junk patch set refs. They
// presumably don't have PatchSets pointing to them.
rw.parseBody(result);
result.add(args.canMergeFlag);
PatchSet.Id psId = result.getPatchsetId();
result.copyFrom(toMerge);
// Got overwriten by copyFrom.
result.setPatchsetId(psId);
result.setStatusCode(CommitMergeStatus.ALREADY_MERGED);
args.commitStatus.put(result);
return result;
}
use of com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk in project gerrit by GerritCodeReview.
the class ConflictsPredicate method predicates.
public static List<Predicate<ChangeData>> predicates(final Arguments args, String value, List<Change> changes) throws QueryParseException, OrmException {
int indexTerms = 0;
List<Predicate<ChangeData>> changePredicates = Lists.newArrayListWithCapacity(changes.size());
final Provider<ReviewDb> db = args.db;
for (final Change c : changes) {
final ChangeDataCache changeDataCache = new ChangeDataCache(c, db, args.changeDataFactory, args.projectCache);
List<String> files = listFiles(c, args, changeDataCache);
indexTerms += 3 + files.size();
if (indexTerms > args.indexConfig.maxTerms()) {
// later on in the query parsing.
throw new QueryParseException(TOO_MANY_FILES);
}
List<Predicate<ChangeData>> filePredicates = Lists.newArrayListWithCapacity(files.size());
for (String file : files) {
filePredicates.add(new EqualsPathPredicate(ChangeQueryBuilder.FIELD_PATH, file));
}
List<Predicate<ChangeData>> predicatesForOneChange = Lists.newArrayListWithCapacity(5);
predicatesForOneChange.add(not(new LegacyChangeIdPredicate(c.getId())));
predicatesForOneChange.add(new ProjectPredicate(c.getProject().get()));
predicatesForOneChange.add(new RefPredicate(c.getDest().get()));
predicatesForOneChange.add(or(or(filePredicates), new IsMergePredicate(args, value)));
predicatesForOneChange.add(new ChangeOperatorPredicate(ChangeQueryBuilder.FIELD_CONFLICTS, value) {
@Override
public boolean match(ChangeData object) throws OrmException {
Change otherChange = object.change();
if (otherChange == null) {
return false;
}
if (!otherChange.getDest().equals(c.getDest())) {
return false;
}
SubmitTypeRecord str = object.submitTypeRecord();
if (!str.isOk()) {
return false;
}
ObjectId other = ObjectId.fromString(object.currentPatchSet().getRevision().get());
ConflictKey conflictsKey = new ConflictKey(changeDataCache.getTestAgainst(), other, str.type, changeDataCache.getProjectState().isUseContentMerge());
Boolean conflicts = args.conflictsCache.getIfPresent(conflictsKey);
if (conflicts != null) {
return conflicts;
}
try (Repository repo = args.repoManager.openRepository(otherChange.getProject());
CodeReviewRevWalk rw = CodeReviewCommit.newRevWalk(repo)) {
conflicts = !args.submitDryRun.run(str.type, repo, rw, otherChange.getDest(), changeDataCache.getTestAgainst(), other, getAlreadyAccepted(repo, rw));
args.conflictsCache.put(conflictsKey, conflicts);
return conflicts;
} catch (IntegrationException | NoSuchProjectException | IOException e) {
throw new OrmException(e);
}
}
@Override
public int getCost() {
return 5;
}
private Set<RevCommit> getAlreadyAccepted(Repository repo, RevWalk rw) throws IntegrationException {
try {
Set<RevCommit> accepted = new HashSet<>();
SubmitDryRun.addCommits(changeDataCache.getAlreadyAccepted(repo), rw, accepted);
ObjectId tip = changeDataCache.getTestAgainst();
if (tip != null) {
accepted.add(rw.parseCommit(tip));
}
return accepted;
} catch (OrmException | IOException e) {
throw new IntegrationException("Failed to determine already accepted commits.", e);
}
}
});
changePredicates.add(and(predicatesForOneChange));
}
return changePredicates;
}
use of com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk in project gerrit by GerritCodeReview.
the class MergeUtil method createMergeCommit.
public static CodeReviewCommit createMergeCommit(ObjectInserter inserter, Config repoConfig, RevCommit mergeTip, RevCommit originalCommit, String mergeStrategy, boolean allowConflicts, PersonIdent authorIdent, PersonIdent committerIdent, String commitMsg, CodeReviewRevWalk rw) throws IOException, MergeIdenticalTreeException, MergeConflictException, InvalidMergeStrategyException {
if (!MergeStrategy.THEIRS.getName().equals(mergeStrategy) && rw.isMergedInto(originalCommit, mergeTip)) {
throw new ChangeAlreadyMergedException("'" + originalCommit.getName() + "' has already been merged");
}
Merger m = newMerger(inserter, repoConfig, mergeStrategy);
DirCache dc = DirCache.newInCore();
if (allowConflicts && m instanceof ResolveMerger) {
// The DirCache must be set on ResolveMerger before calling
// ResolveMerger#merge(AnyObjectId...) otherwise the entries in DirCache don't get populated.
((ResolveMerger) m).setDirCache(dc);
}
ObjectId tree;
ImmutableSet<String> filesWithGitConflicts;
if (m.merge(false, mergeTip, originalCommit)) {
filesWithGitConflicts = null;
tree = m.getResultTreeId();
} else {
List<String> conflicts = ImmutableList.of();
if (m instanceof ResolveMerger) {
conflicts = ((ResolveMerger) m).getUnmergedPaths();
}
if (!allowConflicts) {
throw new MergeConflictException(createConflictMessage(conflicts));
}
// For merging with conflict markers we need a ResolveMerger, double-check that we have one.
if (!(m instanceof ResolveMerger)) {
throw new MergeWithConflictsNotSupportedException(MergeStrategy.get(mergeStrategy));
}
Map<String, MergeResult<? extends Sequence>> mergeResults = ((ResolveMerger) m).getMergeResults();
filesWithGitConflicts = mergeResults.entrySet().stream().filter(e -> e.getValue().containsConflicts()).map(Map.Entry::getKey).collect(toImmutableSet());
tree = mergeWithConflicts(rw, inserter, dc, "TARGET BRANCH", mergeTip, "SOURCE BRANCH", originalCommit, mergeResults);
}
CommitBuilder mergeCommit = new CommitBuilder();
mergeCommit.setTreeId(tree);
mergeCommit.setParentIds(mergeTip, originalCommit);
mergeCommit.setAuthor(authorIdent);
mergeCommit.setCommitter(committerIdent);
mergeCommit.setMessage(commitMsg);
CodeReviewCommit commit = rw.parseCommit(inserter.insert(mergeCommit));
commit.setFilesWithGitConflicts(filesWithGitConflicts);
return commit;
}
Aggregations