Skip to content

Commit

Permalink
feat: Implement updated pull request comments (HTML and MD) (#578)
Browse files Browse the repository at this point in the history
* feat: Implement updated pull request comments (HTML and MD)

Signed-off-by: Oleg Kopysov <[email protected]>

* fix: updated comment messages after code review

Signed-off-by: Oleg Kopysov <[email protected]>

---------

Signed-off-by: Oleg Kopysov <[email protected]>
  • Loading branch information
o-kopysov authored Aug 30, 2024
1 parent ccc06c1 commit 006047b
Show file tree
Hide file tree
Showing 5 changed files with 471 additions and 213 deletions.
244 changes: 242 additions & 2 deletions src/main/java/com/lpvs/entity/report/LPVSReportBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ public String generateCommandLineComment(
long licenseDetected = prohibitedLicenses + restrictedLicenses + unreviewedLicenses;

if (licenseDetected > 0) {
commentBuilder.append(
"Potential license problem(s) detected: " + licenseDetected + "\n");
commentBuilder.append("Potential license issues detected: " + licenseDetected + "\n");
if (prohibitedLicenses > 0) {
commentBuilder.append(" - Prohibited license(s): " + prohibitedLicenses + "\n");
}
Expand Down Expand Up @@ -248,6 +247,247 @@ public static void saveHTMLToFile(String htmlContent, String filePath) {
}
}

/**
* Generates a comment to the pull request for publication to the VCS.
*
* @param scanResults the results of the license scan
* @param conflicts a list of license conflicts found during the scan
* @param webhookConfig configuration related to the repository and webhook
* @param vcs the string representation of the version control system
* @return the code of the generated VCS comment
*/
public String generatePullRequestComment(
List<LPVSFile> scanResults,
List<LPVSLicenseService.Conflict<String, String>> conflicts,
LPVSQueue webhookConfig,
LPVSVcs vcs) {

StringBuilder commitCommentBuilder = new StringBuilder();
commitCommentBuilder.append("**Detected Licenses:**\n\n");

Map<String, GroupInfo<?>> detectedLicenseInfo =
groupScanResultsForLicenseTable(scanResults);
long prohibitedLicenses = getDetectedLicenseCountByType(detectedLicenseInfo, prohibited);
long restrictedLicenses = getDetectedLicenseCountByType(detectedLicenseInfo, restricted);
long unreviewedLicenses = getDetectedLicenseCountByType(detectedLicenseInfo, unreviewed);
long licenseDetected = prohibitedLicenses + restrictedLicenses + unreviewedLicenses;

if (licenseDetected > 0) {
commitCommentBuilder.append("Potential license issues detected:\n");
if (prohibitedLicenses > 0) {
commitCommentBuilder.append(
" - Prohibited license(s): " + prohibitedLicenses + "\n");
}
if (restrictedLicenses > 0) {
commitCommentBuilder.append(
" - Restricted license(s): " + restrictedLicenses + "\n");
}
if (unreviewedLicenses > 0) {
commitCommentBuilder.append(
" - Unreviewed license(s): " + unreviewedLicenses + "\n");
}
} else {
commitCommentBuilder.append("No license problems detected.\n");
}
if (scanResults != null && !scanResults.isEmpty()) {
commitCommentBuilder
.append("\n")
.append(generateLicenseTable(detectedLicenseInfo, webhookConfig, vcs))
.append("\n");
}
commitCommentBuilder.append("\n");
commitCommentBuilder.append("**Detected License Conflicts:**\n\n");
if (conflicts != null && !conflicts.isEmpty()) {
commitCommentBuilder.append(
"Potential license conflict(s) detected: " + conflicts.size() + "\n");
commitCommentBuilder
.append("\n")
.append(generateLicenseConflictsTable(conflicts, vcs))
.append("\n");
} else {
commitCommentBuilder.append("No license conflicts detected.\n");
}
commitCommentBuilder.append("\n");

return commitCommentBuilder.toString();
}

/**
* Generates an HTML code of the license table to pull request comments
*
* @param detectedLicenseInfo grouped scan results by license SPDX ID and access type, component name and vendor
* @param webhookConfig configuration related to the repository and webhook
* @param vcs the string representation of the version control system
* @return the HTML code of the generated license table
*/
private String generateLicenseTable(
Map<String, GroupInfo<?>> detectedLicenseInfo, LPVSQueue webhookConfig, LPVSVcs vcs) {
if (vcs != null && vcs.equals(LPVSVcs.GITHUB)) {
return "<details>"
+ "\n"
+ "<summary>"
+ "Detailed description of detected licenses"
+ "\n"
+ "</summary>"
+ "\n"
+ generateLicenseTableHTML(detectedLicenseInfo, webhookConfig, vcs)
+ "\n"
+ "</details>";
}
return generateLicenseTableMD(detectedLicenseInfo, webhookConfig, vcs);
}

/**
* Generates an HTML code of the license conflicts table to pull request comments
*
* @param conflicts a list of license conflicts found during the scan
* @param vcs the string representation of the version control system
* @return the code of the generated license conflicts table
*/
private String generateLicenseConflictsTable(
List<LPVSLicenseService.Conflict<String, String>> conflicts, LPVSVcs vcs) {
if (vcs != null && vcs.equals(LPVSVcs.GITHUB)) {
return "<details>"
+ "\n"
+ "<summary>"
+ "Detailed description of detected license conflicts"
+ "\n"
+ "</summary>"
+ "\n"
+ generateLicenseConflictsTableHTML(conflicts)
+ "\n"
+ "</details>";
}
return generateLicenseConflictsTableMD(conflicts);
}

/**
* Generates an MD code of the license table to pull request comments
*
* @param detectedLicenseInfo grouped scan results by license SPDX ID and access type, component name and vendor
* @param webhookConfig configuration related to the repository and webhook
* @param vcs the string representation of the version control system
* @return the MD code of the generated license table
*/
private String generateLicenseTableMD(
Map<String, GroupInfo<?>> detectedLicenseInfo, LPVSQueue webhookConfig, LPVSVcs vcs) {
StringBuilder mdBuilder = new StringBuilder();
mdBuilder
.append("|License Type / Explanation")
.append("|License SPDX ID")
.append("|Vendor / Component")
.append("|Version")
.append("|Repository File Path")
.append("|Component File Path")
.append("|Matched Lines")
.append("|Match Value|")
.append("\n")
.append("|-|-|-|-|-|-|-|-|")
.append("\n");
// Prohibited licenses
addBlockOfTableForLicenseTypeMD(
mdBuilder, detectedLicenseInfo, prohibited, webhookConfig, vcs);
// Restricted licenses
addBlockOfTableForLicenseTypeMD(
mdBuilder, detectedLicenseInfo, restricted, webhookConfig, vcs);
// Unreviewed licenses
addBlockOfTableForLicenseTypeMD(
mdBuilder, detectedLicenseInfo, unreviewed, webhookConfig, vcs);
// Permitted licenses
addBlockOfTableForLicenseTypeMD(
mdBuilder, detectedLicenseInfo, permitted, webhookConfig, vcs);

return mdBuilder.toString();
}

/**
* Generates the license conflicts table MD content.
*
* @param conflicts a list of license conflicts
* @return the MD content for the license conflicts table
*/
private String generateLicenseConflictsTableMD(
List<LPVSLicenseService.Conflict<String, String>> conflicts) {
StringBuilder mdBuilder = new StringBuilder();
mdBuilder
.append("|Conflict>")
.append("|Explanation|")
.append("\n")
.append("|-|-|")
.append("\n");

for (LPVSLicenseService.Conflict<String, String> conflict : conflicts) {
mdBuilder
.append("|")
.append(conflict.l1)
.append(" and ")
.append(conflict.l2)
.append("|")
.append(getExplanationForLicenseConflict(conflict.l1, conflict.l2))
.append("|")
.append("\n");
}
return mdBuilder.toString();
}

/**
* Generates an MD code of the license conflicts table to pull request comments
*
* @param mdBuilder the StringBuilder object to which the MD content will be appended
* @param detectedLicenseInfo grouped scan results by license SPDX ID and access type, component name and vendor
* @param webhookConfig configuration related to the repository and webhook
* @param vcs the string representation of the version control system
*/
private void addBlockOfTableForLicenseTypeMD(
StringBuilder mdBuilder,
Map<String, GroupInfo<?>> detectedLicenseInfo,
String type,
LPVSQueue webhookConfig,
LPVSVcs vcs) {
long detectedLicenseCountByType = getDetectedLicenseCountByType(detectedLicenseInfo, type);
if (detectedLicenseCountByType > 0) {
// license spdx id
Map<String, GroupInfo<?>> licenseSpdxIds =
(Map<String, GroupInfo<?>>) detectedLicenseInfo.get(type).elements;
for (String licenseSpdxId : licenseSpdxIds.keySet()) {
// vendor + component
Map<String, GroupInfo<?>> componentAndVendor =
(Map<String, GroupInfo<?>>) licenseSpdxIds.get(licenseSpdxId).elements;
for (String componentInfo : componentAndVendor.keySet()) {
// file info
List<LPVSFile> fileInfos =
(List<LPVSFile>) componentAndVendor.get(componentInfo).elements;
for (LPVSFile fileInfo : fileInfos) {
mdBuilder
.append("|")
.append(type)
.append(" / ")
.append(getExplanationForLicenseType(type))
.append("|")
.append(licenseSpdxId)
.append("|")
.append(componentInfo.split(":::")[0])
.append(" (")
.append(componentInfo.split(":::")[1])
.append(")")
.append("|")
.append(fileInfo.getComponentVersion())
.append("|")
.append(fileInfo.getFilePath())
.append("|")
.append(fileInfo.getComponentFilePath())
.append("|")
.append(getMatchedLinesAsLink(webhookConfig, fileInfo, vcs))
.append("|")
.append(fileInfo.getSnippetMatch())
.append("|")
.append("\n");
}
}
}
}
}

/**
* Generates the license conflicts table HTML content.
*
Expand Down
59 changes: 16 additions & 43 deletions src/main/java/com/lpvs/service/LPVSGitHubService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
import com.lpvs.entity.LPVSQueue;
import com.lpvs.entity.enums.LPVSPullRequestStatus;
import com.lpvs.entity.enums.LPVSVcs;
import com.lpvs.entity.report.LPVSReportBuilder;
import com.lpvs.repository.LPVSDetectedLicenseRepository;
import com.lpvs.repository.LPVSLicenseConflictRepository;
import com.lpvs.repository.LPVSLicenseRepository;
import com.lpvs.repository.LPVSPullRequestRepository;
import com.lpvs.util.LPVSCommentUtil;
import com.lpvs.util.LPVSFileUtil;
import com.lpvs.util.LPVSPayloadUtil;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -176,7 +176,7 @@ public void setPendingCheck(LPVSQueue webhookConfig) {
GHCommitState.PENDING,
null,
"Scanning opensource licenses",
"[License Pre-Validation Service]");
"[LPVS]");
} catch (IOException | IllegalArgumentException e) {
log.error("Can't authorize setPendingCheck(): " + e.getMessage());
}
Expand All @@ -200,7 +200,7 @@ public void setErrorCheck(LPVSQueue webhookConfig) {
GHCommitState.ERROR,
null,
"Scanning process failed",
"[License Pre-Validation Service]");
"[LPVS]");
} catch (IOException | IllegalArgumentException e) {
log.error("Can't authorize setErrorCheck(): " + e.getMessage());
}
Expand Down Expand Up @@ -243,31 +243,19 @@ public void commentResults(
GHCommitState.SUCCESS,
null,
"Files are not found",
"[License Pre-Validation Service]");
"[LPVS]");
return;
}

boolean hasProhibitedOrRestricted = false;
boolean hasConflicts = false;
String commitComment = "";
LPVSReportBuilder reportBuilder = new LPVSReportBuilder(null);
String commitComment =
reportBuilder.generatePullRequestComment(
scanResults, conflicts, webhookConfig, LPVSVcs.GITHUB);

if (scanResults != null && scanResults.size() != 0) {
commitComment = "**Detected licenses:**\n\n\n";
if (scanResults != null && !scanResults.isEmpty()) {
for (LPVSFile file : scanResults) {
commitComment += "**File:** " + file.getFilePath() + "\n";
commitComment += "**License(s):** " + file.convertLicensesToString(LPVSVcs.GITHUB);
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";
for (LPVSLicense license : file.getLicenses()) {
LPVSDetectedLicense detectedIssue = new LPVSDetectedLicense();
detectedIssue.setPullRequest(lpvsPullRequest);
Expand Down Expand Up @@ -297,13 +285,9 @@ public void commentResults(
}
}

StringBuilder commitCommentBuilder = new StringBuilder();
if (conflicts != null && conflicts.size() > 0) {
if (conflicts != null && !conflicts.isEmpty()) {
hasConflicts = true;
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.setPullRequest(lpvsPullRequest);
Long l1 =
Expand All @@ -330,40 +314,29 @@ public void commentResults(
detectedIssue.setIssue(true);
lpvsDetectedLicenseRepository.saveAndFlush(detectedIssue);
}
commitCommentBuilder.append("</ul>");
}
if (null != webhookConfig.getHubLink()) {
commitCommentBuilder.append(
"\n\n###### <p align='right'>Check the validation details at the [link](");
commitCommentBuilder.append(webhookConfig.getHubLink());
commitCommentBuilder.append(")</p>");
}
commitComment += commitCommentBuilder.toString();

if (hasProhibitedOrRestricted || hasConflicts) {
lpvsPullRequest.setStatus(LPVSPullRequestStatus.ISSUES_DETECTED.toString());
pullRequestRepository.save(lpvsPullRequest);
pullRequest.comment(
"**\\[License Pre-Validation Service\\]** Potential license problem(s) detected \n\n"
+ commitComment);
"**\\[LPVS\\]** Potential license issues detected \n\n" + commitComment);
repository.createCommitStatus(
webhookConfig.getHeadCommitSHA(),
GHCommitState.FAILURE,
null,
"Potential license problem(s) detected",
"[License Pre-Validation Service]");
"Potential license issues detected",
"[LPVS]");
} else {
lpvsPullRequest.setStatus(LPVSPullRequestStatus.COMPLETED.toString());
pullRequestRepository.save(lpvsPullRequest);
pullRequest.comment(
"**\\[License Pre-Validation Service\\]** No license issue detected \n\n"
+ commitComment);
pullRequest.comment("**\\[LPVS\\]** No license issue detected \n\n" + commitComment);
repository.createCommitStatus(
webhookConfig.getHeadCommitSHA(),
GHCommitState.SUCCESS,
null,
"No license issue detected",
"[License Pre-Validation Service]");
"No license issues detected",
"[LPVS]");
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/report_single_scan.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ <h1><b>Report</b> - <b>L</b>icense <b>P</b>re-<b>V</b>alidation <b>S</b>ervice (
<hr>
<h3 class="ml-30">Detected Licenses</h3>
<div class="items" th:if="${licenseDetected} > 0">
<b>Potential license problem(s) detected:</b> <span th:text=${licenseDetected}>licenseDetected</span>
<b>Potential license issues detected:</b> <span th:text=${licenseDetected}>licenseDetected</span>
<ul>
<li th:if="${prohibitedLicenses} > 0">Prohibited license(s): <span th:text=${prohibitedLicenses}>prohibitedLicenses</span></li>
<li th:if="${restrictedLicenses} > 0">Restricted license(s): <span th:text=${restrictedLicenses}>restrictedLicenses</span></li>
Expand Down
Loading

0 comments on commit 006047b

Please sign in to comment.