Skip to content

Commit ee2a961

Browse files
authored
Merge branch 'main' into tim/issue-7548
2 parents 7940c80 + ea81d80 commit ee2a961

186 files changed

Lines changed: 15848 additions & 1887 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,45 @@ concurrency:
2020

2121
jobs:
2222
build:
23-
uses: openrewrite/gh-automation/.github/workflows/ci-gradle.yml@main
24-
with:
25-
java_version: |
26-
25
27-
21
28-
secrets:
29-
gradle_enterprise_access_key: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
30-
sonatype_username: ${{ secrets.SONATYPE_USERNAME }}
31-
sonatype_token: ${{ secrets.SONATYPE_TOKEN}}
32-
ossrh_signing_key: ${{ secrets.OSSRH_SIGNING_KEY }}
33-
ossrh_signing_password: ${{ secrets.OSSRH_SIGNING_PASSWORD }}
34-
OPS_GITHUB_ACTIONS_WEBHOOK: ${{ secrets.OPS_GITHUB_ACTIONS_WEBHOOK }}
35-
node_auth_token: ${{ secrets.NPM_TOKEN }}
36-
pypi_token: ${{ secrets.PYPI_OPENREWRITE_PUBLISH }}
37-
nuget_api_key: ${{ secrets.NUGET_API_KEY }}
23+
runs-on: ubuntu-latest
24+
if: github.event_name != 'schedule' || github.repository_owner == 'openrewrite' || github.repository_owner == 'moderneinc'
25+
steps:
26+
- uses: openrewrite/gh-automation/.github/actions/setup@main
27+
with:
28+
java_version: |
29+
25
30+
21
31+
develocity_access_key: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
32+
33+
# Route Maven resolution through Moderne's Artifactory cache to avoid
34+
# Maven Central rate-limiting (HTTP 404 + Retry-After) under parallel
35+
# test load. Picked up by MavenSettingsAutoLoadingExtension at test time.
36+
- uses: s4u/maven-settings-action@v3.1.0
37+
with:
38+
mirrors: '[{"id": "moderne-cache", "name": "Moderne Artifactory Cache", "mirrorOf": "*", "url": "https://artifactory.moderne.ninja/artifactory/moderne-cache-3/"}]'
39+
servers: '[{"id": "moderne-cache", "username": "${{ secrets.ARTIFACTORY_USERNAME }}", "password": "${{ secrets.ARTIFACTORY_PASSWORD }}"}]'
40+
41+
- uses: openrewrite/gh-automation/.github/actions/build@main
42+
env:
43+
REWRITE_GRADLE_MIRROR_URL: https://artifactory.moderne.ninja/artifactory/moderne-cache-3/
44+
REWRITE_GRADLE_MIRROR_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
45+
REWRITE_GRADLE_MIRROR_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
46+
47+
- if: failure() && github.event_name == 'schedule' && (github.repository_owner == 'openrewrite' || github.repository_owner == 'moderneinc')
48+
uses: openrewrite/gh-automation/.github/actions/slack-failure@main
49+
with:
50+
webhook: ${{ secrets.OPS_GITHUB_ACTIONS_WEBHOOK }}
51+
52+
- if: >
53+
github.event_name != 'pull_request' &&
54+
github.ref == 'refs/heads/main' &&
55+
(github.repository_owner == 'openrewrite' || github.repository_owner == 'moderneinc')
56+
uses: openrewrite/gh-automation/.github/actions/publish-snapshots@main
57+
with:
58+
sonatype_username: ${{ secrets.SONATYPE_USERNAME }}
59+
sonatype_token: ${{ secrets.SONATYPE_TOKEN }}
60+
ossrh_signing_key: ${{ secrets.OSSRH_SIGNING_KEY }}
61+
ossrh_signing_password: ${{ secrets.OSSRH_SIGNING_PASSWORD }}
62+
node_auth_token: ${{ secrets.NPM_TOKEN }}
63+
pypi_token: ${{ secrets.PYPI_OPENREWRITE_PUBLISH }}
64+
nuget_api_key: ${{ secrets.NUGET_API_KEY }}

