Skip to content

Commit 7994ffc

Browse files
committed
RewriteTest: framework-agnostic ExecutionContext customizer registry
Adds `RewriteTest.defaultExecutionContextCustomizers`, a `Map<Class<?>, Consumer<ExecutionContext>>` applied to the context built by `defaultExecutionContext`. Test framework integrations (JUnit, TestNG, Spock, …) can register a customizer keyed by their own class without `rewrite-test` taking a dependency on any framework; `putIfAbsent` makes registration naturally idempotent. First consumer: a JUnit Jupiter `BeforeAllCallback` in rewrite-gradle's test sources, auto-detected via service loader, that loads `~/.m2/settings.xml` into the ExecutionContext. Recipes resolving Maven artifacts during rewrite-gradle tests then honor any configured mirror, sidestepping Maven Central rate limits (HTTP 404 + Retry-After) under parallel load. Gradle does not normally read the user's Maven settings, so this opt-in lives entirely in test sources of openrewrite/rewrite — not in any published API surface.
1 parent bbe3b20 commit 7994ffc

4 files changed

Lines changed: 73 additions & 0 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2026 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.gradle;
17+
18+
import org.junit.jupiter.api.extension.BeforeAllCallback;
19+
import org.junit.jupiter.api.extension.ExtensionContext;
20+
import org.openrewrite.ExecutionContext;
21+
import org.openrewrite.maven.MavenExecutionContextView;
22+
import org.openrewrite.maven.MavenSettings;
23+
import org.openrewrite.test.RewriteTest;
24+
25+
import static org.openrewrite.maven.tree.MavenRepository.MAVEN_LOCAL_DEFAULT;
26+
27+
/**
28+
* Loads {@code ~/.m2/settings.xml} (and {@code $M2_HOME/conf/settings.xml}) into the
29+
* default {@link ExecutionContext} for every {@link RewriteTest} in this module, so a
30+
* configured Maven mirror or repository is honored by recipes that resolve artifacts.
31+
* Auto-registered via {@code META-INF/services/org.junit.jupiter.api.extension.Extension};
32+
* Gradle does not normally read the user's Maven settings, so this is opt-in at the
33+
* module test classpath level.
34+
*/
35+
public class MavenSettingsAutoLoadingExtension implements BeforeAllCallback {
36+
37+
@Override
38+
public void beforeAll(ExtensionContext context) {
39+
RewriteTest.defaultExecutionContextCustomizers.putIfAbsent(
40+
MavenSettingsAutoLoadingExtension.class,
41+
MavenSettingsAutoLoadingExtension::loadMavenSettings);
42+
}
43+
44+
private static void loadMavenSettings(ExecutionContext ctx) {
45+
MavenExecutionContextView mctx = MavenExecutionContextView.view(ctx);
46+
boolean nothingConfigured = mctx.getSettings() == null &&
47+
mctx.getLocalRepository().equals(MAVEN_LOCAL_DEFAULT) &&
48+
mctx.getRepositories().isEmpty() &&
49+
mctx.getActiveProfiles().isEmpty() &&
50+
mctx.getMirrors().isEmpty();
51+
if (nothingConfigured) {
52+
mctx.setMavenSettings(MavenSettings.readMavenSettingsFromDisk(mctx));
53+
}
54+
}
55+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.openrewrite.gradle.MavenSettingsAutoLoadingExtension
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
junit.jupiter.extensions.autodetection.enabled=true

rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.nio.charset.StandardCharsets;
3636
import java.nio.file.Path;
3737
import java.util.*;
38+
import java.util.concurrent.ConcurrentHashMap;
3839
import java.util.concurrent.CopyOnWriteArrayList;
3940
import java.util.function.Consumer;
4041
import java.util.function.Function;
@@ -51,6 +52,18 @@
5152

5253
@SuppressWarnings("unused")
5354
public interface RewriteTest extends SourceSpecs {
55+
/**
56+
* Registry of customizers applied to the {@link ExecutionContext} produced by
57+
* {@link #defaultExecutionContext(SourceSpec[])}. Test framework integrations
58+
* (e.g. a JUnit Jupiter {@code BeforeAllCallback}) can register a customizer
59+
* once at startup without {@code rewrite-test} taking a dependency on the
60+
* framework.
61+
* <p>
62+
* The map is keyed by the integration's class so {@code putIfAbsent(MyExt.class, MyExt::load)}
63+
* is naturally idempotent — callers do not need their own one-shot guard.
64+
*/
65+
Map<Class<?>, Consumer<ExecutionContext>> defaultExecutionContextCustomizers = new ConcurrentHashMap<>();
66+
5467
static AdHocRecipe toRecipe(Supplier<TreeVisitor<?, ExecutionContext>> visitor) {
5568
return new AdHocRecipe(null, null, null, visitor, null, null);
5669
}
@@ -696,6 +709,9 @@ default ExecutionContext defaultExecutionContext(SourceSpec<?>[] sourceSpecs) {
696709
}
697710
fail("Failed to parse sources or run recipe", t);
698711
});
712+
for (Consumer<ExecutionContext> customizer : defaultExecutionContextCustomizers.values()) {
713+
customizer.accept(ctx);
714+
}
699715
return ParsingExecutionContextView.view(ctx).setCharset(StandardCharsets.UTF_8);
700716
}
701717

0 commit comments

Comments
 (0)