PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/atlassian/bamboo-dotnet-plugin/
Java | 288 lines | 191 code | 44 blank | 53 comment | 27 complexity | 647e2158b78b83dd23aa2ae62a3afe1e MD5 | raw file
Possible License(s): BSD-3-Clause
  1. package com.atlassian.bamboo.plugin.dotnet.ncover;
  2. import com.atlassian.bamboo.build.CustomBuildProcessor;
  3. import com.atlassian.bamboo.build.fileserver.BuildDirectoryManager;
  4. import com.atlassian.bamboo.resultsummary.BuildResultsSummary;
  5. import com.atlassian.bamboo.resultsummary.ResultsSummaryManager;
  6. import com.atlassian.bamboo.util.NumberUtils;
  7. import com.atlassian.bamboo.utils.FileVisitor;
  8. import com.atlassian.bamboo.utils.error.ErrorCollection;
  9. import com.atlassian.bamboo.utils.error.SimpleErrorCollection;
  10. import com.atlassian.bamboo.v2.build.BaseConfigurableBuildPlugin;
  11. import com.atlassian.bamboo.v2.build.BuildContext;
  12. import com.atlassian.bamboo.v2.build.BuildContextHelper;
  13. import com.atlassian.bamboo.v2.build.CommonContext;
  14. import com.atlassian.bamboo.v2.build.CurrentBuildResult;
  15. import com.atlassian.bamboo.ww2.actions.build.admin.create.BuildConfiguration;
  16. import org.apache.commons.lang3.StringUtils;
  17. import org.apache.log4j.Logger;
  18. import java.io.File;
  19. import java.io.FileNotFoundException;
  20. import java.text.NumberFormat;
  21. import java.util.HashMap;
  22. import java.util.Map;
  23. /**
  24. * Handles parsing NCover report files, and stores the coverage results within
  25. * the specific {@link BuildResultsSummary} custom data.
  26. *
  27. * @author Ross Rowe
  28. */
  29. public class NCoverBuildProcessor extends BaseConfigurableBuildPlugin implements
  30. CustomBuildProcessor {
  31. private static final Logger log = Logger
  32. .getLogger(NCoverBuildProcessor.class);
  33. private static final String NCOVER_PATH = "custom.ncover.path";
  34. public static final String NCOVER_EXISTS = "custom.ncover.exists";
  35. public static final String NCOVER_XML_PATH_KEY = NCOVER_PATH;
  36. public static final String NCOVER_LINE_COVERAGE = "NCOVER_LINE_COVERAGE";
  37. public static final String NCOVER_ASSEMBLIES = "NCOVER_ASSEMBLIES";
  38. public static final String NCOVER_LOC = "NCOVER_LOC";
  39. public static final String NCOVER_LE = "NCOVER_LE";
  40. public static final String NCOVER_LNE = "NCOVER_LNE";
  41. public static final String NCOVER_COVERAGE_DELTA = "NCOVER_COVERAGE_DELTA";
  42. public static final String NCOVER_RESULT_CONTENTS = "NCOVER_RESULT_CONTENTS";
  43. public static final String NCOVER_METHODS = "NCOVER_METHODS";
  44. public static final String NCOVER_CLASSES = "NCOVER_CLASSES";
  45. public static final String NCOVER_COVERAGE_CHANGES = "NCOVER_COVERAGE_CHANGES";
  46. public static final String NCOVER_LINE_RATE = "NCOVER_LINE_RATE";
  47. public static final String LINE_SEPARATOR = System
  48. .getProperty("line.separator");
  49. private BuildDirectoryManager buildDirectoryManager;
  50. private ResultsSummaryManager resultsSummaryManager;
  51. public static final String BUILD_NUMBER = "buildNumber";
  52. public static final String BUILD_KEY = "buildKey";
  53. public static final String NCOVER_POSTBUILD_XMPP = "custom.bamboo.ncover.postbuild.xmpp";
  54. public static final String NCOVER_POSTBUILD_THRESHOLD = "threshold";
  55. public static final String NCOVER_POSTBUILD_EMAIL = "custom.bamboo.ncover.postbuild.email";
  56. public static final String NCOVER_POSTBUILD = "custom.bamboo.ncover.postbuild";
  57. /**
  58. * {@link FileVisitor} subclass that handles identifying and parsing NCover
  59. * report files.
  60. *
  61. * @author Ross Rowe
  62. */
  63. private final class NCoverCoverageFileVisitor extends FileVisitor {
  64. private final Map<String, String> results;
  65. private final CurrentBuildResult buildResults;
  66. /**
  67. * Constructs a NCoverCoverageFileVisitor.
  68. *
  69. * @param file
  70. * @param results
  71. * @param buildResult
  72. */
  73. private NCoverCoverageFileVisitor(File file,
  74. Map<String, String> results, CurrentBuildResult buildResult) {
  75. super(file);
  76. this.results = results;
  77. this.buildResults = buildResult;
  78. }
  79. /**
  80. * Run the parse over the <code>file</code> if the <code>file</code>'s
  81. * name ends with 'xml'.
  82. *
  83. * @param file
  84. * file being visted
  85. */
  86. @Override
  87. public void visitFile(File file) {
  88. if (file.getName().endsWith("xml")) {
  89. runParse(file);
  90. }
  91. }
  92. /**
  93. * Parses the NCover XML report file.
  94. *
  95. * @param file
  96. */
  97. private void runParse(final File file) {
  98. try {
  99. log.info("Parsing file: " + file.getAbsolutePath());
  100. NCoverReportParser parser = new NCoverReportParser();
  101. parser.parse(file);
  102. storeResultsFromParser(parser);
  103. } catch (Exception e) {
  104. log.error("Failed to parse artifact result file \""
  105. + file.getName() + "\"", e);
  106. }
  107. }
  108. /**
  109. * Stores the variables from the {@link NCoverReportParser} instance
  110. * within the <code>results</code> map.
  111. *
  112. * @param parser
  113. * Report File parser
  114. * @throws FileNotFoundException
  115. * if we can't find the file
  116. */
  117. private void storeResultsFromParser(NCoverReportParser parser)
  118. throws FileNotFoundException {
  119. double coverage = NumberUtils.round(parser.getLineRate() * 100, 4);
  120. // store CSV instead of XML to cut down on the file size (the
  121. // CUSTOM_INFO_DATA column of the BUILDRESULTSUMMARY_CUSTOMDATA
  122. // table has a 4000 character limit)
  123. NumberFormat defaultFormat = NumberFormat.getInstance();
  124. appendResults(NCOVER_RESULT_CONTENTS, parser.getCsv());
  125. appendDoubleResults(NCOVER_LINE_RATE, defaultFormat
  126. .format(coverage));
  127. appendLongResults(NCOVER_METHODS, Long
  128. .toString(parser.getMethods()));
  129. appendLongResults(NCOVER_CLASSES, Long
  130. .toString(parser.getClasses()));
  131. appendLongResults(NCOVER_ASSEMBLIES, Long.toString(parser
  132. .getAssemblies()));
  133. appendLongResults(NCOVER_LOC, Long
  134. .toString(parser.getLinesOfCode()));
  135. appendLongResults(NCOVER_LE, Long.toString(parser
  136. .getLinesExecuted()));
  137. appendLongResults(NCOVER_LNE, Long.toString(parser
  138. .getLinesNotExecuted()));
  139. }
  140. private void appendResults(String key, String results) {
  141. log.debug("Appending " + results + " to " + key);
  142. String existingResults = this.results.get(key);
  143. if (existingResults == null)
  144. existingResults = "";
  145. if (results == null)
  146. results = "";
  147. String newValue = existingResults + results;
  148. this.results.put(key, newValue);
  149. }
  150. private void appendLongResults(String key, String results) {
  151. log.debug("Appending " + results + " to " + key);
  152. String existingResults = this.results.get(key);
  153. if (existingResults == null || existingResults.equals(""))
  154. existingResults = Long.toString(0);
  155. if (results == null || results.equals(""))
  156. results = Long.toString(0);
  157. Long newValue = NumberUtils.stringToLong(existingResults)
  158. + NumberUtils.stringToLong(results);
  159. NumberFormat defaultFormat = NumberFormat.getInstance();
  160. this.results.put(key, defaultFormat.format(newValue));
  161. }
  162. private void appendDoubleResults(String key, String results) {
  163. log.debug("Appending " + results + " to " + key);
  164. boolean storeAverage = true;
  165. String existingResults = this.results.get(key);
  166. if (existingResults == null || existingResults.equals("")) {
  167. existingResults = Double.toString(0);
  168. storeAverage = false;
  169. }
  170. if (results == null || results.equals(""))
  171. results = Double.toString(0);
  172. Double newValue = NumberUtils.stringToDouble(existingResults)
  173. + NumberUtils.stringToDouble(results);
  174. if (storeAverage)
  175. newValue = newValue / 2;
  176. NumberFormat defaultFormat = NumberFormat.getInstance();
  177. this.results.put(key, defaultFormat.format(newValue));
  178. }
  179. }
  180. /**
  181. * Validates whether the <code>configuration</code> is valid.
  182. *
  183. * @param configuration
  184. */
  185. @Override
  186. public ErrorCollection validate(BuildConfiguration configuration) {
  187. ErrorCollection ec = new SimpleErrorCollection();
  188. if (configuration.getBoolean(NCOVER_EXISTS)
  189. && StringUtils.isBlank(configuration.getString(NCOVER_PATH))) {
  190. ec
  191. .addError(NCOVER_PATH,
  192. "Please specify the directory containing the XML NCover output files.");
  193. }
  194. return ec;
  195. }
  196. /**
  197. * Processes the build results to run the {@link NCoverReportParser} over
  198. * the result files, and stores the NCover results within the
  199. * <code>buildResult</code>'s customBuildData.
  200. */
  201. @Override
  202. public BuildContext call() throws InterruptedException, Exception {
  203. log.info("inside NCoverBuildProcessor.call()");
  204. final Map<String, String> ncoverResults = new HashMap<String, String>();
  205. CurrentBuildResult buildResult = buildContext.getBuildResult();
  206. if (buildResult != null) {
  207. final Map<String, String> customConfiguration = buildContext.getBuildDefinition()
  208. .getCustomConfiguration();
  209. if (Boolean.parseBoolean(customConfiguration.get(NCOVER_EXISTS)) && customConfiguration.containsKey(NCOVER_XML_PATH_KEY)) {
  210. String pathPattern = (String) customConfiguration
  211. .get(NCOVER_XML_PATH_KEY);
  212. if (!StringUtils.isEmpty(pathPattern)) {
  213. File planSourceDirectory = BuildContextHelper.getBuildWorkingDirectory((CommonContext)buildContext);
  214. FileVisitor fileVisitor = new NCoverCoverageFileVisitor(
  215. planSourceDirectory, ncoverResults, buildResult);
  216. log.info("Running NCover Build Processor over source dir:"
  217. + planSourceDirectory.getAbsolutePath()
  218. + " path pattern: " + pathPattern);
  219. fileVisitor.visitFilesThatMatch(pathPattern);
  220. if (ncoverResults.isEmpty()) {
  221. log
  222. .error("Could not find any NCover results in source dir:"
  223. + planSourceDirectory.getAbsolutePath()
  224. + " path pattern: " + pathPattern);
  225. } else {
  226. buildResult.getCustomBuildData().putAll(ncoverResults);
  227. }
  228. }
  229. }
  230. }
  231. return buildContext;
  232. }
  233. public BuildDirectoryManager getBuildDirectoryManager() {
  234. return buildDirectoryManager;
  235. }
  236. public void setBuildDirectoryManager(
  237. BuildDirectoryManager buildDirectoryManager) {
  238. this.buildDirectoryManager = buildDirectoryManager;
  239. }
  240. public void setResultsSummaryManager(ResultsSummaryManager resultsSummaryManager)
  241. {
  242. this.resultsSummaryManager = resultsSummaryManager;
  243. }
  244. }