Skip to content

Commit

Permalink
feat: Generate html report for single scan mode (#358)
Browse files Browse the repository at this point in the history
* doc: add command description to readme

Signed-off-by: Mykola Rudyk <[email protected]>

* feat: add html reporting option

Signed-off-by: Mykola Rudyk <[email protected]>

* fix: fix style errors

Signed-off-by: Mykola Rudyk <[email protected]>

* fix: apply changes after review comment

Signed-off-by: Mykola Rudyk <[email protected]>

* test: udpate unit tests

Signed-off-by: Mykola Rudyk <[email protected]>

* doc: add javadoc description

Signed-off-by: Mykola Rudyk <[email protected]>

---------

Signed-off-by: Mykola Rudyk <[email protected]>
Signed-off-by: m-rudyk <[email protected]>
  • Loading branch information
m-rudyk authored Dec 18, 2023
1 parent 6298473 commit 2cfc37e
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 32 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@ Alternatively, you can perform a one-time scan on a specific pull request using

These steps streamline the process, allowing you to run a scan on a single pull request without the need for a preconfigured database.

4.b.4. Available option to generate an HTML report and save it in a specified folder. Replace `/path/to/your/folder` with the full path to the folder where you want to save the HTML report, and `your_report_filename.html` with the desired filename for the report.
```bash
java -jar -Dgithub.token=<my-token> lpvs-*.jar --github.pull.request=<PR URL> --build.html.report=</path/to/your/folder/your_report_filename.html>
```

These steps streamline the process, allowing you to run a scan on a single pull request without the need for a preconfigured database.

---

## Frontend Source Code (React)
Expand Down
60 changes: 49 additions & 11 deletions src/main/java/com/lpvs/service/LPVSDetectService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import com.lpvs.entity.LPVSFile;
import com.lpvs.entity.LPVSQueue;
import com.lpvs.service.scanner.scanoss.LPVSScanossDetectService;
import com.lpvs.util.LPVSCommentUtil;
import com.lpvs.util.LPVSFileUtil;
import com.nimbusds.jose.util.IOUtils;

import lombok.extern.slf4j.Slf4j;
import org.kohsuke.github.GHPullRequest;
Expand All @@ -28,8 +28,10 @@

import javax.annotation.PostConstruct;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand All @@ -56,6 +58,11 @@ public class LPVSDetectService {
*/
private LPVSGitHubConnectionService gitHubConnectionService;

/**
* Service responsible for license conflict analysis.
*/
private LPVSLicenseService licenseService;

/**
* Event publisher for triggering application events.
*/
Expand All @@ -67,6 +74,12 @@ public class LPVSDetectService {
@Value("${github.pull.request:}")
private String trigger;

/**
* Optional parameter to save html report to specified location.
*/
@Value("${build.html.report:}")
private String htmlReport;

/**
* Spring application context.
*/
Expand All @@ -83,10 +96,12 @@ public class LPVSDetectService {
public LPVSDetectService(
@Value("${scanner:scanoss}") String scannerType,
LPVSGitHubConnectionService gitHubConnectionService,
LPVSScanossDetectService scanossDetectService) {
LPVSScanossDetectService scanossDetectService,
LPVSLicenseService licenseService) {
this.scannerType = scannerType;
this.gitHubConnectionService = gitHubConnectionService;
this.scanossDetectService = scanossDetectService;
this.licenseService = licenseService;
}

/**
Expand All @@ -102,20 +117,43 @@ private void init() {
*/
@EventListener(ApplicationReadyEvent.class)
public void runOneScan() {
log.info("Triggered signle scan operation");
if (trigger != null && !HtmlUtils.htmlEscape(trigger).equals("")) {
try {
LPVSQueue webhookConfig =
this.getInternalQueueByPullRequest(HtmlUtils.htmlEscape(trigger));
this.runScan(webhookConfig, LPVSDetectService.getPathByPullRequest(webhookConfig));
File scanResult = new File(LPVSFileUtil.getScanResultsJsonFilePath(webhookConfig));
if (scanResult.exists()) {
String jsonTxt = IOUtils.readFileToString(scanResult);
// ToDo: form html report and console output
log.info(jsonTxt);
log.info("\n\n\n Single scan finished successfully \n\n\n");

List<LPVSFile> scanResult =
this.runScan(
webhookConfig,
LPVSDetectService.getPathByPullRequest(webhookConfig));

List<LPVSLicenseService.Conflict<String, String>> detectedConflicts =
licenseService.findConflicts(webhookConfig, scanResult);

if (htmlReport != null && !HtmlUtils.htmlEscape(htmlReport).equals("")) {
Path buildReportPath = Paths.get(htmlReport);
Path parentDirectory = buildReportPath.getParent();

if (parentDirectory != null && Files.isDirectory(parentDirectory)) {
String report =
LPVSCommentUtil.buildHTMLComment(
webhookConfig, scanResult, detectedConflicts);
LPVSCommentUtil.saveHTMLToFile(report, buildReportPath.toString());
} else {
log.error(
"Error: The parent directory '"
+ parentDirectory
+ "' does not exist.");
}
} else {
String report =
LPVSCommentUtil.reportCommentBuilder(
webhookConfig, scanResult, detectedConflicts);
log.info(report);
}
} catch (Exception ex) {
log.info("\n\n\n Single scan finished with errors \n\n\n");
log.error("\n\n\n Single scan finished with errors \n\n\n");
log.error("Can't triger single scan " + ex);
}
// exiting application
Expand Down
148 changes: 148 additions & 0 deletions src/main/java/com/lpvs/util/LPVSCommentUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@
*/
package com.lpvs.util;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import com.lpvs.entity.LPVSDetectedLicense;
import com.lpvs.entity.LPVSFile;
import com.lpvs.entity.LPVSQueue;
import com.lpvs.entity.enums.LPVSVcs;
import com.lpvs.service.LPVSLicenseService;

import lombok.extern.slf4j.Slf4j;

/**
Expand Down Expand Up @@ -66,4 +74,144 @@ public static String getMatchedLinesAsLink(
log.debug("MatchedLines: " + matchedLines);
return matchedLines;
}

/**
* Generates a formatted string for LPVS github comment.
*
* @param webhookConfig The {@link LPVSQueue} configuration for the webhook.
* @param scanResults The List<{@link LPVSFile}> contain preformatted scan results.
* @param conflicts The List<{@link LPVSLicenseService}.Conflict<String, String>> contain license conflict information.
* @return A string containing scan result in github friendly format.
*/
public static String reportCommentBuilder(
LPVSQueue webhookConfig,
List<LPVSFile> scanResults,
List<LPVSLicenseService.Conflict<String, String>> conflicts) {
String commitComment = "";

if (scanResults != null && scanResults.size() != 0) {
commitComment = "**Detected licenses:**\n\n\n";
for (LPVSFile file : scanResults) {
commitComment += "**File:** " + file.getFilePath() + "\n";
commitComment +=
"**License(s):** " + file.convertLicensesToString(LPVSVcs.GITHUB) + "\n";
commitComment +=
"**Component:** "
+ file.getComponentName()
+ " ("
+ file.getComponentFilePath()
+ ")\n";
commitComment +=
"**Matched Lines:** "
+ LPVSCommentUtil.getMatchedLinesAsLink(
webhookConfig, file, LPVSVcs.GITHUB)
+ "\n";
commitComment += "**Snippet Match:** " + file.getSnippetMatch() + "\n\n\n\n";
}
}

if (conflicts != null && conflicts.size() > 0) {
StringBuilder commitCommentBuilder = new StringBuilder();
commitCommentBuilder.append("**Detected license conflicts:**\n\n\n");
commitCommentBuilder.append("<ul>");
for (LPVSLicenseService.Conflict<String, String> conflict : conflicts) {
commitCommentBuilder.append("<li>" + conflict.l1 + " and " + conflict.l2 + "</li>");
LPVSDetectedLicense detectedIssue = new LPVSDetectedLicense();
detectedIssue.setIssue(true);
}
commitCommentBuilder.append("</ul>");
if (null != webhookConfig.getHubLink()) {
commitCommentBuilder.append("(");
commitCommentBuilder.append(webhookConfig.getHubLink());
commitCommentBuilder.append(")");
}
commitComment += commitCommentBuilder.toString();
}

return commitComment;
}

/**
* Generates a formatted string for html report with scan results.
*
* @param webhookConfig The {@link LPVSQueue} configuration for the webhook.
* @param scanResults The List<{@link LPVSFile}> contain preformatted scan results.
* @param conflicts The List<{@link LPVSLicenseService}.Conflict<String, String>> contain license conflict information.
* @return A string containing scan result in html format.
*/
public static String buildHTMLComment(
LPVSQueue webhookConfig,
List<LPVSFile> scanResults,
List<LPVSLicenseService.Conflict<String, String>> conflicts) {
StringBuilder htmlBuilder = new StringBuilder();

htmlBuilder.append("<html><body>");

if (scanResults != null && scanResults.size() != 0) {
htmlBuilder.append("<h2>Detected licenses:</h2>");
for (LPVSFile file : scanResults) {
htmlBuilder
.append("<p><strong>File:</strong> ")
.append(file.getFilePath())
.append("</p>");
htmlBuilder
.append("<p><strong>License(s):</strong> ")
.append(file.convertLicensesToString(LPVSVcs.GITHUB))
.append("</p>");
htmlBuilder
.append("<p><strong>Component:</strong> ")
.append(file.getComponentName())
.append(" (")
.append(file.getComponentFilePath())
.append(")</p>");
htmlBuilder
.append("<p><strong>Matched Lines:</strong> ")
.append(
LPVSCommentUtil.getMatchedLinesAsLink(
webhookConfig, file, LPVSVcs.GITHUB))
.append("</p>");
htmlBuilder
.append("<p><strong>Snippet Match:</strong> ")
.append(file.getSnippetMatch())
.append("</p>");
htmlBuilder.append("<hr>");
}
}

if (conflicts != null && conflicts.size() > 0) {
htmlBuilder.append("<h2>Detected license conflicts:</h2>");
htmlBuilder.append("<ul>");
for (LPVSLicenseService.Conflict<String, String> conflict : conflicts) {
htmlBuilder
.append("<li>")
.append(conflict.l1)
.append(" and ")
.append(conflict.l2)
.append("</li>");
}
htmlBuilder.append("</ul>");
if (webhookConfig.getHubLink() != null) {
htmlBuilder.append("<p>").append(webhookConfig.getHubLink()).append("</p>");
}
}

htmlBuilder.append("</body></html>");

return htmlBuilder.toString();
}

/**
* Saves HTML report to given location.
*
* @param htmlContent The string, containing report in HTML format.
* @param scanResults The path to expected html report file.
*/
public static void saveHTMLToFile(String htmlContent, String filePath) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
writer.write(htmlContent);
log.info("LPVS report saved to: " + filePath);
} catch (IOException ex) {
log.error("error during saving HTML report: " + ex);
}
}
}
Loading

0 comments on commit 2cfc37e

Please sign in to comment.