Skip to content

Commit

Permalink
Add repository results standard data table
Browse files Browse the repository at this point in the history
  • Loading branch information
pstreef committed Feb 13, 2024
1 parent 1fa4b4e commit c383a2b
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.openrewrite.scheduling.RecipeRunCycle;
import org.openrewrite.scheduling.WatchableExecutionContext;
import org.openrewrite.table.RecipeRunStats;
import org.openrewrite.table.RepositoryResults;
import org.openrewrite.table.SourcesFileErrors;
import org.openrewrite.table.SourcesFileResults;

Expand Down Expand Up @@ -57,6 +58,7 @@ private LargeSourceSet runRecipeCycles(Recipe recipe, LargeSourceSet sourceSet,
RecipeRunStats recipeRunStats = new RecipeRunStats(Recipe.noop());
SourcesFileErrors errorsTable = new SourcesFileErrors(Recipe.noop());
SourcesFileResults sourceFileResults = new SourcesFileResults(Recipe.noop());
RepositoryResults repositoryResults = new RepositoryResults(Recipe.noop());

LargeSourceSet after = sourceSet;

Expand All @@ -71,7 +73,7 @@ private LargeSourceSet runRecipeCycles(Recipe recipe, LargeSourceSet sourceSet,
Cursor rootCursor = new Cursor(null, Cursor.ROOT_VALUE);
try {
RecipeRunCycle<LargeSourceSet> cycle = new RecipeRunCycle<>(recipe, i, rootCursor, ctxWithWatch,
recipeRunStats, sourceFileResults, errorsTable, LargeSourceSet::edit);
recipeRunStats, sourceFileResults, repositoryResults, errorsTable, LargeSourceSet::edit);
ctxWithWatch.putCycle(cycle);
after.beforeCycle();

Expand Down Expand Up @@ -111,6 +113,7 @@ private LargeSourceSet runRecipeCycles(Recipe recipe, LargeSourceSet sourceSet,
}
}

repositoryResults.flush(ctx);
recipeRunStats.flush(ctx);
return after;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.openrewrite.marker.Generated;
import org.openrewrite.marker.RecipesThatMadeChanges;
import org.openrewrite.table.RecipeRunStats;
import org.openrewrite.table.RepositoryResults;
import org.openrewrite.table.SourcesFileErrors;
import org.openrewrite.table.SourcesFileResults;

Expand Down Expand Up @@ -59,6 +60,7 @@ public class RecipeRunCycle<LSS extends LargeSourceSet> {
WatchableExecutionContext ctx;
RecipeRunStats recipeRunStats;
SourcesFileResults sourcesFileResults;
RepositoryResults repositoryResults;
SourcesFileErrors errorsTable;
BiFunction<LSS, UnaryOperator<SourceFile>, LSS> sourceSetEditor;

Expand Down Expand Up @@ -209,6 +211,8 @@ private void recordSourceFileResult(@Nullable SourceFile before, @Nullable Sourc
recipeName,
effortSeconds,
cycle));
repositoryResults.recordResult(before, recipeStack, effortSeconds);

if (hierarchical) {
recordSourceFileResult(beforePath, afterPath, recipeStack.subList(0, recipeStack.size() - 1), effortSeconds, ctx);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright 2022 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.table;

import lombok.Value;
import lombok.With;
import org.openrewrite.*;
import org.openrewrite.config.CompositeRecipe;
import org.openrewrite.internal.lang.Nullable;

import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

public class RepositoryResults extends DataTable<RepositoryResults.Row> {

private final Map<RecipeKey, Counter> counters = new HashMap<>();

public RepositoryResults(Recipe recipe) {
super(recipe, "Source files that had results",
"Source files that were modified by the recipe run.");
}

@Value
@With
public static class Row {
@Column(displayName = "Root of the recipe that made changes",
description = "The root recipe that made a change.")
String rootRecipe;

@Column(displayName = "First child recipe that made changes",
description = "The first child recipe that made a change.")
String recipe;

@Column(displayName = "Recipe options",
description = "The options of the first child (or root, if they are equal) recipe that made a change.")
String recipeOptions;

@Column(displayName = "Estimated time saving",
description = "An estimated effort that a developer to fix manually instead of using this recipe," +
" in unit of seconds.")
Long estimatedTimeSaving;

@Column(displayName = "Occurrences",
description = "The total number of changes made to this repository.")
int occurrences;

@Column(displayName = "Files changed",
description = "The number of files changed to this repository.")
int filesChanged;
}

public void recordResult(@Nullable SourceFile before, Stack<Recipe> recipeStack, Long effortSeconds) {
int rootIndex = 0;

Recipe root = recipeStack.get(rootIndex);
// Skip any CompositeRecipe wrappers
while (root instanceof CompositeRecipe) {
root = recipeStack.get(++rootIndex);
}
Recipe recipe = recipeStack.size() < rootIndex + 1 ? root : recipeStack.get(rootIndex + 1);
String rootName = root == null ? "" : root.getName();
String recipeName = recipe == null ? "" : recipe.getName();
String options = recipe == null ? "[]" : recipe.getDescriptor().getOptions().stream()
.filter(option -> option.getValue() != null)
.map(option -> {
String valueAsString = option.getValue().toString();
String quotedValue;
if (valueAsString.contains("\"")) {
quotedValue = "`" + valueAsString + "`";
} else {
quotedValue = "\"" + valueAsString + "\"";
}
return option.getName() + "=" + quotedValue;
})
.collect(Collectors.joining(", ", "[", "]"));

Counter counter = counters.computeIfAbsent(new RecipeKey(rootName, recipeName, options), k -> new Counter());
if (before == null || counter.beforeFiles.add(before.getSourcePath())) {
counter.filesChanged++;
}
counter.occurrences++;
counter.estimatedTimeSavings += effortSeconds;
}

public void flush(ExecutionContext ctx) {
maxCycle = ctx.getCycle(); //allow to write to this data table after last cycle
for (Map.Entry<RecipeKey, Counter> entry : counters.entrySet()) {
insertRow(ctx, new Row(entry.getKey().getRootName(), entry.getKey().getRecipeName(), entry.getKey().getOptions(), entry.getValue().estimatedTimeSavings, entry.getValue().occurrences, entry.getValue().filesChanged));
}
}

private static class Counter {
int occurrences = 0;
long estimatedTimeSavings = 0;
int filesChanged = 0;
Set<Path> beforeFiles = new HashSet<>();
}

@Value
private static class RecipeKey {
String rootName;
String recipeName;
String options;
}

@Value
private static class Option {
String name;
Object value;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.table;

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.test.RewriteTest;

import java.io.ByteArrayInputStream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.openrewrite.test.SourceSpecs.text;

class RepositoryResultsTest implements RewriteTest {

@DocumentExample
@Test
void hierarchical() {
rewriteRun(
spec -> spec
.recipe(
new ByteArrayInputStream(
//language=yml
"""
type: specs.openrewrite.org/v1beta/recipe
name: test.ChangeTextToHello
displayName: Change text to hello
description: Hello world.
recipeList:
- org.openrewrite.text.FindAndReplace:
find: Hi
replace: Hello!
- org.openrewrite.text.FindAndReplace:
find: Hey
replace: '"Hello!"'
""".getBytes()
),
"test.ChangeTextToHello"
).dataTable(RepositoryResults.Row.class, rows -> {
assertThat(rows).hasSize(2);
assertThat(rows.stream().map(RepositoryResults.Row::getOccurrences))
.containsExactly(1, 1);
assertThat(rows.stream().map(RepositoryResults.Row::getRecipe))
.containsExactly("org.openrewrite.text.FindAndReplace", "org.openrewrite.text.FindAndReplace");
assertThat(rows.stream().map(RepositoryResults.Row::getRecipeOptions))
.containsExactly("[find=\"Hi\", replace=\"Hello!\"]", "[find=\"Hey\", replace=`\"Hello!\"`]");
}),
text(
"Hi",
"Hello!"
),
text(
"Hey",
"\"Hello!\""
)
);
}
}

0 comments on commit c383a2b

Please sign in to comment.