PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/java/com/atlassian/bamboo/plugin/dotnet/ncover/NCoverBuildProcessorServer.java

https://bitbucket.org/atlassian/bamboo-dotnet-plugin/
Java | 195 lines | 136 code | 20 blank | 39 comment | 20 complexity | df6b8bb846dc79373513e3769d7e4bca MD5 | raw file
Possible License(s): BSD-3-Clause
  1. package com.atlassian.bamboo.plugin.dotnet.ncover;
  2. import com.atlassian.bamboo.build.CustomBuildProcessorServer;
  3. import com.atlassian.bamboo.resultsummary.ResultsSummary;
  4. import com.atlassian.bamboo.resultsummary.ResultsSummaryManager;
  5. import com.atlassian.bamboo.util.NumberUtils;
  6. import com.atlassian.bamboo.v2.build.BaseConfigurableBuildPlugin;
  7. import com.atlassian.bamboo.v2.build.BuildContext;
  8. import com.atlassian.bamboo.v2.build.CurrentBuildResult;
  9. import com.google.common.collect.Lists;
  10. import org.apache.commons.lang3.StringUtils;
  11. import org.apache.log4j.Logger;
  12. import org.jetbrains.annotations.NotNull;
  13. import java.io.BufferedReader;
  14. import java.io.IOException;
  15. import java.io.StringReader;
  16. import java.util.Collections;
  17. import java.util.HashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.StringTokenizer;
  21. /**
  22. *
  23. */
  24. public class NCoverBuildProcessorServer extends BaseConfigurableBuildPlugin
  25. implements CustomBuildProcessorServer {
  26. public static final String LINE_SEPARATOR = System
  27. .getProperty("line.separator");
  28. private static final Logger log = Logger.getLogger(NCoverBuildProcessorServer.class);
  29. private ResultsSummaryManager resultsSummaryManager;
  30. /**
  31. * @return
  32. * @throws InterruptedException
  33. */
  34. @Override
  35. @NotNull
  36. public BuildContext call() throws InterruptedException {
  37. CurrentBuildResult buildResult = buildContext.getBuildResult();
  38. // only calculate delta when NCover is enabled
  39. final Map<String, String> customConfiguration = buildContext.getBuildDefinition()
  40. .getCustomConfiguration();
  41. if (Boolean.parseBoolean(customConfiguration.get(NCoverBuildProcessor.NCOVER_EXISTS)))
  42. {
  43. calculateDelta(buildResult.getCustomBuildData());
  44. }
  45. return buildContext;
  46. }
  47. /**
  48. * @param results
  49. */
  50. private void calculateDelta(Map<String, String> results) {
  51. try
  52. {
  53. ResultsSummary previousSummary = resultsSummaryManager.getLastSuccessfulResultSummary(buildContext.getPlanResultKey().getPlanKey());
  54. if (previousSummary != null && previousSummary.getCustomBuildData() != null && previousSummary.getCustomBuildData().containsKey(
  55. NCoverBuildProcessor.NCOVER_LINE_RATE))
  56. {
  57. String prevCoverStr = previousSummary
  58. .getCustomBuildData().get(NCoverBuildProcessor.NCOVER_LINE_RATE);
  59. String lineRate = results
  60. .get(NCoverBuildProcessor.NCOVER_LINE_RATE);
  61. if (!prevCoverStr.equals(lineRate))
  62. {
  63. runCoverageChangeComparison(previousSummary, results);
  64. }
  65. double prevCoverDbl = NumberUtils.stringToDouble(prevCoverStr);
  66. double coverage = NumberUtils.stringToDouble(lineRate);
  67. results.put(NCoverBuildProcessor.NCOVER_COVERAGE_DELTA, Double
  68. .toString(coverage - prevCoverDbl));
  69. }
  70. } catch (NumberFormatException e) {
  71. log.error(e);
  72. }
  73. }
  74. /**
  75. * Compares the class/line rates from this build and the previous build.
  76. * Any differences between coverage line rates are recorded in
  77. * {@link NCoverCoverageInformation} instances, which are written
  78. * into the {@link com.atlassian.bamboo.resultsummary.BuildResultsSummary}'s custom data map.
  79. *
  80. * @param previousSummary the {@link com.atlassian.bamboo.resultsummary.BuildResultsSummary} instance for the previous
  81. * build
  82. */
  83. @SuppressWarnings("unchecked")
  84. private void runCoverageChangeComparison(ResultsSummary previousSummary, Map<String, String> results)
  85. {
  86. List<NCoverCoverageInformation> coverageInfoList = Lists.newArrayList();
  87. List<NCoverCoverageInformation> coverageChangeList = Lists.newArrayList();
  88. // build map of current class/coverages
  89. Map<String, String> currentMap = buildClassCoverageMap(results
  90. .get(NCoverBuildProcessor.NCOVER_RESULT_CONTENTS));
  91. String previousCsv = previousSummary.getCustomBuildData()
  92. .get(NCoverBuildProcessor.NCOVER_RESULT_CONTENTS);
  93. if (previousCsv == null || StringUtils.isEmpty(previousCsv))
  94. return;
  95. Map<String, String> previousMap = buildClassCoverageMap(previousCsv);
  96. for (Object o : currentMap.keySet()) {
  97. String className = (String) o;
  98. String lineRate = currentMap.get(className);
  99. String oldLineRate = previousMap.get(className);
  100. if (StringUtils.isEmpty(lineRate)
  101. || StringUtils.isEmpty(oldLineRate))
  102. continue;
  103. Double difference = NumberUtils.stringToDouble(lineRate)
  104. - NumberUtils.stringToDouble(oldLineRate);
  105. // if the line rates are different
  106. if (!difference.equals(0.0D))
  107. coverageInfoList
  108. .add(new NCoverCoverageInformation(className,
  109. NumberUtils.stringToDouble(lineRate), difference));
  110. }
  111. if (coverageInfoList.isEmpty()) {
  112. log.info("No differences in coverage found");
  113. } else {
  114. // sort collection
  115. Collections.sort(coverageInfoList);
  116. int size = Math.min(coverageInfoList.size(), 10);
  117. // TODO populate two collections (positive/negative changes)?
  118. for (int i = 0; i < size; i++) {
  119. coverageChangeList.add(coverageInfoList.get(i));
  120. }
  121. results.put(NCoverBuildProcessor.NCOVER_COVERAGE_CHANGES,
  122. convertToCsv(coverageChangeList));
  123. }
  124. }
  125. /**
  126. * Converts a list of {@link NCoverCoverageInformation} into a CSV
  127. * format.
  128. *
  129. * @param coverageChangeList
  130. * @return String in CSV format
  131. */
  132. private String convertToCsv(
  133. List<NCoverCoverageInformation> coverageChangeList) {
  134. StringBuffer buffer = new StringBuffer();
  135. for (NCoverCoverageInformation information : coverageChangeList) {
  136. buffer.append(information.getClassName()).append(",");
  137. buffer.append(information.getLineRate()).append(",");
  138. buffer.append(information.getDelta());
  139. buffer.append(LINE_SEPARATOR);
  140. }
  141. return buffer.toString();
  142. }
  143. /**
  144. * Builds a Map of classes/line rates of the classes that were covered
  145. * in the NCover coverage report.
  146. *
  147. * @param csv
  148. * @return Map of class names/line rates
  149. */
  150. private Map<String, String> buildClassCoverageMap(String csv) {
  151. Map<String, String> map = new HashMap<String, String>();
  152. BufferedReader reader = new BufferedReader(new StringReader(csv));
  153. String line = null;
  154. try {
  155. while ((line = reader.readLine()) != null) {
  156. StringTokenizer token = new StringTokenizer(line, ",");
  157. String className = token.nextToken();
  158. String lineRate = token.nextToken();
  159. map.put(className, lineRate);
  160. }
  161. } catch (IOException e) {
  162. log.error("Error parsing csv", e);
  163. }
  164. return map;
  165. }
  166. // for test purposes only
  167. ResultsSummaryManager getResultsSummaryManager()
  168. {
  169. return resultsSummaryManager;
  170. }
  171. public void setResultsSummaryManager(ResultsSummaryManager resultsSummaryManager)
  172. {
  173. this.resultsSummaryManager = resultsSummaryManager;
  174. }
  175. }