16 | * For example, one can define a rule where "line coverage must be better than 50%
17 | * for any class", and if this rule is violated, the build will be marked as
18 | * unstable.
19 | *
20 | *
21 | * The rule instances are persisted as a part of {@link Build}, so make sure
22 | * to make your class serializable. This is so that we can consistently mark
23 | * coverage results even if the job configuration changes.
24 | *
25 | * @author Kohsuke Kawaguchi
26 | */
27 | public abstract class Rule implements Serializable, ExtensionPoint {
28 | public abstract void enforce(CoverageReport report, TaskListener listener);
29 |
30 | private static final long serialVersionUID = 1L;
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/model/Coverage.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.model;
2 |
3 | import java.io.Serializable;
4 |
5 | import org.kohsuke.stapler.export.Exported;
6 | import org.kohsuke.stapler.export.ExportedBean;
7 |
8 | /**
9 | * Represents {@code x/y} where x={@link #missed} and y={@link #covered}.
10 | *
11 | * @author Kohsuke Kawaguchi
12 | * @author Jonathan Fuerth
13 | */
14 | @ExportedBean
15 | final public class Coverage implements Serializable {
16 |
17 | private int missed = 0;
18 | private int covered = 0;
19 | private CoverageElement.Type type;
20 | boolean initialized = false;
21 |
22 | public Coverage(int missed, int covered) {
23 | this.missed = missed;
24 | this.covered = covered;
25 | this.initialized = true;
26 | }
27 |
28 | public Coverage() {
29 | }
30 |
31 | @Exported
32 | public int getMissed() {
33 | return missed;
34 | }
35 |
36 | @Exported
37 | public int getCovered() {
38 | return covered;
39 | }
40 |
41 | @Exported
42 | public int getTotal() {
43 | return missed + covered;
44 | }
45 |
46 | /**
47 | * Gets "missed/covered (%)" representation.
48 | */
49 | @Override
50 | public String toString() {
51 | return missed + "/" + covered;
52 | }
53 |
54 | /**
55 | * Gets the percentage as an integer between 0 and 100.
56 | * @return the coverage percentage as a rounded integer between 0 and 100.
57 | * @see #getPercentageFloat()
58 | */
59 | @Exported
60 | public int getPercentage() {
61 | return Math.round(getPercentageFloat());
62 | }
63 |
64 | /**
65 | * Gets the percentage as a float between 0f and 100f.
66 | * @return the coverage percentage as a float between 0f and 100f.
67 | * returns 100f if no coverage data was recorded at all, i.e. covered and missed are zero
68 | * @see #getPercentage()
69 | */
70 | @Exported
71 | public float getPercentageFloat() {
72 | float numerator = covered;
73 | float denominator = missed + covered;
74 |
75 | // there are two cases that we cannot distinguish easily
76 | // a) covered and missing are zero because no code was covered
77 | // b) covered and missing are zero because there is no code to cover in this class, e.g. interfaces
78 |
79 | // we use b) here for now, see JENKINS-56123 for more discussion on this
80 | return denominator <= 0 ? 100 : 100 * (numerator / denominator);
81 | }
82 |
83 | public CoverageElement.Type getType() {
84 | return type;
85 | }
86 |
87 | public void setType(CoverageElement.Type type) {
88 | this.type = type;
89 | }
90 |
91 | @Override
92 | public boolean equals(Object o) {
93 | if (this == o) return true;
94 | if (o == null || getClass() != o.getClass()) return false;
95 |
96 | Coverage ratio = (Coverage) o;
97 |
98 | return ratio.covered == covered
99 | && ratio.missed == missed;
100 |
101 | }
102 |
103 | @Override
104 | public int hashCode() {
105 | int result;
106 | result = missed;
107 | result = 31 * result + covered;
108 | return result;
109 | }
110 |
111 | /**
112 | * Adds the given missed and covered values to the ones already
113 | * contained in this ratio.
114 | *
115 | * @param missed The amount to add to the missed.
116 | * @param covered The amount to add to the covered.
117 | */
118 | public void accumulate(int missed, int covered) {
119 | this.missed = missed;
120 | this.covered = covered;
121 | initialized = true;
122 | }
123 | public void accumulatePP(int missed, int covered) {
124 | this.missed += missed;
125 | this.covered += covered;
126 | initialized = true;
127 | }
128 |
129 | public boolean isInitialized() {
130 | return initialized;
131 | }
132 |
133 | private static final long serialVersionUID = 1L;
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/model/CoverageElement.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.model;
2 |
3 | import java.io.IOException;
4 |
5 | import hudson.plugins.jacoco.report.AbstractReport;
6 |
7 | /**
8 | * This is a transitive object used during the parsing, but not a part of
9 | * the final tree built.
10 | *
11 | * @author Kohsuke Kawaguchi
12 | */
13 | public final class CoverageElement {
14 |
15 | /**
16 | * Enumeration of coverage types that appear in a JaCoCo report.
17 | *
18 | * @author Jonathan Fuerth <jfuerth@gmail.com>
19 | */
20 | public enum Type {
21 | INSTRUCTION {
22 | @Override
23 | public Coverage getAssociatedRatio(AbstractReport, ?> from) {
24 | return from.instruction;
25 | }
26 | },
27 | BRANCH {
28 | @Override
29 | public Coverage getAssociatedRatio(AbstractReport, ?> from) {
30 | return from.branch;
31 | }
32 | },
33 | LINE {
34 | @Override
35 | public Coverage getAssociatedRatio(AbstractReport, ?> from) {
36 | return from.line;
37 | }
38 | },
39 | COMPLEXITY {
40 | @Override
41 | public Coverage getAssociatedRatio(AbstractReport, ?> from) {
42 | return from.complexity;
43 | }
44 | },
45 | METHOD {
46 | @Override
47 | public Coverage getAssociatedRatio(AbstractReport, ?> from) {
48 | return from.method;
49 | }
50 | },
51 | CLASS {
52 | @Override
53 | public Coverage getAssociatedRatio(AbstractReport, ?> from) {
54 | return from.clazz;
55 | }
56 | };
57 |
58 | /**
59 | * Returns the ratio object on the given report that tracks this type of coverage.
60 | *
61 | * @param from The report to return the appropriate Coverage object from. Not null.
62 | * @return the ratio object on the given report that tracks this type of coverage.
63 | */
64 | public abstract Coverage getAssociatedRatio(AbstractReport,?> from);
65 | }
66 |
67 | private Type type;
68 | private int missed;
69 | private int covered;
70 |
71 | /**
72 | * Returns the enum constant that says what type of coverage this bean
73 | * represents.
74 | *
75 | * Warning: don't call this method getType() because that confuses the
76 | * Digester.
77 | * @return the enum constant that says what type of coverage this bean represents.
78 | */
79 | public Type getTypeAsEnum() {
80 | return type;
81 | }
82 |
83 | // set by attributes
84 | public void setType(String type) {
85 | this.type = Type.valueOf(type);
86 | }
87 |
88 | // set by attributes
89 | public void setMissed(int missed) {
90 | this.missed = missed;
91 | }
92 |
93 | // set by attributes
94 | public void setCovered(int covered) {
95 | this.covered = covered;
96 | }
97 |
98 | public void addTo(AbstractReport,?> report) throws IOException {
99 | type.getAssociatedRatio(report).accumulate(missed, covered);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/model/ModuleInfo.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.model;
2 |
3 | import hudson.FilePath;
4 |
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.IOException;
8 |
9 | import org.jacoco.core.analysis.Analyzer;
10 | import org.jacoco.core.analysis.CoverageBuilder;
11 | import org.jacoco.core.analysis.IBundleCoverage;
12 | import org.jacoco.core.data.ExecutionDataReader;
13 | import org.jacoco.core.data.ExecutionDataStore;
14 | import org.jacoco.core.data.SessionInfoStore;
15 |
16 | @Deprecated
17 | public class ModuleInfo {
18 |
19 | private String name;
20 | private FilePath srcDir;
21 | private FilePath classDir;
22 | private FilePath execFile;
23 | private FilePath generatedHTMLsDir;
24 | //private String title;
25 |
26 | private ExecutionDataStore executionDataStore;
27 | private SessionInfoStore sessionInfoStore;
28 |
29 | private IBundleCoverage bundleCoverage;
30 |
31 | public IBundleCoverage getBundleCoverage() {
32 | return bundleCoverage;
33 | }
34 | public String getName() {
35 | return name;
36 | }
37 | public void setName(String name) {
38 | this.name = name;
39 | }
40 | public void setBundleCoverage(IBundleCoverage bundleCoverage) {
41 | this.bundleCoverage = bundleCoverage;
42 | }
43 | public FilePath getGeneratedHTMLsDir() {
44 | return generatedHTMLsDir;
45 | }
46 | public void setGeneratedHTMLsDir(FilePath generatedHTMLsDir) {
47 | this.generatedHTMLsDir = generatedHTMLsDir;
48 | }
49 | public FilePath getSrcDir() {
50 | return srcDir;
51 | }
52 | public void setSrcDir(FilePath srcDir) {
53 | this.srcDir = srcDir;
54 | }
55 | public FilePath getClassDir() {
56 | return classDir;
57 | }
58 | public void setClassDir(FilePath classDir) {
59 | this.classDir = classDir;
60 | }
61 | public FilePath getExecFile() {
62 | return execFile;
63 | }
64 | public void setExecFile(FilePath execFile) {
65 | this.execFile = execFile;
66 | }
67 | private void loadExecutionData() throws IOException {
68 | File executionDataFile = new File(execFile.getRemote());
69 | final FileInputStream fis = new FileInputStream(executionDataFile);
70 | final ExecutionDataReader executionDataReader = new ExecutionDataReader(
71 | fis);
72 | executionDataStore = new ExecutionDataStore();
73 | sessionInfoStore = new SessionInfoStore();
74 |
75 | executionDataReader.setExecutionDataVisitor(executionDataStore);
76 | executionDataReader.setSessionInfoVisitor(sessionInfoStore);
77 |
78 | while (executionDataReader.read()) {
79 | }
80 |
81 | fis.close();
82 | }
83 | private IBundleCoverage analyzeStructure() throws IOException {
84 | File classDirectory = new File(classDir.getRemote());
85 | final CoverageBuilder coverageBuilder = new CoverageBuilder();
86 | final Analyzer analyzer = new Analyzer(executionDataStore,
87 | coverageBuilder);
88 |
89 | analyzer.analyzeAll(classDirectory);
90 |
91 | return coverageBuilder.getBundle(name);
92 | }
93 | public IBundleCoverage loadBundleCoverage() throws IOException {
94 | loadExecutionData();
95 | this.bundleCoverage = analyzeStructure();
96 | return this.bundleCoverage;
97 | }
98 | }
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/portlet/bean/JacocoDeltaCoverageResultSummary.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.portlet.bean;
2 |
3 | import hudson.model.Job;
4 | import hudson.model.Run;
5 | import hudson.plugins.jacoco.portlet.JacocoLoadData;
6 |
7 | /**
8 | * This class encapsulates actual delta coverage of current build.
9 | * It calculates absolute difference between coverage of last successful build and current build
10 | */
11 | public class JacocoDeltaCoverageResultSummary {
12 |
13 | /**
14 | * Variables to capture delta coverage of current build
15 | */
16 | private float instructionCoverage;
17 |
18 | private float branchCoverage;
19 |
20 | private float complexityCoverage;
21 |
22 | private float lineCoverage;
23 |
24 | private float methodCoverage;
25 |
26 | private float classCoverage;
27 |
28 | public JacocoDeltaCoverageResultSummary() {
29 | }
30 |
31 | // Used to extract coverage result of current and last successful build and encapsulate delta coverage values
32 | public static JacocoDeltaCoverageResultSummary build(Run,?> run){
33 | Run,?> lastSuccessfulBuild = run.getParent().getLastSuccessfulBuild();
34 | JacocoCoverageResultSummary lastBuildCoverage = lastSuccessfulBuild!=null ? JacocoLoadData.getResult(lastSuccessfulBuild):new JacocoCoverageResultSummary();
35 | JacocoCoverageResultSummary currentBuildCoverage = JacocoLoadData.getResult(run);
36 |
37 | JacocoDeltaCoverageResultSummary jacocoDeltaCoverageResultSummary = new JacocoDeltaCoverageResultSummary();
38 | jacocoDeltaCoverageResultSummary.instructionCoverage = currentBuildCoverage.getInstructionCoverage() - lastBuildCoverage.getInstructionCoverage();
39 | jacocoDeltaCoverageResultSummary.branchCoverage = currentBuildCoverage.getBranchCoverage() - lastBuildCoverage.getBranchCoverage();
40 | jacocoDeltaCoverageResultSummary.complexityCoverage = currentBuildCoverage.getComplexityScore() - lastBuildCoverage.getComplexityScore();
41 | jacocoDeltaCoverageResultSummary.lineCoverage = currentBuildCoverage.getLineCoverage() - lastBuildCoverage.getLineCoverage();
42 | jacocoDeltaCoverageResultSummary.methodCoverage = currentBuildCoverage.getMethodCoverage() - lastBuildCoverage.getMethodCoverage();
43 | jacocoDeltaCoverageResultSummary.classCoverage = currentBuildCoverage.getClassCoverage() - lastBuildCoverage.getClassCoverage();
44 |
45 | return jacocoDeltaCoverageResultSummary;
46 | }
47 |
48 | public float getInstructionCoverage() {
49 | return instructionCoverage;
50 | }
51 |
52 | public float getBranchCoverage() {
53 | return branchCoverage;
54 | }
55 |
56 | public float getComplexityCoverage() {
57 | return complexityCoverage;
58 | }
59 |
60 | public float getLineCoverage() {
61 | return lineCoverage;
62 | }
63 |
64 | public float getMethodCoverage() {
65 | return methodCoverage;
66 | }
67 |
68 | public float getClassCoverage() {
69 | return classCoverage;
70 | }
71 |
72 | public void setInstructionCoverage(float instructionCoverage) {
73 | this.instructionCoverage = instructionCoverage;
74 | }
75 |
76 | public void setBranchCoverage(float branchCoverage) {
77 | this.branchCoverage = branchCoverage;
78 | }
79 |
80 | public void setComplexityCoverage(float complexityCoverage) {
81 | this.complexityCoverage = complexityCoverage;
82 | }
83 |
84 | public void setLineCoverage(float lineCoverage) {
85 | this.lineCoverage = lineCoverage;
86 | }
87 |
88 | public void setMethodCoverage(float methodCoverage) {
89 | this.methodCoverage = methodCoverage;
90 | }
91 |
92 | public void setClassCoverage(float classCoverage) {
93 | this.classCoverage = classCoverage;
94 | }
95 |
96 | @Override
97 | public String toString() {
98 | return "JacocoDeltaCoverageResultSummary [" +
99 | "instructionCoverage=" + instructionCoverage +
100 | ", branchCoverage=" + branchCoverage +
101 | ", complexityCoverage=" + complexityCoverage +
102 | ", lineCoverage=" + lineCoverage +
103 | ", methodCoverage=" + methodCoverage +
104 | ", classCoverage=" + classCoverage +
105 | ']';
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/portlet/grid/JacocoBuilderGrid.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2010 Sony Ericsson Mobile Communications. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | /*
26 | * @author Allyn Pierre (Allyn.GreyDeAlmeidaLimaPierre@sonyericsson.com)
27 | * @author Eduardo Palazzo (Eduardo.Palazzo@sonyericsson.com)
28 | * @author Mauro Durante (Mauro.DuranteJunior@sonyericsson.com)
29 | */
30 | package hudson.plugins.jacoco.portlet.grid;
31 |
32 | import java.util.Collection;
33 |
34 | import org.kohsuke.stapler.DataBoundConstructor;
35 |
36 | import hudson.Extension;
37 | import hudson.model.Descriptor;
38 | import hudson.model.Job;
39 | import hudson.plugins.jacoco.portlet.JacocoLoadData;
40 | import hudson.plugins.jacoco.portlet.Messages;
41 | import hudson.plugins.jacoco.portlet.bean.JacocoCoverageResultSummary;
42 | import hudson.plugins.view.dashboard.DashboardPortlet;
43 |
44 | /**
45 | * A portlet for JaCoCo Coverage results - Grid data.
46 | *
47 | * See http://wiki.hudson-ci.org/display/HUDSON/Dashboard+View
48 | */
49 | public class JacocoBuilderGrid extends DashboardPortlet {
50 |
51 | /**
52 | * Constructor with grid name as parameter. DataBoundConstructor
53 | * annotation helps the Stapler class to find which constructor that
54 | * should be used when automatically copying values from a web form
55 | * to a class.
56 | *
57 | * @param name
58 | * grid name
59 | */
60 | @DataBoundConstructor
61 | public JacocoBuilderGrid(String name) {
62 | super(name);
63 | }
64 |
65 | /**
66 | * This method will be called by portlet.jelly to load data and
67 | * create the grid.
68 | *
69 | * @param jobs
70 | * a Collection of Job objects
71 | * @return JacocoCoverageResultSummary a coverage result summary
72 | */
73 | public JacocoCoverageResultSummary getJaCoCoCoverageResultSummary(Collection> jobs) {
74 | return JacocoLoadData.getResultSummary(jobs);
75 | }
76 |
77 | /**
78 | * Descriptor that will be shown on Dashboard Portlets view.
79 | */
80 | @Extension(optional = true)
81 | public static class JacocoGridDescriptor extends Descriptor {
82 |
83 | @Override
84 | public String getDisplayName() {
85 | return Messages.gridTitle();
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/portlet/utils/Constants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2010 Sony Ericsson Mobile Communications. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | /*
26 | * @author Allyn Pierre (Allyn.GreyDeAlmeidaLimaPierre@sonyericsson.com)
27 | * @author Eduardo Palazzo (Eduardo.Palazzo@sonyericsson.com)
28 | * @author Mauro Durante (Mauro.DuranteJunior@sonyericsson.com)
29 | */
30 | package hudson.plugins.jacoco.portlet.utils;
31 |
32 | /**
33 | * Defines the variables with pre-defined values.
34 | */
35 | public final class Constants {
36 | /**
37 | * Private constructor: class contains only static methods.
38 | */
39 | private Constants() {
40 | }
41 |
42 | /**
43 | * Default width of the Graph.
44 | */
45 | public static final int DEFAULT_WIDTH = 500;
46 |
47 | /**
48 | * Default height of the Graph.
49 | */
50 | public static final int DEFAULT_HEIGHT = 250;
51 |
52 | /**
53 | * Default number of days of the Graph.
54 | */
55 | public static final int DEFAULT_DAYS_NUMBER = 30;
56 |
57 | /**
58 | * The default foreground alpha transparency.
59 | */
60 | public static final float FOREGROUND_ALPHA = 0.8f;
61 |
62 | /**
63 | * The chart axis label.
64 | */
65 | public static final String AXIS_LABEL = "Days";
66 |
67 | /**
68 | * The chart axis label value.
69 | */
70 | public static final String AXIS_LABEL_VALUE = "Coverage(%)";
71 |
72 | /**
73 | * The chart upper bound value.
74 | */
75 | public static final int UPPER_BOUND = 100;
76 |
77 | /**
78 | * The chart lower bound value.
79 | */
80 | public static final int LOWER_BOUND = 0;
81 |
82 | /**
83 | * The chart line thickness value.
84 | */
85 | public static final float LINE_THICKNESS = 3.5f;
86 |
87 | /**
88 | * The chart default margin value.
89 | */
90 | public static final double DEFAULT_MARGIN = 0.0;
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/portlet/utils/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | *
4 | * Copyright 2010 Sony Ericsson Mobile Communications. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | /*
26 | * @author Allyn Pierre (Allyn.GreyDeAlmeidaLimaPierre@sonyericsson.com)
27 | * @author Eduardo Palazzo (Eduardo.Palazzo@sonyericsson.com)
28 | * @author Mauro Durante (Mauro.DuranteJunior@sonyericsson.com)
29 | */
30 | package hudson.plugins.jacoco.portlet.utils;
31 |
32 | import java.math.BigDecimal;
33 | import java.math.RoundingMode;
34 | import java.util.Calendar;
35 | import java.util.List;
36 |
37 | import hudson.model.Job;
38 | import hudson.model.Result;
39 | import hudson.model.Run;
40 |
41 | /**
42 | * Defines common methods that are used for the whole project.
43 | */
44 | public final class Utils {
45 |
46 | /**
47 | * Private constructor: class contains only static methods.
48 | */
49 | private Utils() {
50 | }
51 |
52 | /**
53 | * Validate chart attributes returning a valid value to the object.
54 | *
55 | * @param attribute
56 | * the attribute: width, height, number of days
57 | * @param defaultValue
58 | * default value for the attribute
59 | * @return int attribute valid value
60 | */
61 | public static int validateChartAttributes(String attribute, int defaultValue) {
62 |
63 | // If user fills the attributes with negative, empty or not number
64 | // values, Hudson will not show an invalid message, it will assume
65 | // default values
66 |
67 | if (attribute != null) {
68 | if (attribute.equals("") || attribute.equals("0")) {
69 | return defaultValue;
70 | }
71 |
72 | // Check if attribute value is a number
73 | try {
74 | int validAttributeValue = Integer.parseInt(attribute);
75 | // Attribute value is a number - check if it is negative
76 | if (validAttributeValue < 0) {
77 | return defaultValue;
78 | }
79 | return validAttributeValue;
80 | } catch (NumberFormatException e) {
81 | return defaultValue;
82 | }
83 | }
84 |
85 | return defaultValue;
86 | }
87 |
88 | /**
89 | * For the given list of jobs, this will search all jobs and return
90 | * the last run date of all.
91 | *
92 | * @param jobs
93 | * a list of jobs from the DashBoard Portlet view
94 | * @return LocalDate the last date of all jobs that belongs to
95 | * Dashboard View.
96 | */
97 | public static Calendar getLastDate(List> jobs) {
98 | Calendar lastDate = null;
99 | for (Job,?> job : jobs) {
100 | Run,?> lastRun = job.getLastCompletedBuild();
101 | if (lastRun != null) {
102 | Calendar date = lastRun.getTimestamp();
103 | if (lastDate == null) {
104 | lastDate = date;
105 | }
106 | if (date.after(lastDate)) {
107 | lastDate = date;
108 | }
109 | }
110 | }
111 | return lastDate;
112 | }
113 |
114 | /**
115 | * Method for rounding float values according to the requested mode.
116 | *
117 | * @param scale
118 | * the rounding scale
119 | * @param roundingMode
120 | * the rounding direction @see java.math.RoundingMode
121 | * @param value
122 | * the value to be rounded
123 | * @return the rounded value
124 | */
125 | public static float roundFloat(int scale, RoundingMode roundingMode, float value) {
126 | BigDecimal bigDecimal = new BigDecimal(value);
127 | bigDecimal = bigDecimal.setScale(scale, roundingMode);
128 | return bigDecimal.floatValue();
129 | }
130 |
131 |
132 | public static int nthOccurrence(String str, char c, int n) {
133 | int pos = str.indexOf(c, 0);
134 | while (n-- > 0 && pos != -1)
135 | pos = str.indexOf(c, pos+1);
136 | return pos;
137 | }
138 |
139 | /** Logical AND operation of Jenkins build results:
140 | * Success AND Success = Success
141 | * Unstable AND Unstable = Unstable
142 | * Failure AND Failure = Failure
143 | * X AND Failure = Failure, Failure AND X = Failure, X = Success/Unstable/Failure
144 | * Y AND Unstable = Unstable, Unstable AND Y = Unstable, Y = Success/Unstable
145 | * @param op1 first result
146 | * @param op2 second result
147 | * @return Logical AND operation of {@code op1 AND op2}
148 | */
149 | public static Result applyLogicalAnd(Result op1, Result op2){
150 |
151 | if(op1.toString().equals("FAILURE") || op2.toString().equals("FAILURE"))
152 | return Result.FAILURE;
153 |
154 | if(op1.toString().equals("UNSTABLE") || op2.toString().equals("UNSTABLE"))
155 | return Result.UNSTABLE;
156 |
157 | if(op1.toString().equals("SUCCESS") && op2.toString().equals("SUCCESS"))
158 | return Result.SUCCESS;
159 |
160 | return Result.FAILURE;
161 |
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/report/AbstractReport.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.report;
2 |
3 | import hudson.model.ModelObject;
4 | import hudson.model.Run;
5 | import hudson.plugins.jacoco.model.CoverageElement;
6 | import hudson.plugins.jacoco.model.CoverageObject;
7 |
8 | import java.io.IOException;
9 |
10 | /**
11 | * Base class of the coverage report tree,
12 | * which maintains the details of the coverage report.
13 | *
14 | * @author Kohsuke Kawaguchi
15 | * @param Parent type
16 | * @param Self type
17 | */
18 | public abstract class AbstractReport,
19 | SELF extends CoverageObject> extends CoverageObject implements ModelObject {
20 |
21 | private String name;
22 |
23 | private PARENT parent;
24 |
25 | public void addCoverage(CoverageElement cv) throws IOException {
26 | cv.addTo(this);
27 | }
28 |
29 | public String getName() {
30 | return name;
31 | }
32 |
33 | public void setName(String name) {
34 | this.name = sanitizeName(name);
35 | }
36 |
37 | protected static String sanitizeName(String name) {
38 | // sanitize names contained in .class files
39 | return name
40 | .replace(':', '_')
41 | .replace(';', '_')
42 | .replace('&', '_')
43 | .replace('%', '_')
44 | .replace('<', '_')
45 | .replace('>', '_');
46 | }
47 |
48 | public String getDisplayName() {
49 | return getName();
50 | }
51 |
52 | /**
53 | * Called at the last stage of the tree construction,
54 | * to set the back pointer.
55 | * @param p parent
56 | */
57 | protected void setParent(PARENT p) {
58 | this.parent = p;
59 | }
60 |
61 | /**
62 | * Gets the back pointer to the parent coverage object.
63 | */
64 | @Override
65 | public PARENT getParent() {
66 | return parent;
67 | }
68 |
69 | @Override
70 | public SELF getPreviousResult() {
71 | PARENT p = parent;
72 | while(true) {
73 | p = p.getPreviousResult();
74 | if(p==null)
75 | return null;
76 | SELF prev = (SELF)p.getChildren().get(name);
77 | if(prev!=null)
78 | return prev;
79 | }
80 | }
81 |
82 | @Override
83 | public Run,?> getBuild() {
84 | return parent.getBuild();
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/report/AggregatedReport.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.report;
2 |
3 | import org.kohsuke.stapler.StaplerRequest;
4 | import org.kohsuke.stapler.StaplerResponse;
5 |
6 | import java.io.IOException;
7 | import java.util.Map;
8 | import java.util.TreeMap;
9 |
10 | /**
11 | * Reports that have children.
12 | *
13 | * @author Kohsuke Kawaguchi
14 | * @param Parent type
15 | * @param Self type
16 | * @param Child type
17 | */
18 | public abstract class AggregatedReport,
19 | SELF extends AggregatedReport,
20 | CHILD extends AbstractReport> extends AbstractReport {
21 |
22 | private final Map children = new TreeMap<>();
23 |
24 | public void add(CHILD child) {
25 | children.put(child.getName(),child);
26 | }
27 |
28 | public Map getChildren() {
29 | return children;
30 | }
31 |
32 | @Override
33 | protected void setParent(PARENT p) {
34 | super.setParent(p);
35 | for (CHILD c : children.values())
36 | c.setParent((SELF)this);
37 | }
38 |
39 | public CHILD getDynamic(String token, StaplerRequest req, StaplerResponse rsp ) throws IOException {
40 | return getChildren().get(token);
41 | }
42 |
43 | @Override
44 | public void setFailed() {
45 | super.setFailed();
46 |
47 | if (getParent() != null)
48 | getParent().setFailed();
49 | }
50 |
51 | public boolean hasChildren() {
52 | return getChildren().size() > 0;
53 | }
54 |
55 | public boolean hasChildrenLineCoverage() {
56 | for (CHILD child : getChildren().values()){
57 | if (child.hasLineCoverage()) {
58 | return true;
59 | }
60 | }
61 | return false;
62 | }
63 |
64 | public boolean hasChildrenClassCoverage() {
65 | for (CHILD child : getChildren().values()){
66 | if (child.hasClassCoverage()) {
67 | return true;
68 | }
69 | }
70 | return false;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/report/ClassReport.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.report;
2 |
3 | import java.io.File;
4 | import java.io.Writer;
5 |
6 | import org.jacoco.core.analysis.IClassCoverage;
7 |
8 | /**
9 | * @author Kohsuke Kawaguchi
10 | */
11 | public final class ClassReport extends AggregatedReport {
12 |
13 | private String sourceFilePath;
14 | private IClassCoverage classCov;
15 |
16 | @Override
17 | public void setName(String name) {
18 | super.setName(name.replace('/', '.'));
19 | //logger.log(Level.INFO, "ClassReport");
20 | }
21 |
22 | @Override
23 | public void add(MethodReport child) {
24 | String newChildName = child.getName();
25 | child.setName(newChildName);
26 | getChildren().put(child.getName(), child);
27 | }
28 |
29 | public void setSrcFileInfo(IClassCoverage classCov, String sourceFilePath) {
30 | this.sourceFilePath = sourceFilePath;
31 | this.classCov = classCov;
32 | }
33 |
34 | /**
35 | * Read the source Java file for this class.
36 | * @return the source Java file for this class.
37 | */
38 | public File getSourceFilePath() {
39 | return new File(sourceFilePath);
40 | }
41 |
42 | public void printHighlightedSrcFile(Writer output) {
43 | new SourceAnnotator(getSourceFilePath()).printHighlightedSrcFile(classCov,output);
44 | }
45 |
46 | @Override
47 | public String toString() {
48 | return getClass().getSimpleName() + ":"
49 | + " instruction=" + instruction
50 | + " branch=" + branch
51 | + " complexity=" + complexity
52 | + " line=" + line
53 | + " method=" + method;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/report/MethodReport.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.report;
2 |
3 | import hudson.plugins.jacoco.model.CoverageElement;
4 |
5 | import java.io.Writer;
6 |
7 | import org.jacoco.core.analysis.IMethodCoverage;
8 |
9 | /**
10 | * @author Kohsuke Kawaguchi
11 | * @author David Carver
12 | * @author Ognjen Bubalo
13 | */
14 | //AggregatedReport - AbstractReport
15 | public final class MethodReport extends AggregatedReport {
16 |
17 | private IMethodCoverage methodCov;
18 |
19 | @Override
20 | public String printFourCoverageColumns() {
21 | StringBuilder buf = new StringBuilder();
22 | instruction.setType(CoverageElement.Type.INSTRUCTION);
23 | complexity.setType(CoverageElement.Type.COMPLEXITY);
24 | branch.setType(CoverageElement.Type.BRANCH);
25 | line.setType(CoverageElement.Type.LINE);
26 | method.setType(CoverageElement.Type.METHOD);
27 | printRatioCell(isFailed(), this.instruction, buf);
28 | printRatioCell(isFailed(), this.branch, buf);
29 | printRatioCell(isFailed(), this.complexity, buf);
30 | printRatioCell(isFailed(), this.line, buf);
31 | printRatioCell(isFailed(), this.method, buf);
32 | //logger.log(Level.INFO, "Printing Ratio cells within MethodReport.");
33 | return buf.toString();
34 | }
35 |
36 | @Override
37 | public void add(SourceFileReport child) {
38 | String newChildName = child.getName().replace(this.getName() + ".", "");
39 | child.setName(newChildName);
40 | getChildren().put(child.getName(), child);
41 | //logger.log(Level.INFO, "SourceFileReport");
42 | }
43 |
44 | @Override
45 | public boolean hasClassCoverage() {
46 | return false;
47 | }
48 |
49 | public void setSrcFileInfo(IMethodCoverage methodCov) {
50 | this.methodCov = methodCov;
51 | }
52 |
53 | public void printHighlightedSrcFile(Writer output) {
54 | new SourceAnnotator(getParent().getSourceFilePath()).printHighlightedSrcFile(methodCov,output);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/report/PackageReport.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.report;
2 |
3 |
4 | /**
5 | * @author Kohsuke Kawaguchi
6 | * @author David Carver
7 | */
8 | public final class PackageReport extends AggregatedReport {
9 |
10 | /**
11 | * Give the default no-name package a non-empty name.
12 | */
13 | @Override
14 | public String getName() {
15 | String n = super.getName();
16 | return n.length() == 0 ? "(default)" : n;
17 | }
18 |
19 | @Override
20 | public void setName(String name) {
21 | super.setName(name.replace('/', '.'));
22 | }
23 |
24 | @Override
25 | public void add(ClassReport child) {
26 | String newChildName = child.getName().replace(this.getName() + ".", "");
27 | child.setName(newChildName);
28 | this.getChildren().put(child.getName(), child);
29 | //logger.log(Level.INFO, "PackageReport");
30 | }
31 |
32 | //private static final Logger logger = Logger.getLogger(CoverageObject.class.getName());
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/report/SourceAnnotator.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.report;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.InputStreamReader;
7 | import java.io.IOException;
8 | import java.io.Writer;
9 | import java.nio.charset.StandardCharsets;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | import org.jacoco.core.analysis.ICounter;
14 | import org.jacoco.core.analysis.ILine;
15 | import org.jacoco.core.analysis.ISourceNode;
16 |
17 | /**
18 | * Parses source file and annotates that with the coverage information.
19 | *
20 | * @author Kohsuke Kawaguchi
21 | * @author Marcus Bauer
22 | */
23 | public class SourceAnnotator {
24 | private final File src;
25 |
26 | public SourceAnnotator(File src) {
27 | this.src = src;
28 | }
29 |
30 | /**
31 | * Parses the source file into individual lines.
32 | */
33 | private List readLines() throws IOException {
34 | try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(src), StandardCharsets.UTF_8))) {
35 | ArrayList aList = new ArrayList<>();
36 | String line;
37 | while ((line = br.readLine()) != null) {
38 | aList.add(line.replaceAll("\\t", "        ").replaceAll("<", "<").replaceAll(">", ">"));
39 | }
40 | return aList;
41 | }
42 | }
43 |
44 | public void printHighlightedSrcFile(ISourceNode cov, Writer output) {
45 | try {
46 | StringBuilder buf = new StringBuilder();
47 | List sourceLines;
48 | try {
49 | sourceLines = readLines();
50 | } catch (IOException e) {
51 | e.printStackTrace();
52 | output.write("ERROR: Error while reading the sourcefile!");
53 | return;
54 | }
55 | output.write("");
56 | for (int i = 1; i <= sourceLines.size(); ++i) {
57 | buf.setLength(0);
58 |
59 | ILine line = cov.getLine(i);
60 | ICounter branches = line.getBranchCounter();
61 | int status = line.getStatus();
62 | if (status != ICounter.EMPTY) {
63 | printHighlightedLine(buf, i, branches, sourceLines.get(i - 1), status);
64 | } else {
65 | buf.append(i).append(": ").append(sourceLines.get(i - 1)).append(" ");
66 | }
67 | output.write(buf.toString());
68 | }
69 | output.write("");
70 |
71 | //logger.log(Level.INFO, "lines: " + buf);
72 | } catch (IOException e) {
73 | throw new RuntimeException(e);
74 | }
75 | }
76 |
77 | /**
78 | * Formats a source code line
79 | *
80 | * @param buf
81 | * source to write to.
82 | * @param lineNumber
83 | * line number to output
84 | * @param cov
85 | * branch coverage data for this line
86 | * @param sourceLine
87 | * source code line
88 | * @param status
89 | * coverage status of this line
90 | */
91 | private void printHighlightedLine(StringBuilder buf, int lineNumber, ICounter cov, String sourceLine, int status) {
92 | buf.append(lineNumber).append(":");
93 |
94 | String tooltip = getTooltip(cov);
95 | if (tooltip != null) {
96 | buf.append("•").append(sourceLine).append("").append(" ");
102 | }
103 |
104 | /**
105 | * Returns a tooltip for the branch coverage data.
106 | *
107 | * @param cov
108 | * branch coverage data
109 | * @return Tooltip if branch coverage data exists for the given line,
110 | * otherwise null
111 | */
112 | private String getTooltip(ICounter cov) {
113 | switch (cov.getStatus()) {
114 | case ICounter.FULLY_COVERED:
115 | return "All " + cov.getTotalCount() + " branches covered.";
116 |
117 | case ICounter.PARTLY_COVERED:
118 | return cov.getMissedCount() + " of " + cov.getTotalCount() + " branches missed.";
119 |
120 | case ICounter.NOT_COVERED:
121 | return "All " + cov.getTotalCount() + " branches missed.";
122 |
123 | default:
124 | return null;
125 | }
126 | }
127 |
128 | /**
129 | * Returns a HTML color for each line status
130 | *
131 | * @param status
132 | * Status of the line
133 | * @return HTML color code for the background of the line, "none" if none
134 | * @see ICounter#getStatus()
135 | */
136 | private String getStatusColor(int status) {
137 | switch (status) {
138 | case ICounter.FULLY_COVERED:
139 | return "#ccffcc";
140 |
141 | case ICounter.PARTLY_COVERED:
142 | return "#ffff80";
143 |
144 | case ICounter.NOT_COVERED:
145 | return "#ffaaaa";
146 |
147 | default:
148 | return "none";
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/report/SourceFileReport.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.report;
2 |
3 |
4 | /**
5 | * @author Kohsuke Kawaguchi
6 | */
7 | public final class SourceFileReport extends AbstractReport {
8 |
9 | @Override
10 | public void setName(String name) {
11 | super.setName(name.replace('/', '.'));
12 | //logger.log(Level.INFO, "SourceFileReport");
13 | }
14 |
15 | //private static final Logger logger = Logger.getLogger(SourceFileReport.class.getName());
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacoco/rules/LineCoveragePerSourceFileRule.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacoco.rules;
2 |
3 | import hudson.model.TaskListener;
4 | import hudson.plugins.jacoco.Rule;
5 | import hudson.plugins.jacoco.report.CoverageReport;
6 |
7 | /**
8 | * Flags a failure if the line coverage of a source file
9 | * goes below a certain threshold.
10 | */
11 | public class LineCoveragePerSourceFileRule extends Rule {
12 |
13 | private static final long serialVersionUID = -2869893039051762047L;
14 |
15 | //private final float minPercentage;
16 |
17 | public LineCoveragePerSourceFileRule(float minPercentage) {
18 | //this.minPercentage = minPercentage;
19 | }
20 |
21 | @Override
22 | public void enforce(CoverageReport report, TaskListener listener) {
23 | // for (PackageReport pack : report.getChildren().values()) {
24 | // for (SourceFileReport sfReport : pack.getChildren().values()) {
25 | // float percentage = sfReport.getLineCoverage().getPercentageFloat();
26 | //
27 | // if (percentage < minPercentage) {
28 | // listener.getLogger().println("Emma: " + sfReport.getDisplayName() + " failed (below " + minPercentage + "%).");
29 | // sfReport.setFailed();
30 | // }
31 | // }
32 | // }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacococoveragecolumn/AbstractJaCoCoCoverageColumn.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacococoveragecolumn;
2 |
3 | import hudson.model.Job;
4 | import hudson.model.Run;
5 | import hudson.plugins.jacoco.JacocoBuildAction;
6 | import hudson.plugins.jacoco.model.Coverage;
7 | import hudson.views.ListViewColumn;
8 |
9 | import java.awt.*;
10 | import java.math.BigDecimal;
11 | import java.math.RoundingMode;
12 | import java.util.function.Function;
13 |
14 | /**
15 | * Abstract view column to show the code coverage percentage
16 | *
17 | */
18 | public abstract class AbstractJaCoCoCoverageColumn extends ListViewColumn {
19 |
20 | protected abstract Float getPercentageFloat(final Run, ?> build);
21 |
22 | protected Float getPercentageFloat(final Run, ?> lastSuccessfulBuild,
23 | Function percentageFunction) {
24 | if(lastSuccessfulBuild == null) {
25 | return 0f;
26 | }
27 |
28 | final JacocoBuildAction action = lastSuccessfulBuild
29 | .getAction(JacocoBuildAction.class);
30 |
31 | if(action == null) {
32 | return 0f;
33 | }
34 |
35 | return percentageFunction.apply(action);
36 | }
37 |
38 |
39 | public boolean hasCoverage(final Job, ?> job) {
40 | final Run, ?> lastSuccessfulBuild = job.getLastSuccessfulBuild();
41 | return lastSuccessfulBuild != null &&
42 | lastSuccessfulBuild.getAction(JacocoBuildAction.class) != null;
43 | }
44 |
45 | public String getPercent(final Job, ?> job) {
46 | final StringBuilder stringBuilder = new StringBuilder();
47 |
48 | if (!hasCoverage(job)) {
49 | stringBuilder.append("N/A");
50 | } else {
51 | final Run, ?> lastSuccessfulBuild = job.getLastSuccessfulBuild();
52 | final Double percent = getPercent(lastSuccessfulBuild);
53 | stringBuilder.append(percent);
54 | }
55 |
56 | return stringBuilder.toString();
57 | }
58 |
59 | public String getColor(final Job, ?> job, final BigDecimal amount) {
60 | if (amount == null) {
61 | return null;
62 | }
63 |
64 | if(job != null && !hasCoverage(job)) {
65 | return CoverageRange.NA.getLineHexString();
66 | }
67 |
68 | return CoverageRange.valueOf(amount.doubleValue()).getLineHexString();
69 | }
70 |
71 | public String getFillColor(final Job, ?> job, final BigDecimal amount) {
72 | if (amount == null) {
73 | return null;
74 | }
75 |
76 | if(job != null && !hasCoverage(job)) {
77 | return CoverageRange.NA.getFillHexString();
78 | }
79 |
80 | final Color c = CoverageRange.fillColorOf(amount.doubleValue());
81 | return CoverageRange.colorAsHexString(c);
82 | }
83 |
84 | public BigDecimal getCoverage(final Job, ?> job) {
85 | final Run, ?> lastSuccessfulBuild = job.getLastSuccessfulBuild();
86 | return BigDecimal.valueOf(getPercent(lastSuccessfulBuild));
87 | }
88 |
89 | private Double getPercent(final Run, ?> lastSuccessfulBuild) {
90 | final Float percentageFloat = getPercentageFloat(lastSuccessfulBuild);
91 | final double doubleValue = percentageFloat.doubleValue();
92 |
93 | final int decimalPlaces = 2;
94 | BigDecimal bigDecimal = new BigDecimal(doubleValue);
95 |
96 | // setScale is immutable
97 | bigDecimal = bigDecimal.setScale(decimalPlaces,
98 | RoundingMode.HALF_UP);
99 | return bigDecimal.doubleValue();
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacococoveragecolumn/BranchCoverageColumn.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacococoveragecolumn;
2 |
3 | import hudson.Extension;
4 | import hudson.model.Descriptor;
5 | import hudson.model.Run;
6 | import hudson.views.ListViewColumn;
7 | import hudson.views.ListViewColumnDescriptor;
8 | import net.sf.json.JSONObject;
9 | import org.kohsuke.stapler.DataBoundConstructor;
10 | import org.kohsuke.stapler.StaplerRequest;
11 |
12 | import edu.umd.cs.findbugs.annotations.NonNull;
13 |
14 | /**
15 | * View column that shows the code branch coverage percentage
16 | *
17 | */
18 | public class BranchCoverageColumn extends AbstractJaCoCoCoverageColumn {
19 |
20 | @DataBoundConstructor
21 | public BranchCoverageColumn() {
22 | }
23 |
24 | @Override
25 | protected Float getPercentageFloat(final Run, ?> lastSuccessfulBuild) {
26 | return getPercentageFloat(lastSuccessfulBuild,
27 | (a) -> a.getBranchCoverage().getPercentageFloat());
28 | }
29 |
30 | @Extension
31 | public static final Descriptor DESCRIPTOR = new DescriptorImpl();
32 |
33 | @Override
34 | public Descriptor getDescriptor() {
35 | return DESCRIPTOR;
36 | }
37 |
38 | private static class DescriptorImpl extends ListViewColumnDescriptor {
39 | @Override
40 | public ListViewColumn newInstance(final StaplerRequest req,
41 | @NonNull final JSONObject formData) {
42 | return new BranchCoverageColumn();
43 | }
44 |
45 | @Override
46 | public boolean shownByDefault() {
47 | return false;
48 | }
49 |
50 | @NonNull
51 | @Override
52 | public String getDisplayName() {
53 | return "JaCoCo Branch Coverage";
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacococoveragecolumn/CoverageRange.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacococoveragecolumn;
2 |
3 | import java.awt.Color;
4 |
5 | public enum CoverageRange {
6 | /*
7 | * This ordering is important for the lookup; the lowest value should be
8 | * last
9 | */
10 | PERFECT(100.0, new Color(0x00, 0x8B, 0x00), new Color(0xEE, 0xEE, 0xEE)), //
11 | EXCELLENT(97.0, new Color(0x00, 0xCD, 0x00), new Color(0x00, 0x00, 0x00)), //
12 | GOOD(92.0, new Color(0x7A, 0xFF, 0x3F), new Color(0x00, 0x00, 0x00)), //
13 | SUFFICIENT(85.0, new Color(0xC8, 0xFF, 0x3F), new Color(0x00, 0x00, 0x00)), //
14 | FAIR(75.0, new Color(0xFF, 0xFF, 0x00), new Color(0x00, 0x00, 0x00)), //
15 | POOR(50.0, new Color(0xFF, 0x7F, 0x00), new Color(0x00, 0x00, 0x00)), //
16 | TRAGIC(25.0, new Color(0xFF, 0x00, 0x00), new Color(0xEE, 0xEE, 0xEE)), //
17 | ABYSSMAL(0.0, new Color(0x00, 0x00, 0x00), new Color(0xEE, 0xEE, 0xEE)),
18 | NA(0.0, new Color(0xFF, 0xFF, 0xFF), new Color(0x00, 0x00, 0x00));
19 |
20 | /**
21 | * Minimum coverage amount for this range
22 | */
23 | private final double floor;
24 |
25 | private final Color fillColor;
26 | private final Color lineColor;
27 |
28 | CoverageRange(final double floor, final Color fillColor,
29 | final Color lineColor) {
30 | this.floor = floor;
31 | this.fillColor = fillColor;
32 | this.lineColor = lineColor;
33 | }
34 |
35 | public static CoverageRange valueOf(final Double amount) {
36 | for (final CoverageRange range : values()) {
37 | if (amount >= range.floor) {
38 | return range;
39 | }
40 | }
41 | return ABYSSMAL;
42 | }
43 |
44 | public static Color fillColorOf(final double amount) {
45 | for (int i = 0; i < values().length; i++) {
46 | final CoverageRange range = values()[i];
47 | if (amount == range.floor) {
48 | return range.fillColor;
49 | } else if (amount > range.floor) {
50 | if (i == 0) {
51 | // This method used to throw ArrayIndexOutOfBoundsException
52 | // in this case, catch it and return this value:
53 | return ABYSSMAL.fillColor;
54 | }
55 | final CoverageRange range1 = values()[i - 1];
56 | final double t0 = amount - range.floor;
57 | final double t1 = range1.floor - amount;
58 | return blendedColor(range.fillColor, range1.fillColor, t0,
59 | t1);
60 | }
61 | }
62 | return ABYSSMAL.fillColor;
63 | }
64 |
65 | private static Color blendedColor(final Color fillColor0,
66 | final Color fillColor1, final double t0, final double t1) {
67 | final double total = t0 + t1;
68 | if (total == 0) {
69 | return ABYSSMAL.fillColor;
70 | }
71 | final int r = (int) ((fillColor0.getRed() * t1 + fillColor1.getRed()
72 | * t0) / total);
73 | final int g = (int) ((fillColor0.getGreen() * t1 + fillColor1
74 | .getGreen() * t0) / total);
75 | final int b = (int) ((fillColor0.getBlue() * t1 + fillColor1.getBlue()
76 | * t0) / total);
77 | return new Color(r, g, b);
78 | }
79 |
80 | public Color getFillColor() {
81 | return fillColor;
82 | }
83 |
84 | public Color getLineColor() {
85 | return lineColor;
86 | }
87 |
88 | public String getFillHexString() {
89 | return colorAsHexString(fillColor);
90 | }
91 |
92 | public String getLineHexString() {
93 | return colorAsHexString(lineColor);
94 | }
95 |
96 | public static String colorAsHexString(final Color c) {
97 | return String.format("%02X%02X%02X", c.getRed(), c.getGreen(),
98 | c.getBlue());
99 | }
100 |
101 | public double getFloor() {
102 | return floor;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/hudson/plugins/jacococoveragecolumn/JaCoCoColumn.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.jacococoveragecolumn;
2 |
3 | import hudson.Extension;
4 | import hudson.model.Descriptor;
5 | import hudson.model.Run;
6 | import hudson.views.ListViewColumnDescriptor;
7 | import hudson.views.ListViewColumn;
8 |
9 | import net.sf.json.JSONObject;
10 |
11 | import org.kohsuke.stapler.DataBoundConstructor;
12 | import org.kohsuke.stapler.StaplerRequest;
13 |
14 | import edu.umd.cs.findbugs.annotations.NonNull;
15 |
16 | /**
17 | * View column that shows the code line coverage percentage
18 | *
19 | */
20 | public class JaCoCoColumn extends AbstractJaCoCoCoverageColumn {
21 |
22 | @DataBoundConstructor
23 | public JaCoCoColumn() {
24 | }
25 |
26 | @Override
27 | protected Float getPercentageFloat(final Run, ?> lastSuccessfulBuild) {
28 | return getPercentageFloat(lastSuccessfulBuild,
29 | (a) -> a.getLineCoverage().getPercentageFloat());
30 | }
31 |
32 | @Extension
33 | public static final Descriptor DESCRIPTOR = new DescriptorImpl();
34 |
35 | @Override
36 | public Descriptor getDescriptor() {
37 | return DESCRIPTOR;
38 | }
39 |
40 | private static class DescriptorImpl extends ListViewColumnDescriptor {
41 | @Override
42 | public ListViewColumn newInstance(final StaplerRequest req,
43 | @NonNull final JSONObject formData) {
44 | return new JaCoCoColumn();
45 | }
46 |
47 | @Override
48 | public boolean shownByDefault() {
49 | return false;
50 | }
51 |
52 | @NonNull
53 | @Override
54 | public String getDisplayName() {
55 | return "JaCoCo Line Coverage";
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoBuildAction/summary.jelly:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Jacoco - ${%Overall Coverage Summary}
8 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoProjectAction/index_de.properties:
--------------------------------------------------------------------------------
1 | JaCoCo\ Coverage\ Trend=Trend der JaCoCo-Code-Abdeckung
2 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoProjectAction/index_es.properties:
--------------------------------------------------------------------------------
1 | JaCoCo\ Coverage\ Trend=Tendencia de cobertura JaCoCo
2 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoProjectAction/index_ja.properties:
--------------------------------------------------------------------------------
1 | JaCoCo\ Coverage\ Trend=JaCoCo\u30ab\u30d0\u30ec\u30c3\u30b8\u306e\u63a8\u79fb
2 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoPublisher/config.properties:
--------------------------------------------------------------------------------
1 |
2 | entry.title=Folders or files containing JaCoCo XML reports
3 | includes.description=\
4 | Specify the path to the JaCoCo''s XML report files, relative to \
5 | the workspace root \
6 | - If you left this field blank the plugin will look for files matching the pattern: **/jacoco/jacoco*.xml in the workspace. \
7 | - Or you can enclose the search specifying a list of files and folders separated by semicolon. \
8 | - Or use an Ant 'Fileset' pattern.
9 |
10 | minLineCoveragePerSource.description=\
11 | % min line coverage - 0 (or empty) is as if you disable MinLineCoverage-Enforcer.
12 | MinLine\ Coverage=Minimal line coverage
13 |
14 | Instructions=% Instructions
15 | Branch=% Branch
16 | Complexity=% Complexity
17 | Line=% Line
18 | Method=% Method
19 | Class=% Class
20 |
21 |
22 |
23 |
24 | health.100.title=Report health as 100% when coverage is greater than
25 | health.0.title=Report health as 0% when coverage is less than
26 |
27 | #thresholds.description=\
28 | # Configure health reporting thresholds. \
29 | # For the \
30 | # row, leave blank to use the default values (i.e. 80, 80, 80, 80, 70 and 100 for instruction, method, line, \
31 | # complexity, instructions, and branch respectively). \
32 | # For the row, leave blank to \
33 | # use the default values (i.e. 0, 0, 0, 0, 0, 0, 0).
34 |
35 |
36 | Health\ reporting=Health reporting
37 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoPublisher/config_es.properties:
--------------------------------------------------------------------------------
1 |
2 | entry.title=Directorios o archivos donde JaCoCo deja la informaci\u00f3n.
3 | includes.description=\
4 | Especifica la ruta donde est\u00e1n los ficheros XML de JaCoCo. Esta ruta es relativa al directorio de trabajo. \
5 | - Si dejas este campo vac\u00edo, el plugin buscar\u00e1 todos los ficheros en todo el espacio de trabajo que cumplan el patr\u00f3n: \
6 | **/jacoco/jacoco*.xml \
7 | - O bien puedes especificar una lista de ficheros y/o directorios donde buscar separados por punto y coma. \
8 | - O usar un patr\u00f3n 'Fileset' de Ant
9 |
10 | minLineCoveragePerSource.description=\
11 | Umbral (%) de cobertura m\u00ednima de l\u00edneas de c\u00f3digo necesario para no marcar el proyecto como fallido. \
12 | Un valor 0 o dejar el campo vac\u00edo significa desactivar esta restricci\u00f3n.
13 | MinLine\ Coverage=Cobertura m\u00ednima de l\u00edneas
14 |
15 | Class=% Clases
16 | Method=% M\u00e9todos
17 | Block=% Bloques
18 | Line=% L\u00edneas
19 |
20 | health.100.title=Muestra un estado de salud como si fuera de 100% cuando la cobertura es mayor a este valor.
21 | health.0.title=Muestra un estado de salud como si fuera de 0% cuando la cobertura es inferior a este valor.
22 |
23 | thresholds.description=\
24 | Configuraci\u00f3n de los umbrales de salud del c\u00f3digo. \
25 | Para el estado: \
26 | deja las casillas en blanco si quieres usar los valores por defecto \
27 | (100, 70, 80, y 80 para clases, m\u00e9todos, bloques y l\u00edneas respectivamente). \
28 | Para el estado \
29 | deja las casillas en blanco para usar los valores por defecto (0, 0, 0, 0).
30 |
31 |
32 | Health\ reporting=Estado de salud del proyecto
33 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoPublisher/config_ja.properties:
--------------------------------------------------------------------------------
1 |
2 | entry.title=\u30ec\u30dd\u30fc\u30c8\u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea/\u30d5\u30a1\u30a4\u30eb
3 | includes.description=\
4 | JaCoCo\u306eXML\u5f62\u5f0f\u306e\u30ec\u30dd\u30fc\u30c8\u30d5\u30a1\u30a4\u30eb\u3078\u306e\u30d1\u30b9\u3092\u3001\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u304b\u3089\u306e\u76f8\u5bfe\u30d1\u30b9\u3067\u6307\u5b9a\u3057\u307e\u3059\u3002 \
5 | - \u672a\u5165\u529b\u306e\u5834\u5408\u3001\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u306e **/jacoco/jacoco*.xml \u306b\u4e00\u81f4\u3059\u308b\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22\u3057\u307e\u3059\u3002 \
6 | - \u691c\u7d22\u3059\u308b\u30d5\u30a1\u30a4\u30eb\u3084\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30ea\u30b9\u30c8\u3092\u30bb\u30df\u30b3\u30ed\u30f3\u533a\u5207\u308a\u3067\u6307\u5b9a\u3059\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002 \
7 | - Ant\u306e'Fileset'\u30d1\u30bf\u30fc\u30f3\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002
8 |
9 | minLineCoveragePerSource.description=\
10 | % min line coverage - 0 (or empty) is as if you disable MinLineCoverage-Enforcer.
11 | MinLine\ Coverage=Minimal line coverage
12 |
13 | Class=% \u30af\u30e9\u30b9
14 | Method=% \u30e1\u30bd\u30c3\u30c9
15 | Block=% \u30d6\u30ed\u30c3\u30af
16 | Line=% \u884c
17 |
18 | health.100.title=\u30ab\u30d0\u30ec\u30c3\u30b8\u304c\u3053\u306e\u5024\u3088\u308a\u5927\u304d\u3044\u5834\u5408\u3001\u72b6\u614b\u3092100%\u3068\u5831\u544a\u3057\u307e\u3059\u3002
19 | health.0.title=\u30ab\u30d0\u30ec\u30c3\u30b8\u304c\u3053\u306e\u5024\u3088\u308a\u5c0f\u3055\u3044\u5834\u5408\u3001\u72b6\u614b\u30920%\u3068\u5831\u544a\u3057\u307e\u3059\u3002
20 |
21 | thresholds.description=\
22 | \u72b6\u614b\u306e\u95be\u5024\u3092\u8a2d\u5b9a\u3057\u307e\u3059\u3002 \
23 | \u306e\u884c\u304c\u672a\u5165\u529b\u306e\u5834\u5408\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 \
24 | (\u30af\u30e9\u30b9\u3001\u30e1\u30bd\u30c3\u30c9\u3001\u30d6\u30ed\u30c3\u30af\u304a\u3088\u3073\u884c\u306e\u5024\u3068\u3057\u3066\u3001100, 70, 80, 80)\u3002 \
25 | \u306e\u884c\u304c\u672a\u5165\u529b\u306e\u5834\u5408\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059(0, 0, 0 ,0)\u3002
26 |
27 |
28 | Health\ reporting=\u72b6\u614b\u30ec\u30dd\u30fc\u30c8
29 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoPublisher/global.jelly:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/jacoco/JacocoPublisher/help-buildOverBuild.html:
--------------------------------------------------------------------------------
1 |
2 | Check this to set the build status to failure if the delta coverage thresholds are violated. Delta coverage is the difference between coverage of last successful and current build.
3 |
2 | Change build status if coverage degrades.
3 | The build status degrades to unstable (or failed) if branch coverage decreases by more than this delta threshold compared to the previous build.
4 |
2 | Change build status if coverage degrades.
3 | The build status degrades to unstable (or failed) if class coverage decreases by more than this delta threshold compared to the previous build.
4 |
2 | Change build status if coverage degrades.
3 | The build status degrades to unstable (or failed) if complexity coverage decreases by more than this delta threshold compared to the previous build.
4 |
2 | Change build status if coverage degrades.
3 | The build status degrades to unstable (or failed) if instruction coverage decreases by more than this delta threshold compared to the previous build.
4 |
2 | Change build status if coverage degrades.
3 | The build status degrades to unstable (or failed) if line coverage decreases by more than this delta threshold compared to the previous build.
4 |
2 | Change build status if coverage degrades.
3 | The build status degrades to unstable (or failed) if method coverage decreases by more than this delta threshold compared to the previous build.
4 |
2 | Allows to configure various aspects of the JaCoCo code coverage report. The paths define where the various types of files
3 | can be found in the workspace, inclusions and exclusions allow to exclude certain class files.
4 |
5 | And the coverage thresholds allow to configure how much coverage is necessary to make the build green (if changing the build
6 | status is enabled).
7 |
The default value is 30. The chart will consider only the builds within the specified number of days from the last build date (including it) of all jobs chosen on Dashboard View.
The default value is 250. This field will set the height of the chart. The chart will consider the default value if some negative, null or non-numeric value is filled in this field.
The default value is 500. This field will set the width of the chart. The chart will consider the default value if some negative, null or non-numeric value is filled in this field.