Search in sources :

Example 21 with PatchSetApproval

use of com.google.gerrit.entities.PatchSetApproval in project gerrit by GerritCodeReview.

the class ChangeNotesParser method backFillMissingCopiedApprovalsFromSubmitRecords.

/**
 * Returns patch-set approvals that do not exist on the latest patch-set but for which a submit
 * record exists in NoteDb when the change was merged.
 */
private List<PatchSetApproval> backFillMissingCopiedApprovalsFromSubmitRecords(ListMultimap<PatchSet.Id, PatchSetApproval> allApprovals, @Nullable PatchSet.Id latestPs) {
    List<PatchSetApproval> copiedApprovals = new ArrayList<>();
    if (latestPs == null) {
        return copiedApprovals;
    }
    List<PatchSetApproval> approvalsOnLatestPs = allApprovals.get(latestPs);
    ListMultimap<Account.Id, PatchSetApproval> approvalsByUser = getApprovalsByUser(allApprovals);
    List<SubmitRecord.Label> submitRecordLabels = submitRecords.stream().filter(r -> r.labels != null).flatMap(r -> r.labels.stream()).filter(label -> Status.OK.equals(label.status) || Status.MAY.equals(label.status)).collect(Collectors.toList());
    for (SubmitRecord.Label recordLabel : submitRecordLabels) {
        String labelName = recordLabel.label;
        Account.Id appliedBy = recordLabel.appliedBy;
        if (appliedBy == null || labelName == null) {
            continue;
        }
        boolean existsAtLatestPs = approvalsOnLatestPs.stream().anyMatch(a -> a.accountId().equals(appliedBy) && a.label().equals(labelName));
        if (existsAtLatestPs) {
            continue;
        }
        // Search for an approval for this label on the max previous patch-set and copy the approval.
        Collection<PatchSetApproval> userApprovals = approvalsByUser.get(appliedBy).stream().filter(approval -> approval.label().equals(labelName)).collect(Collectors.toList());
        if (userApprovals.isEmpty()) {
            continue;
        }
        PatchSetApproval lastApproved = Collections.max(userApprovals, comparingInt(a -> a.patchSetId().get()));
        copiedApprovals.add(lastApproved.copyWithPatchSet(latestPs));
    }
    return copiedApprovals;
}
Also used : FOOTER_SUBMITTED_WITH(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH) ListMultimap(com.google.common.collect.ListMultimap) MultimapBuilder(com.google.common.collect.MultimapBuilder) FOOTER_HASHTAGS(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_HASHTAGS) HumanComment(com.google.gerrit.entities.HumanComment) HashBasedTable(com.google.common.collect.HashBasedTable) ReviewerSet(com.google.gerrit.server.ReviewerSet) SubmitRequirementResult(com.google.gerrit.entities.SubmitRequirementResult) FooterKey(org.eclipse.jgit.revwalk.FooterKey) FOOTER_ASSIGNEE(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ASSIGNEE) PatchSetApproval(com.google.gerrit.entities.PatchSetApproval) InvalidObjectIdException(org.eclipse.jgit.errors.InvalidObjectIdException) FOOTER_PATCH_SET_DESCRIPTION(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET_DESCRIPTION) Tables(com.google.common.collect.Tables) LabelType(com.google.gerrit.entities.LabelType) AttentionSetUpdate(com.google.gerrit.entities.AttentionSetUpdate) Map(java.util.Map) RefNames(com.google.gerrit.entities.RefNames) Splitter(com.google.common.base.Splitter) NoteMap(org.eclipse.jgit.notes.NoteMap) FOOTER_ATTENTION(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ATTENTION) FOOTER_WORK_IN_PROGRESS(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_WORK_IN_PROGRESS) ImmutableSet(com.google.common.collect.ImmutableSet) FOOTER_SUBJECT(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBJECT) Timer0(com.google.gerrit.metrics.Timer0) Timestamp(java.sql.Timestamp) Collection(java.util.Collection) RawParseUtils(org.eclipse.jgit.util.RawParseUtils) Account(com.google.gerrit.entities.Account) ChangeNotesRevWalk(com.google.gerrit.server.notedb.ChangeNotesCommit.ChangeNotesRevWalk) Set(java.util.Set) ReviewerStatusUpdate(com.google.gerrit.server.ReviewerStatusUpdate) Instant(java.time.Instant) SubmitRecord(com.google.gerrit.entities.SubmitRecord) Collectors(java.util.stream.Collectors) Collectors.joining(java.util.stream.Collectors.joining) Sets(com.google.common.collect.Sets) Objects(java.util.Objects) PersonIdent(org.eclipse.jgit.lib.PersonIdent) List(java.util.List) FOOTER_STATUS(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_STATUS) Nullable(com.google.gerrit.common.Nullable) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) Optional(java.util.Optional) MoreObjects.firstNonNull(com.google.common.base.MoreObjects.firstNonNull) FOOTER_LABEL(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_LABEL) FOOTER_SUBMISSION_ID(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMISSION_ID) FluentLogger(com.google.common.flogger.FluentLogger) FOOTER_COMMIT(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_COMMIT) FOOTER_CHANGE_ID(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHANGE_ID) FOOTER_REVERT_OF(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_REVERT_OF) LabelId(com.google.gerrit.entities.LabelId) ConfigInvalidException(org.eclipse.jgit.errors.ConfigInvalidException) HashMap(java.util.HashMap) Function(java.util.function.Function) TreeSet(java.util.TreeSet) Enums(com.google.common.base.Enums) ArrayList(java.util.ArrayList) FOOTER_TAG(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_TAG) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) ChangeMessage(com.google.gerrit.entities.ChangeMessage) FOOTER_REAL_USER(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_REAL_USER) ChangeNoteUtil.parseCommitMessageRange(com.google.gerrit.server.notedb.ChangeNoteUtil.parseCommitMessageRange) Lists(com.google.common.collect.Lists) Charset(java.nio.charset.Charset) FormatMethod(com.google.errorprone.annotations.FormatMethod) Change(com.google.gerrit.entities.Change) PatchSet(com.google.gerrit.entities.PatchSet) Comparator.comparing(java.util.Comparator.comparing) Status(com.google.gerrit.entities.SubmitRecord.Label.Status) Address(com.google.gerrit.entities.Address) FOOTER_BRANCH(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_BRANCH) AssigneeStatusUpdate(com.google.gerrit.server.AssigneeStatusUpdate) FOOTER_PATCH_SET(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET) ParsedPatchSetApproval(com.google.gerrit.server.notedb.ChangeNoteUtil.ParsedPatchSetApproval) FOOTER_GROUPS(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_GROUPS) FOOTER_COPIED_LABEL(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_COPIED_LABEL) FOOTER_PRIVATE(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PRIVATE) FOOTER_TOPIC(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_TOPIC) Comparator.comparingInt(java.util.Comparator.comparingInt) Iterator(java.util.Iterator) FOOTER_CURRENT(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CURRENT) IOException(java.io.IOException) Maps(com.google.common.collect.Maps) Ints(com.google.common.primitives.Ints) ObjectId(org.eclipse.jgit.lib.ObjectId) FOOTER_CHERRY_PICK_OF(com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHERRY_PICK_OF) ImmutableTable(com.google.common.collect.ImmutableTable) LabelVote(com.google.gerrit.server.util.LabelVote) ReviewerByEmailSet(com.google.gerrit.server.ReviewerByEmailSet) Table(com.google.common.collect.Table) Collections(java.util.Collections) ObjectReader(org.eclipse.jgit.lib.ObjectReader) Account(com.google.gerrit.entities.Account) ArrayList(java.util.ArrayList) PatchSetApproval(com.google.gerrit.entities.PatchSetApproval) ParsedPatchSetApproval(com.google.gerrit.server.notedb.ChangeNoteUtil.ParsedPatchSetApproval) SubmitRecord(com.google.gerrit.entities.SubmitRecord) LabelId(com.google.gerrit.entities.LabelId) ObjectId(org.eclipse.jgit.lib.ObjectId)

