package hudson.plugins.cigame.model; import hudson.maven.MavenBuild; import hudson.maven.MavenModule; import hudson.maven.MavenModuleSetBuild; import hudson.model.BuildListener; import hudson.model.AbstractBuild; import hudson.plugins.cigame.util.BuildUtil; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; /** * Score card containing the results of evaluating the rules against a build. * * */ @ExportedBean(defaultVisibility=999) public class ScoreCard { private List<Score> scores; /** * Record points for the rules in the rule set * * @param build build to evaluate * @param ruleset rule set to use for evaluation * @param listener */ public void record(AbstractBuild<?, ?> build, RuleSet ruleset, BuildListener listener) { List<Score> scoresForBuild = new LinkedList<Score>(); for (Rule rule : ruleset.getRules()) { if (null != rule){ if (listener != null) { listener.getLogger().append("[ci-game] evaluating rule: " + rule.getName() + "\n"); } RuleResult<?> result = evaluate(build, rule); if ((result != null) && (result.getPoints() != 0)) { Score score = new Score(ruleset.getName(), rule.getName(), result.getPoints(), result.getDescription()); scoresForBuild.add(score); if (listener != null) { listener.getLogger().append("[ci-game] scored: " + score.getValue() + "\n"); } } } else { if (listener != null) { listener.getLogger().append("[ci-game] null rule encountered\n"); } } } // prevent ConcurrentModificationExceptions for e.g. matrix builds (see JENKINS-11498): synchronized(this) { if (scores == null) { scores = new LinkedList<Score>(); } scores.addAll(scoresForBuild); Collections.sort(scores); } } @SuppressWarnings({ "unchecked", "rawtypes" }) RuleResult<?> evaluate(AbstractBuild<?, ?> build, Rule rule) { if (rule instanceof AggregatableRule<?> && build instanceof MavenModuleSetBuild) { AggregatableRule aRule = (AggregatableRule<?>)rule; MavenModuleSetBuild mavenModuleSetBuild = (MavenModuleSetBuild)build; List<RuleResult> results = new ArrayList<RuleResult>(); for (Map.Entry<MavenModule, MavenBuild> e : mavenModuleSetBuild.getModuleLastBuilds().entrySet()) { MavenBuild moduleBuild = e.getValue(); if (moduleBuild != null) { AbstractBuild<?, ?> previousBuild = BuildUtil.getPreviousBuiltBuild(moduleBuild); results.add(aRule.evaluate(previousBuild, moduleBuild)); } else { // module was probably removed from multimodule if (mavenModuleSetBuild.getPreviousBuild() != null) { MavenModuleSetBuild prevBuild = mavenModuleSetBuild.getPreviousBuild(); AbstractBuild<?, ?> prevModuleBuild = prevBuild.getModuleLastBuilds().get(e.getKey()); if (prevModuleBuild.getResult() == null) { prevModuleBuild = BuildUtil.getPreviousBuiltBuild(prevModuleBuild); } results.add(aRule.evaluate(prevModuleBuild, null)); } else { //results.add(aRule.evaluate(null, null)); return RuleResult.EMPTY_RESULT; } } } return aRule.aggregate(results); } else { if (rule instanceof AggregatableRule<?>) { AggregatableRule<?> aRule = (AggregatableRule<?>) rule; return aRule.evaluate(build.getPreviousBuild(), build); } else { return rule.evaluate(build); } } } /** * Record points for the rules in the rule book * * @param build build to evaluate * @param ruleBook rule book to use for evaluation * @param listener */ public void record(AbstractBuild<?, ?> build, RuleBook ruleBook, BuildListener listener) { if (scores == null) { scores = new LinkedList<Score>(); } for (RuleSet set : ruleBook.getRuleSets()) { record(build, set, listener); } } /** * Returns a collection of scores. May not be called before the score has * been recorded. * * @return a collection of scores. * @throws IllegalStateException thrown if the method is called before the scores has been recorded. */ @Exported public Collection<Score> getScores() throws IllegalStateException { if (scores == null) { throw new IllegalStateException("No scores are available"); //$NON-NLS-1$ } return scores; } /** * Returns the total points for this score card * * @return the total points for this score card * @throws IllegalStateException thrown if the method is called before scores has been calculated */ @Exported public double getTotalPoints() throws IllegalStateException { if (scores == null) { throw new IllegalStateException("No scores are available"); //$NON-NLS-1$ } double value = 0; for (Score score : scores) { value += score.getValue(); } return value; } }