com.google.gerrit.entities.SubmitRequirementResult Maven / Gradle / Ivy
// 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 applicabilityExpressionResult();
  /**
   * Result of evaluating a {@link SubmitRequirement#submittabilityExpression()} on a change.
   *
   * Empty if submit requirement does not apply.
   */
  public abstract Optional submittabilityExpressionResult();
  /**
   * Result of evaluating a {@link SubmitRequirement#overrideExpression()} on a change.
   *
   * Empty if submit requirement does not apply, or if the submit requirement did not define an
   * override expression.
   */
  public abstract Optional 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}.
   *
   * If equals {@link Optional#empty()}, we treat the result as non-legacy (false).
   */
  public abstract Optional 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 forced();
  /**
   * Whether this result should be filtered out when returned from REST API.
   *
   * 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 hidden();
  public boolean isHidden() {
    return hidden().orElse(false);
  }
  public Optional 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 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 value);
    public abstract Builder submittabilityExpressionResult(
        Optional value);
    public abstract Builder submittabilityExpressionResult(
        @Nullable SubmitRequirementExpressionResult value);
    public abstract Builder overrideExpressionResult(
        Optional value);
    public abstract Builder patchSetCommitId(ObjectId value);
    public abstract Builder legacy(Optional value);
    public abstract Builder forced(Optional value);
    public abstract Builder hidden(Optional value);
    public abstract SubmitRequirementResult build();
  }
  public static boolean assertPass(Optional expressionResult) {
    return assertStatus(expressionResult, SubmitRequirementExpressionResult.Status.PASS);
  }
  public static boolean assertFail(Optional expressionResult) {
    return assertStatus(expressionResult, SubmitRequirementExpressionResult.Status.FAIL);
  }
  public static boolean assertError(Optional 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 expressionResult,
      SubmitRequirementExpressionResult.Status status) {
    return expressionResult.isPresent() && assertStatus(expressionResult.get(), status);
  }
}