Example 22 with PatchSetApproval

use of com.google.gerrit.entities.PatchSetApproval in project gerrit by GerritCodeReview.

the class ChangeUpdate method applyImpl.

@Override
protected CommitBuilder applyImpl(RevWalk rw, ObjectInserter ins, ObjectId curr) throws IOException {
    checkState(deleteCommentRewriter == null && deleteChangeMessageRewriter == null, "cannot update and rewrite ref in one BatchUpdate");
    PatchSet.Id patchSetId = psId != null ? psId : getChange().currentPatchSetId();
    StringBuilder msg = new StringBuilder();
    if (commitSubject != null) {
        msg.append(commitSubject);
    } else {
        msg.append("Update patch set ").append(patchSetId.get());
    }
    msg.append("\n\n");
    if (changeMessage != null) {
        msg.append(changeMessage);
        msg.append("\n\n");
    }
    addPatchSetFooter(msg, patchSetId);
    if (currentPatchSet) {
        addFooter(msg, FOOTER_CURRENT, Boolean.TRUE);
    }
    if (psDescription != null) {
        addFooter(msg, FOOTER_PATCH_SET_DESCRIPTION, psDescription);
    }
    if (changeId != null) {
        addFooter(msg, FOOTER_CHANGE_ID, changeId);
    }
    if (subject != null) {
        addFooter(msg, FOOTER_SUBJECT, subject);
    }
    if (branch != null) {
        addFooter(msg, FOOTER_BRANCH, branch);
    }
    if (status != null) {
        addFooter(msg, FOOTER_STATUS, status.name().toLowerCase());
        if (status.equals(Change.Status.ABANDONED)) {
            clearAttentionSet("Change was abandoned");
        }
        if (status.equals(Change.Status.MERGED)) {
            clearAttentionSet("Change was submitted");
        }
    }
    if (topic != null) {
        addFooter(msg, FOOTER_TOPIC, topic);
    }
    if (commit != null) {
        addFooter(msg, FOOTER_COMMIT, commit);
    }
    if (assignee != null) {
        if (assignee.isPresent()) {
            addFooter(msg, FOOTER_ASSIGNEE);
            noteUtil.appendAccountIdIdentString(msg, assignee.get()).append('\n');
        } else {
            addFooter(msg, FOOTER_ASSIGNEE).append('\n');
        }
    }
    Joiner comma = Joiner.on(',');
    if (hashtags != null) {
        addFooter(msg, FOOTER_HASHTAGS, comma.join(hashtags));
    }
    if (tag != null) {
        addFooter(msg, FOOTER_TAG, tag);
    }
    if (groups != null) {
        addFooter(msg, FOOTER_GROUPS, comma.join(groups));
    }
    for (Map.Entry<Account.Id, ReviewerStateInternal> e : reviewers.entrySet()) {
        addFooter(msg, e.getValue().getFooterKey());
        noteUtil.appendAccountIdIdentString(msg, e.getKey()).append('\n');
    }
    applyReviewerUpdatesToAttentionSet();
    for (Map.Entry<Address, ReviewerStateInternal> e : reviewersByEmail.entrySet()) {
        addFooter(msg, e.getValue().getByEmailFooterKey(), e.getKey().toString());
    }
    for (Table.Cell<String, Account.Id, Optional<Short>> c : approvals.cellSet()) {
        addLabelFooter(msg, c, patchSetId);
    }
    for (PatchSetApproval patchSetApproval : copiedApprovals) {
        addCopiedLabelFooter(msg, patchSetApproval);
    }
    if (submissionId != null) {
        addFooter(msg, FOOTER_SUBMISSION_ID, submissionId);
    }
    if (submitRecords != null) {
        for (SubmitRecord rec : submitRecords) {
            addFooter(msg, FOOTER_SUBMITTED_WITH).append(rec.status);
            if (rec.errorMessage != null) {
                msg.append(' ').append(sanitizeFooter(rec.errorMessage));
            }
            msg.append('\n');
            if (rec.ruleName != null) {
                addFooter(msg, FOOTER_SUBMITTED_WITH).append("Rule-Name: ").append(rec.ruleName);
                msg.append('\n');
            }
            if (rec.labels != null) {
                for (SubmitRecord.Label label : rec.labels) {
                    // Label names/values are safe to append without sanitizing.
                    addFooter(msg, FOOTER_SUBMITTED_WITH).append(label.status).append(": ").append(label.label);
                    if (label.appliedBy != null) {
                        msg.append(": ");
                        noteUtil.appendAccountIdIdentString(msg, label.appliedBy);
                    }
                    msg.append('\n');
                }
            }
        }
    }
    if (!Objects.equals(accountId, realAccountId)) {
        addFooter(msg, FOOTER_REAL_USER);
        noteUtil.appendAccountIdIdentString(msg, realAccountId).append('\n');
    }
    if (isPrivate != null) {
        addFooter(msg, FOOTER_PRIVATE, isPrivate);
    }
    if (workInProgress != null) {
        addFooter(msg, FOOTER_WORK_IN_PROGRESS, workInProgress);
        if (workInProgress) {
            clearAttentionSet("Change was marked work in progress");
        } else {
            addAllReviewersToAttentionSet();
        }
    }
    if (revertOf != null) {
        addFooter(msg, FOOTER_REVERT_OF, revertOf);
    }
    if (cherryPickOf != null) {
        if (cherryPickOf.isPresent()) {
            addFooter(msg, FOOTER_CHERRY_PICK_OF, cherryPickOf.get());
        } else {
            // Update cherryPickOf with an empty value.
            addFooter(msg, FOOTER_CHERRY_PICK_OF).append('\n');
        }
    }
    updateAttentionSet(msg);
    CommitBuilder cb = new CommitBuilder();
    cb.setMessage(msg.toString());
    try {
        ObjectId treeId = storeRevisionNotes(rw, ins, curr);
        if (treeId != null) {
            cb.setTreeId(treeId);
        }
    } catch (ConfigInvalidException e) {
        throw new StorageException(e);
    }
    return cb;
}
Also used : Joiner(com.google.common.base.Joiner) TreeBasedTable(com.google.common.collect.TreeBasedTable) Table(com.google.common.collect.Table) Address(com.google.gerrit.entities.Address) Optional(java.util.Optional) ConfigInvalidException(org.eclipse.jgit.errors.ConfigInvalidException) ObjectId(org.eclipse.jgit.lib.ObjectId) CommitBuilder(org.eclipse.jgit.lib.CommitBuilder) PatchSet(com.google.gerrit.entities.PatchSet) PatchSetApproval(com.google.gerrit.entities.PatchSetApproval) SubmitRecord(com.google.gerrit.entities.SubmitRecord) SubmissionId(com.google.gerrit.entities.SubmissionId) LabelId(com.google.gerrit.entities.LabelId) ObjectId(org.eclipse.jgit.lib.ObjectId) Map(java.util.Map) NoteMap(org.eclipse.jgit.notes.NoteMap) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) StorageException(com.google.gerrit.exceptions.StorageException)

