org.sonarlint.cli.report.HtmlReport.java Source code

Java tutorial

Introduction

Here is the source code for org.sonarlint.cli.report.HtmlReport.java

Source

/*
 * SonarLint CLI
 * Copyright (C) 2016-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonarlint.cli.report;

import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.apache.commons.io.FileUtils;
import org.sonarlint.cli.util.Logger;
import org.sonarlint.cli.util.Util;
import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;
import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;

public class HtmlReport implements Reporter {
    private static final Logger LOGGER = Logger.get();
    private final Path reportFile;
    private final Path reportDir;
    private final Charset charset;
    private final Path basePath;

    HtmlReport(Path basePath, Path reportFile, Charset charset) {
        this.basePath = basePath;
        this.charset = charset;
        this.reportDir = reportFile.getParent().toAbsolutePath();
        this.reportFile = reportFile.toAbsolutePath();
    }

    @Override
    public void execute(String projectName, Date date, List<Issue> issues, AnalysisResults result,
            Function<String, RuleDetails> ruleDescriptionProducer) {
        IssuesReport report = new IssuesReport(basePath, charset);
        for (Issue i : issues) {
            report.addIssue(i);
        }
        report.setTitle(projectName);
        report.setDate(date);
        report.setFilesAnalyzed(result.fileCount());
        copyRuleHtmlDescriptions(ruleDescriptionProducer, report);
        print(report);
    }

    private void copyRuleHtmlDescriptions(Function<String, RuleDetails> ruleDescriptionProducer,
            IssuesReport report) {
        try {
            Set<String> ruleKeys = report.getSummary().getTotalByRuleKey().keySet();
            Path target = reportDir.resolve("sonarlintreport_rules");
            Files.createDirectories(target);
            copyDependency(target, "rule.css");
            for (String ruleKey : ruleKeys) {
                RuleDetails ruleDetails = ruleDescriptionProducer.apply(ruleKey);
                FileUtils.write(target.resolve(Util.escapeFileName(ruleKey) + ".html").toFile(),
                        "<!doctype html><html><head><link href=\"rule.css\" rel=\"stylesheet\" type=\"text/css\" /></head><body><h1><big>"
                                + ruleDetails.getName() + "</big> (" + ruleKey + ")</h1><div class=\"rule-desc\">"
                                + ruleDetails.getHtmlDescription() + "</div></body></html>",
                        StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            throw new IllegalStateException("Unable to copy rule descriptions", e);
        }
    }

    public void print(IssuesReport report) {
        LOGGER.debug("Generating SonarLint Report to: " + reportFile);
        writeToFile(report, reportFile);
        LOGGER.info("SonarLint HTML Report generated: " + reportFile);
        try {
            copyDependencies(reportDir);
        } catch (Exception e) {
            throw new IllegalStateException("Fail to copy HTML report resources to: " + reportDir, e);
        }
    }

    private static void writeToFile(IssuesReport report, Path toFile) {
        try {
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_25);
            cfg.setClassForTemplateLoading(HtmlReport.class, "");

            Map<String, Object> root = new HashMap<>();
            root.put("report", report);

            Template template = cfg.getTemplate("sonarlintreport.ftl");

            try (FileOutputStream fos = new FileOutputStream(toFile.toFile());
                    Writer writer = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
                template.process(root, writer);
                writer.flush();
            }
        } catch (Exception e) {
            throw new IllegalStateException("Fail to generate HTML Issues Report to: " + toFile, e);
        }
    }

    private void copyDependencies(Path toDir) throws URISyntaxException, IOException {
        Path target = toDir.resolve("sonarlintreport_files");
        Files.createDirectories(target);

        // I don't know how to extract a directory from classpath, that's why an exhaustive list of files is provided here :
        copyDependency(target, "sonar.eot");
        copyDependency(target, "sonar.svg");
        copyDependency(target, "sonar.ttf");
        copyDependency(target, "sonar.woff");
        copyDependency(target, "favicon.ico");
        copyDependency(target, "PRJ.png");
        copyDependency(target, "DIR.png");
        copyDependency(target, "FIL.png");
        copyDependency(target, "jquery.min.js");
        copyDependency(target, "sep12.png");
        copyDependency(target, "sonar.css");
        copyDependency(target, "sonarlint.png");
    }

    private void copyDependency(Path target, String filename) {
        String resource = "sonarlintreport_files/" + filename;
        try (InputStream in = getClass().getResourceAsStream(resource)) {
            Files.copy(in, target.resolve(filename), StandardCopyOption.REPLACE_EXISTING);

        } catch (IOException e) {
            throw new IllegalStateException("Fail to copy file " + filename + " to " + target, e);
        }
    }
}