blob: d9bb162650d5d33234ad1a2982e509e7f4cc4ba1 [file] [log] [blame]
// 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.entities;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.gerrit.common.Nullable;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import java.util.Optional;
import org.eclipse.jgit.lib.ObjectId;
/** Result of evaluating a {@link SubmitRequirement} on a given Change. */
@AutoValue
public abstract class SubmitRequirementResult {
/** Submit requirement for which this result is evaluated. */
public abstract SubmitRequirement submitRequirement();
/** Result of evaluating a {@link SubmitRequirement#applicabilityExpression()} on a change. */
public abstract Optional<SubmitRequirementExpressionResult> applicabilityExpressionResult();
/**
* Result of evaluating a {@link SubmitRequirement#submittabilityExpression()} on a change.
*
* <p>Empty if submit requirement does not apply.
*/
public abstract Optional<SubmitRequirementExpressionResult> submittabilityExpressionResult();
/**
* Result of evaluating a {@link SubmitRequirement#overrideExpression()} on a change.
*
* <p>Empty if submit requirement does not apply, or if the submit requirement did not define an
* override expression.
*/
public abstract Optional<SubmitRequirementExpressionResult> overrideExpressionResult();
/** SHA-1 of the patchset commit ID for which the submit requirement was evaluated. */
public abstract ObjectId patchSetCommitId();
/**
* Whether this result was created from a legacy {@link SubmitRecord}, or by evaluating a {@link
* SubmitRequirement}.
*
* <p>If equals {@link Optional#empty()}, we treat the result as non-legacy (false).
*/
public abstract Optional<Boolean> legacy();
public boolean isLegacy() {
return legacy().orElse(false);
}
/**
* Boolean indicating if the "submit requirement" was bypassed during submission, e.g. by
* performing a push with the %submit option.
*/
public abstract Optional<Boolean> forced();
/**
* Whether this result should be filtered out when returned from REST API.
*
* <p>This can be used by {@link
* com.google.gerrit.server.project.OnStoreSubmitRequirementResultModifier}. It can override the
* {@code SubmitRequirementResult} status and might want to hide the SR from the API as if it was
* non-applicable (non-applicable SRs are currently hidden on UI).
*/
public abstract Optional<Boolean> hidden();
public boolean isHidden() {
return hidden().orElse(false);
}
public Optional<String> errorMessage() {
if (!status().equals(Status.ERROR)) {
return Optional.empty();
}
if (applicabilityExpressionResult().isPresent()
&& applicabilityExpressionResult().get().errorMessage().isPresent()) {
return Optional.of(
"Applicability expression result has an error: "
+ applicabilityExpressionResult().get().errorMessage().get());
}
if (submittabilityExpressionResult().isPresent()
&& submittabilityExpressionResult().get().errorMessage().isPresent()) {
return Optional.of(
"Submittability expression result has an error: "
+ submittabilityExpressionResult().get().errorMessage().get());
}
if (overrideExpressionResult().isPresent()
&& overrideExpressionResult().get().errorMessage().isPresent()) {
return Optional.of(
"Override expression result has an error: "
+ overrideExpressionResult().get().errorMessage().get());
}
return Optional.of("No error logged.");
}
@Memoized
public Status status() {
if (forced().orElse(false)) {
return Status.FORCED;
} else if (assertError(submittabilityExpressionResult())
|| assertError(applicabilityExpressionResult())
|| assertError(overrideExpressionResult())) {
return Status.ERROR;
} else if (assertFail(applicabilityExpressionResult())) {
return Status.NOT_APPLICABLE;
} else if (assertPass(overrideExpressionResult())) {
return Status.OVERRIDDEN;
} else if (assertPass(submittabilityExpressionResult())) {
return Status.SATISFIED;
} else {
return Status.UNSATISFIED;
}
}
/** Returns true if the submit requirement is fulfilled and can allow change submission. */
@Memoized
public boolean fulfilled() {
Status s = status();
return s == Status.SATISFIED
|| s == Status.OVERRIDDEN
|| s == Status.NOT_APPLICABLE
|| s == Status.FORCED;
}
public static Builder builder() {
return new AutoValue_SubmitRequirementResult.Builder();
}
public abstract Builder toBuilder();
public static TypeAdapter<SubmitRequirementResult> typeAdapter(Gson gson) {
return new AutoValue_SubmitRequirementResult.GsonTypeAdapter(gson);
}
public enum Status {
/** Submit requirement is fulfilled. */
SATISFIED,
/**
* Submit requirement is not satisfied. Happens when {@link
* SubmitRequirement#submittabilityExpression()} evaluates to false.
*/
UNSATISFIED,
/**
* Submit requirement is overridden. Happens when {@link SubmitRequirement#overrideExpression()}
* evaluates to true.
*/
OVERRIDDEN,
/**
* Submit requirement is not applicable for a given change. Happens when {@link
* SubmitRequirement#applicabilityExpression()} evaluates to false.
*/
NOT_APPLICABLE,
/**
* Any of the applicability, submittability or override expressions contain invalid syntax and
* are not parsable.
*/
ERROR,
/**
* The "submit requirement" was bypassed during submission, e.g. by pushing for review with the
* %submit option.
*/
FORCED
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder submitRequirement(SubmitRequirement submitRequirement);
public abstract Builder applicabilityExpressionResult(
Optional<SubmitRequirementExpressionResult> value);
public abstract Builder submittabilityExpressionResult(
Optional<SubmitRequirementExpressionResult> value);
public abstract Builder submittabilityExpressionResult(
@Nullable SubmitRequirementExpressionResult value);
public abstract Builder overrideExpressionResult(
Optional<SubmitRequirementExpressionResult> value);
public abstract Builder patchSetCommitId(ObjectId value);
public abstract Builder legacy(Optional<Boolean> value);
public abstract Builder forced(Optional<Boolean> value);
public abstract Builder hidden(Optional<Boolean> value);
public abstract SubmitRequirementResult build();
}
public static boolean assertPass(Optional<SubmitRequirementExpressionResult> expressionResult) {
return assertStatus(expressionResult, SubmitRequirementExpressionResult.Status.PASS);
}
public static boolean assertFail(Optional<SubmitRequirementExpressionResult> expressionResult) {
return assertStatus(expressionResult, SubmitRequirementExpressionResult.Status.FAIL);
}
public static boolean assertError(Optional<SubmitRequirementExpressionResult> expressionResult) {
return assertStatus(expressionResult, SubmitRequirementExpressionResult.Status.ERROR);
}
private static boolean assertStatus(
SubmitRequirementExpressionResult expressionResult,
SubmitRequirementExpressionResult.Status status) {
return expressionResult.status() == status;
}
private static boolean assertStatus(
Optional<SubmitRequirementExpressionResult> expressionResult,
SubmitRequirementExpressionResult.Status status) {
return expressionResult.isPresent() && assertStatus(expressionResult.get(), status);
}
}