Example 23 with PatchSetApproval

use of com.google.gerrit.entities.PatchSetApproval in project gerrit by GerritCodeReview.

the class SubmitWithStickyApprovalDiff method getLatestApprovedPatchsetId.

private PatchSet.Id getLatestApprovedPatchsetId(ChangeNotes notes) {
    ProjectState projectState = projectCache.get(notes.getProjectName()).orElseThrow(illegalState(notes.getProjectName()));
    PatchSet.Id maxPatchSetId = PatchSet.id(notes.getChangeId(), 1);
    for (PatchSetApproval patchSetApproval : notes.getApprovals().values()) {
        if (!patchSetApproval.label().equals(LabelId.CODE_REVIEW)) {
            continue;
        }
        Optional<LabelType> lt = projectState.getLabelTypes(notes).byLabel(patchSetApproval.labelId());
        if (!lt.isPresent() || !lt.get().isMaxPositive(patchSetApproval)) {
            continue;
        }
        if (patchSetApproval.patchSetId().get() > maxPatchSetId.get()) {
            maxPatchSetId = patchSetApproval.patchSetId();
        }
    }
    return maxPatchSetId;
}
Also used : LabelType(com.google.gerrit.entities.LabelType) ProjectState(com.google.gerrit.server.project.ProjectState) PatchSet(com.google.gerrit.entities.PatchSet) PatchSetApproval(com.google.gerrit.entities.PatchSetApproval)

