From 2ab75969df9e9b8729564f246092b393474a6eea Mon Sep 17 00:00:00 2001
From: Peter Streef
Date: Tue, 27 Aug 2024 10:49:08 +0200
Subject: [PATCH] Flush `RecipeRunStats` on exception to record stats for
failing recipes
---
.../java/org/openrewrite/RecipeScheduler.java | 90 ++++++++++---------
1 file changed, 46 insertions(+), 44 deletions(-)
diff --git a/rewrite-core/src/main/java/org/openrewrite/RecipeScheduler.java b/rewrite-core/src/main/java/org/openrewrite/RecipeScheduler.java
index 73eb8832a07..795dad5b841 100644
--- a/rewrite-core/src/main/java/org/openrewrite/RecipeScheduler.java
+++ b/rewrite-core/src/main/java/org/openrewrite/RecipeScheduler.java
@@ -60,58 +60,60 @@ private LargeSourceSet runRecipeCycles(Recipe recipe, LargeSourceSet sourceSet,
LargeSourceSet after = sourceSet;
- for (int i = 1; i <= maxCycles; i++) {
- if (ctx.getMessage(PANIC) != null) {
- break;
- }
-
- // this root cursor is shared by all `TreeVisitor` instances used created from `getVisitor` and
- // single source applicable tests so that data can be shared at the root (especially for caching
- // use cases like sharing a `JavaTypeCache` between `JavaTemplate` parsers).
- Cursor rootCursor = new Cursor(null, Cursor.ROOT_VALUE);
- try {
- RecipeRunCycle cycle = new RecipeRunCycle<>(recipe, i, rootCursor, ctxWithWatch,
- recipeRunStats, sourceFileResults, errorsTable, LargeSourceSet::edit);
- ctxWithWatch.putCycle(cycle);
- after.beforeCycle(i == maxCycles);
-
- // pre-transformation scanning phase where there can only be modifications to capture exceptions
- // occurring during the scanning phase
- if (hasScanningRecipe(recipe)) {
- after = cycle.scanSources(after);
+ try {
+ for (int i = 1; i <= maxCycles; i++) {
+ if (ctx.getMessage(PANIC) != null) {
+ break;
}
- // transformation phases
- after = cycle.generateSources(after);
- after = cycle.editSources(after);
+ // this root cursor is shared by all `TreeVisitor` instances used created from `getVisitor` and
+ // single source applicable tests so that data can be shared at the root (especially for caching
+ // use cases like sharing a `JavaTypeCache` between `JavaTemplate` parsers).
+ Cursor rootCursor = new Cursor(null, Cursor.ROOT_VALUE);
+ try {
+ RecipeRunCycle cycle = new RecipeRunCycle<>(recipe, i, rootCursor, ctxWithWatch,
+ recipeRunStats, sourceFileResults, errorsTable, LargeSourceSet::edit);
+ ctxWithWatch.putCycle(cycle);
+ after.beforeCycle(i == maxCycles);
+
+ // pre-transformation scanning phase where there can only be modifications to capture exceptions
+ // occurring during the scanning phase
+ if (hasScanningRecipe(recipe)) {
+ after = cycle.scanSources(after);
+ }
+
+ // transformation phases
+ after = cycle.generateSources(after);
+ after = cycle.editSources(after);
- boolean anyRecipeCausingAnotherCycle = false;
- for (Recipe madeChanges : cycle.getMadeChangesInThisCycle()) {
- if (madeChanges.causesAnotherCycle()) {
- anyRecipeCausingAnotherCycle = true;
+ boolean anyRecipeCausingAnotherCycle = false;
+ for (Recipe madeChanges : cycle.getMadeChangesInThisCycle()) {
+ if (madeChanges.causesAnotherCycle()) {
+ anyRecipeCausingAnotherCycle = true;
+ }
}
- }
- if (i >= minCycles &&
- (cycle.getMadeChangesInThisCycle().isEmpty() || !anyRecipeCausingAnotherCycle)) {
- after.afterCycle(true);
- break;
- }
+ if (i >= minCycles &&
+ (cycle.getMadeChangesInThisCycle().isEmpty() || !anyRecipeCausingAnotherCycle)) {
+ after.afterCycle(true);
+ break;
+ }
- after.afterCycle(i == maxCycles);
- ctxWithWatch.resetHasNewMessages();
- } finally {
- // Clear any messages that were added to the root cursor during the cycle. This is important
- // to avoid leaking memory in the case when a recipe defines a static TreeVisitor. That
- // TreeVisitor will still contain a reference to this rootCursor and any messages in it
- // after recipe execution completes. The pattern of holding a static TreeVisitor isn't
- // recommended, but isn't possible for us to guard against at an API level, and so we are
- // defensive about memory consumption here.
- rootCursor.clearMessages();
+ after.afterCycle(i == maxCycles);
+ ctxWithWatch.resetHasNewMessages();
+ } finally {
+ // Clear any messages that were added to the root cursor during the cycle. This is important
+ // to avoid leaking memory in the case when a recipe defines a static TreeVisitor. That
+ // TreeVisitor will still contain a reference to this rootCursor and any messages in it
+ // after recipe execution completes. The pattern of holding a static TreeVisitor isn't
+ // recommended, but isn't possible for us to guard against at an API level, and so we are
+ // defensive about memory consumption here.
+ rootCursor.clearMessages();
+ }
}
+ } finally {
+ recipeRunStats.flush(ctx);
}
-
- recipeRunStats.flush(ctx);
return after;
}