Skip to content

Adding HTML, JSON & CSV report output #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
/cognitive-analysis.log

### STS ###
.apt_generated
Expand Down
Empty file removed cognitive_analysis.log
Empty file.
36 changes: 28 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,32 @@
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.floriankraemer</groupId>
<artifactId>cognitive_analysis</artifactId>
<artifactId>cognitive-analysis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cognitive_analysis</name>
<name>cognitive-analysis</name>
<description>Cognitive Code Analysis for Java Applications</description>
<url/>
<licenses>
<license/>
<license>
<name>GNU General Public License, Version 3</name>
<url>https://www.gnu.org/licenses/gpl-3.0.html</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer/>
<developer>
<name>Florian Krämer</name>
<url>https://floriankraemer.net</url>
<roles>
<role>Developer</role>
</roles>
</developer>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
<connection>https://github.com/floriankraemer/cognitive-code-analysis-java.git</connection>
<developerConnection>git@github.com:floriankraemer/cognitive-code-analysis-java.git</developerConnection>
<tag>HEAD</tag>
<url>https://github.com/floriankraemer/cognitive-code-analysis-java</url>
</scm>
<properties>
<java.version>17</java.version>
Expand Down Expand Up @@ -56,6 +66,16 @@
<artifactId>spring-shell-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4.1</version>
</dependency>
</dependencies>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.shell.command.annotation.CommandScan;

@SpringBootApplication
@CommandScan(basePackages = "net.floriankraemer.cognitive_analysis.application")
public class CognitiveAnalysisApplication implements ApplicationRunner {

public static void main(final String[] args) {
SpringApplication.run(CognitiveAnalysisApplication.class, args);
}

@Override
public void run(final ApplicationArguments args) throws Exception {
}
public void run(ApplicationArguments args) throws Exception {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package net.floriankraemer.cognitive_analysis.application;

import java.io.IOException;
import java.io.OutputStreamWriter;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import java.util.Map;

import net.floriankraemer.cognitive_analysis.application.report.ReportBuilder;
import net.floriankraemer.cognitive_analysis.domain.CognitiveMetrics;
import net.floriankraemer.cognitive_analysis.domain.CognitiveMetricsFacade;

import net.floriankraemer.cognitive_analysis.domain.MetricsCollection;
import org.jline.utils.AttributedString;

import org.springframework.shell.command.annotation.Command;
import org.springframework.shell.standard.ShellOption;

@Command
public class AnalyseCommand {

final CognitiveMetricsFacade cognitiveMetricsFacade;
final OutputStreamWriter out;
final ResultTableBuilder resultTableBuilder;
final ReportBuilder reportBuilder;

public AnalyseCommand(
CognitiveMetricsFacade cognitiveMetricsFacade,
ResultTableBuilder resultTableBuilder,
ReportBuilder reportBuilder
) {
this.cognitiveMetricsFacade = cognitiveMetricsFacade;
this.resultTableBuilder = resultTableBuilder;
this.reportBuilder = reportBuilder;
this.out = new OutputStreamWriter(System.out);
}

/**
* Calculate cognitive metrics for the Java code in a given directory.
*
* @param directoryPath The path to the directory to calculate cognitive metrics for.
* @throws IOException If the directory does not exist.
*/
@Command(command = "analyse")
public void analyse(
final @ShellOption(defaultValue = "") String directoryPath,
final @ShellOption(defaultValue = "") String output,
final @ShellOption(defaultValue = "") String reportType
) throws IOException {
if (directoryPath.isEmpty()) {
System.err.println("Please provide a directory path.");
System.exit(1);
return;
}

if (!pathExists(directoryPath)) {
System.err.println("Directory does not exist: " + directoryPath);
System.exit(1);
return;
}

MetricsCollection metricsCollection =
cognitiveMetricsFacade.calculateCognitiveMetrics(directoryPath);

if (reportType != null && !reportType.isEmpty() && !output.isEmpty()) {
generateReport(output, reportType, metricsCollection);
System.exit(1);
return;
}

consoleOutput(metricsCollection, directoryPath);
System.exit(0);
}

private void generateReport(
String output,
String reportType,
MetricsCollection metricsCollection
) throws IOException {
try {
ReportBuilder.ReportType type = ReportBuilder.ReportType.valueOf(reportType);
reportBuilder.build(type, output, metricsCollection);

System.out.println("Report generated at: " + output);
} catch (Exception e) {
out.write(e.getLocalizedMessage());
System.exit(1);
}
}

private void consoleOutput(
MetricsCollection metricsCollection,
String directoryPath
) throws IOException {
for (Map.Entry<String, Map<String, CognitiveMetrics>> entry : metricsCollection.entrySet()) {
System.out.println("\nFile: " + entry.getKey());
final String table = resultTableBuilder.build(entry.getValue());
System.out.println(AttributedString.fromAnsi(table));
System.out.println();
}

out.write("Cognitive metrics calculated for " + directoryPath);
out.flush();
}

private boolean pathExists(final String directoryPath) throws IOException {
Path path = Paths.get(directoryPath);
if (!Files.isDirectory(path)) {
return false;
}

return true;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package net.floriankraemer.cognitive_analysis.application.report;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import net.floriankraemer.cognitive_analysis.domain.MetricsCollection;

public abstract class AbstractReportBuilder {

public abstract void build(MetricsCollection metricsCollection, String outputPath);

protected void writeToFile(String content, String filePath) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
writer.write(content);
} catch (IOException e) {
throw new RuntimeException("Failed to write the report to disk.", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package net.floriankraemer.cognitive_analysis.application.report;

import net.floriankraemer.cognitive_analysis.domain.CognitiveMetrics;
import net.floriankraemer.cognitive_analysis.domain.MetricsCollection;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;

@Component
public class CsvReportBuilder extends AbstractReportBuilder {

@Override
public void build(MetricsCollection metricsCollection, String outputPath) {
String csvContent = buildCsvReport(metricsCollection);
writeToFile(csvContent, outputPath);
}

// Method to build the CSV content from the metrics
private String buildCsvReport(MetricsCollection metricsCollection) {
StringWriter out = new StringWriter();

try (CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT
.withHeader("Package", "Class", "Method", "Line Count", "If Count", "If-Nesting Level", "Else Count", "Loop Count",
"Switch Count", "Method Call Count", "Return Count", "Argument Count", "Try-Catch Nesting Level", "Complexity"))) {

// Iterate through each file's metrics
metricsCollection.forEach((fileName, methodMetrics) -> {
methodMetrics.forEach((methodName, metrics) -> {
try {
printer.printRecord(
metrics.getPackageName(),
metrics.getClassName(),
metrics.getMethodName(),
metrics.getLineCount(),
metrics.getIfCount(),
metrics.getIfNestingLevel(),
metrics.getElseCount(),
metrics.getLoopCount(),
metrics.getSwitchCount(),
metrics.getMethodCallCount(),
metrics.getReturnCount(),
metrics.getArgumentCount(),
metrics.getTryCatchNestingLevel(),
String.format("%.3f", metrics.getCognitiveComplexity())
);
} catch (IOException e) {
throw new RuntimeException("Error writing CSV record", e);
}
});
});

} catch (IOException e) {
throw new RuntimeException("Failed to build CSV report", e);
}

return out.toString();
}
}
Loading