Example 24 with PatchSetApproval

use of com.google.gerrit.entities.PatchSetApproval in project gerrit by GerritCodeReview.

the class StickyApprovalsIT method stickyVoteStoredOnUploadWithRealAccount.

@Test
public void stickyVoteStoredOnUploadWithRealAccount() throws Exception {
    // Give "user" permission to vote on behalf of other users.
    projectOperations.project(project).forUpdate().add(allowLabel(TestLabels.codeReview().getName()).impersonation(true).ref("refs/heads/*").group(REGISTERED_USERS).range(-1, 1)).update();
    // Code-Review will be sticky.
    String label = LabelId.CODE_REVIEW;
    try (ProjectConfigUpdate u = updateProject(project)) {
        u.getConfig().updateLabelType(label, b -> b.setCopyAnyScore(true));
        u.save();
    }
    PushOneCommit.Result r = createChange();
    // Add a new vote as user
    requestScopeOperations.setApiUser(user.id());
    ReviewInput input = new ReviewInput().label(LabelId.CODE_REVIEW, 1);
    input.onBehalfOf = admin.email();
    gApi.changes().id(r.getChangeId()).current().review(input);
    // Make a new patchset, keeping the Code-Review +1 vote.
    amendChange(r.getChangeId());
    List<PatchSetApproval> patchSetApprovals = r.getChange().notes().getApprovalsWithCopied().values().stream().sorted(comparing(a -> a.patchSetId().get())).collect(toImmutableList());
    PatchSetApproval nonCopied = patchSetApprovals.get(0);
    assertThat(nonCopied.patchSetId().get()).isEqualTo(1);
    assertThat(nonCopied.accountId().get()).isEqualTo(admin.id().get());
    assertThat(nonCopied.realAccountId().get()).isEqualTo(user.id().get());
    assertThat(nonCopied.label()).isEqualTo(LabelId.CODE_REVIEW);
    assertThat(nonCopied.value()).isEqualTo((short) 1);
    assertThat(nonCopied.copied()).isFalse();
    PatchSetApproval copied = patchSetApprovals.get(1);
    assertThat(copied.patchSetId().get()).isEqualTo(2);
    assertThat(copied.accountId().get()).isEqualTo(admin.id().get());
    assertThat(copied.realAccountId().get()).isEqualTo(user.id().get());
    assertThat(copied.label()).isEqualTo(LabelId.CODE_REVIEW);
    assertThat(copied.value()).isEqualTo((short) 1);
    assertThat(copied.copied()).isTrue();
}
Also used : ReviewInput(com.google.gerrit.extensions.api.changes.ReviewInput) PatchSetApproval(com.google.gerrit.entities.PatchSetApproval) PushOneCommit(com.google.gerrit.acceptance.PushOneCommit) AbstractDaemonTest(com.google.gerrit.acceptance.AbstractDaemonTest) Test(org.junit.Test)

