LCOV - code coverage report
Current view: top level - server/query/change - ChangePredicates.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 70 75 93.3 %
Date: 2022-11-19 15:00:39 Functions: 38 41 92.7 %

          Line data    Source code
       1             : // Copyright (C) 2021 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.server.query.change;
      16             : 
      17             : import static com.google.common.collect.ImmutableSet.toImmutableSet;
      18             : 
      19             : import com.google.common.base.CharMatcher;
      20             : import com.google.gerrit.entities.Account;
      21             : import com.google.gerrit.entities.Change;
      22             : import com.google.gerrit.entities.PatchSet;
      23             : import com.google.gerrit.entities.Project;
      24             : import com.google.gerrit.git.ObjectIds;
      25             : import com.google.gerrit.index.query.Predicate;
      26             : import com.google.gerrit.server.CommentsUtil;
      27             : import com.google.gerrit.server.StarredChangesUtil;
      28             : import com.google.gerrit.server.change.HashtagsUtil;
      29             : import com.google.gerrit.server.index.change.ChangeField;
      30             : import java.util.ArrayList;
      31             : import java.util.Collection;
      32             : import java.util.List;
      33             : import java.util.Locale;
      34             : import java.util.Set;
      35             : 
      36             : /** Predicates that match against {@link ChangeData}. */
      37             : public class ChangePredicates {
      38             :   private ChangePredicates() {}
      39             : 
      40             :   /**
      41             :    * Returns a predicate that matches changes where the provided {@link
      42             :    * com.google.gerrit.entities.Account.Id} is in the attention set.
      43             :    */
      44             :   public static Predicate<ChangeData> attentionSet(Account.Id id) {
      45           4 :     return new ChangeIndexPredicate(ChangeField.ATTENTION_SET_USERS, id.toString());
      46             :   }
      47             : 
      48             :   /**
      49             :    * Returns a predicate that matches changes that are assigned to the provided {@link
      50             :    * com.google.gerrit.entities.Account.Id}.
      51             :    */
      52             :   public static Predicate<ChangeData> assignee(Account.Id id) {
      53           4 :     return new ChangeIndexPredicate(ChangeField.ASSIGNEE_SPEC, id.toString());
      54             :   }
      55             : 
      56             :   /**
      57             :    * Returns a predicate that matches changes that are a revert of the provided {@link
      58             :    * com.google.gerrit.entities.Change.Id}.
      59             :    */
      60             :   public static Predicate<ChangeData> revertOf(Change.Id revertOf) {
      61           4 :     return new ChangeIndexCardinalPredicate(ChangeField.REVERT_OF, revertOf.toString(), 1);
      62             :   }
      63             : 
      64             :   /**
      65             :    * Returns a predicate that matches changes that have a comment authored by the provided {@link
      66             :    * com.google.gerrit.entities.Account.Id}.
      67             :    */
      68             :   public static Predicate<ChangeData> commentBy(Account.Id id) {
      69           4 :     return new ChangeIndexPredicate(ChangeField.COMMENTBY, id.toString());
      70             :   }
      71             : 
      72             :   /**
      73             :    * Returns a predicate that matches changes where the provided {@link
      74             :    * com.google.gerrit.entities.Account.Id} has a pending change edit.
      75             :    */
      76             :   public static Predicate<ChangeData> editBy(Account.Id id) {
      77           8 :     return new ChangeIndexPredicate(ChangeField.EDITBY, id.toString());
      78             :   }
      79             : 
      80             :   /**
      81             :    * Returns a predicate that matches changes where the provided {@link
      82             :    * com.google.gerrit.entities.Account.Id} has a pending draft comment.
      83             :    */
      84             :   public static Predicate<ChangeData> draftBy(CommentsUtil commentsUtil, Account.Id id) {
      85           7 :     Set<Predicate<ChangeData>> changeIdPredicates =
      86           7 :         commentsUtil.getChangesWithDrafts(id).stream()
      87           7 :             .map(ChangePredicates::idStr)
      88           7 :             .collect(toImmutableSet());
      89           7 :     return changeIdPredicates.isEmpty()
      90           5 :         ? ChangeIndexPredicate.none()
      91           7 :         : Predicate.or(changeIdPredicates);
      92             :   }
      93             : 
      94             :   /**
      95             :    * Returns a predicate that matches changes where the provided {@link
      96             :    * com.google.gerrit.entities.Account.Id} has starred changes with {@code label}.
      97             :    */
      98             :   public static Predicate<ChangeData> starBy(
      99             :       StarredChangesUtil starredChangesUtil, Account.Id id, String label) {
     100           4 :     Set<Predicate<ChangeData>> starredChanges =
     101           4 :         starredChangesUtil.byAccountId(id, label).stream()
     102           4 :             .map(ChangePredicates::idStr)
     103           4 :             .collect(toImmutableSet());
     104           4 :     return starredChanges.isEmpty() ? ChangeIndexPredicate.none() : Predicate.or(starredChanges);
     105             :   }
     106             : 
     107             :   /**
     108             :    * Returns a predicate that matches changes that were reviewed by any of the provided {@link
     109             :    * com.google.gerrit.entities.Account.Id}.
     110             :    */
     111             :   public static Predicate<ChangeData> reviewedBy(Collection<Account.Id> ids) {
     112           4 :     List<Predicate<ChangeData>> predicates = new ArrayList<>(ids.size());
     113           4 :     for (Account.Id id : ids) {
     114           4 :       predicates.add(new ChangeIndexPredicate(ChangeField.REVIEWEDBY, id.toString()));
     115           4 :     }
     116           4 :     return Predicate.or(predicates);
     117             :   }
     118             : 
     119             :   /** Returns a predicate that matches changes that were not yet reviewed. */
     120             :   public static Predicate<ChangeData> unreviewed() {
     121           4 :     return Predicate.not(
     122           4 :         new ChangeIndexPredicate(ChangeField.REVIEWEDBY, ChangeField.NOT_REVIEWED.toString()));
     123             :   }
     124             : 
     125             :   /**
     126             :    * Returns a predicate that matches the change with the provided {@link
     127             :    * com.google.gerrit.entities.Change.Id}.
     128             :    */
     129             :   public static Predicate<ChangeData> idStr(Change.Id id) {
     130          68 :     return new ChangeIndexCardinalPredicate(
     131          68 :         ChangeField.LEGACY_ID_STR, ChangeQueryBuilder.FIELD_CHANGE, id.toString(), 1);
     132             :   }
     133             : 
     134             :   /**
     135             :    * Returns a predicate that matches changes owned by the provided {@link
     136             :    * com.google.gerrit.entities.Account.Id}.
     137             :    */
     138             :   public static Predicate<ChangeData> owner(Account.Id id) {
     139         102 :     return new ChangeIndexCardinalPredicate(ChangeField.OWNER_SPEC, id.toString(), 5000);
     140             :   }
     141             : 
     142             :   /**
     143             :    * Returns a predicate that matches changes where the latest patch set was uploaded by the
     144             :    * provided {@link com.google.gerrit.entities.Account.Id}.
     145             :    */
     146             :   public static Predicate<ChangeData> uploader(Account.Id id) {
     147           4 :     return new ChangeIndexPredicate(ChangeField.UPLOADER_SPEC, id.toString());
     148             :   }
     149             : 
     150             :   /**
     151             :    * Returns a predicate that matches changes that are a cherry pick of the provided {@link
     152             :    * com.google.gerrit.entities.Change.Id}.
     153             :    */
     154             :   public static Predicate<ChangeData> cherryPickOf(Change.Id id) {
     155           0 :     return new ChangeIndexPredicate(ChangeField.CHERRY_PICK_OF_CHANGE, id.toString());
     156             :   }
     157             : 
     158             :   /**
     159             :    * Returns a predicate that matches changes that are a cherry pick of the provided {@link
     160             :    * com.google.gerrit.entities.PatchSet.Id}.
     161             :    */
     162             :   public static Predicate<ChangeData> cherryPickOf(PatchSet.Id psId) {
     163           0 :     return Predicate.and(
     164           0 :         cherryPickOf(psId.changeId()),
     165           0 :         new ChangeIndexPredicate(ChangeField.CHERRY_PICK_OF_PATCHSET, String.valueOf(psId.get())));
     166             :   }
     167             : 
     168             :   /**
     169             :    * Returns a predicate that matches changes in the provided {@link
     170             :    * com.google.gerrit.entities.Project.NameKey}.
     171             :    */
     172             :   public static Predicate<ChangeData> project(Project.NameKey id) {
     173         110 :     return new ChangeIndexCardinalPredicate(ChangeField.PROJECT_SPEC, id.get(), 1_000_000);
     174             :   }
     175             : 
     176             :   /** Returns a predicate that matches changes targeted at the provided {@code refName}. */
     177             :   public static Predicate<ChangeData> ref(String refName) {
     178         104 :     return new ChangeIndexCardinalPredicate(ChangeField.REF_SPEC, refName, 10_000);
     179             :   }
     180             : 
     181             :   /** Returns a predicate that matches changes in the provided {@code topic}. */
     182             :   public static Predicate<ChangeData> exactTopic(String topic) {
     183          27 :     return new ChangeIndexPredicate(ChangeField.EXACT_TOPIC, topic);
     184             :   }
     185             : 
     186             :   /** Returns a predicate that matches changes in the provided {@code topic}. */
     187             :   public static Predicate<ChangeData> fuzzyTopic(String topic) {
     188           4 :     return new ChangeIndexPredicate(ChangeField.FUZZY_TOPIC, topic);
     189             :   }
     190             : 
     191             :   /** Returns a predicate that matches changes in the provided {@code topic}. Used with prefixes */
     192             :   public static Predicate<ChangeData> prefixTopic(String topic) {
     193           4 :     return new ChangeIndexPredicate(ChangeField.PREFIX_TOPIC, topic);
     194             :   }
     195             : 
     196             :   /** Returns a predicate that matches changes submitted in the provided {@code changeSet}. */
     197             :   public static Predicate<ChangeData> submissionId(String changeSet) {
     198          26 :     return new ChangeIndexPredicate(ChangeField.SUBMISSIONID_SPEC, changeSet);
     199             :   }
     200             : 
     201             :   /** Returns a predicate that matches changes that modified the provided {@code path}. */
     202             :   public static Predicate<ChangeData> path(String path) {
     203          11 :     return new ChangeIndexPredicate(ChangeField.PATH_SPEC, path);
     204             :   }
     205             : 
     206             :   /** Returns a predicate that matches changes tagged with the provided {@code hashtag}. */
     207             :   public static Predicate<ChangeData> hashtag(String hashtag) {
     208             :     // Use toLowerCase without locale to match behavior in ChangeField.
     209           4 :     return new ChangeIndexPredicate(
     210           4 :         ChangeField.HASHTAG_SPEC, HashtagsUtil.cleanupHashtag(hashtag).toLowerCase());
     211             :   }
     212             : 
     213             :   /** Returns a predicate that matches changes tagged with the provided {@code hashtag}. */
     214             :   public static Predicate<ChangeData> fuzzyHashtag(String hashtag) {
     215             :     // Use toLowerCase without locale to match behavior in ChangeField.
     216           4 :     return new ChangeIndexPredicate(
     217           4 :         ChangeField.FUZZY_HASHTAG, HashtagsUtil.cleanupHashtag(hashtag).toLowerCase());
     218             :   }
     219             : 
     220             :   /**
     221             :    * Returns a predicate that matches changes in the provided {@code hashtag}. Used with prefixes
     222             :    */
     223             :   public static Predicate<ChangeData> prefixHashtag(String hashtag) {
     224             :     // Use toLowerCase without locale to match behavior in ChangeField.
     225           4 :     return new ChangeIndexPredicate(
     226           4 :         ChangeField.PREFIX_HASHTAG, HashtagsUtil.cleanupHashtag(hashtag).toLowerCase());
     227             :   }
     228             : 
     229             :   /** Returns a predicate that matches changes that modified the provided {@code file}. */
     230             :   public static Predicate<ChangeData> file(ChangeQueryBuilder.Arguments args, String file) {
     231          11 :     Predicate<ChangeData> eqPath = path(file);
     232          11 :     if (!args.getSchema().hasField(ChangeField.FILE_PART_SPEC)) {
     233           1 :       return eqPath;
     234             :     }
     235          10 :     return Predicate.or(eqPath, new ChangeIndexPredicate(ChangeField.FILE_PART_SPEC, file));
     236             :   }
     237             : 
     238             :   /**
     239             :    * Returns a predicate that matches changes with the provided {@code footer} in their commit
     240             :    * message.
     241             :    */
     242             :   public static Predicate<ChangeData> footer(String footer) {
     243           4 :     int indexEquals = footer.indexOf('=');
     244           4 :     int indexColon = footer.indexOf(':');
     245             : 
     246             :     // footer key cannot contain '='
     247           4 :     if (indexEquals > 0 && (indexEquals < indexColon || indexColon < 0)) {
     248           4 :       footer = footer.substring(0, indexEquals) + ": " + footer.substring(indexEquals + 1);
     249             :     }
     250           4 :     return new ChangeIndexPredicate(ChangeField.FOOTER_SPEC, footer.toLowerCase(Locale.US));
     251             :   }
     252             : 
     253             :   /**
     254             :    * Returns a predicate that matches changes with the provided {@code footer} name in their commit
     255             :    * message.
     256             :    */
     257             :   public static Predicate<ChangeData> hasFooter(String footerName) {
     258           4 :     return new ChangeIndexPredicate(ChangeField.FOOTER_NAME, footerName);
     259             :   }
     260             : 
     261             :   /**
     262             :    * Returns a predicate that matches changes that modified files in the provided {@code directory}.
     263             :    */
     264             :   public static Predicate<ChangeData> directory(String directory) {
     265           5 :     return new ChangeIndexPredicate(
     266           5 :         ChangeField.DIRECTORY_SPEC, CharMatcher.is('/').trimFrom(directory).toLowerCase(Locale.US));
     267             :   }
     268             : 
     269             :   /** Returns a predicate that matches changes with the provided {@code trackingId}. */
     270             :   public static Predicate<ChangeData> trackingId(String trackingId) {
     271           4 :     return new ChangeIndexCardinalPredicate(ChangeField.TR, trackingId, 5);
     272             :   }
     273             : 
     274             :   /** Returns a predicate that matches changes authored by the provided {@code exactAuthor}. */
     275             :   public static Predicate<ChangeData> exactAuthor(String exactAuthor) {
     276           4 :     return new ChangeIndexPredicate(
     277           4 :         ChangeField.EXACT_AUTHOR_SPEC, exactAuthor.toLowerCase(Locale.US));
     278             :   }
     279             : 
     280             :   /** Returns a predicate that matches changes authored by the provided {@code author}. */
     281             :   public static Predicate<ChangeData> author(String author) {
     282           4 :     return new ChangeIndexPredicate(ChangeField.AUTHOR_PARTS_SPEC, author);
     283             :   }
     284             : 
     285             :   /**
     286             :    * Returns a predicate that matches changes where the patch set was committed by {@code
     287             :    * exactCommitter}.
     288             :    */
     289             :   public static Predicate<ChangeData> exactCommitter(String exactCommitter) {
     290           4 :     return new ChangeIndexPredicate(
     291           4 :         ChangeField.EXACT_COMMITTER_SPEC, exactCommitter.toLowerCase(Locale.US));
     292             :   }
     293             : 
     294             :   /**
     295             :    * Returns a predicate that matches changes where the patch set was committed by {@code
     296             :    * committer}.
     297             :    */
     298             :   public static Predicate<ChangeData> committer(String comitter) {
     299           4 :     return new ChangeIndexPredicate(
     300           4 :         ChangeField.COMMITTER_PARTS_SPEC, comitter.toLowerCase(Locale.US));
     301             :   }
     302             : 
     303             :   /** Returns a predicate that matches changes whose ID starts with the provided {@code id}. */
     304             :   public static Predicate<ChangeData> idPrefix(String id) {
     305          99 :     return new ChangeIndexCardinalPredicate(ChangeField.ID, id, 5);
     306             :   }
     307             : 
     308             :   /**
     309             :    * Returns a predicate that matches changes in a project that has the provided {@code prefix} in
     310             :    * its name.
     311             :    */
     312             :   public static Predicate<ChangeData> projectPrefix(String prefix) {
     313          10 :     return new ChangeIndexPredicate(ChangeField.PROJECTS_SPEC, prefix);
     314             :   }
     315             : 
     316             :   /**
     317             :    * Returns a predicate that matches changes where a patch set has the provided {@code commitId}
     318             :    * either as prefix or as full {@link org.eclipse.jgit.lib.ObjectId}.
     319             :    */
     320             :   public static Predicate<ChangeData> commitPrefix(String commitId) {
     321          82 :     if (commitId.length() == ObjectIds.STR_LEN) {
     322          82 :       return new ChangeIndexCardinalPredicate(ChangeField.EXACT_COMMIT, commitId, 5);
     323             :     }
     324           8 :     return new ChangeIndexCardinalPredicate(ChangeField.COMMIT, commitId, 5);
     325             :   }
     326             : 
     327             :   /**
     328             :    * Returns a predicate that matches changes where the provided {@code message} appears in the
     329             :    * commit message. Uses full-text search semantics.
     330             :    */
     331             :   public static Predicate<ChangeData> message(String message) {
     332          13 :     return new ChangeIndexPredicate(ChangeField.COMMIT_MESSAGE, message);
     333             :   }
     334             : 
     335             :   /**
     336             :    * Returns a predicate that matches changes where the provided {@code comment} appears in any
     337             :    * comment on any patch set of the change. Uses full-text search semantics.
     338             :    */
     339             :   public static Predicate<ChangeData> comment(String comment) {
     340          10 :     return new ChangeIndexPredicate(ChangeField.COMMENT, comment);
     341             :   }
     342             : 
     343             :   /**
     344             :    * Returns a predicate that matches with changes having a specific submit rule evaluating to a
     345             :    * certain result. Value should be in the form of "$ruleName=$status" with $ruleName equals to
     346             :    * '$plugin_name~$rule_name' and $rule_name equals to the name of the class that implements the
     347             :    * {@link com.google.gerrit.server.rules.SubmitRule}. For gerrit core rules, $ruleName should be
     348             :    * in the form of 'gerrit~$rule_name'.
     349             :    */
     350             :   public static Predicate<ChangeData> submitRuleStatus(String value) {
     351           4 :     return new ChangeIndexPredicate(ChangeField.SUBMIT_RULE_RESULT, value);
     352             :   }
     353             : 
     354             :   /**
     355             :    * Returns a predicate that matches with changes that are pure reverts if {@code value} is equal
     356             :    * to "1", or non-pure reverts if {@code value} is "0".
     357             :    */
     358             :   public static Predicate<ChangeData> pureRevert(String value) {
     359           5 :     return new ChangeIndexPredicate(ChangeField.IS_PURE_REVERT_SPEC, value);
     360             :   }
     361             : 
     362             :   /**
     363             :    * Returns a predicate that matches with changes that are submittable if {@code value} is equal to
     364             :    * "1", or non-submittable if {@code value} is "0".
     365             :    *
     366             :    * <p>The computation of this field is based on the evaluation of {@link
     367             :    * com.google.gerrit.entities.SubmitRequirement}s.
     368             :    */
     369             :   public static Predicate<ChangeData> isSubmittable(String value) {
     370           0 :     return new ChangeIndexPredicate(ChangeField.IS_SUBMITTABLE_SPEC, value);
     371             :   }
     372             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750