Skip to content

Commit 14611d6

Browse files
Merge pull request #183 from refactorfirst/#182-add-hyperlinks
#182 Add hyperlinks for classes
2 parents 24a1b76 + 6a85c53 commit 14611d6

7 files changed

Lines changed: 298 additions & 93 deletions

File tree

change-proneness-ranker/src/main/java/org/hjug/git/GitLogReader.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,29 @@ public File getGitDir(File basedir) {
5656
return repositoryBuilder.getGitDir();
5757
}
5858

59+
/**
60+
* Returns the current commit hash at HEAD
61+
*
62+
* @return the commit hash as a String, or null if HEAD cannot be resolved
63+
* @throws IOException if an I/O error occurs
64+
*/
65+
public String getCurrentCommitHash() throws IOException {
66+
ObjectId headCommit = gitRepository.resolve("HEAD");
67+
if (headCommit == null) {
68+
return null;
69+
}
70+
return headCommit.getName();
71+
}
72+
73+
/**
74+
* Returns the repository's origin URL
75+
*
76+
* @return the origin URL as a String, or null if not configured
77+
*/
78+
public String getOriginUrl() {
79+
return gitRepository.getConfig().getString("remote", "origin", "url");
80+
}
81+
5982
// log --follow implementation may be worth adopting in the future
6083
// https://github.com/spearce/jgit/blob/master/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
6184

refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenReport.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.hjug.mavenreport;
22

33
import java.util.*;
4+
5+
import lombok.SneakyThrows;
46
import lombok.extern.slf4j.Slf4j;
57
import org.apache.maven.doxia.markup.HtmlMarkup;
68
import org.apache.maven.doxia.sink.Sink;
@@ -63,6 +65,7 @@ public String getDescription(Locale locale) {
6365
+ " have the highest priority values.";
6466
}
6567

