Search in sources :

Example 21 with RevId

use of com.google.gerrit.reviewdb.client.RevId in project gerrit by GerritCodeReview.

the class ChangeNoteUtil method parseNote.

public List<Comment> parseNote(byte[] note, MutableInteger p, Change.Id changeId) throws ConfigInvalidException {
    if (p.value >= note.length) {
        return ImmutableList.of();
    }
    Set<Comment.Key> seen = new HashSet<>();
    List<Comment> result = new ArrayList<>();
    int sizeOfNote = note.length;
    byte[] psb = PATCH_SET.getBytes(UTF_8);
    byte[] bpsb = BASE_PATCH_SET.getBytes(UTF_8);
    byte[] bpn = PARENT_NUMBER.getBytes(UTF_8);
    RevId revId = new RevId(parseStringField(note, p, changeId, REVISION));
    String fileName = null;
    PatchSet.Id psId = null;
    boolean isForBase = false;
    Integer parentNumber = null;
    while (p.value < sizeOfNote) {
        boolean matchPs = match(note, p, psb);
        boolean matchBase = match(note, p, bpsb);
        if (matchPs) {
            fileName = null;
            psId = parsePsId(note, p, changeId, PATCH_SET);
            isForBase = false;
        } else if (matchBase) {
            fileName = null;
            psId = parsePsId(note, p, changeId, BASE_PATCH_SET);
            isForBase = true;
            if (match(note, p, bpn)) {
                parentNumber = parseParentNumber(note, p, changeId);
            }
        } else if (psId == null) {
            throw parseException(changeId, "missing %s or %s header", PATCH_SET, BASE_PATCH_SET);
        }
        Comment c = parseComment(note, p, fileName, psId, revId, isForBase, parentNumber);
        fileName = c.key.filename;
        if (!seen.add(c.key)) {
            throw parseException(changeId, "multiple comments for %s in note", c.key);
        }
        result.add(c);
    }
    return result;
}
Also used : Comment(com.google.gerrit.reviewdb.client.Comment) ArrayList(java.util.ArrayList) PatchSet(com.google.gerrit.reviewdb.client.PatchSet) QuotedString(org.eclipse.jgit.util.QuotedString) RevId(com.google.gerrit.reviewdb.client.RevId) MutableInteger(org.eclipse.jgit.util.MutableInteger) FooterKey(org.eclipse.jgit.revwalk.FooterKey) HashSet(java.util.HashSet)

Example 22 with RevId

use of com.google.gerrit.reviewdb.client.RevId in project gerrit by GerritCodeReview.

the class ReceiveCommits method selectNewAndReplacedChangesFromMagicBranch.

