Skip to content

Commit

Permalink
Provide JSON as an option to generate report (#972)
Browse files Browse the repository at this point in the history
  • Loading branch information
sourabhsparkala authored Aug 15, 2023
1 parent bf9dc06 commit cefb871
Show file tree
Hide file tree
Showing 13 changed files with 1,067 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,8 @@ private static void checkOptionsIn(CommandLine commandLine) {
}

if (commandLine.hasOption("report-type")
&& !asList("text", "markdown").contains(commandLine.getOptionValue("report-type"))) {
&& !asList("text", "markdown", "json").contains(
commandLine.getOptionValue("report-type"))) {

throw new IllegalArgumentException(
format("Unknown report type: %s", commandLine.getOptionValue("report-type")));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
import com.sap.oss.phosphor.fosstars.model.rating.oss.OssSecurityRating;
import com.sap.oss.phosphor.fosstars.model.subject.oss.GitHubProject;
import com.sap.oss.phosphor.fosstars.tool.format.Formatter;
import com.sap.oss.phosphor.fosstars.tool.format.JsonPrettyPrinter;
import com.sap.oss.phosphor.fosstars.tool.format.OssSecurityRatingMarkdownFormatter;
import com.sap.oss.phosphor.fosstars.tool.format.PrettyPrinter;
import com.sap.oss.phosphor.fosstars.tool.report.MergedJsonReporter;
import com.sap.oss.phosphor.fosstars.tool.report.OssSecurityRatingJsonReporter;
import com.sap.oss.phosphor.fosstars.tool.report.OssSecurityRatingMarkdownReporter;
import com.sap.oss.phosphor.fosstars.tool.report.Reporter;
import java.io.File;
Expand Down Expand Up @@ -177,6 +179,8 @@ Formatter createFormatter(String type) {
return PrettyPrinter.withVerboseOutput(OSS_SECURITY_GITHUB_ADVISOR);
case "markdown":
return new OssSecurityRatingMarkdownFormatter(OSS_SECURITY_GITHUB_ADVISOR);
case "json":
return new JsonPrettyPrinter(OSS_SECURITY_GITHUB_ADVISOR);
default:
throw new IllegalArgumentException(format("Unsupported report type: %s", type));
}
Expand All @@ -192,6 +196,10 @@ Optional<Reporter<GitHubProject>> reporterFrom(ReportConfig reportConfig) throws
return Optional.of(
new OssSecurityRatingMarkdownReporter(reportConfig.where, reportConfig.source,
rating(), OSS_SECURITY_GITHUB_ADVISOR));
case JSON_REPORT:
return Optional.of(
new OssSecurityRatingJsonReporter(reportConfig.where, reportConfig.source,
rating(), OSS_SECURITY_GITHUB_ADVISOR));
default:
logger.warn("Oops! That's an unknown type of report: {}", reportConfig.type);
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ReportConfig {
* Types of reports.
*/
public enum ReportType {
MARKDOWN, JSON, ISSUES
MARKDOWN, JSON, ISSUES, JSON_REPORT
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.sap.oss.phosphor.fosstars.tool.format.Markdown.DOUBLE_NEW_LINE;
import static com.sap.oss.phosphor.fosstars.tool.format.Markdown.NEW_LINE;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;

import com.sap.oss.phosphor.fosstars.advice.Advice;
Expand All @@ -29,12 +30,20 @@
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* A base class for Markdown formatters.
*/
public abstract class AbstractMarkdownFormatter extends CommonFormatter {

/**
* A logger.
*/
private static final Logger LOGGER
= LogManager.getLogger(AbstractMarkdownFormatter.class);

/**
* Create a new formatter.
*
Expand Down Expand Up @@ -67,7 +76,7 @@ protected MarkdownElement markdownAdviceFor(Subject subject) {
throw new UncheckedIOException("Oops! Could not print advice!", e);
}

if (adviceList.isEmpty()) {
if (adviceList == null || adviceList.isEmpty()) {
return MarkdownString.EMPTY;
}

Expand All @@ -85,6 +94,21 @@ protected MarkdownElement markdownAdviceFor(Subject subject) {
return Markdown.section().with(markdownAdviceHeader()).thatContains(advice);
}

/**
* Extract advices for a subject.
*
* @param subject The subject.
* @return Advices collected form a subject.
*/
protected List<Advice> adviceFor(Subject subject) {
try {
return advisor.adviceFor(subject);
} catch (IOException e) {
LOGGER.warn("Oops! Could not collect advices!", e);
return emptyList();
}
}

/**
* Convert links from advice to Markdown elements.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package com.sap.oss.phosphor.fosstars.tool.format;

import static java.util.Collections.emptyList;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sap.oss.phosphor.fosstars.advice.Advice;
import com.sap.oss.phosphor.fosstars.advice.AdviceContent;
import com.sap.oss.phosphor.fosstars.advice.Advisor;
import com.sap.oss.phosphor.fosstars.model.Subject;
import com.sap.oss.phosphor.fosstars.model.Value;
import com.sap.oss.phosphor.fosstars.model.value.RatingValue;
import com.sap.oss.phosphor.fosstars.model.value.ScoreValue;
import com.sap.oss.phosphor.fosstars.tool.format.model.Advices;
import com.sap.oss.phosphor.fosstars.tool.format.model.Feature;
import com.sap.oss.phosphor.fosstars.tool.format.model.Rating;
import com.sap.oss.phosphor.fosstars.tool.format.model.Score;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.text.DecimalFormat;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* The class prints a pretty rating value in JSON.
*/
public class JsonPrettyPrinter extends CommonFormatter {

/**
* Object Mapper for Json.
*/
private static final ObjectMapper mapper = new ObjectMapper();

/**
* A logger.
*/
private static final Logger LOGGER
= LogManager.getLogger(JsonPrettyPrinter.class);

/**
* A formatter for doubles.
*/
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.#");

static {
DECIMAL_FORMAT.setMinimumFractionDigits(1);
DECIMAL_FORMAT.setMaximumFractionDigits(2);
}

/**
* Initializes a pretty printer.
*
* @param advisor to be added to the printed output.
*/
public JsonPrettyPrinter(Advisor advisor) {
super(advisor);
}

@Override
public String print(Subject subject) {
if (!subject.ratingValue().isPresent()) {
return StringUtils.EMPTY;
}
RatingValue ratingValue = subject.ratingValue().get();
Rating rating = from(ratingValue, subject);
rating.advices(adviceFor(subject));
StringBuilder output = new StringBuilder();
try {
output.append(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rating));
} catch (JsonProcessingException e) {
throw new UncheckedIOException(
"Oops! Could not parse the rating value object to Json string!", e);
}

return output.toString();
}

/**
* Extract advices for a subject.
*
* @param subject The subject.
* @return Advices collected form a subject.
*/
private List<Advices> adviceFor(Subject subject) {
try {
return advisor.adviceFor(subject).stream().map(JsonPrettyPrinter::from)
.collect(Collectors.toList());
} catch (IOException e) {
LOGGER.warn("Oops! Could not collect advices!", e);
return emptyList();
}
}

/**
* Map Advice to serializable class.
*
* @param advice The Advice.
* @return The serializable class.
*/
private static Advices from(Advice advice) {
AdviceContent content = advice.content();
return new Advices(content.text(), content.feature().name(), content.links());
}

/**
* Format a rating value.
*
* @param ratingValue The rating value.
* @param subject The subject.
* @return A formatted rating value.
*/
private static Rating from(RatingValue ratingValue, Subject subject) {
ScoreValue scoreValue = ratingValue.scoreValue();
Rating rating = new Rating()
.purl(subject.purl())
.label(ratingValue.label().name());
Score score = from(scoreValue);
rating.score(score);
return rating;
}

/**
* Extract Score from Score Value.
*
* @param scoreValue The score value.
* @return the serializable Score.
*/
private static Score from(ScoreValue scoreValue) {
Score score = new Score()
.name(scoreValue.score().name())
.value(tellMeActualValueOf(scoreValue))
.confidence(printValue(scoreValue.confidence()))
.weight(printValue(scoreValue.weight()));
from(scoreValue, score);
return score;
}

/**
* Map feature value to serializable class.
*
* @param featureValue The feature value.
* @return The serializable class from feature value.
*/
private static Feature from(Value<?> featureValue) {
return new Feature()
.name(featureValue.feature().name())
.value(tellMeActualValueOf(featureValue));
}

/**
* Extract Sub scores from the score value.
*
* @param scoreValue The score value to be printed.
* @param score Tells if the score is a top-level score in the rating.
*/
private static void from(ScoreValue scoreValue, Score score) {
for (Value<?> usedValue : scoreValue.usedValues()) {
if (usedValue instanceof ScoreValue) {
score.subScore(from((ScoreValue) usedValue));
} else {
score.feature(from(usedValue));
}
}
}

/**
* Prints an actual value of a score value. The method takes care about unknown and not-applicable
* score values.
*
* @param scoreValue The score value.
* @return A string that represents the score value.
*/
public static String tellMeActualValueOf(ScoreValue scoreValue) {
if (scoreValue.isNotApplicable()) {
return "N/A";
}

if (scoreValue.isUnknown()) {
return "unknown";
}

return printValue(scoreValue.get());
}

/**
* Prints an actual value. The method takes care about unknown and not-applicable values.
*
* @param value The value.
* @return A string that represents the score value.
*/
public static String tellMeActualValueOf(Value<?> value) {
if (value.isNotApplicable()) {
return "N/A";
}

if (value.isUnknown()) {
return "unknown";
}

return String.format("%s", value.get());
}

/**
* Prints out a number with its max value.
*
* @param value The number.
* @return A formatted string with the number and max value.
*/
public static String printValue(double value) {
return String.format("%-4s",
DECIMAL_FORMAT.format(value));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import static com.sap.oss.phosphor.fosstars.tool.format.Markdown.SPACE;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.requireNonNull;
Expand Down Expand Up @@ -46,8 +45,6 @@
import java.util.Set;
import java.util.function.BooleanSupplier;
import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* The class prints a rating value
Expand All @@ -67,12 +64,6 @@ public class OssRulesOfPlayRatingMarkdownFormatter extends AbstractMarkdownForma
private static final String DEFAULT_RATING_VALUE_TEMPLATE
= loadFrom(RATING_VALUE_TEMPLATE_RESOURCE, OssRulesOfPlayRatingMarkdownFormatter.class);

/**
* A logger.
*/
private static final Logger LOGGER
= LogManager.getLogger(OssRulesOfPlayRatingMarkdownFormatter.class);

/**
* Maps a rule to its identifier.
*/
Expand Down Expand Up @@ -192,21 +183,6 @@ String print(RatingValue ratingValue, List<Advice> advice) {
.replace("%ADVICE%", makeAdviceFrom(violations, warnings, passedRules, unclearRules));
}

/**
* Looks for advice for a subject.
*
* @param subject The subject.
* @return A list of advice.
*/
private List<Advice> adviceFor(Subject subject) {
try {
return advisor.adviceFor(subject);
} catch (IOException e) {
LOGGER.warn("Oops! Could not print advice!", e);
return emptyList();
}
}

/**
* Convert a list of formatted rules to Markdown-formatted advice.
*
Expand Down
Loading

0 comments on commit cefb871

Please sign in to comment.