rewrite-core/src/main/java/org/openrewrite/rpc/RewriteRpc.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,29 @@ protected Boolean handle(TraceGetObject request) {
176176
jsonRpc.rpc("GetLanguages", new JsonRpcMethod<Void>() {
177177
@Override
178178
protected Object handle(Void noParams) {
179+
// Advertise every SourceFile type Java has a receiver for so that
180+
// remote peers know they can hand any of these off to Java for
181+
// visiting. Each entry is gated by ifOnClasspath so the actual
182+
// set narrows to whichever rewrite-* modules are loaded in this
183+
// process.
179184
return Stream.of(
180185
ifOnClasspath("org.openrewrite.text.PlainText"),
181186
ifOnClasspath("org.openrewrite.json.tree.Json$Document"),
187+
ifOnClasspath("org.openrewrite.yaml.tree.Yaml$Documents"),
188+
ifOnClasspath("org.openrewrite.xml.tree.Xml$Document"),
189+
ifOnClasspath("org.openrewrite.hcl.tree.Hcl$ConfigFile"),
190+
ifOnClasspath("org.openrewrite.properties.tree.Properties$File"),
191+
ifOnClasspath("org.openrewrite.toml.tree.Toml$Document"),
192+
ifOnClasspath("org.openrewrite.protobuf.tree.Proto$Document"),
193+
ifOnClasspath("org.openrewrite.docker.tree.Docker$File"),
182194
ifOnClasspath("org.openrewrite.java.tree.J$CompilationUnit"),
183-
ifOnClasspath("org.openrewrite.javascript.tree.JS$CompilationUnit")
195+
ifOnClasspath("org.openrewrite.javascript.tree.JS$CompilationUnit"),
196+
ifOnClasspath("org.openrewrite.kotlin.tree.K$CompilationUnit"),
197+
ifOnClasspath("org.openrewrite.groovy.tree.G$CompilationUnit"),
198+
ifOnClasspath("org.openrewrite.csharp.tree.Cs$CompilationUnit"),
199+
ifOnClasspath("org.openrewrite.python.tree.Py$CompilationUnit"),
200+
ifOnClasspath("org.openrewrite.golang.tree.Go$CompilationUnit"),
201+
ifOnClasspath("org.openrewrite.scala.tree.S$CompilationUnit")
184202
).filter(Objects::nonNull).toArray(String[]::new);
185203
}
186204

rewrite-core/src/main/java/org/openrewrite/scheduling/RecipeRunCycle.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -327,14 +327,20 @@ void clear() {
327327
}
328328

329329
if (isInBatch) {
330-
// Batch path: accumulate visitor names instead of executing
331-
RpcRecipe rpcRecipe = (RpcRecipe) recipe;
332-
batch.items.add(new BatchVisit.BatchVisitItem(rpcRecipe.getEditVisitor(), null));
333-
batch.recipeStacks.add(recipeStack);
334-
if (batch.originalBeforeBatch == null) {
335-
batch.originalBeforeBatch = src;
330+
// Batch path: accumulate visitor names instead of executing.
331+
// Only batch if the remote actually has a codec for this source file type;
332+
// otherwise the BatchVisit RPC fails on the remote side and the resulting
333+
// exception gets attached to the source as a Markup$Error, falsely marking
334+
// the file as modified.
335+
if (currentRpc.getLanguages().contains(src.getClass().getName())) {
336+
RpcRecipe rpcRecipe = (RpcRecipe) recipe;
337+
batch.items.add(new BatchVisit.BatchVisitItem(rpcRecipe.getEditVisitor(), null));
338+
batch.recipeStacks.add(recipeStack);
339+
if (batch.originalBeforeBatch == null) {
340+
batch.originalBeforeBatch = src;
341+
}
342+
batch.rpc = currentRpc;
336343
}
337-
batch.rpc = currentRpc;
338344

339345
// If this is the last recipe in the batch, flush now
340346
if (nextRpc != currentRpc) {

rewrite-core/src/test/java/org/openrewrite/rpc/RewriteRpcTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,35 @@ void batchVisitExceptionProducesErrorMarker() {
451451
.isPresent();
452452
}
453453

454+
/**
455+
* Source files whose type the remote does not advertise via GetLanguages must
456+
* not be added to a BatchVisit. Without this gate the remote's receiver crashes
457+
* on the unknown type and the resulting exception is attached to the file as a
458+
* Markup.Error marker, falsely reporting the file as modified.
459+
*/
460+
@Test
461+
void batchSkipsSourceFilesNotInRemoteLanguages() {
462+
// given
463+
// Two consecutive same-RPC recipes are required for the batch path to kick in
464+
Recipe r1 = client.prepareRecipe("org.openrewrite.text.ChangeText", Map.of("toText", "step1"));
465+
Recipe r2 = client.prepareRecipe("org.openrewrite.text.ChangeText", Map.of("toText", "step2"));
466+
467+
// Quark is not in the hardcoded GetLanguages list, so the batch path must skip it.
468+
var quark = new org.openrewrite.quark.Quark(UUID.randomUUID(), Path.of("unknown.bin"), Markers.EMPTY, null, null);
469+
470+
var ctx = new InMemoryExecutionContext();
471+
RecipeRun run = new RecipeScheduler().scheduleRun(
472+
new CompositeRecipe(List.of(r1, r2)),
473+
new InMemoryLargeSourceSet(List.of(quark)), ctx, 1, 1);
474+
475+
// then
476+
assertThat(run.getChangeset().getAllResults())
477+
.describedAs("Quark of an unsupported language type should pass through untouched")
478+
.allSatisfy(result -> assertThat(result.getAfter().getMarkers().findFirst(Markup.Error.class))
479+
.describedAs("No Markup.Error should be attached for an unsupported source type")
480+
.isEmpty());
481+
}
482+
454483
@Test
455484
void getCursor() {
456485
var parent = new Cursor(null, Cursor.ROOT_VALUE);

rewrite-go/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
rewrite/test-classpath.txt
1+
test-classpath.txt
2+
/rpc

rewrite-go/Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.PHONY: test parity
2+
3+
# Default test run — what CI executes. Build-tag-gated tests stay out.
4+
test:
5+
go test ./...
6+
7+
# Printer fidelity audit. Loads every fixture under
8+
# test/printer-corpus/, parses + prints, and asserts byte-equality.
9+
# Gated behind the `parityaudit` build tag so it never runs in CI;
10+
# devs invoke it manually when investigating printer regressions.
11+
#
12+
# Trade-off (per the eng review's P2 decision): corpus regressions ship
13+
# undetected by automation in exchange for fast iteration and simple
14+
# test infra. Re-evaluate if a corpus-detectable bug ever lands.
15+
parity:
16+
go test -tags parityaudit ./pkg/printer/...

rewrite-go/PLAN.md

Lines changed: 0 additions & 63 deletions
This file was deleted.

rewrite-go/build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ tasks.withType<Javadoc>().configureEach {
3030
exclude("**/G.java")
3131
}
3232

33+
// Test fixtures for the GoMod conformance corpus are .gomod / .gosum / .json
34+
// files; none of these formats accept a leading license header.
35+
configure<nl.javadude.gradle.plugins.license.LicenseExtension> {
36+
excludePatterns.addAll(listOf("**/*.gomod", "**/*.gosum", "**/*.json"))
37+
}
38+
3339
val goBuild = tasks.register<Exec>("goBuild") {
3440
workingDir = projectDir
3541
// Use relative path to avoid absolute paths in cache key (Exec args are cache inputs)

0 commit comments

Comments
 (0)