package hudson.plugins.analysis.dashboard; import java.util.Collection; import java.util.List; import javax.annotation.CheckForNull; import org.apache.commons.lang.StringUtils; import com.google.common.collect.Lists; import hudson.model.Job; import hudson.plugins.analysis.core.ResultAction; import hudson.plugins.analysis.core.AbstractProjectAction; import hudson.plugins.analysis.core.BuildResult; /** * A portlet that shows a table with the number of warnings in the selected jobs. * * @author Ulli Hafner */ public abstract class AbstractWarningsTablePortlet extends AbstractPortlet { private static final String CLOSE_TAG = ">"; private static final String OPEN_TAG = "<"; /** Message to be shown if no result action is found. */ private static final String NO_RESULTS_FOUND = "-"; private final boolean canHideZeroWarningsProjects; /** * Creates a new instance of {@link AbstractWarningsTablePortlet}. * * @param name * the name of the portlet */ public AbstractWarningsTablePortlet(final String name) { this(name, false); } /** * Creates a new instance of {@link AbstractWarningsTablePortlet}. * * @param name * the name of the portlet * @param canHideZeroWarningsProjects * determines if zero warnings projects should be hidden in the * table */ public AbstractWarningsTablePortlet(final String name, final boolean canHideZeroWarningsProjects) { super(name); this.canHideZeroWarningsProjects = canHideZeroWarningsProjects; } /** * Returns whether zero warnings projects should be hidden in the table. * * @return <code>true</code> then only projects that contain warnings are * shown, <code>false</code> all projects are shown */ public boolean getCanHideZeroWarningsProjects() { return canHideZeroWarningsProjects; } /** * Returns all jobs that have warnings. * * @param jobs * all jobs * @return the jobs with warnings */ public Collection<Job<?, ?>> filterZeroWarningsJobs(final Collection<Job<?, ?>> jobs) { if (canHideZeroWarningsProjects) { return filter(jobs); } else { return jobs; } } /** * Filters the specified collection of jobs using overridable method * {@link #isVisibleJob(Job)}. * * @param jobs * the jobs to filter * @return the filtered jobs * @see #isVisibleJob(Job) filter predicate */ protected Collection<Job<?, ?>> filter(final Collection<Job<?, ?>> jobs) { List<Job<?, ?>> filtered = Lists.newArrayList(); for (Job<?, ?> job : jobs) { if (isVisibleJob(job)) { filtered.add(job); } } return filtered; } /** * Returns whether the specified job is visible. This default implementation * returns true if there is at least one warning for the job. * * @param job * the job to check * @return <code>true</code> if the job is visible, <code>false</code> * otherwise */ protected boolean isVisibleJob(final Job<?, ?> job) { return toInt(getWarnings(job)) > 0; } /** * Returns the name of the plug-in this portlet belongs to. * * @return the plug-in name * @deprecated is not used anymore, the URL is resolved from the actions */ @Deprecated protected String getPluginName() { return StringUtils.EMPTY; } /** * Returns the number of compiler warnings for the specified jobs. * * @param jobs * the jobs to get the warnings for * @return the number of compiler warnings */ public String getWarnings(final Collection<Job<?, ?>> jobs) { int sum = 0; for (Job<?, ?> job : jobs) { sum += toInt(getWarnings(job)); } return String.valueOf(sum); } /** * Returns the number of compiler warnings for the specified jobs. * * @param jobs * the jobs to get the warnings for * @param priority * the priority * @return the number of compiler warnings */ public String getWarnings(final Collection<Job<?, ?>> jobs, final String priority) { int sum = 0; for (Job<?, ?> job : jobs) { sum += toInt(getWarnings(job, priority)); } return String.valueOf(sum); } /** * Converts the string to an integer. If the string is not valid then 0 * is returned. * * @param value * the value to convert * @return the integer value or 0 */ protected int toInt(final String value) { try { if (value.contains(OPEN_TAG)) { return Integer.parseInt(StringUtils.substringBetween(value, CLOSE_TAG, OPEN_TAG)); } else { return Integer.parseInt(value); } } catch (NumberFormatException exception) { return 0; } } /** * Returns the total number of warnings for the specified job. * * @param job * the job to get the warnings for * @return the number of compiler warnings */ public String getWarnings(final Job<?, ?> job) { AbstractProjectAction<?> action = selectAction(job); if (action != null) { ResultAction<?> lastAction = action.getLastAction(); if (lastAction != null) { BuildResult result = lastAction.getResult(); int numberOfAnnotations = result.getNumberOfAnnotations(); String value; if (numberOfAnnotations > 0) { value = String.format("<a href=\"%s%s\">%d</a>", job.getShortUrl(), action.getUrlName(), numberOfAnnotations); } else { value = String.valueOf(numberOfAnnotations); } if (result.isSuccessfulTouched() && !result.isSuccessful()) { return value + result.getResultIcon(); } return value; } } return NO_RESULTS_FOUND; } /** * Returns the total number of warnings for the specified job. * * @param job * the job to get the warnings for * @param priority * the priority * @return the number of compiler warnings */ public String getWarnings(final Job<?, ?> job, final String priority) { AbstractProjectAction<?> action = selectAction(job); if (action != null) { ResultAction<?> lastAction = action.getLastAction(); if (lastAction != null) { BuildResult result = lastAction.getResult(); return String.valueOf(result.getNumberOfAnnotations(priority)); } } return NO_RESULTS_FOUND; } /** * Selects the action to show the results from. This default implementation * simply returns the first action that matches the given type. * * @param job * the job to get the action from * @return the action */ @CheckForNull protected AbstractProjectAction<?> selectAction(final Job<?, ?> job) { if (job == null) { return null; } else { return job.getAction(getAction()); } } }