Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support configurable metrics for Jacoco and SonarQube... #41

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ class CloverParser implements CoverageReportParser {
private static final String TOTAL_STATEMENTS_XPATH = "/coverage/project/metrics/@statements";
private static final String COVER_STATEMENTS_XPATH = "/coverage/project/metrics/@coveredstatements";

@Override
public boolean canAggregate() {
return false;
}
@Override
public float getAggregate() {
throw new UnsupportedOperationException();
}

private int getByXpath(final String filePath, final String content, final String xpath) {
try {
return Integer.parseInt(XmlUtils.findInXml(content, xpath));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@
*/
class CoberturaParser implements CoverageReportParser {

@Override
public boolean canAggregate() {
return false;
}
@Override
public float getAggregate() {
throw new UnsupportedOperationException();
}

private static String findFirst(String string, String pattern) {
String result = findFirstOrNull(string, pattern);
if (result != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ public void perform(
final int prId = PrIdAndUrlUtils.getPrId(scmVars, build, listener);
final String gitUrl = PrIdAndUrlUtils.getGitUrl(scmVars, build, listener);

if (settingsRepository.getSonarCoverageMetric() != null) {
buildLog.println(BUILD_LOG_PREFIX + "using coverage metrics: " + settingsRepository.getSonarCoverageMetric());
}

if (settingsRepository.getCoverageRoundingDigits() != 0) {
buildLog.println(BUILD_LOG_PREFIX + "using round-up to digits: " + settingsRepository.getCoverageRoundingDigits());
}

buildLog.println(BUILD_LOG_PREFIX + "using aggregates for coverage: " + settingsRepository.isUseAggregatesForCoverage());

buildLog.println(BUILD_LOG_PREFIX + "getting master coverage...");
MasterCoverageRepository masterCoverageRepository = ServiceRegistry.getMasterCoverageRepository(buildLog, sonarLogin, sonarPassword);
final GHRepository gitHubRepository = ServiceRegistry.getPullRequestRepository().getGitHubRepository(gitUrl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,22 @@ public static Boolean isUseSonarForMasterCoverage() {
return DESCRIPTOR.isUseSonarForMasterCoverage();
}

public static String getSonarCoverageMetric() {
return DESCRIPTOR.getSonarCoverageMetric();
}

public static int getCoverageRoundingDigits() {
return DESCRIPTOR.getCoverageRoundingDigits();
}

public static void setMasterCoverage(final String repo, final float coverage) {
DESCRIPTOR.set(repo, coverage);
}

public static Boolean isUseAggregatesForCoverage() {
return DESCRIPTOR.isUseAggregatesForCoverage();
}

@Override
public ConfigurationDescriptor getDescriptor() {
return DESCRIPTOR;
Expand All @@ -100,13 +112,16 @@ public static final class ConfigurationDescriptor extends Descriptor<Configurati
private String jenkinsUrl;
private boolean privateJenkinsPublicGitHub;
private boolean useSonarForMasterCoverage;
private boolean useAggregatesForCoverage;
private String sonarUrl;
private String sonarToken;
private String sonarLogin;
private String sonarPassword;
private String sonarCoverageMetric;

private int yellowThreshold = DEFAULT_YELLOW_THRESHOLD;
private int greenThreshold = DEFAULT_GREEN_THRESHOLD;
private int coverageRoundingDigits;

public ConfigurationDescriptor() {
load();
Expand Down Expand Up @@ -157,6 +172,11 @@ public boolean isUseSonarForMasterCoverage() {
return useSonarForMasterCoverage;
}

@Override
public boolean isUseAggregatesForCoverage() {
return useAggregatesForCoverage;
}

@Override
public boolean isDisableSimpleCov() {
return disableSimpleCov;
Expand Down Expand Up @@ -184,6 +204,16 @@ public String getSonarLogin() {
public String getSonarPassword() {
return sonarPassword;
}

@Override
public String getSonarCoverageMetric() {
return sonarCoverageMetric;
}

@Override
public int getCoverageRoundingDigits() {
return coverageRoundingDigits;
}

@Override
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
Expand All @@ -199,6 +229,9 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc
sonarToken = StringUtils.trimToNull(formData.getString("sonarToken"));
sonarLogin = StringUtils.trimToNull(formData.getString("sonarLogin"));
sonarPassword = StringUtils.trimToNull(formData.getString("sonarPassword"));
sonarCoverageMetric = StringUtils.trimToNull(formData.getString("sonarCoverageMetric"));
coverageRoundingDigits = NumberUtils.toInt(formData.getString("coverageRoundingDigits"), 0);
useAggregatesForCoverage = BooleanUtils.toBoolean(formData.getString("useAggregatesForCoverage"));
save();
return super.configure(req, formData);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@
interface CoverageReportParser {

float get(String filePath);

boolean canAggregate();

float getAggregate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ private static List<Float> getFloats(File ws, String path, CoverageReportParser
String[] files = ds.getIncludedFiles();
List<Float> cov = new ArrayList<Float>();
for (String file : files) cov.add(parser.get(new File(ds.getBasedir(), file).getAbsolutePath()));
if (cov.size() > 0 && parser.canAggregate()) {
cov.clear();
cov.add(parser.getAggregate());
}
return cov;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@
*/
class JacocoParser implements CoverageReportParser {

private static final String MISSED_XPATH = "/report/counter[@type='LINE']/@missed";
private static final String COVERAGE_XPATH = "/report/counter[@type='LINE']/@covered";
public static final String MISSED_INSTRUCTION_XPATH = "/report/counter[@type='INSTRUCTION']/@missed";
public static final String COVERAGE_INSTRUCTION_XPATH = "/report/counter[@type='INSTRUCTION']/@covered";
public static final String MISSED_LINE_XPATH = "/report/counter[@type='LINE']/@missed";
public static final String COVERAGE_LINE_XPATH = "/report/counter[@type='LINE']/@covered";
public static final String MISSED_BRANCH_XPATH = "/report/counter[@type='BRANCH']/@missed";
public static final String COVERAGE_BRANCH_XPATH = "/report/counter[@type='BRANCH']/@covered";

private float getByXpath(final String filePath, final String content, final String xpath) {
public static float getByXpath(final String filePath, final String content, final String xpath) {
try {
return Float.parseFloat(XmlUtils.findInXml(content, xpath));
} catch (NumberFormatException e) {
Expand All @@ -45,7 +49,16 @@ private float getByXpath(final String filePath, final String content, final Stri
"from:\n" + content);
}
}

@Override
public boolean canAggregate() {
final SettingsRepository settingsRepository = ServiceRegistry.getSettingsRepository();
return settingsRepository.isUseAggregatesForCoverage();
}

private volatile float totalCovered = 0.0f;
private volatile float totalMissed = 0.0f;

@Override
public float get(final String jacocoFilePath) {
final String content;
Expand All @@ -56,14 +69,43 @@ public float get(final String jacocoFilePath) {
"Can't read Jacoco report by path: " + jacocoFilePath);
}

final float lineMissed = getByXpath(jacocoFilePath, content, MISSED_XPATH);
final float lineCovered = getByXpath(jacocoFilePath, content, COVERAGE_XPATH);
final float lines = lineCovered + lineMissed;
if (lines == 0) {
final SettingsRepository settingsRepository = ServiceRegistry.getSettingsRepository();
String missedMetric;
String coverageMetric;
if (settingsRepository.getSonarCoverageMetric() != null && SonarMasterCoverageRepository.SONAR_OVERALL_INSTRUCTION_COVERAGE_METRIC_NAME.equalsIgnoreCase(settingsRepository.getSonarCoverageMetric())) {
missedMetric = MISSED_INSTRUCTION_XPATH;
coverageMetric = COVERAGE_INSTRUCTION_XPATH;
} else if (settingsRepository.getSonarCoverageMetric() != null && SonarMasterCoverageRepository.SONAR_OVERALL_BRANCH_COVERAGE_METRIC_NAME.equalsIgnoreCase(settingsRepository.getSonarCoverageMetric())) {
missedMetric = MISSED_BRANCH_XPATH;
coverageMetric = COVERAGE_BRANCH_XPATH;
} else {
missedMetric = MISSED_LINE_XPATH;
coverageMetric = COVERAGE_LINE_XPATH;
}

final float countMissed = getByXpath(jacocoFilePath, content, missedMetric);
final float countCovered = getByXpath(jacocoFilePath, content, coverageMetric);

totalCovered += countCovered;
totalMissed += countMissed;

final float count = countCovered + countMissed;
if (count == 0) {
return 0;
} else {
return lineCovered / (lines);
return countCovered / (count);
}
}

@Override
public float getAggregate () {
final float count = totalCovered + totalMissed;
if (count == 0) {
return 0;
} else {
return totalCovered / (count);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,14 @@ class Message {
private final float masterCoverage;

public Message(float coverage, float masterCoverage) {
this.coverage = Percent.roundFourAfterDigit(coverage);
this.masterCoverage = Percent.roundFourAfterDigit(masterCoverage);
final SettingsRepository settingsRepository = ServiceRegistry.getSettingsRepository();
if (settingsRepository.getCoverageRoundingDigits() == 0) {
this.coverage = Percent.roundFourAfterDigit(coverage);
this.masterCoverage = Percent.roundFourAfterDigit(masterCoverage);
} else {
this.coverage = Percent.roundCustomAfterDigit(coverage, settingsRepository.getCoverageRoundingDigits());
this.masterCoverage = Percent.roundCustomAfterDigit(masterCoverage, settingsRepository.getCoverageRoundingDigits());
}
}

public String forConsole() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public static float roundFourAfterDigit(float value) {
return ((float) Math.round(value * 10000)) / 10000;
}

public static float roundCustomAfterDigit(float value, int places) {
double scale = Math.pow(10, places);
return (float) (Math.ceil(value * scale) / scale);
}

public static String toWholeString(float value) {
return (value < 0 ? "-" : value > 0 ? "+" : "") + toWholeNoSignString(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ interface SettingsRepository {
boolean isUseSonarForMasterCoverage();

boolean isDisableSimpleCov();

boolean isUseAggregatesForCoverage();

String getSonarUrl();

String getSonarToken();

String getSonarCoverageMetric();

int getCoverageRoundingDigits();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ public class SimpleCovParser implements CoverageReportParser {

private static final String METRIC_PATH = "$.metrics.covered_percent";

@Override
public boolean canAggregate() {
return false;
}
@Override
public float getAggregate() {
throw new UnsupportedOperationException();
}

@Override
public float get(String simpleCovFilePath) {
final String content;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ public class SonarMasterCoverageRepository implements MasterCoverageRepository {

private static final String SONAR_SEARCH_PROJECTS_API_PATH = "/api/projects/index";
private static final String SONAR_COMPONENT_MEASURE_API_PATH = "/api/measures/component";
public static final String SONAR_OVERALL_LINE_COVERAGE_METRIC_NAME = "coverage";
public static final String SONAR_OVERALL_INSTRUCTION_COVERAGE_METRIC_NAME = "coverage";
public static final String SONAR_OVERALL_LINE_COVERAGE_METRIC_NAME = "line_coverage";
public static final String SONAR_OVERALL_BRANCH_COVERAGE_METRIC_NAME = "branch_coverage";

private final String sonarUrl;
private final String login;
Expand Down Expand Up @@ -92,7 +94,13 @@ private SonarProject getSonarProject(final String repoName) throws SonarProjectR
log("Found project for repo name %s - %s", repoName, sonarProjects.get(0));
return sonarProjects.get(0);
} else {
log("Found multiple projects for repo name %s - found %s - returning first result", repoName, sonarProjects);
log("Found multiple projects for repo name %s - found %s - looking for repo/key exact match", repoName, sonarProjects);
for (SonarProject project: sonarProjects) {
if (project.getKey().equalsIgnoreCase(repoName)) {
return project;
}
}
log("No repo/key exact match, returning first result");
return sonarProjects.get(0);
}
} catch (final Exception e) {
Expand All @@ -107,7 +115,10 @@ private SonarProject getSonarProject(final String repoName) throws SonarProjectR
* @throws SonarCoverageMeasureRetrievalException if an error occurred during retrieval of the coverage
*/
private float getCoverageMeasure(SonarProject project) throws SonarCoverageMeasureRetrievalException {
final String uri = MessageFormat.format("{0}{1}?componentKey={2}&metricKeys={3}", sonarUrl, SONAR_COMPONENT_MEASURE_API_PATH, URLEncoder.encode(project.getKey()), SONAR_OVERALL_LINE_COVERAGE_METRIC_NAME);
final SettingsRepository settingsRepository = ServiceRegistry.getSettingsRepository();
String metricName = settingsRepository.getSonarCoverageMetric();
if (metricName == null) metricName = SONAR_OVERALL_INSTRUCTION_COVERAGE_METRIC_NAME;
final String uri = MessageFormat.format("{0}{1}?componentKey={2}&metricKeys={3}", sonarUrl, SONAR_COMPONENT_MEASURE_API_PATH, URLEncoder.encode(project.getKey()), metricName);
try {
final GetMethod method = executeGetRequest(uri);
String value = JsonUtils.findInJson(method.getResponseBodyAsString(), "component.measures[0].value");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ f.section(title: descriptor.displayName) {
f.password()
}

f.entry(field: "sonarCoverageMetric", title: _("Sonar coverage metric")) {
f.textbox()
}

f.entry(field: "coverageRoundingDigits", title: _("Rounding digits")) {
f.textbox()
}

f.entry(field: "useAggregatesForCoverage", title: _("Use aggregate calculations for coverage")) {
f.checkbox()
}

f.entry(field: "disableSimpleCov", title: _("Disable SimpleCov coverage parser")) {
f.checkbox()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Number of digits to round at(Optional). If not specified, no rounding will be performed. In order to match SonarQube, it always rounds up.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Coverage metric to retrieve from Sonar(Optional). It will use &quot;coverage&quot; if not specified. Known values are &quot;coverage&quot;, &quot;line_coverage&quot;, and &quot;branch_coverage&quot;.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
When enabled compatible plugins will calculate coverage based on aggregate covered/missed amounts, not as an average of all sub-modules.
</div>
Loading