package hudson.plugins.analysis.collector.dashboard; import hudson.Extension; import hudson.model.Descriptor; import hudson.model.Job; import hudson.plugins.analysis.collector.AnalysisDescriptor; import hudson.plugins.analysis.collector.AnalysisProjectAction; import hudson.plugins.analysis.collector.Messages; import hudson.plugins.analysis.core.BuildResult; import hudson.plugins.analysis.core.AbstractProjectAction; import hudson.plugins.analysis.dashboard.AbstractWarningsTablePortlet; import hudson.plugins.checkstyle.CheckStyleProjectAction; import hudson.plugins.dry.DryProjectAction; import hudson.plugins.findbugs.FindBugsProjectAction; import hudson.plugins.pmd.PmdProjectAction; import hudson.plugins.tasks.TasksProjectAction; import hudson.plugins.view.dashboard.DashboardPortlet; import hudson.plugins.warnings.WarningsProjectAction; import java.util.Collection; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; /** * A portlet that shows a table with the number of warnings in a job. * * @author Ulli Hafner */ public class WarningsTablePortlet extends AbstractWarningsTablePortlet { /** Message to be shown if no result action is found. */ private static final String NO_RESULTS_FOUND = "-"; /** Determines whether images should be used in the table header. */ private final boolean useImages; /** * Creates a new instance of {@link WarningsTablePortlet}. * * @param name * the name of the portlet * @param useImages * determines whether images should be used in the table header. */ @DataBoundConstructor public WarningsTablePortlet(final String name, final boolean useImages) { super(name); this.useImages = useImages; } /** {@inheritDoc} */ @Override protected Class<? extends AbstractProjectAction<?>> getAction() { return AnalysisProjectAction.class; } /** {@inheritDoc} */ @Override protected String getPluginName() { return "analysis"; } /** * Returns whether images should be used in the table header. * * @return <code>true</code> if images should be used, <code>false</code> if * text shuld be used */ public boolean getUseImages() { return useImages; } /** * Returns whether icons should be used in the table header. * * @return <code>true</code> if icons should be used, <code>false</code> if * text shuld be used */ public boolean useIcons() { return useImages; } /** * Returns whether the Checkstyle plug-in is installed. * * @return <code>true</code> if the Checkstyle plug-in is installed, * <code>false</code> if not. */ public boolean isCheckStyleInstalled() { return AnalysisDescriptor.isCheckStyleInstalled(); } /** * Returns whether the Dry plug-in is installed. * * @return <code>true</code> if the Dry plug-in is installed, * <code>false</code> if not. */ public boolean isDryInstalled() { return AnalysisDescriptor.isDryInstalled(); } /** * Returns whether the FindBugs plug-in is installed. * * @return <code>true</code> if the FindBugs plug-in is installed, * <code>false</code> if not. */ public boolean isFindBugsInstalled() { return AnalysisDescriptor.isFindBugsInstalled(); } /** * Returns whether the PMD plug-in is installed. * * @return <code>true</code> if the PMD plug-in is installed, * <code>false</code> if not. */ public boolean isPmdInstalled() { return AnalysisDescriptor.isPmdInstalled(); } /** * Returns whether the Open Tasks plug-in is installed. * * @return <code>true</code> if the Open Tasks plug-in is installed, * <code>false</code> if not. */ public boolean isTasksInstalled() { return AnalysisDescriptor.isOpenTasksInstalled(); } /** * Returns whether the Warnings plug-in is installed. * * @return <code>true</code> if the Warnings plug-in is installed, * <code>false</code> if not. */ public boolean isWarningsInstalled() { return AnalysisDescriptor.isWarningsInstalled(); } /** * Returns the number of Checkstyle warnings for the specified job. * * @param job * the job to get the warnings for * @return the number of Checkstyle warnings */ public String getCheckStyle(final Job<?, ?> job) { if (AnalysisDescriptor.isCheckStyleInstalled()) { return getWarnings(job, CheckStyleProjectAction.class, "checkstyle"); } return NO_RESULTS_FOUND; } /** * Returns the number of duplicate code warnings for the specified job. * * @param job * the job to get the warnings for * @return the number of duplicate code warnings */ public String getDry(final Job<?, ?> job) { if (AnalysisDescriptor.isDryInstalled()) { return getWarnings(job, DryProjectAction.class, "dry"); } return NO_RESULTS_FOUND; } /** * Returns the number of FindBugs warnings for the specified job. * * @param job * the job to get the warnings for * @return the number of FindBugs warnings */ public String getFindBugs(final Job<?, ?> job) { if (AnalysisDescriptor.isFindBugsInstalled()) { return getWarnings(job, FindBugsProjectAction.class, "findbugs"); } return NO_RESULTS_FOUND; } /** * Returns the number of PMD warnings for the specified job. * * @param job * the job to get the warnings for * @return the number of PMD warnings */ public String getPmd(final Job<?, ?> job) { if (AnalysisDescriptor.isPmdInstalled()) { return getWarnings(job, PmdProjectAction.class, "pmd"); } return NO_RESULTS_FOUND; } /** * Returns the number of open tasks for the specified job. * * @param job * the job to get the tasks for * @return the number of open tasks */ public String getTasks(final Job<?, ?> job) { if (AnalysisDescriptor.isOpenTasksInstalled()) { return getWarnings(job, TasksProjectAction.class, "tasks"); } return NO_RESULTS_FOUND; } /** * 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 */ @Override public String getWarnings(final Job<?, ?> job) { if (AnalysisDescriptor.isWarningsInstalled()) { return getWarnings(job, WarningsProjectAction.class, "warnings"); } return NO_RESULTS_FOUND; } /** * Returns the number of warnings for the specified job. * * @param job * the job to get the warnings for * @return the number of warnings */ public String getTotal(final Job<?, ?> job) { return String.valueOf( toInt(getCheckStyle(job)) + toInt(getDry(job)) + toInt(getFindBugs(job)) + toInt(getPmd(job)) + toInt(getTasks(job)) + toInt(getWarnings(job))); } /** * Returns the number of Checkstyle warnings for the specified jobs. * * @param jobs * the jobs to get the warnings for * @return the number of Checkstyle warnings */ public String getCheckStyle(final Collection<Job<?, ?>> jobs) { int sum = 0; for (Job<?, ?> job : jobs) { sum += toInt(getCheckStyle(job)); } return String.valueOf(sum); } /** * Returns the number of Dry warnings for the specified jobs. * * @param jobs * the jobs to get the warnings for * @return the number of Dry warnings */ public String getDry(final Collection<Job<?, ?>> jobs) { int sum = 0; for (Job<?, ?> job : jobs) { sum += toInt(getDry(job)); } return String.valueOf(sum); } /** * Returns the number of FindBugs warnings for the specified jobs. * * @param jobs * the jobs to get the warnings for * @return the number of FindBugs warnings */ public String getFindBugs(final Collection<Job<?, ?>> jobs) { int sum = 0; for (Job<?, ?> job : jobs) { sum += toInt(getFindBugs(job)); } return String.valueOf(sum); } /** * Returns the number of PMD warnings for the specified jobs. * * @param jobs * the jobs to get the warnings for * @return the number of PMD warnings */ public String getPmd(final Collection<Job<?, ?>> jobs) { int sum = 0; for (Job<?, ?> job : jobs) { sum += toInt(getPmd(job)); } return String.valueOf(sum); } /** * Returns the number of open tasks for the specified jobs. * * @param jobs * the jobs to get the warnings for * @return the number of open tasks warnings */ public String getTasks(final Collection<Job<?, ?>> jobs) { int sum = 0; for (Job<?, ?> job : jobs) { sum += toInt(getTasks(job)); } return String.valueOf(sum); } /** * 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 */ @Override public String getWarnings(final Collection<Job<?, ?>> jobs) { int sum = 0; for (Job<?, ?> job : jobs) { sum += toInt(getWarnings(job)); } return String.valueOf(sum); } /** * Returns the total number of warnings for all jobs. * * @param jobs * the jobs to get the warnings for * @return the total number of warnings */ public String getTotal(final Collection<Job<?, ?>> jobs) { int sum = 0; for (Job<?, ?> job : jobs) { sum += Integer.parseInt(getTotal(job)); } 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 */ private int toInt(final String value) { try { return Integer.parseInt(StringUtils.substringBetween(value, ">", "<")); } catch (NumberFormatException exception) { return 0; } } /** * Returns the warnings for the specified action. * * @param job * the job to get the action from * @param actionType * the type of the action * @param plugin * the plug-in that is target of the link * @return the number of warnings */ private String getWarnings(final Job<?, ?> job, final Class<? extends AbstractProjectAction<?>> actionType, final String plugin) { AbstractProjectAction<?> action = job.getAction(actionType); if (action != null && action.hasValidResults()) { BuildResult result = action.getLastAction().getResult(); int numberOfAnnotations = result.getNumberOfAnnotations(); String value; if (numberOfAnnotations > 0) { value = String.format("<a href=\"%s%s\">%d</a>", job.getShortUrl(), plugin, numberOfAnnotations); } else { value = String.valueOf(numberOfAnnotations); } if (result.isSuccessfulTouched() && !result.isSuccessful()) { return value + result.getResultIcon(); } return value; } return NO_RESULTS_FOUND; } /** * Extension point registration. * * @author Ulli Hafner */ @Extension(optional = true) public static class WarningsPerJobDescriptor extends Descriptor<DashboardPortlet> { @Override public String getDisplayName() { return Messages.Portlet_WarningsTable(); } } }