private void selectNewAndReplacedChangesFromMagicBranch() {
    logDebug("Finding new and replaced changes");
    newChanges = new ArrayList<>();
    ListMultimap<ObjectId, Ref> existing = changeRefsById();
    GroupCollector groupCollector = GroupCollector.create(changeRefsById(), db, psUtil, notesFactory, project.getNameKey());
    try {
        RevCommit start = setUpWalkForSelectingChanges();
        if (start == null) {
            return;
        }
        LinkedHashMap<RevCommit, ChangeLookup> pending = new LinkedHashMap<>();
        Set<Change.Key> newChangeIds = new HashSet<>();
        int maxBatchChanges = receiveConfig.getEffectiveMaxBatchChangesLimit(user);
        int total = 0;
        int alreadyTracked = 0;
        boolean rejectImplicitMerges = start.getParentCount() == 1 && projectCache.get(project.getNameKey()).isRejectImplicitMerges() && // late.
        !magicBranch.merged;
        Set<RevCommit> mergedParents;
        if (rejectImplicitMerges) {
            mergedParents = new HashSet<>();
        } else {
            mergedParents = null;
        }
        for (; ; ) {
            RevCommit c = rp.getRevWalk().next();
            if (c == null) {
                break;
            }
            total++;
            rp.getRevWalk().parseBody(c);
            String name = c.name();
            groupCollector.visit(c);
            Collection<Ref> existingRefs = existing.get(c);
            if (rejectImplicitMerges) {
                Collections.addAll(mergedParents, c.getParents());
                mergedParents.remove(c);
            }
            boolean commitAlreadyTracked = !existingRefs.isEmpty();
            if (commitAlreadyTracked) {
                alreadyTracked++;
                //    different target branch.
                for (Ref ref : existingRefs) {
                    updateGroups.add(new UpdateGroupsRequest(ref, c));
                }
                if (!(newChangeForAllNotInTarget || magicBranch.base != null)) {
                    continue;
                }
            }
            List<String> idList = c.getFooterLines(CHANGE_ID);
            String idStr = !idList.isEmpty() ? idList.get(idList.size() - 1).trim() : null;
            if (idStr != null) {
                pending.put(c, new ChangeLookup(c, new Change.Key(idStr)));
            } else {
                pending.put(c, new ChangeLookup(c));
            }
            int n = pending.size() + newChanges.size();
            if (maxBatchChanges != 0 && n > maxBatchChanges) {
                logDebug("{} changes exceeds limit of {}", n, maxBatchChanges);
                reject(magicBranch.cmd, "the number of pushed changes in a batch exceeds the max limit " + maxBatchChanges);
                newChanges = Collections.emptyList();
                return;
            }
            if (commitAlreadyTracked) {
                boolean changeExistsOnDestBranch = false;
                for (ChangeData cd : pending.get(c).destChanges) {
                    if (cd.change().getDest().equals(magicBranch.dest)) {
                        changeExistsOnDestBranch = true;
                        break;
                    }
                }
                if (changeExistsOnDestBranch) {
                    continue;
                }
                logDebug("Creating new change for {} even though it is already tracked", name);
            }
            if (!validCommit(rp.getRevWalk(), magicBranch.ctl, magicBranch.cmd, c)) {
                // Not a change the user can propose? Abort as early as possible.
                newChanges = Collections.emptyList();
                logDebug("Aborting early due to invalid commit");
                return;
            }
            // Don't allow merges to be uploaded in commit chain via all-not-in-target
            if (newChangeForAllNotInTarget && c.getParentCount() > 1) {
                reject(magicBranch.cmd, "Pushing merges in commit chains with 'all not in target' is not allowed,\n" + "to override please set the base manually");
                logDebug("Rejecting merge commit {} with newChangeForAllNotInTarget", name);
            // TODO(dborowitz): Should we early return here?
            }
            if (idList.isEmpty()) {
                newChanges.add(new CreateRequest(c, magicBranch.dest.get()));
                continue;
            }
        }
        logDebug("Finished initial RevWalk with {} commits total: {} already" + " tracked, {} new changes with no Change-Id, and {} deferred" + " lookups", total, alreadyTracked, newChanges.size(), pending.size());
        if (rejectImplicitMerges) {
            rejectImplicitMerges(mergedParents);
        }
        for (Iterator<ChangeLookup> itr = pending.values().iterator(); itr.hasNext(); ) {
            ChangeLookup p = itr.next();
            if (p.changeKey == null) {
                continue;
            }
            if (newChangeIds.contains(p.changeKey)) {
                logDebug("Multiple commits with Change-Id {}", p.changeKey);
                reject(magicBranch.cmd, SAME_CHANGE_ID_IN_MULTIPLE_CHANGES);
                newChanges = Collections.emptyList();
                return;
            }
            List<ChangeData> changes = p.destChanges;
            if (changes.size() > 1) {
                logDebug("Multiple changes in branch {} with Change-Id {}: {}", magicBranch.dest, p.changeKey, changes.stream().map(cd -> cd.getId().toString()).collect(joining()));
                // WTF, multiple changes in this branch have the same key?
                // Since the commit is new, the user should recreate it with
                // a different Change-Id. In practice, we should never see
                // this error message as Change-Id should be unique per branch.
                //
                reject(magicBranch.cmd, p.changeKey.get() + " has duplicates");
                newChanges = Collections.emptyList();
                return;
            }
            if (changes.size() == 1) {
                // Schedule as a replacement to this one matching change.
                //
                RevId currentPs = changes.get(0).currentPatchSet().getRevision();
                // If Commit is already current PatchSet of target Change.
                if (p.commit.name().equals(currentPs.get())) {
                    if (pending.size() == 1) {
                        // There are no commits left to check, all commits in pending were already
                        // current PatchSet of the corresponding target changes.
                        reject(magicBranch.cmd, "commit(s) already exists (as current patchset)");
                    } else {
                        // Commit is already current PatchSet.
                        // Remove from pending and try next commit.
                        itr.remove();
                        continue;
                    }
                }
                if (requestReplace(magicBranch.cmd, false, changes.get(0).change(), p.commit)) {
                    continue;
                }
                newChanges = Collections.emptyList();
                return;
            }
            if (changes.size() == 0) {
                if (!isValidChangeId(p.changeKey.get())) {
                    reject(magicBranch.cmd, "invalid Change-Id");
                    newChanges = Collections.emptyList();
                    return;
                }
                // double check against the existing refs
                if (foundInExistingRef(existing.get(p.commit))) {
                    if (pending.size() == 1) {
                        reject(magicBranch.cmd, "commit(s) already exists (as current patchset)");
                        newChanges = Collections.emptyList();
                        return;
                    }
                    itr.remove();
                    continue;
                }
                newChangeIds.add(p.changeKey);
            }
            newChanges.add(new CreateRequest(p.commit, magicBranch.dest.get()));
        }
        logDebug("Finished deferred lookups with {} updates and {} new changes", replaceByChange.size(), newChanges.size());
    } catch (IOException e) {
        // Should never happen, the core receive process would have
        // identified the missing object earlier before we got control.
        //
        magicBranch.cmd.setResult(REJECTED_MISSING_OBJECT);
        logError("Invalid pack upload; one or more objects weren't sent", e);
        newChanges = Collections.emptyList();
        return;
    } catch (OrmException e) {
        logError("Cannot query database to locate prior changes", e);
        reject(magicBranch.cmd, "database error");
        newChanges = Collections.emptyList();
        return;
    }
    if (newChanges.isEmpty() && replaceByChange.isEmpty()) {
        reject(magicBranch.cmd, "no new changes");
        return;
    }
    if (!newChanges.isEmpty() && magicBranch.edit) {
        reject(magicBranch.cmd, "edit is not supported for new changes");
        return;
    }
    try {
        SortedSetMultimap<ObjectId, String> groups = groupCollector.getGroups();
        List<Integer> newIds = seq.nextChangeIds(newChanges.size());
        for (int i = 0; i < newChanges.size(); i++) {
            CreateRequest create = newChanges.get(i);
            create.setChangeId(newIds.get(i));
            create.groups = ImmutableList.copyOf(groups.get(create.commit));
        }
        for (ReplaceRequest replace : replaceByChange.values()) {
            replace.groups = ImmutableList.copyOf(groups.get(replace.newCommitId));
        }
        for (UpdateGroupsRequest update : updateGroups) {
            update.groups = ImmutableList.copyOf((groups.get(update.commit)));
        }
        logDebug("Finished updating groups from GroupCollector");
    } catch (OrmException e) {
        logError("Error collecting groups for changes", e);
        reject(magicBranch.cmd, "internal server error");
        return;
    }
}
Also used : RevId(com.google.gerrit.reviewdb.client.RevId) LinkedHashMap(java.util.LinkedHashMap) OrmException(com.google.gwtorm.server.OrmException) RevCommit(org.eclipse.jgit.revwalk.RevCommit) HashSet(java.util.HashSet) ObjectId(org.eclipse.jgit.lib.ObjectId) IOException(java.io.IOException) ChangeData(com.google.gerrit.server.query.change.ChangeData) Ref(org.eclipse.jgit.lib.Ref)

Aggregations

RevId (com.google.gerrit.reviewdb.client.RevId)22 PatchSet (com.google.gerrit.reviewdb.client.PatchSet)16 Change (com.google.gerrit.reviewdb.client.Change)13 Test (org.junit.Test)11 Comment (com.google.gerrit.reviewdb.client.Comment)4 LabelId (com.google.gerrit.reviewdb.client.LabelId)3 PatchSetApproval (com.google.gerrit.reviewdb.client.PatchSetApproval)3 ChangeData (com.google.gerrit.server.query.change.ChangeData)3 Timestamp (java.sql.Timestamp)3 Note (org.eclipse.jgit.notes.Note)3 RevCommit (org.eclipse.jgit.revwalk.RevCommit)3 ResourceConflictException (com.google.gerrit.extensions.restapi.ResourceConflictException)2 Account (com.google.gerrit.reviewdb.client.Account)2 CommentRange (com.google.gerrit.reviewdb.client.CommentRange)2 Project (com.google.gerrit.reviewdb.client.Project)2 OrmException (com.google.gwtorm.server.OrmException)2 IOException (java.io.IOException)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 ObjectId (org.eclipse.jgit.lib.ObjectId)2