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.entities; 16 : 17 : import com.google.auto.value.AutoValue; 18 : import com.google.common.collect.ImmutableList; 19 : import com.google.gson.Gson; 20 : import com.google.gson.TypeAdapter; 21 : import java.util.Optional; 22 : 23 : /** Result of evaluating a submit requirement expression on a given Change. */ 24 : @AutoValue 25 104 : public abstract class SubmitRequirementExpressionResult { 26 : 27 : /** Submit requirement expression for which this result is evaluated. */ 28 : public abstract SubmitRequirementExpression expression(); 29 : 30 : /** Status of evaluation. */ 31 : public abstract Status status(); 32 : 33 : /** 34 : * Optional error message. Populated if the evaluator fails to evaluate the expression for a 35 : * certain change. 36 : */ 37 : public abstract Optional<String> errorMessage(); 38 : 39 : /** 40 : * List leaf predicates that are fulfilled, for example the expression 41 : * 42 : * <p><i>label:Code-Review=+2 and branch:refs/heads/master</i> 43 : * 44 : * <p>has two leaf predicates: 45 : * 46 : * <ul> 47 : * <li>label:Code-Review=+2 48 : * <li>branch:refs/heads/master 49 : * </ul> 50 : * 51 : * This method will return the leaf predicates that were fulfilled, for example if only the first 52 : * predicate was fulfilled, the returned list will be equal to ["label:Code-Review=+2"]. 53 : */ 54 : public abstract ImmutableList<String> passingAtoms(); 55 : 56 : /** 57 : * List of leaf predicates that are not fulfilled. See {@link #passingAtoms()} for more details. 58 : */ 59 : public abstract ImmutableList<String> failingAtoms(); 60 : 61 : public static SubmitRequirementExpressionResult create( 62 : SubmitRequirementExpression expression, PredicateResult predicateResult) { 63 3 : return create( 64 : expression, 65 3 : predicateResult.status() ? Status.PASS : Status.FAIL, 66 3 : predicateResult.getPassingAtoms(), 67 3 : predicateResult.getFailingAtoms()); 68 : } 69 : 70 : public static SubmitRequirementExpressionResult create( 71 : SubmitRequirementExpression expression, 72 : Status status, 73 : ImmutableList<String> passingAtoms, 74 : ImmutableList<String> failingAtoms) { 75 104 : return create(expression, status, passingAtoms, failingAtoms, Optional.empty()); 76 : } 77 : 78 : public static SubmitRequirementExpressionResult create( 79 : SubmitRequirementExpression expression, 80 : Status status, 81 : ImmutableList<String> passingAtoms, 82 : ImmutableList<String> failingAtoms, 83 : Optional<String> errorMessage) { 84 104 : return new AutoValue_SubmitRequirementExpressionResult( 85 : expression, status, errorMessage, passingAtoms, failingAtoms); 86 : } 87 : 88 : public static SubmitRequirementExpressionResult error( 89 : SubmitRequirementExpression expression, String errorMessage) { 90 3 : return new AutoValue_SubmitRequirementExpressionResult( 91 : expression, 92 : Status.ERROR, 93 3 : Optional.of(errorMessage), 94 3 : ImmutableList.of(), 95 3 : ImmutableList.of()); 96 : } 97 : 98 : public static SubmitRequirementExpressionResult notEvaluated(SubmitRequirementExpression expr) { 99 2 : return SubmitRequirementExpressionResult.create( 100 2 : expr, Status.NOT_EVALUATED, ImmutableList.of(), ImmutableList.of()); 101 : } 102 : 103 : public static TypeAdapter<SubmitRequirementExpressionResult> typeAdapter(Gson gson) { 104 3 : return new AutoValue_SubmitRequirementExpressionResult.GsonTypeAdapter(gson); 105 : } 106 : 107 : public abstract Builder toBuilder(); 108 : 109 : @AutoValue.Builder 110 3 : public abstract static class Builder { 111 : public abstract Builder expression(SubmitRequirementExpression expression); 112 : 113 : public abstract Builder status(Status status); 114 : 115 : public abstract Builder errorMessage(Optional<String> errorMessage); 116 : 117 : public abstract Builder passingAtoms(ImmutableList<String> passingAtoms); 118 : 119 : public abstract Builder failingAtoms(ImmutableList<String> failingAtoms); 120 : 121 : public abstract SubmitRequirementExpressionResult build(); 122 : } 123 : 124 104 : public enum Status { 125 : /** Submit requirement expression is fulfilled for a given change. */ 126 104 : PASS, 127 : 128 : /** Submit requirement expression is failing for a given change. */ 129 104 : FAIL, 130 : 131 : /** Submit requirement expression contains invalid syntax and is not parsable. */ 132 104 : ERROR, 133 : 134 : /** Submit requirement expression was not evaluated. */ 135 104 : NOT_EVALUATED 136 : } 137 : 138 : /** 139 : * Entity detailing the result of evaluating a predicate. 140 : * 141 : * <p>Example - branch:refs/heads/foo and has:unresolved 142 : * 143 : * <p>The above predicate is an "And" predicate having two child predicates: 144 : * 145 : * <ul> 146 : * <li>branch:refs/heads/foo 147 : * <li>has:unresolved 148 : * </ul> 149 : * 150 : * <p>Each child predicate as well as the parent contains the result of its evaluation. 151 : */ 152 : @AutoValue 153 3 : public abstract static class PredicateResult { 154 : abstract ImmutableList<PredicateResult> childPredicateResults(); 155 : 156 : /** We only set this field for leaf predicates. */ 157 : public abstract String predicateString(); 158 : 159 : /** true if the predicate is passing for a given change. */ 160 : abstract boolean status(); 161 : 162 : /** Returns a list of leaf predicate results whose {@link PredicateResult#status()} is true. */ 163 : ImmutableList<String> getPassingAtoms() { 164 3 : return getAtoms(/* status= */ true).stream() 165 3 : .map(PredicateResult::predicateString) 166 3 : .collect(ImmutableList.toImmutableList()); 167 : } 168 : 169 : /** Returns a list of leaf predicate results whose {@link PredicateResult#status()} is false. */ 170 : ImmutableList<String> getFailingAtoms() { 171 3 : return getAtoms(/* status= */ false).stream() 172 3 : .map(PredicateResult::predicateString) 173 3 : .collect(ImmutableList.toImmutableList()); 174 : } 175 : 176 : /** 177 : * Returns the list of leaf {@link PredicateResult} whose {@link #status()} is equal to the 178 : * {@code status} parameter. 179 : */ 180 : private ImmutableList<PredicateResult> getAtoms(boolean status) { 181 3 : ImmutableList.Builder<PredicateResult> atomsList = ImmutableList.builder(); 182 3 : getAtomsRecursively(atomsList, status); 183 3 : return atomsList.build(); 184 : } 185 : 186 : private void getAtomsRecursively(ImmutableList.Builder<PredicateResult> list, boolean status) { 187 3 : if (!predicateString().isEmpty() && status() == status) { 188 3 : list.add(this); 189 3 : return; 190 : } 191 3 : childPredicateResults().forEach(c -> c.getAtomsRecursively(list, status)); 192 3 : } 193 : 194 : public static Builder builder() { 195 3 : return new AutoValue_SubmitRequirementExpressionResult_PredicateResult.Builder(); 196 : } 197 : 198 : @AutoValue.Builder 199 3 : public abstract static class Builder { 200 : public abstract Builder childPredicateResults(ImmutableList<PredicateResult> value); 201 : 202 : protected abstract ImmutableList.Builder<PredicateResult> childPredicateResultsBuilder(); 203 : 204 : public abstract Builder predicateString(String value); 205 : 206 : public abstract Builder status(boolean value); 207 : 208 : public Builder addChildPredicateResult(PredicateResult result) { 209 2 : childPredicateResultsBuilder().add(result); 210 2 : return this; 211 : } 212 : 213 : public abstract PredicateResult build(); 214 : } 215 : } 216 : }