You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

HtmlReport.java 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2016 SonarSource SA
  4. * mailto:contact AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.scanner.scan.report;
  21. import com.google.common.collect.Maps;
  22. import freemarker.template.Template;
  23. import java.io.File;
  24. import java.io.FileOutputStream;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.io.OutputStream;
  28. import java.io.OutputStreamWriter;
  29. import java.io.Writer;
  30. import java.net.URISyntaxException;
  31. import java.util.Map;
  32. import org.apache.commons.io.FileUtils;
  33. import org.apache.commons.io.IOUtils;
  34. import org.apache.commons.lang.StringUtils;
  35. import org.slf4j.Logger;
  36. import org.slf4j.LoggerFactory;
  37. import org.sonar.api.Properties;
  38. import org.sonar.api.Property;
  39. import org.sonar.api.PropertyType;
  40. import org.sonar.api.batch.fs.FileSystem;
  41. import org.sonar.api.config.Settings;
  42. @Properties({
  43. @Property(key = HtmlReport.HTML_REPORT_ENABLED_KEY, defaultValue = "false", name = "Enable HTML report", description = "Set this to true to generate an HTML report",
  44. type = PropertyType.BOOLEAN),
  45. @Property(key = HtmlReport.HTML_REPORT_LOCATION_KEY, defaultValue = HtmlReport.HTML_REPORT_LOCATION_DEFAULT, name = "HTML Report location",
  46. description = "Location of the generated report. Can be absolute or relative to working directory", project = false, global = false, type = PropertyType.STRING),
  47. @Property(key = HtmlReport.HTML_REPORT_NAME_KEY, defaultValue = HtmlReport.HTML_REPORT_NAME_DEFAULT, name = "HTML Report name",
  48. description = "Name of the generated report. Will be suffixed by .html or -light.html", project = false, global = false, type = PropertyType.STRING),
  49. @Property(key = HtmlReport.HTML_REPORT_LIGHTMODE_ONLY, defaultValue = "false", name = "Html report in light mode only",
  50. description = "Set this to true to only generate the new issues report (light report)", project = true, type = PropertyType.BOOLEAN)})
  51. public class HtmlReport implements Reporter {
  52. private static final Logger LOG = LoggerFactory.getLogger(HtmlReport.class);
  53. public static final String HTML_REPORT_ENABLED_KEY = "sonar.issuesReport.html.enable";
  54. public static final String HTML_REPORT_LOCATION_KEY = "sonar.issuesReport.html.location";
  55. public static final String HTML_REPORT_LOCATION_DEFAULT = "issues-report";
  56. public static final String HTML_REPORT_NAME_KEY = "sonar.issuesReport.html.name";
  57. public static final String HTML_REPORT_NAME_DEFAULT = "issues-report";
  58. public static final String HTML_REPORT_LIGHTMODE_ONLY = "sonar.issuesReport.lightModeOnly";
  59. private final Settings settings;
  60. private final FileSystem fs;
  61. private final IssuesReportBuilder builder;
  62. private final SourceProvider sourceProvider;
  63. private final RuleNameProvider ruleNameProvider;
  64. public HtmlReport(Settings settings, FileSystem fs, IssuesReportBuilder builder, SourceProvider sourceProvider, RuleNameProvider ruleNameProvider) {
  65. this.settings = settings;
  66. this.fs = fs;
  67. this.builder = builder;
  68. this.sourceProvider = sourceProvider;
  69. this.ruleNameProvider = ruleNameProvider;
  70. }
  71. @Override
  72. public void execute() {
  73. if (settings.getBoolean(HTML_REPORT_ENABLED_KEY)) {
  74. LOG.warn("HTML report is deprecated. Use SonarLint CLI to have local reports of issues");
  75. IssuesReport report = builder.buildReport();
  76. print(report);
  77. }
  78. }
  79. public void print(IssuesReport report) {
  80. File reportFileDir = getReportFileDir();
  81. String reportName = settings.getString(HTML_REPORT_NAME_KEY);
  82. if (!isLightModeOnly()) {
  83. File reportFile = new File(reportFileDir, reportName + ".html");
  84. LOG.debug("Generating HTML Report to: " + reportFile.getAbsolutePath());
  85. writeToFile(report, reportFile, true);
  86. LOG.info("HTML Issues Report generated: " + reportFile.getAbsolutePath());
  87. }
  88. File lightReportFile = new File(reportFileDir, reportName + "-light.html");
  89. LOG.debug("Generating Light HTML Report to: " + lightReportFile.getAbsolutePath());
  90. writeToFile(report, lightReportFile, false);
  91. LOG.info("Light HTML Issues Report generated: " + lightReportFile.getAbsolutePath());
  92. try {
  93. copyDependencies(reportFileDir);
  94. } catch (Exception e) {
  95. throw new IllegalStateException("Fail to copy HTML report resources to: " + reportFileDir, e);
  96. }
  97. }
  98. private File getReportFileDir() {
  99. String reportFileDirStr = settings.getString(HTML_REPORT_LOCATION_KEY);
  100. File reportFileDir = new File(reportFileDirStr);
  101. if (!reportFileDir.isAbsolute()) {
  102. reportFileDir = new File(fs.workDir(), reportFileDirStr);
  103. }
  104. if (StringUtils.endsWith(reportFileDirStr, ".html")) {
  105. LOG.warn("{} should indicate a directory. Using parent folder.", HTML_REPORT_LOCATION_KEY);
  106. reportFileDir = reportFileDir.getParentFile();
  107. }
  108. try {
  109. FileUtils.forceMkdir(reportFileDir);
  110. } catch (IOException e) {
  111. throw new IllegalStateException("Fail to create the directory " + reportFileDirStr, e);
  112. }
  113. return reportFileDir;
  114. }
  115. public void writeToFile(IssuesReport report, File toFile, boolean complete) {
  116. try {
  117. freemarker.log.Logger.selectLoggerLibrary(freemarker.log.Logger.LIBRARY_NONE);
  118. freemarker.template.Configuration cfg = new freemarker.template.Configuration();
  119. cfg.setClassForTemplateLoading(HtmlReport.class, "");
  120. Map<String, Object> root = Maps.newHashMap();
  121. root.put("report", report);
  122. root.put("ruleNameProvider", ruleNameProvider);
  123. root.put("sourceProvider", sourceProvider);
  124. root.put("complete", complete);
  125. Template template = cfg.getTemplate("issuesreport.ftl");
  126. try (FileOutputStream fos = new FileOutputStream(toFile); Writer writer = new OutputStreamWriter(fos, fs.encoding())) {
  127. template.process(root, writer);
  128. writer.flush();
  129. }
  130. } catch (Exception e) {
  131. throw new IllegalStateException("Fail to generate HTML Issues Report to: " + toFile, e);
  132. }
  133. }
  134. void copyDependencies(File toDir) throws URISyntaxException, IOException {
  135. File target = new File(toDir, "issuesreport_files");
  136. FileUtils.forceMkdir(target);
  137. // I don't know how to extract a directory from classpath, that's why an exhaustive list of files
  138. // is provided here :
  139. copyDependency(target, "sonar.eot");
  140. copyDependency(target, "sonar.svg");
  141. copyDependency(target, "sonar.ttf");
  142. copyDependency(target, "sonar.woff");
  143. copyDependency(target, "favicon.ico");
  144. copyDependency(target, "PRJ.png");
  145. copyDependency(target, "DIR.png");
  146. copyDependency(target, "FIL.png");
  147. copyDependency(target, "jquery.min.js");
  148. copyDependency(target, "sep12.png");
  149. copyDependency(target, "sonar.css");
  150. copyDependency(target, "sonarqube-24x100.png");
  151. }
  152. private void copyDependency(File target, String filename) {
  153. try (InputStream input = getClass().getResourceAsStream("/org/sonar/scanner/scan/report/issuesreport_files/" + filename);
  154. OutputStream output = new FileOutputStream(new File(target, filename))) {
  155. IOUtils.copy(input, output);
  156. } catch (IOException e) {
  157. throw new IllegalStateException("Fail to copy file " + filename + " to " + target, e);
  158. }
  159. }
  160. public boolean isLightModeOnly() {
  161. return settings.getBoolean(HTML_REPORT_LIGHTMODE_ONLY);
  162. }
  163. }