All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.server.notedb.ChangeNotesParseApprovalUtil Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2022 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.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.notedb;

import static com.google.gerrit.server.notedb.ChangeNoteFooters.FOOTER_COPIED_LABEL;
import static com.google.gerrit.server.notedb.ChangeNoteFooters.FOOTER_LABEL;

import com.google.auto.value.AutoValue;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.revwalk.FooterKey;

/**
 * Util to extract {@link com.google.gerrit.entities.PatchSetApproval} from {@link
 * ChangeNoteFooters#FOOTER_LABEL} or {@link ChangeNoteFooters#FOOTER_COPIED_LABEL}.
 */
public class ChangeNotesParseApprovalUtil {
  private static final String LABEL_VOTE_UUID_SEPARATOR = ", ";

  /**
   * {@link com.google.gerrit.entities.PatchSetApproval}, parsed from {@link
   * ChangeNoteFooters#FOOTER_LABEL} or {@link ChangeNoteFooters#FOOTER_COPIED_LABEL}.
   *
   * 

In comparison to {@link com.google.gerrit.entities.PatchSetApproval}, this entity represent * the raw fields, parsed from the NoteDB footer line, without any interpretation of the parsed * values. See {@link #parseApproval} and {@link #parseCopiedApproval} for the valid {@link * #footerLine} values. */ @AutoValue public abstract static class ParsedPatchSetApproval { /** The original footer value, that this entity was parsed from. */ public abstract String footerLine(); public abstract boolean isRemoval(); /** Either

Valid added approval footer examples: * *

    *
  • Label: <LABEL>=VOTE *
  • Label: <LABEL>=VOTE <Gerrit Account> *
  • Label: <LABEL>=VOTE, <UUID> *
  • Label: <LABEL>=VOTE, <UUID> <Gerrit Account> *
* *

<UUID> is optional, since the approval might have been granted before {@link * com.google.gerrit.entities.PatchSetApproval.UUID} was introduced. * *

is only persisted in cases, when the account, that granted the vote does * not match the account, that issued {@link ChangeUpdate} (created this NoteDB commit). */ private static ParsedPatchSetApproval parseAddedApproval(String footerLine) throws ConfigInvalidException { ParsedPatchSetApproval.Builder rawPatchSetApproval = ParsedPatchSetApproval.builder().footerLine(footerLine); rawPatchSetApproval.isRemoval(false); // We need some additional logic to differentiate between labels that have a UUID and those that // have a user with a comma. This allows us to separate the following cases (note that the // leading `Label: ` has been elided at this point): // Label:

Valid removed approval footer examples: * *

    *
  • -<LABEL> *
  • -<LABEL> <Gerrit Account> *
* *

<Gerrit Account> is only persisted in cases, when the account, that granted the vote * does not match the account, that issued {@link ChangeUpdate} (created this NoteDB commit). */ private static ParsedPatchSetApproval parseRemovedApproval(String footerLine) { ParsedPatchSetApproval.Builder rawPatchSetApproval = ParsedPatchSetApproval.builder().footerLine(footerLine); rawPatchSetApproval.isRemoval(true); int labelStart = 1; int reviewerStart = footerLine.indexOf(' ', labelStart); rawPatchSetApproval.labelVote( reviewerStart != -1 ? footerLine.substring(labelStart, reviewerStart) : footerLine.substring(labelStart)); if (reviewerStart > 0) { String ident = footerLine.substring(reviewerStart + 1); rawPatchSetApproval.accountIdent(Optional.of(ident)); } return rawPatchSetApproval.build(); } /** * Parses copied {@link ParsedPatchSetApproval} from {@link ChangeNoteFooters#FOOTER_COPIED_LABEL} * line. * *

Footer example: Copied-Label:

    *
  • ":<"TAG>"" is optional. *
  • is also optional, if it was not set. *
  • is optional, since the approval might have been granted before {@link * com.google.gerrit.entities.PatchSetApproval.UUID} was introduced. *
  • The label, vote, and the Gerrit account are mandatory (unlike FOOTER_LABEL where Gerrit * Account is also optional since by default it's the committer). *
* *

Footer example for removal: Copied-Label: -

    *
  • is also optional, if it was not set. *
*/ public static ParsedPatchSetApproval parseCopiedApproval(String labelLine) throws ConfigInvalidException { try { ParsedPatchSetApproval.Builder rawPatchSetApproval = ParsedPatchSetApproval.builder().footerLine(labelLine); boolean isRemoval = labelLine.startsWith("-"); rawPatchSetApproval.isRemoval(isRemoval); int labelStart = isRemoval ? 1 : 0; int tagStart = isRemoval ? -1 : labelLine.indexOf(":\""); int uuidStart = parseCopiedApprovalUuidStart(labelLine, tagStart); checkFooter(!isRemoval || uuidStart == -1, FOOTER_LABEL, labelLine); // Weird tag that contains uuid delimiter. The uuid is actually not present. if (tagStart != -1 && uuidStart > tagStart) { uuidStart = -1; } int identitiesStart = labelLine.indexOf( ' ', uuidStart != -1 ? uuidStart + LABEL_VOTE_UUID_SEPARATOR.length() : 0); checkFooter( identitiesStart != -1 && identitiesStart < labelLine.length(), FOOTER_COPIED_LABEL, labelLine); String labelVoteStr = labelLine.substring(labelStart, uuidStart != -1 ? uuidStart : identitiesStart); rawPatchSetApproval.labelVote(labelVoteStr); if (uuidStart != -1) { String uuid = labelLine.substring(uuidStart + 2, identitiesStart); checkFooter(!Strings.isNullOrEmpty(uuid), FOOTER_COPIED_LABEL, labelLine); rawPatchSetApproval.uuid(Optional.of(uuid)); } // The first account is the accountId, and second (if applicable) is the realAccountId. List identities = parseIdentities( labelLine.substring( identitiesStart + 1, tagStart == -1 ? labelLine.length() : tagStart)); rawPatchSetApproval.accountIdent(Optional.of(identities.get(0))); if (identities.size() > 1) { rawPatchSetApproval.realAccountIdent(Optional.of(identities.get(1))); } if (tagStart != -1) { // tagStart+2 skips ":\"" to parse the actual tag. Tags are in brackets. // line.length()-1 skips the last ". String tag = labelLine.substring(tagStart + 2, labelLine.length() - 1); rawPatchSetApproval.tag(Optional.of(tag)); } return rawPatchSetApproval.build(); } catch (StringIndexOutOfBoundsException ex) { throw parseException(FOOTER_COPIED_LABEL, labelLine, ex); } } // Return the UUID start index or -1 if no UUID is present private static int parseCopiedApprovalUuidStart(String line, int tagStart) { int separatorIndex = line.indexOf(LABEL_VOTE_UUID_SEPARATOR); // The first part of the condition checks whether the footer has the following format: // Copied-Label:




© 2015 - 2024 Weber Informatics LLC | Privacy Policy