From 6f8e2ed66f33d08727d5d6cb0eb5ad0e621aa005 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Fri, 31 Jan 2025 09:06:55 +0100 Subject: [PATCH] Add `FindParseFailures#createdAfter` option This option allows restricting the reporting to source files that were created after a given date. --- .../org/openrewrite/FindParseFailures.java | 41 ++++++++++++- .../openrewrite/FindParseFailuresTest.java | 57 ++++++++++++++++++- 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/FindParseFailures.java b/rewrite-core/src/main/java/org/openrewrite/FindParseFailures.java index 4e9168b6439..3b0b1caa844 100644 --- a/rewrite-core/src/main/java/org/openrewrite/FindParseFailures.java +++ b/rewrite-core/src/main/java/org/openrewrite/FindParseFailures.java @@ -18,10 +18,13 @@ import lombok.EqualsAndHashCode; import lombok.Value; import org.jspecify.annotations.Nullable; +import org.openrewrite.marker.BuildMetadata; import org.openrewrite.marker.DeserializationError; import org.openrewrite.marker.Markup; import org.openrewrite.table.ParseFailures; +import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.Objects; @Value @@ -48,6 +51,13 @@ public class FindParseFailures extends Recipe { @Nullable String stackTrace; + @Option(displayName = "Created after", + description = "Only report on source files that were created after this date.", + example = "2025-01-01", + required = false) + @Nullable + String createdAfter; + transient ParseFailures failures = new ParseFailures(this); @Override @@ -61,9 +71,36 @@ public String getDescription() { "failures that can occur and prioritizing fixes according to the most common problems."; } + @Override + public Validated validate() { + return super.validate().and(Validated.test("createdAfter", "Must be empty or a valid date of format yyyy-MM-dd", createdAfter, date -> { + if (date != null && !date.isEmpty()) { + try { + LocalDate.parse(date); + } catch (Exception e) { + return false; + } + } + return true; + })); + } + @Override public TreeVisitor getVisitor() { - return new TreeVisitor() { + TreeVisitor precondition = new TreeVisitor() { + final long createdAfterEpoch = createdAfter == null ? -1L : LocalDate.parse(createdAfter).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli(); + + @Override + public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + return createdAfterEpoch == -1L || tree != null && tree.getMarkers().findFirst(BuildMetadata.class) + .map(BuildMetadata::getMetadata) + .map(m -> m.get("createdAt")) + .map(Long::parseLong) + .map(t -> t >= createdAfterEpoch) + .orElse(false) ? null : tree; + } + }; + return Preconditions.check(precondition, new TreeVisitor() { @Override public Tree postVisit(Tree tree, ExecutionContext ctx) { @@ -117,6 +154,6 @@ private Tree report(Tree tree, ParseExceptionResult exceptionResult, ExecutionCo return Markup.info(tree, exceptionResult.getMessage()); } - }; + }); } } diff --git a/rewrite-core/src/test/java/org/openrewrite/FindParseFailuresTest.java b/rewrite-core/src/test/java/org/openrewrite/FindParseFailuresTest.java index 2c814f88c97..8cc2a532cd1 100644 --- a/rewrite-core/src/test/java/org/openrewrite/FindParseFailuresTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/FindParseFailuresTest.java @@ -16,6 +16,7 @@ package org.openrewrite; import org.junit.jupiter.api.Test; +import org.openrewrite.marker.BuildMetadata; import org.openrewrite.marker.Markers; import org.openrewrite.table.ParseFailures; import org.openrewrite.test.RecipeSpec; @@ -23,16 +24,21 @@ import org.openrewrite.text.PlainText; import org.openrewrite.text.PlainTextParser; +import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.List; +import java.util.Map; +import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; +import static org.openrewrite.Tree.randomId; import static org.openrewrite.test.SourceSpecs.text; class FindParseFailuresTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe(new FindParseFailures(5, null, null)); + spec.recipe(new FindParseFailures(5, null, null, null)); } @Test @@ -53,8 +59,53 @@ void findParseFailures() { spec -> spec .mapBeforeRecipe(pt -> pt .withSnippets(List.of(new PlainText.Snippet( - Tree.randomId(), - new Markers(Tree.randomId(), List.of(per)), + randomId(), + new Markers(randomId(), List.of(per)), + pt.getText()))) + .withText("") + ) + ) + ); + } + + @Test + void findParseFailuresAfter() { + long t0 = LocalDate.parse("2025-01-01").atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli(); + long t1 = LocalDate.parse("2025-01-02").atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli(); + ParseExceptionResult per = ParseExceptionResult.build(PlainTextParser.class, new RuntimeException("boom"), null); + rewriteRun( + spec -> spec.recipe(new FindParseFailures(5, null, null, "2025-01-02")) + .dataTable(ParseFailures.Row.class, rows -> { + assertThat(rows).hasSize(1); + ParseFailures.Row row = rows.get(0); + assertThat(row.getParser()).isEqualTo("PlainTextParser"); + assertThat(row.getSourcePath()).isEqualTo("file1.txt"); + assertThat(row.getExceptionType()).isEqualTo("RuntimeException"); + assertThat(row.getSnippet()).isEqualTo("hello"); + }), + text( + "hello world!", + spec -> spec + .path("file0.txt") + .mapBeforeRecipe(pt -> pt + .withMarkers(Markers.build(Set.of(new BuildMetadata(randomId(), Map.of("createdAt", Long.toString(t0)))))) + .withSnippets(List.of(new PlainText.Snippet( + randomId(), + new Markers(randomId(), List.of(per)), + pt.getText()))) + .withText("") + ) + ), + text( + "hello world!", + "~~(%s)~~>hello world!".formatted(per.getMessage()), + spec -> spec + .path("file1.txt") + .mapBeforeRecipe(pt -> pt + .withMarkers(Markers.build(Set.of(new BuildMetadata(randomId(), Map.of("createdAt", Long.toString(t1)))))) + .withSnippets(List.of(new PlainText.Snippet( + randomId(), + new Markers(randomId(), List.of(per)), pt.getText()))) .withText("") )