68+
@SneakyThrows
6669
@Override
6770
public void executeReport(Locale locale) {
6871
HtmlReport htmlReport = new HtmlReport();

report/src/main/java/org/hjug/refactorfirst/report/HtmlReport.java

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package org.hjug.refactorfirst.report;
22

3-
import java.util.HashSet;
4-
import java.util.List;
5-
import java.util.Locale;
6-
import java.util.Set;
3+
import java.util.*;
74
import lombok.extern.slf4j.Slf4j;
85
import org.hjug.cbc.RankedCycle;
96
import org.hjug.cbc.RankedDisharmony;
107
import org.hjug.gdg.GraphDataGenerator;
8+
import org.hjug.graphbuilder.CodebaseGraphDTO;
119
import org.jgrapht.Graph;
1210
import org.jgrapht.graph.DefaultWeightedEdge;
1311

@@ -417,6 +415,17 @@ public String printTitle(String projectName, String projectVersion) {
417415
return "<title>Refactor First Report for " + projectName + " " + projectVersion + " </title>\n";
418416
}
419417

418+
@Override
419+
StringBuilder createMenu(
420+
List<DisharmonySpec> disharmonySpecs,
421+
Map<String, List<RankedDisharmony>> rankedDisharmoniesByAnchor,
422+
List<RankedCycle> rankedCycles) {
423+
StringBuilder stringBuilder = new StringBuilder();
424+
stringBuilder.append("<li><a href=\"#CLASSMAP\">Class Map</a></li>\n");
425+
stringBuilder.append(super.createMenu(disharmonySpecs, rankedDisharmoniesByAnchor, rankedCycles));
426+
return stringBuilder;
427+
}
428+
420429
@Override
421430
String renderGithubButtons() {
422431
return "<div align=\"center\">\n" + "Show RefactorFirst some &#10084;&#65039;\n"
@@ -465,8 +474,8 @@ String renderDisharmonyChart(String anchorId, String title, List<RankedDisharmon
465474
}
466475

467476
@Override
468-
public String renderClassGraphVisuals() {
469-
String dot = buildClassGraphDot(classGraph);
477+
public String renderClassGraphVisuals(String repoUrl, CodebaseGraphDTO codebaseGraphDTO) {
478+
String dot = buildClassGraphDot(classGraph, repoUrl, codebaseGraphDTO);
470479
String classGraphName = "classGraph";
471480

472481
StringBuilder stringBuilder = new StringBuilder();
@@ -491,7 +500,7 @@ public String renderClassGraphVisuals() {
491500

492501
private StringBuilder generateGraphButtons(String graphName, String dot) {
493502
StringBuilder stringBuilder = new StringBuilder();
494-
stringBuilder.append("<h1 align=\"center\">Class Map</h1>");
503+
stringBuilder.append("<h1 align=\"center\"><a id=\"CLASSMAP\">Class Map</a></h1>");
495504
stringBuilder.append("<script>\n");
496505
stringBuilder.append("const " + graphName + "_dot = " + dot + "\n");
497506
stringBuilder.append("</script>\n");
@@ -501,7 +510,9 @@ private StringBuilder generateGraphButtons(String graphName, String dot) {
501510

502511
stringBuilder.append("<div align=\"center\">\nRed lines represent relationships to remove.<br>\n");
503512
stringBuilder.append("Red nodes represent classes to remove.<br>\n");
504-
stringBuilder.append("Zoom in / out with your mouse wheel and click/move to drag the image.\n");
513+
stringBuilder.append("Zoom in / out with your mouse wheel and click/move to drag the image.<br>\n");
514+
stringBuilder.append(
515+
"Clicking on a node in the DOT graph (if present below) will open its source file in the repo. It will not open a new browser window.\n");
505516
stringBuilder.append("</div>\n");
506517
return stringBuilder;
507518
}
@@ -511,7 +522,7 @@ private static String generateDotImage(String graphName) {
511522
return "<div id=\"" + graphName
512523
+ "\" style=\"width: 95%; height: 70vh; margin: auto; border: thin solid black\"></div>\n"
513524
+ "<script type=\"module\">\n"
514-
+ "import init, { DotParser } from \"https://esm.run/@vizdom/vizdom-ts-web\";\n"
525+
+ "import init, { DotParser } from \"https://cdn.jsdelivr.net/npm/@vizdom/vizdom-ts-web@0.1.19/vizdom_ts.min.js\";\n"
515526
+ " if(DotParser) {\n"
516527
+ " // Wait for the WASM binary to be compiled and the 'wasm' object to be populated\n"
517528
+ " await init();\n"
@@ -534,7 +545,8 @@ private static String generateDotImage(String graphName) {
534545
+ " }\n" + "</script>\n";
535546
}
536547

537-
String buildClassGraphDot(Graph<String, DefaultWeightedEdge> classGraph) {
548+
String buildClassGraphDot(
549+
Graph<String, DefaultWeightedEdge> classGraph, String repoUrl, CodebaseGraphDTO codebaseGraphDTO) {
538550
StringBuilder dot = new StringBuilder();
539551
dot.append("`strict digraph G {\n");
540552

@@ -563,17 +575,26 @@ String buildClassGraphDot(Graph<String, DefaultWeightedEdge> classGraph) {
563575

564576
dot.append(className.replace("$", "_"));
565577

578+
dot.append(" [");
579+
dot.append(hyperlinkClassForDot(vertex, repoUrl, codebaseGraphDTO));
580+
566581
if (vertexesToRemove.contains(vertex)) {
567-
dot.append(" [color=red style=filled]\n");
582+
dot.append(" color=red style=filled");
568583
}
569584

570-
dot.append(";\n");
585+
dot.append("];\n");
571586
}
572587

573588
dot.append("}`;");
574589
return dot.toString();
575590
}
576591

592+
String hyperlinkClassForDot(String fqClassName, String repoUrl, CodebaseGraphDTO codebaseGraphDTO) {
593+
StringBuilder sb = new StringBuilder();
594+
String path = codebaseGraphDTO.getClassToSourceFilePathMapping().get(fqClassName);
595+
return sb.append("URL=\"" + repoUrl + path + "\" target=\"_blank\"").toString();
596+
}
597+
577598
private void renderEdge(
578599
Graph<String, DefaultWeightedEdge> classGraph, DefaultWeightedEdge edge, StringBuilder dot) {
579600
// render edge
@@ -622,8 +643,8 @@ private void renderEdge(
622643
}
623644

624645
@Override
625-
public String renderCycleVisuals(RankedCycle cycle) {
626-
String dot = buildCycleDot(classGraph, cycle);
646+
public String renderCycleVisuals(RankedCycle cycle, String repoUrl, CodebaseGraphDTO codebaseGraphDTO) {
647+
String dot = buildCycleDot(classGraph, cycle, repoUrl, codebaseGraphDTO);
627648

628649
String cycleName = getClassName(cycle.getCycleName()).replace("$", "_");
629650

@@ -643,7 +664,11 @@ public String renderCycleVisuals(RankedCycle cycle) {
643664
return stringBuilder.toString();
644665
}
645666

646-
String buildCycleDot(Graph<String, DefaultWeightedEdge> classGraph, RankedCycle cycle) {
667+
String buildCycleDot(
668+
Graph<String, DefaultWeightedEdge> classGraph,
669+
RankedCycle cycle,
670+
String repoUrl,
671+
CodebaseGraphDTO codebaseGraphDTO) {
647672
StringBuilder dot = new StringBuilder();
648673
dot.append("`strict digraph G {\n");
649674

@@ -653,18 +678,29 @@ String buildCycleDot(Graph<String, DefaultWeightedEdge> classGraph, RankedCycle
653678

654679
// render vertices
655680
for (String vertex : cycle.getVertexSet()) {
656-
dot.append(getClassName(vertex).replace("$", "_"));
681+
String className = getClassName(vertex);
682+
683+
// if the vertex is a nested class and has no outgoing edges, skip it
684+
if (className.contains("$")
685+
&& className.split("\\$")[className.split("\\$").length - 1].matches("\\d+")
686+
&& classGraph.outDegreeOf(vertex) == 0) {
687+
continue;
688+
}
689+
690+
dot.append(className.replace("$", "_"));
691+
692+
dot.append(" [");
693+
dot.append(hyperlinkClassForDot(vertex, repoUrl, codebaseGraphDTO));
657694

658695
if (vertexesToRemove.contains(vertex)) {
659-
dot.append(" [color=red style=filled]\n");
696+
dot.append(" color=red style=filled");
660697
}
661698

662-
dot.append(";\n");
699+
dot.append("];\n");
663700
}
664701

665702
dot.append("}`;");
666-
667-
return dot.toString().replace("$", "_");
703+
return dot.toString();
668704
}
669705

670706
String generate2DPopup(String cycleName) {

0 commit comments

Comments
 (0)