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

com.google.gerrit.server.query.change.SubmitRequirementChangeQueryBuilder Maven / Gradle / Ivy

There is a newer version: 3.11.0-rc3
Show newest version
// Copyright (C) 2021 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.query.change;

import com.google.common.base.Splitter;
import com.google.gerrit.entities.Account;
import com.google.gerrit.index.SchemaFieldDefs.SchemaField;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryBuilder;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.server.submitrequirement.predicate.ConstantPredicate;
import com.google.gerrit.server.submitrequirement.predicate.DistinctVotersPredicate;
import com.google.gerrit.server.submitrequirement.predicate.FileEditsPredicate;
import com.google.gerrit.server.submitrequirement.predicate.FileEditsPredicate.FileEditsArgs;
import com.google.gerrit.server.submitrequirement.predicate.HasSubmoduleUpdatePredicate;
import com.google.gerrit.server.submitrequirement.predicate.RegexAuthorEmailPredicate;
import com.google.gerrit.server.submitrequirement.predicate.RegexCommitterEmailPredicate;
import com.google.gerrit.server.submitrequirement.predicate.RegexUploaderEmailPredicateFactory;
import com.google.inject.Inject;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * A query builder for submit requirement expressions that includes all {@link ChangeQueryBuilder}
 * operators, in addition to extra operators contributed by this class.
 *
 * 

Operators defined in this class cannot be used in change queries. */ public class SubmitRequirementChangeQueryBuilder extends ChangeQueryBuilder { private static final QueryBuilder.Definition def = new QueryBuilder.Definition<>(SubmitRequirementChangeQueryBuilder.class); private final DistinctVotersPredicate.Factory distinctVotersPredicateFactory; private final HasSubmoduleUpdatePredicate.Factory hasSubmoduleUpdateFactory; /** * Regular expression for the {@link #file(String)} operator. Field value is of the form: * *

'$fileRegex',withDiffContaining='$contentRegex' * *

Both $fileRegex and $contentRegex may contain escaped single or double quotes. */ private static final Pattern FILE_EDITS_PATTERN = Pattern.compile("'((?:(?:\\\\')|(?:[^']))*)',withDiffContaining='((?:(?:\\\\')|(?:[^']))*)'"); public static final String SUBMODULE_UPDATE_HAS_ARG = "submodule-update"; private static final Splitter SUBMODULE_UPDATE_SPLITTER = Splitter.on(","); private final FileEditsPredicate.Factory fileEditsPredicateFactory; private final RegexUploaderEmailPredicateFactory regexUploaderEmailPredicateFactory; @Inject SubmitRequirementChangeQueryBuilder( Arguments args, DistinctVotersPredicate.Factory distinctVotersPredicateFactory, FileEditsPredicate.Factory fileEditsPredicateFactory, HasSubmoduleUpdatePredicate.Factory hasSubmoduleUpdateFactory, RegexUploaderEmailPredicateFactory regexUploaderEmailPredicateFactory) { super(def, args); this.distinctVotersPredicateFactory = distinctVotersPredicateFactory; this.fileEditsPredicateFactory = fileEditsPredicateFactory; this.hasSubmoduleUpdateFactory = hasSubmoduleUpdateFactory; this.regexUploaderEmailPredicateFactory = regexUploaderEmailPredicateFactory; } @Override protected void checkFieldAvailable(SchemaField field, String operator) { // Submit requirements don't rely on the index, so they can be used regardless of index schema // version. } @Override public Predicate is(String value) throws QueryParseException { if ("submittable".equalsIgnoreCase(value)) { throw new QueryParseException( String.format( "Operator 'is:submittable' cannot be used in submit requirement expressions.")); } if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) { return new ConstantPredicate(value); } return super.is(value); } @Override public Predicate has(String value) throws QueryParseException { if (value.toLowerCase(Locale.US).startsWith(SUBMODULE_UPDATE_HAS_ARG)) { List args = SUBMODULE_UPDATE_SPLITTER.splitToList(value); if (args.size() > 2) { throw error( String.format( "wrong number of arguments for the has:%s operator", SUBMODULE_UPDATE_HAS_ARG)); } else if (args.size() == 2) { List baseValue = Splitter.on("=").splitToList(args.get(1)); if (baseValue.size() != 2) { throw error("unexpected base value format"); } if (!baseValue.get(0).toLowerCase(Locale.US).equals("base")) { throw error("unexpected base value format"); } try { int base = Integer.parseInt(baseValue.get(1)); return hasSubmoduleUpdateFactory.create(base); } catch (NumberFormatException e) { throw error( String.format( "failed to parse the parent number %s: %s", baseValue.get(1), e.getMessage())); } } else { return hasSubmoduleUpdateFactory.create(0); } } return super.has(value); } @Operator public Predicate authoremail(String who) throws QueryParseException { return new RegexAuthorEmailPredicate(who); } @Operator public Predicate committerEmail(String who) throws QueryParseException { return new RegexCommitterEmailPredicate(who); } @Operator public Predicate uploaderEmail(String who) throws QueryParseException { return regexUploaderEmailPredicateFactory.create(who); } @Operator public Predicate distinctvoters(String value) throws QueryParseException { return distinctVotersPredicateFactory.create(value); } /** * A SR operator that can match with file path and content pattern. The value should be of the * form: * *

file:"'$filePattern',withDiffContaining='$contentPattern'" * *

The operator matches with changes that have their latest PS vs. base diff containing a file * path matching the {@code filePattern} with an edit (added, deleted, modified) matching the * {@code contentPattern}. {@code filePattern} and {@code contentPattern} can start with "^" to * use regular expression matching. * *

If the specified value does not match this form, we fall back to the operator's * implementation in {@link ChangeQueryBuilder}. */ @Override public Predicate file(String value) throws QueryParseException { Matcher matcher = FILE_EDITS_PATTERN.matcher(value); if (!matcher.find()) { return super.file(value); } String filePattern = matcher.group(1); String contentPattern = matcher.group(2); if (filePattern.startsWith("^")) { validateRegularExpression(filePattern, "Invalid file pattern."); } if (contentPattern.startsWith("^")) { validateRegularExpression(contentPattern, "Invalid content pattern."); } return fileEditsPredicateFactory.create(FileEditsArgs.create(filePattern, contentPattern)); } @Override protected void validateLabelArgs(Set accountIds) throws QueryParseException {} private static void validateRegularExpression(String pattern, String errorMessage) throws QueryParseException { try { Pattern.compile(pattern); } catch (PatternSyntaxException e) { throw new QueryParseException(errorMessage, e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy