/* * The MIT License * * Copyright (c) 2011, Christoph Kutzinski * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package hudson.model; import org.jvnet.localizer.Localizable; import java.util.Locale; /** * Describes an {@link Result} trend by taking the comparing the result of the current and the previous build. * * @author kutzi * @since 1.416 */ public enum ResultTrend { /** * Previous build was {@link Result#FAILURE} or {@link Result#UNSTABLE} * and is now {@link Result#SUCCESS}. */ FIXED(Messages._ResultTrend_Fixed()), /** * Build as well as previous build (if it has a previous build) are {@link Result#SUCCESS} */ SUCCESS(Messages._ResultTrend_Success()), /** * Previous build was {@link Result#FAILURE} and is now 'only' {@link Result#UNSTABLE}. */ NOW_UNSTABLE(Messages._ResultTrend_NowUnstable()), /** * Build as well as previous build are {@link Result#UNSTABLE}. */ STILL_UNSTABLE(Messages._ResultTrend_StillUnstable()), /** * Previous build (if there is one) was {@link Result#SUCCESS} and current build is {@link Result#UNSTABLE}. */ UNSTABLE(Messages._ResultTrend_Unstable()), /** * Build as well as previous build are {@link Result#FAILURE}. */ STILL_FAILING(Messages._ResultTrend_StillFailing()), /** * Previous build (if there is one) was {@link Result#SUCCESS} or {@link Result#UNSTABLE} * and current build is {@link Result#FAILURE}. */ FAILURE(Messages._ResultTrend_Failure()), /** * Build was aborted. */ ABORTED(Messages._ResultTrend_Aborted()), /** * Build didn't run (yet). */ NOT_BUILT(Messages._ResultTrend_NotBuilt()); private final Localizable description; private ResultTrend(Localizable description) { this.description = description; } /** * Returns a short human-readable description of the result. */ public String getDescription() { return this.description.toString(); } /** * Gets all upper case ID like token of the build status. */ public String getID() { return this.description.toString(Locale.ENGLISH).toUpperCase(Locale.ENGLISH); } /** * Returns the result trend of a build. * * @param build the build * @return the result trend */ public static ResultTrend getResultTrend(AbstractBuild<?, ?> build) { return getResultTrend((Run<?,?>)build); } /** * Returns the result trend of a run. * * @param run the run * @return the result trend * * @since 1.441 */ public static ResultTrend getResultTrend(Run<?, ?> run) { Result result = run.getResult(); if (result == Result.ABORTED) { return ABORTED; } else if (result == Result.NOT_BUILT) { return NOT_BUILT; } if (result == Result.SUCCESS) { if (isFix(run)) { return FIXED; } else { return SUCCESS; } } Run<?, ?> previousBuild = getPreviousNonAbortedBuild(run); if (result == Result.UNSTABLE) { if (previousBuild == null) { return UNSTABLE; } if (previousBuild.getResult() == Result.UNSTABLE) { return STILL_UNSTABLE; } else if (previousBuild.getResult() == Result.FAILURE) { return NOW_UNSTABLE; } else { return UNSTABLE; } } else if (result == Result.FAILURE) { if (previousBuild != null && previousBuild.getResult() == Result.FAILURE) { return STILL_FAILING; } else { return FAILURE; } } throw new IllegalArgumentException("Unknown result: '" + result + "' for build: " + run); } /** * Returns the previous 'not aborted' build (i.e. ignores ABORTED and NOT_BUILT builds) * or null. */ private static Run<?, ?> getPreviousNonAbortedBuild(Run<?, ?> build) { Run<?, ?> previousBuild = build.getPreviousBuild(); while (previousBuild != null) { if (previousBuild.getResult() == null || previousBuild.getResult() == Result.ABORTED || previousBuild.getResult() == Result.NOT_BUILT) { previousBuild = previousBuild.getPreviousBuild(); } else { return previousBuild; } } return previousBuild; } /** * Returns true if this build represents a 'fix'. * I.e. it is the first successful build after previous * 'failed' and/or 'unstable' builds. * Ignores 'aborted' and 'not built' builds. */ private static boolean isFix(Run<?, ?> build) { if (build.getResult() != Result.SUCCESS) { return false; } Run<?, ?> previousBuild = getPreviousNonAbortedBuild(build); if (previousBuild != null) { return previousBuild.getResult().isWorseThan(Result.SUCCESS); } return false; } }