From 2d88f865091246891868a898b5173effd1f6a942 Mon Sep 17 00:00:00 2001 From: Simon Massey <322608+simbo1905@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:46:41 +0000 Subject: [PATCH 1/5] Issue #109 Add fingerprint-based issue deduplication and auto-issue creation - Add generateFingerprint() to create SHA256-based 7-char hash of API diffs - Add generateSummary() to create markdown summary for issue body - Add hasDifferences() helper method - Update ApiTrackerRunner to write outputs to target/api-tracker/ - Update Java 25 workflow to: - Upload report artifacts - Check for existing issues with matching fingerprint - Create new issue only if no match found --- .github/workflows/api-tracker-java25.yml | 59 +++++++++ .../github/simbo1905/tracker/ApiTracker.java | 115 ++++++++++++++++++ .../simbo1905/tracker/ApiTrackerRunner.java | 49 +++++++- 3 files changed, 222 insertions(+), 1 deletion(-) diff --git a/.github/workflows/api-tracker-java25.yml b/.github/workflows/api-tracker-java25.yml index f85cf23..c40eb94 100644 --- a/.github/workflows/api-tracker-java25.yml +++ b/.github/workflows/api-tracker-java25.yml @@ -32,9 +32,68 @@ jobs: run: mvn clean install - name: Run API Tracker + id: tracker run: | mvn exec:java \ -pl json-java21-api-tracker \ -Dexec.mainClass="io.github.simbo1905.tracker.ApiTrackerRunner" \ -Dexec.args="INFO" \ -Djava.util.logging.ConsoleHandler.level=INFO + + # Read outputs into environment + echo "fingerprint=$(cat json-java21-api-tracker/target/api-tracker/fingerprint.txt)" >> $GITHUB_OUTPUT + echo "has_differences=$(cat json-java21-api-tracker/target/api-tracker/has-differences.txt)" >> $GITHUB_OUTPUT + + - name: Upload API report artifact + uses: actions/upload-artifact@v4 + with: + name: api-tracker-report + path: json-java21-api-tracker/target/api-tracker/ + retention-days: 90 + + - name: Check for existing issue + if: steps.tracker.outputs.has_differences == 'true' + id: check_issue + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + FINGERPRINT="${{ steps.tracker.outputs.fingerprint }}" + echo "Looking for existing issue with hash:${FINGERPRINT}" + + # Search for open issues with this fingerprint + EXISTING=$(gh issue list --state open --search "hash:${FINGERPRINT} in:title" --json number --jq '.[0].number // empty') + + if [ -n "$EXISTING" ]; then + echo "Found existing issue #${EXISTING}" + echo "issue_exists=true" >> $GITHUB_OUTPUT + echo "existing_issue=${EXISTING}" >> $GITHUB_OUTPUT + else + echo "No existing issue found" + echo "issue_exists=false" >> $GITHUB_OUTPUT + fi + + - name: Create issue for API differences + if: steps.tracker.outputs.has_differences == 'true' && steps.check_issue.outputs.issue_exists == 'false' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + FINGERPRINT="${{ steps.tracker.outputs.fingerprint }}" + SUMMARY=$(cat json-java21-api-tracker/target/api-tracker/summary.md) + + # Create issue body + cat > /tmp/issue_body.md << EOF + ${SUMMARY} + + ## Details + + - **Fingerprint**: \`hash:${FINGERPRINT}\` + - **Workflow Run**: [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) + - **Artifact**: Download the full JSON report from the workflow artifacts + + This issue was auto-generated by the API Tracker workflow. + EOF + + gh issue create \ + --title "API drift detected [hash:${FINGERPRINT}]" \ + --body-file /tmp/issue_body.md \ + --label "api-tracking,upstream-sync" diff --git a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java index 177eb25..ce08c83 100644 --- a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java +++ b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java @@ -13,6 +13,8 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.time.Duration; import java.time.Instant; import java.util.*; @@ -947,4 +949,117 @@ static String fetchUpstreamSource(String className) { FETCH_CACHE.put(className, source); return source; } + + /// Generates a SHA256 fingerprint of the differences (first 7 chars) + /// Used for deduplicating GitHub issues + /// @param report the full comparison report + /// @return 7-character fingerprint or "0000000" if no differences + static String generateFingerprint(JsonObject report) { + final var summary = (JsonObject) report.members().get("summary"); + final var differentApi = ((JsonNumber) summary.members().get("differentApi")).toNumber().longValue(); + + if (differentApi == 0) { + return "0000000"; + } + + // Extract just the differences array for fingerprinting + final var differences = (JsonArray) report.members().get("differences"); + final var diffsOnly = differences.values().stream() + .filter(v -> { + final var obj = (JsonObject) v; + final var status = ((JsonString) obj.members().get("status")).value(); + return "DIFFERENT".equals(status); + }) + .toList(); + + // Serialize to stable JSON string for hashing + final var jsonString = JsonArray.of(diffsOnly).toString(); + + try { + final var digest = MessageDigest.getInstance("SHA-256"); + final var hash = digest.digest(jsonString.getBytes(StandardCharsets.UTF_8)); + final var hexString = new StringBuilder(); + for (final var b : hash) { + hexString.append(String.format("%02x", b)); + } + return hexString.substring(0, 7); + } catch (NoSuchAlgorithmException e) { + LOGGER.warning("SHA-256 not available, using fallback fingerprint"); + return String.format("%07d", jsonString.hashCode() & 0xFFFFFFF); + } + } + + /// Generates a terse human-readable summary of the API differences + /// Suitable for GitHub issue body + /// @param report the full comparison report + /// @return markdown-formatted summary + static String generateSummary(JsonObject report) { + final var sb = new StringBuilder(); + final var summary = (JsonObject) report.members().get("summary"); + final var differences = (JsonArray) report.members().get("differences"); + + final var totalClasses = ((JsonNumber) summary.members().get("totalClasses")).toNumber().longValue(); + final var matchingClasses = ((JsonNumber) summary.members().get("matchingClasses")).toNumber().longValue(); + final var differentApi = ((JsonNumber) summary.members().get("differentApi")).toNumber().longValue(); + final var missingUpstream = ((JsonNumber) summary.members().get("missingUpstream")).toNumber().longValue(); + + sb.append("## API Comparison Summary\n\n"); + sb.append("| Metric | Count |\n"); + sb.append("|--------|-------|\n"); + sb.append("| Total Classes | ").append(totalClasses).append(" |\n"); + sb.append("| Matching | ").append(matchingClasses).append(" |\n"); + sb.append("| Different | ").append(differentApi).append(" |\n"); + sb.append("| Missing Upstream | ").append(missingUpstream).append(" |\n\n"); + + if (differentApi > 0) { + sb.append("## Changes Detected\n\n"); + + for (final var diff : differences.values()) { + final var diffObj = (JsonObject) diff; + final var status = ((JsonString) diffObj.members().get("status")).value(); + + if (!"DIFFERENT".equals(status)) continue; + + final var className = ((JsonString) diffObj.members().get("className")).value(); + sb.append("### ").append(className).append("\n\n"); + + final var classDiffs = (JsonArray) diffObj.members().get("differences"); + if (classDiffs != null) { + for (final var change : classDiffs.values()) { + final var changeObj = (JsonObject) change; + final var type = ((JsonString) changeObj.members().get("type")).value(); + final var methodValue = changeObj.members().get("method"); + final var method = methodValue instanceof JsonString js ? js.value() : "unknown"; + + final var emoji = switch (type) { + case "methodRemoved" -> "➖"; + case "methodAdded" -> "➕"; + case "methodChanged" -> "🔄"; + case "inheritanceChanged" -> "🔗"; + case "fieldsChanged" -> "📦"; + case "constructorsChanged" -> "🏗️"; + default -> "❓"; + }; + + sb.append("- ").append(emoji).append(" **").append(type).append("**: `").append(method).append("`\n"); + } + } + sb.append("\n"); + } + } + + sb.append("---\n"); + sb.append("*Generated by API Tracker on ").append(Instant.now().toString().split("T")[0]).append("*\n"); + + return sb.toString(); + } + + /// Checks if there are any API differences in the report + /// @param report the comparison report + /// @return true if differentApi > 0 + static boolean hasDifferences(JsonObject report) { + final var summary = (JsonObject) report.members().get("summary"); + final var differentApi = ((JsonNumber) summary.members().get("differentApi")).toNumber().longValue(); + return differentApi > 0; + } } \ No newline at end of file diff --git a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTrackerRunner.java b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTrackerRunner.java index aa140b7..3331b43 100644 --- a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTrackerRunner.java +++ b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTrackerRunner.java @@ -2,6 +2,9 @@ import jdk.sandbox.java.util.json.Json; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import java.util.logging.Logger; @@ -43,7 +46,26 @@ public static void main(String[] args) { // Pretty print the report System.out.println("=== Comparison Report ==="); - System.out.println(Json.toDisplayString(report, 2)); + final var jsonOutput = Json.toDisplayString(report, 2); + System.out.println(jsonOutput); + + // Generate fingerprint and summary + final var fingerprint = ApiTracker.generateFingerprint(report); + final var summary = ApiTracker.generateSummary(report); + final var hasDiffs = ApiTracker.hasDifferences(report); + + System.out.println(); + System.out.println("=== Fingerprint ==="); + System.out.println("hash:" + fingerprint); + + if (hasDiffs) { + System.out.println(); + System.out.println("=== Summary ==="); + System.out.println(summary); + } + + // Write outputs to files for workflow artifact upload + writeOutputFiles(jsonOutput, fingerprint, summary, hasDiffs); } catch (Exception e) { System.err.println("Error during comparison: " + e.getMessage()); @@ -53,6 +75,31 @@ public static void main(String[] args) { } } + private static void writeOutputFiles(String jsonOutput, String fingerprint, String summary, boolean hasDiffs) { + try { + // Create output directory + final var outputDir = Path.of("target", "api-tracker"); + Files.createDirectories(outputDir); + + // Write full JSON report + Files.writeString(outputDir.resolve("report.json"), jsonOutput); + + // Write fingerprint + Files.writeString(outputDir.resolve("fingerprint.txt"), fingerprint); + + // Write summary markdown + Files.writeString(outputDir.resolve("summary.md"), summary); + + // Write has-differences flag for workflow + Files.writeString(outputDir.resolve("has-differences.txt"), String.valueOf(hasDiffs)); + + System.out.println(); + System.out.println("Output files written to: " + outputDir.toAbsolutePath()); + } catch (IOException e) { + System.err.println("Warning: Could not write output files: " + e.getMessage()); + } + } + private static void configureLogging(Level level) { // Get root logger final var rootLogger = Logger.getLogger(""); From d611202809485d15b50139fdc435a0ff4a2389e8 Mon Sep 17 00:00:00 2001 From: Simon Massey <322608+simbo1905@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:48:56 +0000 Subject: [PATCH 2/5] Issue #109 Fix artifact paths in workflow --- .github/workflows/api-tracker-java25.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/api-tracker-java25.yml b/.github/workflows/api-tracker-java25.yml index c40eb94..72610f4 100644 --- a/.github/workflows/api-tracker-java25.yml +++ b/.github/workflows/api-tracker-java25.yml @@ -41,14 +41,14 @@ jobs: -Djava.util.logging.ConsoleHandler.level=INFO # Read outputs into environment - echo "fingerprint=$(cat json-java21-api-tracker/target/api-tracker/fingerprint.txt)" >> $GITHUB_OUTPUT - echo "has_differences=$(cat json-java21-api-tracker/target/api-tracker/has-differences.txt)" >> $GITHUB_OUTPUT + echo "fingerprint=$(cat target/api-tracker/fingerprint.txt)" >> $GITHUB_OUTPUT + echo "has_differences=$(cat target/api-tracker/has-differences.txt)" >> $GITHUB_OUTPUT - name: Upload API report artifact uses: actions/upload-artifact@v4 with: name: api-tracker-report - path: json-java21-api-tracker/target/api-tracker/ + path: target/api-tracker/ retention-days: 90 - name: Check for existing issue @@ -78,7 +78,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | FINGERPRINT="${{ steps.tracker.outputs.fingerprint }}" - SUMMARY=$(cat json-java21-api-tracker/target/api-tracker/summary.md) + SUMMARY=$(cat target/api-tracker/summary.md) # Create issue body cat > /tmp/issue_body.md << EOF From dcbdc8e340cce9155f9104c13146000d3db60aab Mon Sep 17 00:00:00 2001 From: Simon Massey <322608+simbo1905@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:52:23 +0000 Subject: [PATCH 3/5] Issue #109 Fix fingerprint to use stable sorted representation --- .../github/simbo1905/tracker/ApiTracker.java | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java index ce08c83..96aef36 100644 --- a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java +++ b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java @@ -951,6 +951,7 @@ static String fetchUpstreamSource(String className) { } /// Generates a SHA256 fingerprint of the differences (first 7 chars) + /// Uses only essential, stable information: class names and change types (sorted) /// Used for deduplicating GitHub issues /// @param report the full comparison report /// @return 7-character fingerprint or "0000000" if no differences @@ -962,22 +963,38 @@ static String generateFingerprint(JsonObject report) { return "0000000"; } - // Extract just the differences array for fingerprinting + // Build a stable, sorted representation of just the essential diff info final var differences = (JsonArray) report.members().get("differences"); - final var diffsOnly = differences.values().stream() - .filter(v -> { - final var obj = (JsonObject) v; - final var status = ((JsonString) obj.members().get("status")).value(); - return "DIFFERENT".equals(status); - }) - .toList(); + final var stableLines = new ArrayList(); - // Serialize to stable JSON string for hashing - final var jsonString = JsonArray.of(diffsOnly).toString(); + for (final var diff : differences.values()) { + final var diffObj = (JsonObject) diff; + final var status = ((JsonString) diffObj.members().get("status")).value(); + + if (!"DIFFERENT".equals(status)) continue; + + final var className = ((JsonString) diffObj.members().get("className")).value(); + final var classDiffs = (JsonArray) diffObj.members().get("differences"); + + if (classDiffs != null) { + for (final var change : classDiffs.values()) { + final var changeObj = (JsonObject) change; + final var type = ((JsonString) changeObj.members().get("type")).value(); + final var methodValue = changeObj.members().get("method"); + final var method = methodValue instanceof JsonString js ? js.value() : ""; + // Create stable line: "ClassName:changeType:methodName" + stableLines.add(className + ":" + type + ":" + method); + } + } + } + + // Sort for deterministic ordering + Collections.sort(stableLines); + final var stableString = String.join("\n", stableLines); try { final var digest = MessageDigest.getInstance("SHA-256"); - final var hash = digest.digest(jsonString.getBytes(StandardCharsets.UTF_8)); + final var hash = digest.digest(stableString.getBytes(StandardCharsets.UTF_8)); final var hexString = new StringBuilder(); for (final var b : hash) { hexString.append(String.format("%02x", b)); @@ -985,7 +1002,7 @@ static String generateFingerprint(JsonObject report) { return hexString.substring(0, 7); } catch (NoSuchAlgorithmException e) { LOGGER.warning("SHA-256 not available, using fallback fingerprint"); - return String.format("%07d", jsonString.hashCode() & 0xFFFFFFF); + return String.format("%07d", stableString.hashCode() & 0xFFFFFFF); } } From 206ad18c817852a539bc79041df52b1b97b91d7a Mon Sep 17 00:00:00 2001 From: Simon Massey <322608+simbo1905@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:55:52 +0000 Subject: [PATCH 4/5] Issue #109 Update daily tracker to use fingerprint deduplication and Java 25 --- .github/workflows/daily-api-tracker.yml | 81 ++++++++++++++++++------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/.github/workflows/daily-api-tracker.yml b/.github/workflows/daily-api-tracker.yml index 72190a0..f2b71d8 100644 --- a/.github/workflows/daily-api-tracker.yml +++ b/.github/workflows/daily-api-tracker.yml @@ -18,10 +18,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up JDK 24 + - name: Set up JDK 25 uses: actions/setup-java@v4 with: - java-version: '24' + java-version: '25' distribution: 'temurin' - name: Cache Maven dependencies @@ -35,29 +35,68 @@ jobs: run: mvn clean install - name: Run API Tracker + id: tracker run: | mvn exec:java \ -pl json-java21-api-tracker \ -Dexec.mainClass="io.github.simbo1905.tracker.ApiTrackerRunner" \ -Dexec.args="INFO" \ -Djava.util.logging.ConsoleHandler.level=INFO - - - name: Create issue if differences found - if: failure() - uses: actions/github-script@v7 + + # Read outputs into environment + echo "fingerprint=$(cat target/api-tracker/fingerprint.txt)" >> $GITHUB_OUTPUT + echo "has_differences=$(cat target/api-tracker/has-differences.txt)" >> $GITHUB_OUTPUT + + - name: Upload API report artifact + uses: actions/upload-artifact@v4 with: - script: | - const title = 'API differences detected between local and upstream'; - const body = `The daily API tracker found differences between our local implementation and upstream. - - Check the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. - - Date: ${new Date().toISOString().split('T')[0]}`; - - github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: title, - body: body, - labels: ['api-tracking', 'upstream-sync'] - }); \ No newline at end of file + name: api-tracker-report + path: target/api-tracker/ + retention-days: 90 + + - name: Check for existing issue + if: steps.tracker.outputs.has_differences == 'true' + id: check_issue + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + FINGERPRINT="${{ steps.tracker.outputs.fingerprint }}" + echo "Looking for existing issue with hash:${FINGERPRINT}" + + # Search for open issues with this fingerprint + EXISTING=$(gh issue list --state open --search "hash:${FINGERPRINT} in:title" --json number --jq '.[0].number // empty') + + if [ -n "$EXISTING" ]; then + echo "Found existing issue #${EXISTING}" + echo "issue_exists=true" >> $GITHUB_OUTPUT + echo "existing_issue=${EXISTING}" >> $GITHUB_OUTPUT + else + echo "No existing issue found" + echo "issue_exists=false" >> $GITHUB_OUTPUT + fi + + - name: Create issue for API differences + if: steps.tracker.outputs.has_differences == 'true' && steps.check_issue.outputs.issue_exists == 'false' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + FINGERPRINT="${{ steps.tracker.outputs.fingerprint }}" + SUMMARY=$(cat target/api-tracker/summary.md) + + # Create issue body + cat > /tmp/issue_body.md << EOF + ${SUMMARY} + + ## Details + + - **Fingerprint**: \`hash:${FINGERPRINT}\` + - **Workflow Run**: [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) + - **Artifact**: Download the full JSON report from the workflow artifacts + + This issue was auto-generated by the Daily API Tracker workflow. + EOF + + gh issue create \ + --title "API drift detected [hash:${FINGERPRINT}]" \ + --body-file /tmp/issue_body.md \ + --label "api-tracking,upstream-sync" From 539125e97618ef19919b100c5f570ee24e3fd3d5 Mon Sep 17 00:00:00 2001 From: Simon Massey <322608+simbo1905@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:04:57 +0000 Subject: [PATCH 5/5] Issue #109 Address code review feedback - Exit non-zero on IOException when writing output files - Use hex format for fallback fingerprint (%07x) - Use report timestamp instead of Instant.now() in summary - Extract getDifferentApiCount() helper to reduce duplication - Use helper in generateFingerprint(), generateSummary(), hasDifferences() --- .../github/simbo1905/tracker/ApiTracker.java | 31 +++++++++++++------ .../simbo1905/tracker/ApiTrackerRunner.java | 5 ++- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java index 96aef36..589363f 100644 --- a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java +++ b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTracker.java @@ -956,10 +956,7 @@ static String fetchUpstreamSource(String className) { /// @param report the full comparison report /// @return 7-character fingerprint or "0000000" if no differences static String generateFingerprint(JsonObject report) { - final var summary = (JsonObject) report.members().get("summary"); - final var differentApi = ((JsonNumber) summary.members().get("differentApi")).toNumber().longValue(); - - if (differentApi == 0) { + if (getDifferentApiCount(report) == 0) { return "0000000"; } @@ -1002,10 +999,25 @@ static String generateFingerprint(JsonObject report) { return hexString.substring(0, 7); } catch (NoSuchAlgorithmException e) { LOGGER.warning("SHA-256 not available, using fallback fingerprint"); - return String.format("%07d", stableString.hashCode() & 0xFFFFFFF); + return String.format("%07x", stableString.hashCode() & 0xFFFFFFF); } } + /// Extracts the differentApi count from a report summary + /// @param report the comparison report + /// @return the count of classes with different APIs + private static long getDifferentApiCount(JsonObject report) { + final var summary = (JsonObject) report.members().get("summary"); + if (summary == null) { + return 0; + } + final var differentApiValue = summary.members().get("differentApi"); + if (differentApiValue instanceof JsonNumber num) { + return num.toNumber().longValue(); + } + return 0; + } + /// Generates a terse human-readable summary of the API differences /// Suitable for GitHub issue body /// @param report the full comparison report @@ -1017,7 +1029,7 @@ static String generateSummary(JsonObject report) { final var totalClasses = ((JsonNumber) summary.members().get("totalClasses")).toNumber().longValue(); final var matchingClasses = ((JsonNumber) summary.members().get("matchingClasses")).toNumber().longValue(); - final var differentApi = ((JsonNumber) summary.members().get("differentApi")).toNumber().longValue(); + final var differentApi = getDifferentApiCount(report); final var missingUpstream = ((JsonNumber) summary.members().get("missingUpstream")).toNumber().longValue(); sb.append("## API Comparison Summary\n\n"); @@ -1066,7 +1078,8 @@ static String generateSummary(JsonObject report) { } sb.append("---\n"); - sb.append("*Generated by API Tracker on ").append(Instant.now().toString().split("T")[0]).append("*\n"); + final var timestamp = ((JsonString) report.members().get("timestamp")).value(); + sb.append("*Generated by API Tracker on ").append(timestamp.split("T")[0]).append("*\n"); return sb.toString(); } @@ -1075,8 +1088,6 @@ static String generateSummary(JsonObject report) { /// @param report the comparison report /// @return true if differentApi > 0 static boolean hasDifferences(JsonObject report) { - final var summary = (JsonObject) report.members().get("summary"); - final var differentApi = ((JsonNumber) summary.members().get("differentApi")).toNumber().longValue(); - return differentApi > 0; + return getDifferentApiCount(report) > 0; } } \ No newline at end of file diff --git a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTrackerRunner.java b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTrackerRunner.java index 3331b43..610127b 100644 --- a/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTrackerRunner.java +++ b/json-java21-api-tracker/src/main/java/io/github/simbo1905/tracker/ApiTrackerRunner.java @@ -96,7 +96,10 @@ private static void writeOutputFiles(String jsonOutput, String fingerprint, Stri System.out.println(); System.out.println("Output files written to: " + outputDir.toAbsolutePath()); } catch (IOException e) { - System.err.println("Warning: Could not write output files: " + e.getMessage()); + System.err.println("Error: Could not write output files: " + e.getMessage()); + //noinspection CallToPrintStackTrace + e.printStackTrace(); + System.exit(1); } }