Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
2581500
Go mod tidy recipe + module-graph resolution (modgraph, proxy/HttpSen…
sambsnyd Jun 18, 2026
5c18cb1
Go: immutable RPC visitor + cross-language whitespace round-trip fix
sambsnyd Jun 20, 2026
5d09d2e
Go: write-through module cache + recipe-time graph re-resolution
sambsnyd Jun 20, 2026
8f125d8
Go: add go1.17+ pruning-completeness roots to GoModTidy (exact parity)
sambsnyd Jun 20, 2026
8a2f2db
Go: compute pruned selection in memory, dropping per-iteration re-res…
sambsnyd Jun 20, 2026
f42ff4b
Go: scope GoModTidy imports per-module for multi-module repositories
sambsnyd Jun 20, 2026
9dd862d
Go: process pruning-completeness roots frontier-by-frontier (depth or…
sambsnyd Jun 20, 2026
b302dc5
Go: tidy GoModTidy after the recipe gained full module-graph resolution
sambsnyd Jun 20, 2026
c0ace04
Go: remove dead PlainText paths; recover imports from build-excluded …
sambsnyd Jun 22, 2026
58efe41
Go: drop bespoke offline env vars; use GOPROXY=off like the toolchain
sambsnyd Jun 23, 2026
49253f8
Polish
sambsnyd Jun 23, 2026
1b0c2c7
Go: Java module resolver, phase 1-2 (foundations + HttpSender ModSource)
sambsnyd Jun 23, 2026
34538f3
Go: Java module resolver, phase 3 (pruned MVS Resolve)
sambsnyd Jun 23, 2026
f1aeb35
Go: Java module resolver, phase 4 (tidy require set + pruning-complet…
sambsnyd Jun 23, 2026
bb4fe7d
Go: phase 5 — route go.mod tidy to the Java resolver; remove Go modgr…
sambsnyd Jun 24, 2026
e1308e1
Go: wire test for the GoModResolveTidy RPC client half
sambsnyd Jun 24, 2026
df403d2
Go: move HttpSender plumbing out of core RewriteRpc into GoRewriteRpc
sambsnyd Jun 24, 2026
9bf5535
Go: keep RewriteRpc untouched — self-register + capture HttpSender in…
sambsnyd Jun 24, 2026
c0c3d01
Moving go-mod-tidy to recipes-go
sambsnyd Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 203 additions & 92 deletions rewrite-go/cmd/rpc/main.go

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions rewrite-go/cmd/rpc/receive_resilience_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ func TestGetObjectFromJavaPanicResetsBaselineButKeepsRefs(t *testing.T) {
// Pre-seed state a live session would hold from prior successful cycles:
// - a baseline that diverges from Java's once the receive panics, and
// - a shared ref the panic must NOT wipe.
s.reverseRemoteObjects[id] = "STALE-BASELINE"
s.reverseRemoteRefs[5] = "shared-value-from-earlier-transfer"
s.remoteObjects[id] = "STALE-BASELINE"
s.remoteRefs[5] = "shared-value-from-earlier-transfer"

// Transfer 1: must panic mid-receive.
panicked := func() (p bool) {
Expand All @@ -93,12 +93,12 @@ func TestGetObjectFromJavaPanicResetsBaselineButKeepsRefs(t *testing.T) {
}

// Containment: the diverged per-id baseline is dropped.
if v, ok := s.reverseRemoteObjects[id]; ok {
t.Errorf("reverseRemoteObjects[%q] should be deleted after a receive panic, still present: %v", id, v)
if v, ok := s.remoteObjects[id]; ok {
t.Errorf("remoteObjects[%q] should be deleted after a receive panic, still present: %v", id, v)
}
// ...but the shared ref table survives.
if got := s.reverseRemoteRefs[5]; got != "shared-value-from-earlier-transfer" {
t.Errorf("reverseRemoteRefs[5] should survive a receive panic, got %v", got)
if got := s.remoteRefs[5]; got != "shared-value-from-earlier-transfer" {
t.Errorf("remoteRefs[5] should survive a receive panic, got %v", got)
}

// Transfer 2: a fresh request on the same server must succeed cleanly,
Expand All @@ -107,7 +107,7 @@ func TestGetObjectFromJavaPanicResetsBaselineButKeepsRefs(t *testing.T) {
if got != "package main\n" {
t.Errorf("transfer 2: want clean ADD value %q, got %#v", "package main\n", got)
}
if s.reverseRemoteObjects[id] != "package main\n" {
t.Errorf("transfer 2: baseline should be repopulated, got %#v", s.reverseRemoteObjects[id])
if s.remoteObjects[id] != "package main\n" {
t.Errorf("transfer 2: baseline should be repopulated, got %#v", s.remoteObjects[id])
}
}
100 changes: 100 additions & 0 deletions rewrite-go/cmd/rpc/resolve_tidy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2026 the original author or authors.
*
* Licensed under the Moderne Source Available License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://docs.moderne.io/licensing/moderne-source-available-license
*
* 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 main

import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"path/filepath"
"strings"
"testing"
)

// TestResolveTidyViaJavaWireProtocol exercises the Go half of the
// GoModResolveTidy RPC: it feeds a canned Java response and asserts both that
// resolveTidyViaJava parses it correctly AND that the request it writes carries
// the exact field names the Java GoModResolveTidyRequest expects. This guards
// the cross-process contract that the in-Java handler test cannot see.
func TestResolveTidyViaJavaWireProtocol(t *testing.T) {
s := newServer(serverConfig{logFile: filepath.Join(t.TempDir(), "server.log")})

// Canned host response: direct/indirect/complete, JSON-RPC framed.
respBody := `{"jsonrpc":"2.0","id":"go-GoModResolveTidy","result":` +
`{"direct":{"github.com/a/x":"v1.2.3"},"indirect":{"github.com/b/y":"v0.4.0"},"complete":true}}`
framed := fmt.Sprintf("Content-Length: %d\r\n\r\n%s", len(respBody), respBody)
s.reader = bufio.NewReader(strings.NewReader(framed))
var written bytes.Buffer
s.writer = &written

rs, ok := s.resolveTidyViaJava("module example.com/m\n\ngo 1.21\n",
[]string{"github.com/a/x", "fmt"}, "example.com/m", true)

// Response parsed correctly.
if !ok {
t.Fatal("expected ok=true")
}
if !rs.Complete {
t.Error("expected Complete=true")
}
if rs.Direct["github.com/a/x"] != "v1.2.3" {
t.Errorf("direct: got %v", rs.Direct)
}
if rs.Indirect["github.com/b/y"] != "v0.4.0" {
t.Errorf("indirect: got %v", rs.Indirect)
}

// Request written with the method and param field names the Java side expects.
body := written.String()
if i := strings.Index(body, "\r\n\r\n"); i >= 0 {
body = body[i+4:]
}
var req struct {
Method string `json:"method"`
Params struct {
GoMod string `json:"goMod"`
MainImports []string `json:"mainImports"`
ModulePath string `json:"modulePath"`
SeparateIndirect bool `json:"separateIndirect"`
Goproxy string `json:"goproxy"`
Gomodcache string `json:"gomodcache"`
} `json:"params"`
}
if err := json.Unmarshal([]byte(body), &req); err != nil {
t.Fatalf("request JSON: %v\nbody=%s", err, body)
}
if req.Method != "GoModResolveTidy" {
t.Errorf("method: got %q", req.Method)
}
if !strings.Contains(req.Params.GoMod, "module example.com/m") {
t.Errorf("goMod not propagated: %q", req.Params.GoMod)
}
if req.Params.ModulePath != "example.com/m" {
t.Errorf("modulePath: got %q", req.Params.ModulePath)
}
if !req.Params.SeparateIndirect {
t.Error("separateIndirect should be true")
}
if len(req.Params.MainImports) != 2 || req.Params.MainImports[0] != "github.com/a/x" {
t.Errorf("mainImports: got %v", req.Params.MainImports)
}
if req.Params.Goproxy == "" || req.Params.Gomodcache == "" {
t.Errorf("goproxy/gomodcache should be populated from env: %q / %q",
req.Params.Goproxy, req.Params.Gomodcache)
}
}
Loading