Example 25 with PatchSetApproval

use of com.google.gerrit.entities.PatchSetApproval in project gerrit by GerritCodeReview.

the class StickyApprovalsIT method stickyVoteStoredOnRebase.

@Test
public void stickyVoteStoredOnRebase() throws Exception {
    // Code-Review will be sticky.
    String label = LabelId.CODE_REVIEW;
    try (ProjectConfigUpdate u = updateProject(project)) {
        u.getConfig().updateLabelType(label, b -> b.setCopyAnyScore(true));
        u.save();
    }
    // Create two changes both with the same parent
    PushOneCommit.Result r = createChange();
    testRepo.reset("HEAD~1");
    PushOneCommit.Result r2 = createChange();
    // Approve and submit the first change
    RevisionApi revision = gApi.changes().id(r.getChangeId()).current();
    revision.review(ReviewInput.approve().label(LabelId.VERIFIED, 1));
    revision.submit();
    // Add an approval whose score should be copied.
    gApi.changes().id(r2.getChangeId()).current().review(ReviewInput.recommend());
    // Rebase the second change
    gApi.changes().id(r2.getChangeId()).rebase();
    List<PatchSetApproval> patchSetApprovals = r2.getChange().notes().getApprovalsWithCopied().values().stream().sorted(comparing(a -> a.patchSetId().get())).collect(toImmutableList());
    PatchSetApproval nonCopied = patchSetApprovals.get(0);
    PatchSetApproval copied = patchSetApprovals.get(1);
    assertCopied(nonCopied, 1, LabelId.CODE_REVIEW, (short) 1, /* copied= */
    false);
    assertCopied(copied, 2, LabelId.CODE_REVIEW, (short) 1, /* copied= */
    true);
}
Also used : RevisionApi(com.google.gerrit.extensions.api.changes.RevisionApi) PatchSetApproval(com.google.gerrit.entities.PatchSetApproval) PushOneCommit(com.google.gerrit.acceptance.PushOneCommit) AbstractDaemonTest(com.google.gerrit.acceptance.AbstractDaemonTest) Test(org.junit.Test)

Aggregations

PatchSetApproval (com.google.gerrit.entities.PatchSetApproval)93 Test (org.junit.Test)57 Change (com.google.gerrit.entities.Change)41 LabelType (com.google.gerrit.entities.LabelType)22 Account (com.google.gerrit.entities.Account)20 PushOneCommit (com.google.gerrit.acceptance.PushOneCommit)14 Map (java.util.Map)14 ObjectId (org.eclipse.jgit.lib.ObjectId)14 LabelId (com.google.gerrit.entities.LabelId)13 PatchSet (com.google.gerrit.entities.PatchSet)12 SubmitRecord (com.google.gerrit.entities.SubmitRecord)12 AbstractDaemonTest (com.google.gerrit.acceptance.AbstractDaemonTest)11 ReviewInput (com.google.gerrit.extensions.api.changes.ReviewInput)10 SubmissionId (com.google.gerrit.entities.SubmissionId)9 ChangeData (com.google.gerrit.server.query.change.ChangeData)9 Inject (com.google.inject.Inject)9 Instant (java.time.Instant)9 HashMap (java.util.HashMap)9 List (java.util.List)9 ChangeMessage (com.google.gerrit.entities.ChangeMessage)8