diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fe223a81..dc0a0ac7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,7 +2,7 @@ name: ci on: push: branches: [main, v2] - tags: ['v*'] + tags: ['v*', 'cmd/connect-go-v2-migrate/v*'] pull_request: branches: [main, v2] schedule: @@ -86,9 +86,10 @@ jobs: with: fetch-depth: 1 - name: Install Go - uses: actions/setup-go@v6 + uses: actions/setup-go@v7 with: # only the latest - go-version: 1.26.x + go-version: 1.27.x + check-latest: true - name: Test Migration Tool run: make testmigrate diff --git a/Makefile b/Makefile index 87f88b97..b79691c1 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ clean: ## Delete intermediate build artifacts git clean -Xdf .PHONY: test -test: shorttest slowtest +test: shorttest slowtest testmigrate .PHONY: shorttest shorttest: build ## Run unit tests @@ -54,7 +54,7 @@ runconformance: build ## Run conformance test suite .PHONY: testmigrate testmigrate: ## Run connect-go-v2-migrate test suite - cd cmd/connect-go-v2-migrate && go test ./... + cd ./cmd/connect-go-v2-migrate && go test ./... .PHONY: bench bench: BENCH ?= .* @@ -64,27 +64,33 @@ bench: build ## Run benchmarks for root package .PHONY: build build: generate ## Build all packages go build ./... + cd ./cmd/connect-go-v2-migrate && go build -o /dev/null . .PHONY: install install: ## Install all binaries go install ./... + cd ./cmd/connect-go-v2-migrate && go install ./... .PHONY: lint lint: $(BIN)/golangci-lint $(BIN)/buf ## Lint Go and protobuf go vet ./... golangci-lint run --modules-download-mode=readonly --timeout=3m0s + cd ./cmd/connect-go-v2-migrate && go vet ./... + cd ./cmd/connect-go-v2-migrate && golangci-lint run --modules-download-mode=readonly --timeout=3m0s buf lint buf format -d --exit-code .PHONY: lintfix lintfix: $(BIN)/golangci-lint $(BIN)/buf ## Automatically fix some lint errors golangci-lint run --fix --modules-download-mode=readonly --timeout=3m0s + cd ./cmd/connect-go-v2-migrate && golangci-lint run --fix --modules-download-mode=readonly --timeout=3m0s buf format -w .PHONY: generate generate: $(BIN)/buf $(BIN)/protoc-gen-go $(BIN)/protoc-gen-connect-go $(BIN)/license-header ## Regenerate code and licenses go mod tidy cd ./internal/conformance && go mod tidy + cd ./cmd/connect-go-v2-migrate && go mod tidy buf generate cd internal/conformance && buf generate --template buf.gen.yaml buf.build/connectrpc/conformance cd ./cmd/protoc-gen-connect-go/internal && \ @@ -97,6 +103,7 @@ generate: $(BIN)/buf $(BIN)/protoc-gen-go $(BIN)/protoc-gen-connect-go $(BIN)/li .PHONY: upgrade upgrade: ## Upgrade dependencies go get -u -t ./... && go mod tidy -v + cd ./cmd/connect-go-v2-migrate && go get -u -t ./... && go mod tidy -v .PHONY: checkgenerate checkgenerate: diff --git a/RELEASE.md b/RELEASE.md index de7e70a5..653adea4 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,6 +1,6 @@ # Releasing connect-go -This document outlines how to create a release of connect-go. +This document outlines how to create a release of connect-go v2 from the main branch. v1 releases follow the same steps on the `v1` branch. 1. Clone the repo, ensuring you have the latest main. @@ -9,8 +9,8 @@ This document outlines how to create a release of connect-go. * If there are features being released, remove the `-dev` suffix, set the MINOR number to be 1 more than the MINOR number of the [latest release], and set the PATCH number to `0`. In the common case, the diff here will just be to remove the `-dev` suffix. ```patch - -const Version = "1.14.0-dev" - +const Version = "1.14.0" + -const Version = "2.0.0-dev" + +const Version = "2.0.0" ``` 3. Check for any changes in [cmd/protoc-gen-connect-go/main.go](cmd/protoc-gen-connect-go/main.go) that require a version restriction. A constant `IsAtLeastVersionX_Y_Z` should be defined in [connect.go](connect.go) if generated code has begun to use a new API. Make sure the generated code references this constant. If a new constant has been added since the last release, ensure that the name of the constant matches the version being released ([Example PR #496](https://github.com/connectrpc/connect-go/pull/496)). @@ -35,10 +35,24 @@ This document outlines how to create a release of connect-go. 8. On a new branch, open [connect.go](connect.go) and change the `Version` to increment the minor tag and append the `-dev` suffix. Use the next minor release - we never anticipate bugs and patch releases. ```patch - -const Version = "1.14.0" - +const Version = "1.15.0-dev" + -const Version = "2.0.0" + +const Version = "2.1.0-dev" ``` 9. Open a PR titled "Back to development" ([Example PR #662](https://github.com/connectrpc/connect-go/pull/662)). Once it's reviewed and CI passes, merge it. [latest release]: https://github.com/connectrpc/connect-go/releases/latest + +# Releasing connect-go-v2-migrate + +`cmd/connect-go-v2-migrate` is its own Go module, `connectrpc.com/connect/v2/cmd/connect-go-v2-migrate`. + +1. Using the Github UI, create a new release. + - Under “Choose a tag”, type in “cmd/connect-go-v2-migrate/vX.Y.Z” to create a new tag for the release upon publish. The directory prefix is what keeps it from colliding with the library’s tags in this repository. The version is the module’s own and starts at `v1.0.0`. + - Target the main branch. + - Title the Release “connect-go-v2-migrate vX.Y.Z”. + - Do not click “set as latest release”. That badge is picked by date, so it should stay on the most recent connect-go release. + - Set the last connect-go-v2-migrate release as the “Previous tag”, so the generated notes cover this module rather than the library. + - Click “Generate release notes” to autogenerate release notes. + +2. Publish the release. diff --git a/cmd/connect-go-v2-migrate/bufgen.go b/cmd/connect-go-v2-migrate/bufgen.go index 83e47171..4e5cc075 100644 --- a/cmd/connect-go-v2-migrate/bufgen.go +++ b/cmd/connect-go-v2-migrate/bufgen.go @@ -16,16 +16,19 @@ package main import ( "path" + "regexp" "strings" ) const ( - connectV2Module = "connectrpc.com/connect/v2" - connectLocalPlugin = "protoc-gen-connect-go" - connectRemotePlugin = "buf.build/connectrpc/go" - connectRemotePluginV2 = connectRemotePlugin + ":v2.0.0" + connectV2Module = "connectrpc.com/connect/v2" + connectLocalPlugin = "protoc-gen-connect-go" + connectRemotePluginVersion = "v2.0.0" ) +// connectRemotePluginRef matches connect-go remotes plugins. +var connectRemotePluginRef = regexp.MustCompile(`^(` + bsrHostPattern + `)/connectrpc/(go|gosimple)(?::(\S+))?$`) + // Plugin entry kinds returned by connectPluginItem. const ( kindLocal = "local" // a local binary on $PATH @@ -80,7 +83,7 @@ func RewriteBufGen(filename string, src []byte) ([]byte, Report, error) { case kindGotool: report.warnAtLinef(filename, index+1, ruleBufgenGoMod, "the plugin runs via go.mod (%s). Update the tool dependency to the v2 module with `go get -tool %s/cmd/%s` then `go mod tidy`. The buf.gen.yaml entry stays the same.", ref, connectV2Module, connectLocalPlugin) case kindRemote: - pinRemotePluginV2(lines, index, ref, &edits, &report) + pinRemotePluginV2(filename, lines, index, ref, &edits, &report) } index = end - 1 } @@ -91,14 +94,26 @@ func RewriteBufGen(filename string, src []byte) ([]byte, Report, error) { return []byte(strings.Join(edits.apply(lines), "\n")), report, nil } -// pinRemotePluginV2 pins a v1 remote plugin reference (versioned or not) to -// the v2 release. References already at v2 are left alone. -func pinRemotePluginV2(lines []string, index int, ref string, edits *lineEdits, report *Report) { - if strings.HasPrefix(ref, connectRemotePlugin+":v2") { +// pinRemotePluginV2 pins a v1 remote plugin reference (versioned or not) to the +// v2 release. References already at v2 are left alone. +func pinRemotePluginV2(filename string, lines []string, index int, ref string, edits *lineEdits, report *Report) { + match := connectRemotePluginRef.FindStringSubmatch(ref) + if match == nil { + return + } + host, simple, version := match[1], match[2] == "gosimple", match[3] + if !simple && strings.HasPrefix(version, "v2") { return } - edits.replace[index] = strings.Replace(lines[index], ref, connectRemotePluginV2, 1) - report.bump("bufgen_pin_remote_v2") + pinned := host + "/connectrpc/go:" + connectRemotePluginVersion + edits.replace[index] = strings.Replace(lines[index], ref, pinned, 1) + if simple { + report.bump("bufgen_replace_gosimple") + } else { + report.bump("bufgen_pin_remote_v2") + } + // TODO: drop once connect-go v2.0.0 ships and the plugin is on the BSR. + report.warnAtLinef(filename, index+1, ruleBufgenRemoteUnpublished, "%s is not published yet. Until connect-go %s is released, generate with the local plugin instead: `go install %s/cmd/%s@latest` and a `local: %s` entry.", pinned, connectRemotePluginVersion, connectV2Module, connectLocalPlugin, connectLocalPlugin) } // lineEdits records pending line replacements or deletions keyed by line index. @@ -157,10 +172,10 @@ func connectPluginItem(line string) (kind, ref string, ok bool) { return "", "", false } -// isConnectRemoteRef reports whether value references the connect-go remote +// isConnectRemoteRef reports whether value references either connect-go remote // plugin, bare or version-tagged. func isConnectRemoteRef(value string) bool { - return value == connectRemotePlugin || strings.HasPrefix(value, connectRemotePlugin+":") + return connectRemotePluginRef.MatchString(value) } // pathOverride scans a v1 plugin block for a `path:` whose value is a command diff --git a/cmd/connect-go-v2-migrate/bufgen_test.go b/cmd/connect-go-v2-migrate/bufgen_test.go index a4cfecec..d6679790 100644 --- a/cmd/connect-go-v2-migrate/bufgen_test.go +++ b/cmd/connect-go-v2-migrate/bufgen_test.go @@ -135,6 +135,116 @@ plugins: want: "", wantChanged: false, }, + { + // v2 folds the simple API into the default generator, so the + // gosimple plugin migrates onto connectrpc/go, not a gosimple v2. + name: "remote_gosimple_replaced_by_default_plugin", + in: `version: v2 +plugins: + - remote: buf.build/connectrpc/gosimple:v1.18.1 + out: gen +`, + want: `version: v2 +plugins: + - remote: buf.build/connectrpc/go:v2.0.0 + out: gen +`, + wantChanged: true, + }, + { + name: "remote_gosimple_unversioned_replaced", + in: `version: v2 +plugins: + - remote: buf.build/connectrpc/gosimple + out: gen +`, + want: `version: v2 +plugins: + - remote: buf.build/connectrpc/go:v2.0.0 + out: gen +`, + wantChanged: true, + }, + { + name: "v1_plugin_gosimple_replaced", + in: `version: v1 +plugins: + - plugin: buf.build/connectrpc/gosimple:v1.18.1 + out: gen +`, + want: `version: v1 +plugins: + - plugin: buf.build/connectrpc/go:v2.0.0 + out: gen +`, + wantChanged: true, + }, + { + // Private BSR instances use the same plugin path under another host, + // and the rewrite must keep that host rather than jump to buf.build. + name: "remote_private_host_keeps_host", + in: `version: v2 +plugins: + - remote: buf.example.com/connectrpc/go:v1.18.1 + out: gen +`, + want: `version: v2 +plugins: + - remote: buf.example.com/connectrpc/go:v2.0.0 + out: gen +`, + wantChanged: true, + }, + { + name: "remote_private_host_gosimple_replaced", + in: `version: v2 +plugins: + - remote: bsr.internal.acme.dev/connectrpc/gosimple:v1.18.1 + out: gen +`, + want: `version: v2 +plugins: + - remote: bsr.internal.acme.dev/connectrpc/go:v2.0.0 + out: gen +`, + wantChanged: true, + }, + { + name: "remote_private_host_already_v2_is_noop", + in: `version: v2 +plugins: + - remote: buf.example.com/connectrpc/go:v2.0.0 + out: gen +`, + want: "", + wantChanged: false, + }, + { + // A hostless reference is not a BSR plugin and must be left alone. + name: "remote_hostless_ref_ignored", + in: `version: v2 +plugins: + - remote: connectrpc/go:v1.18.1 + out: gen +`, + want: "", + wantChanged: false, + }, + { + name: "remote_pin_warns_plugin_not_published", + in: `version: v2 +plugins: + - remote: buf.build/connectrpc/go:v1.18.1 + out: gen +`, + want: `version: v2 +plugins: + - remote: buf.build/connectrpc/go:v2.0.0 + out: gen +`, + wantChanged: true, + wantWarn: "is not published yet", + }, { name: "gotool_warns_about_gomod_and_strips", in: `version: v2 diff --git a/cmd/connect-go-v2-migrate/discover.go b/cmd/connect-go-v2-migrate/discover.go index 21a9e1ce..1ad76d66 100644 --- a/cmd/connect-go-v2-migrate/discover.go +++ b/cmd/connect-go-v2-migrate/discover.go @@ -20,6 +20,7 @@ import ( "go/types" "os" "path/filepath" + "regexp" "sort" "strconv" "strings" @@ -29,24 +30,21 @@ import ( ) const ( - generatedMarker = "DO NOT EDIT" - // connectStubMarker identifies protoc-gen-connect-go output. Only these - // stubs decide the regenerate-first phase; other connect importers (mocks) - // do not. + generatedMarker = "DO NOT EDIT" connectStubMarker = "protoc-gen-connect-go" connectV1Path = "connectrpc.com/connect" - // bsrModulePrefix is the BSR Go SDK import-path prefix: - // buf.build/gen/go////. - bsrModulePrefix = "buf.build/gen/go/" - // bsrConnectPlugin is the connect plugin's segment; only its output is - // versioned with connect, so only it takes the @v2 query. - bsrConnectPlugin = "/connectrpc/" ) +// bsrHostPattern matches a registry host, not pinned to buf.build. +const bsrHostPattern = `[^/:]+\.[^/:]+` + +// bsrConnectModule matches a connect generated SDK. +var bsrConnectModule = regexp.MustCompile(`^` + bsrHostPattern + `/gen/go/[^/]+/[^/]+/connectrpc/(?:go|gosimple)$`) + // isBSRConnectModule reports whether modulePath is a BSR Go SDK generated by the // connect-go plugin, so `go get @v2` resolves to the connect-v2 build. func isBSRConnectModule(modulePath string) bool { - return strings.HasPrefix(modulePath, bsrModulePrefix) && strings.Contains(modulePath, bsrConnectPlugin) + return bsrConnectModule.MatchString(modulePath) } // fileContent pairs a path with its bytes. ready is false when the source binds diff --git a/cmd/connect-go-v2-migrate/discover_test.go b/cmd/connect-go-v2-migrate/discover_test.go index 1889bf3c..a880e834 100644 --- a/cmd/connect-go-v2-migrate/discover_test.go +++ b/cmd/connect-go-v2-migrate/discover_test.go @@ -82,7 +82,8 @@ func TestIsConnectStubAST(t *testing.T) { // TestIsBSRConnectModule covers which BSR modules get the @v2 advice: only the // connect-go plugin's output (.../connectrpc/go), not other plugins under the -// same buf.build/gen/go prefix, and not non-BSR modules. +// same gen/go prefix, and not non-BSR modules. Self-hosted BSR instances use +// the same path layout under a different host, so they match too. func TestIsBSRConnectModule(t *testing.T) { t.Parallel() tests := []struct { @@ -95,6 +96,15 @@ func TestIsBSRConnectModule(t *testing.T) { {module: "buf.build/gen/go/acme/api/grpc/go", want: false}, // a different plugin {module: "github.com/grafana/pyroscope/api", want: false}, // not a BSR module {module: "connectrpc.com/connect", want: false}, + // Self-hosted BSR instances share the layout under another host. + {module: "buf.example.com/gen/go/acme/api/connectrpc/go", want: true}, + {module: "bsr.internal.acme.dev/gen/go/acme/api/connectrpc/go", want: true}, + {module: "buf.example.com/gen/go/acme/api/protocolbuffers/go", want: false}, + // A hostless or malformed path must not match. + {module: "gen/go/acme/api/connectrpc/go", want: false}, + {module: "buf.build/gen/go/acme/api/connectrpc/go/extra", want: false}, + {module: "buf.build/gen/go/acme/connectrpc/go", want: false}, + {module: "notahost/gen/go/acme/api/connectrpc/go", want: false}, } for _, test := range tests { if got := isBSRConnectModule(test.module); got != test.want { diff --git a/cmd/connect-go-v2-migrate/go.mod b/cmd/connect-go-v2-migrate/go.mod new file mode 100644 index 00000000..8e29ea15 --- /dev/null +++ b/cmd/connect-go-v2-migrate/go.mod @@ -0,0 +1,10 @@ +module connectrpc.com/connect/v2/cmd/connect-go-v2-migrate + +go 1.25.0 + +require ( + golang.org/x/mod v0.38.0 + golang.org/x/tools v0.48.0 +) + +require golang.org/x/sync v0.22.0 // indirect diff --git a/cmd/connect-go-v2-migrate/go.sum b/cmd/connect-go-v2-migrate/go.sum new file mode 100644 index 00000000..2a37fb76 --- /dev/null +++ b/cmd/connect-go-v2-migrate/go.sum @@ -0,0 +1,8 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= diff --git a/cmd/connect-go-v2-migrate/main.go b/cmd/connect-go-v2-migrate/main.go index a57766eb..9e9a29d5 100644 --- a/cmd/connect-go-v2-migrate/main.go +++ b/cmd/connect-go-v2-migrate/main.go @@ -17,7 +17,7 @@ // transformations to update v1 code automatically, emitting warnings for // patterns that require manual intervention. // -// Usage: connect-go-v2-migrate [-w] [-json] [paths...]. Paths default to the +// Usage: connect-go-v2-migrate [-w] [-json] [-version] [paths...]. Paths default to the // current directory. Without -w the tool is a dry run that prints diffs. package main @@ -28,6 +28,7 @@ import ( "fmt" "os" "path/filepath" + "runtime/debug" "slices" "strings" ) @@ -57,7 +58,7 @@ Migration runs in two phases. When v1 generated code is present, the tool only updates Buf templates and prints the steps to generate v2 bindings. Run it again after generation to rewrite Go call sites. -usage: connect-go-v2-migrate [-w] [-json] [paths...] +usage: connect-go-v2-migrate [-w] [-json] [-version] [paths...] Paths may be files or directories. They default to the current directory ("."). By default the tool is a dry run that prints unified diffs for changed files. @@ -69,6 +70,15 @@ Flags: fmt.Fprintf(out, "\nFull migration guide: %s\n", migratingGuideURL) } +// toolVersion reports the module version stamped into the binary. +func toolVersion() string { + info, ok := debug.ReadBuildInfo() + if !ok || info.Main.Version == "" { + return "(unknown)" + } + return info.Main.Version +} + func main() { os.Exit(runMain(os.Args[1:])) } @@ -77,10 +87,15 @@ func runMain(args []string) int { flags := flag.NewFlagSet("connect-go-v2-migrate", flag.ContinueOnError) write := flags.Bool("w", false, "write rewrites back to disk (default: dry-run, print diffs).") jsonOut := flags.Bool("json", false, "emit a structured JSON report instead of text.") + showVersion := flags.Bool("version", false, "print the tool version and exit.") flags.Usage = func() { usage(flags) } if err := flags.Parse(args); err != nil { return 2 } + if *showVersion { + fmt.Println("connect-go-v2-migrate", toolVersion()) + return 0 + } roots := flags.Args() if len(roots) == 0 { @@ -209,7 +224,7 @@ func processFile(file fileContent, rewrite func(string, []byte) ([]byte, Report, // A failed write must not be reported as applied. recorded := true if write { - if err := os.WriteFile(file.path, out, 0o644); err != nil { //nolint:gosec // rewriting Go source files, world-readable matches typical repo perms + if err := writeFilePreservingMode(file.path, out); err != nil { fmt.Fprintf(os.Stderr, "%s: write: %v\n", file.path, err) run.errored++ recorded = false @@ -226,6 +241,16 @@ func processFile(file fileContent, rewrite func(string, []byte) ([]byte, Report, } } +// writeFilePreservingMode writes data to path, keeping its current permissions. +// os.WriteFile applies perm only on create, so 0644 only affects a new file. +func writeFilePreservingMode(path string, data []byte) error { + mode := os.FileMode(0o644) + if info, err := os.Stat(path); err == nil { + mode = info.Mode().Perm() + } + return os.WriteFile(path, data, mode) +} + // stripDanglingMsgPass runs the type-directed .Msg post-pass over an overlay of // the per-file rewrites and merges its edits into run, updating an existing // rewrite or adding one for a file (often a _test.go) the pass never touched. @@ -245,7 +270,7 @@ func stripDanglingMsgPass(roots []string, write bool, run *results) { } for path, edit := range edits { if write { - if err := os.WriteFile(path, edit.content, 0o644); err != nil { //nolint:gosec // rewriting Go source files, world-readable matches typical repo perms + if err := writeFilePreservingMode(path, edit.content); err != nil { fmt.Fprintf(os.Stderr, "%s: write: %v\n", path, err) run.errored++ continue @@ -440,6 +465,15 @@ func printPhase1Text(run *results, proj *project, write, color bool) { } } + // Sources are skipped in this phase, so any manual diagnostic here belongs to + // a Buf template. Show it before the steps: it can change how they are run. + if manual := byCategory(run.diagnostics, categoryManual); len(manual) > 0 { + fmt.Print("\nThe following issues require a manual update:\n") + for _, diag := range manual { + fmt.Printf(" %s\n", formatDiagnostic(diag)) + } + } + fmt.Print("\nFirst, move the dependencies and generated code to v2:\n\n") for number, step := range phase1Steps(run, proj, write) { fmt.Printf(" %d. %s\n", number+1, step.cmd) diff --git a/cmd/connect-go-v2-migrate/main_test.go b/cmd/connect-go-v2-migrate/main_test.go index 0a1e9ab0..735ea4fc 100644 --- a/cmd/connect-go-v2-migrate/main_test.go +++ b/cmd/connect-go-v2-migrate/main_test.go @@ -25,7 +25,6 @@ import ( // TestMain dispatches to the real tool instead of the tests. const migrateExecEnv = "MIGRATE_TEST_EXEC" -// TestMain lets the test binary stand in for the migrate binary. func TestMain(m *testing.M) { if os.Getenv(migrateExecEnv) == "1" { os.Exit(runMain(os.Args[1:])) @@ -33,9 +32,6 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -// TestProcessFileWriteFailure checks that a file whose write fails is not -// recorded as an applied rewrite: a failed write counts as an error, never a -// success, so the report cannot claim a change that never reached disk. func TestProcessFileWriteFailure(t *testing.T) { t.Parallel() // A path under a directory that does not exist makes os.WriteFile fail. @@ -50,8 +46,6 @@ func TestProcessFileWriteFailure(t *testing.T) { } } -// TestProcessFileDryRunRecords checks the dry-run path still records the -// proposed rewrite: nothing is written, so there is no failure to gate on. func TestProcessFileDryRunRecords(t *testing.T) { t.Parallel() var run results @@ -64,6 +58,61 @@ func TestProcessFileDryRunRecords(t *testing.T) { } } +func TestWriteFilePreservingMode(t *testing.T) { + t.Parallel() + for _, mode := range []os.FileMode{0o600, 0o644, 0o664, 0o755} { + path := filepath.Join(t.TempDir(), "src.go") + if err := os.WriteFile(path, []byte("before"), mode); err != nil { + t.Fatal(err) + } + // Chmod explicitly: the umask would otherwise clear bits at creation. + if err := os.Chmod(path, mode); err != nil { + t.Fatal(err) + } + if err := writeFilePreservingMode(path, []byte("after")); err != nil { + t.Fatal(err) + } + info, err := os.Stat(path) + if err != nil { + t.Fatal(err) + } + if got := info.Mode().Perm(); got != mode { + t.Errorf("mode = %v, want %v", got, mode) + } + content, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + if string(content) != "after" { + t.Errorf("content = %q, want %q", content, "after") + } + } + + fresh := filepath.Join(t.TempDir(), "new.go") + if err := writeFilePreservingMode(fresh, []byte("x")); err != nil { + t.Fatal(err) + } + info, err := os.Stat(fresh) + if err != nil { + t.Fatal(err) + } + // The umask may clear bits on creation, so assert only that nothing beyond + // 0644 was granted. + if got := info.Mode().Perm(); got&^0o644 != 0 { + t.Errorf("new file mode = %v, want no bits beyond %v", got, os.FileMode(0o644)) + } +} + +func TestVersionFlag(t *testing.T) { + t.Parallel() + if got := runMain([]string{"-version"}); got != 0 { + t.Errorf("runMain(-version) = %d, want 0", got) + } + if toolVersion() == "" { + t.Error("toolVersion() is empty") + } +} + func copyFile(src, dst string) error { data, err := os.ReadFile(src) if err != nil { diff --git a/cmd/connect-go-v2-migrate/rewrite.go b/cmd/connect-go-v2-migrate/rewrite.go index 7e38d67c..5ec916e8 100644 --- a/cmd/connect-go-v2-migrate/rewrite.go +++ b/cmd/connect-go-v2-migrate/rewrite.go @@ -26,7 +26,6 @@ import ( "strconv" "strings" - connect "connectrpc.com/connect/v2" "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/imports" ) @@ -48,19 +47,20 @@ const ( // Diagnostic rule identifiers, surfaced as stable handles in JSON output. const ( - ruleAwaitingV2Bindings = "awaiting_v2_bindings" - ruleRemoveV1Import = "remove_v1_import" - ruleRequestMetadata = "request_metadata_migration" - ruleHandlerConstruction = "handler_construction" - ruleConnectHTTPOption = "connecthttp_option_migration" - ruleErrorAPI = "error_api_migration" - ruleServerInterceptor = "server_interceptor_migration" - ruleInterceptorMigration = "interceptor_migration" - ruleStreamParamType = "stream_param_type" - ruleStreamParamAmbiguous = "stream_param_ambiguous" - ruleEcosystemMigration = "ecosystem_migration" - ruleBufgenReinstall = "bufgen_reinstall_plugin" - ruleBufgenGoMod = "bufgen_update_go_mod" + ruleAwaitingV2Bindings = "awaiting_v2_bindings" + ruleRemoveV1Import = "remove_v1_import" + ruleRequestMetadata = "request_metadata_migration" + ruleHandlerConstruction = "handler_construction" + ruleConnectHTTPOption = "connecthttp_option_migration" + ruleErrorAPI = "error_api_migration" + ruleServerInterceptor = "server_interceptor_migration" + ruleInterceptorMigration = "interceptor_migration" + ruleStreamParamType = "stream_param_type" + ruleStreamParamAmbiguous = "stream_param_ambiguous" + ruleEcosystemMigration = "ecosystem_migration" + ruleBufgenReinstall = "bufgen_reinstall_plugin" + ruleBufgenGoMod = "bufgen_update_go_mod" + ruleBufgenRemoteUnpublished = "bufgen_remote_unpublished" ) var ( @@ -100,10 +100,11 @@ var ( } // connectProtocolOptions is the set of v1 protocol-selecting options. They keep // their names in connecthttp (connect.WithGRPC() becomes connecthttp.WithGRPC()), - // so only the package qualifier changes. + // so only the package qualifier changes. Values mirror connect.ProtocolName*, + // inlined to keep this module free of a connect dependency. connectProtocolOptions = map[string]string{ - "WithGRPC": connect.ProtocolNameGRPC, - "WithGRPCWeb": connect.ProtocolNameGRPCWeb, + "WithGRPC": "grpc", + "WithGRPCWeb": "grpcweb", } // reshapedErrorAPI maps v1 connect error helpers that v2 folded into *connect.Error diff --git a/cmd/connect-go-v2-migrate/testdata/script/bsr_sdk.txtar b/cmd/connect-go-v2-migrate/testdata/script/bsr_sdk.txtar index d546077c..e315290a 100644 --- a/cmd/connect-go-v2-migrate/testdata/script/bsr_sdk.txtar +++ b/cmd/connect-go-v2-migrate/testdata/script/bsr_sdk.txtar @@ -14,20 +14,6 @@ go 1.25 require connectrpc.com/connect v1.18.1 -- bsrsdk/test.connect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - // Code generated by protoc-gen-connect-go. DO NOT EDIT. // // This stands in for a BSR-generated SDK: a generated package that imports the @@ -51,20 +37,6 @@ type ServiceClient interface { // NewServiceClient builds the v1 client. func NewServiceClient(baseURL string) ServiceClient { return nil } -- client.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 app import ( @@ -85,20 +57,6 @@ func ping() (*testv1connect.PingResponse, error) { return res.Msg, nil } -- connectv1/connect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 connect is a minimal v1 stub for the fixture. package connect @@ -135,20 +93,6 @@ module connectrpc.com/otelconnect go 1.25 -- otelconnect/otelconnect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 otelconnect is a minimal stub of the connectrpc.com/otelconnect // ecosystem module, so the fixture exercises the ecosystem entry in the go get // advice. diff --git a/cmd/connect-go-v2-migrate/testdata/script/bufgen_gosimple.txtar b/cmd/connect-go-v2-migrate/testdata/script/bufgen_gosimple.txtar new file mode 100644 index 00000000..6ef0c36c --- /dev/null +++ b/cmd/connect-go-v2-migrate/testdata/script/bufgen_gosimple.txtar @@ -0,0 +1,38 @@ +# buf.gen.yaml with the v1 gosimple plugin: v2 makes the simple API the default +# generator, so the entry moves to connectrpc/go rather than a gosimple v2. +exec migrate +cmp stdout out.txt +exec migrate -w +cmp buf.gen.yaml want.yaml +exec go build ./... +-- doc.go -- +package app +-- buf.gen.yaml -- +version: v2 +plugins: + - remote: buf.build/connectrpc/gosimple:v1.18.1 + out: gen +-- want.yaml -- +version: v2 +plugins: + - remote: buf.build/connectrpc/go:v2.0.0 + out: gen +-- out.txt -- +Proposed rewrites (rerun with -w to apply): + ./buf.gen.yaml: bufgen_replace_gosimple=1 +--- ./buf.gen.yaml ++++ ./buf.gen.yaml +@@ -1,5 +1,5 @@ + version: v2 + plugins: +- - remote: buf.build/connectrpc/gosimple:v1.18.1 ++ - remote: buf.build/connectrpc/go:v2.0.0 + out: gen + + + +The following issues require manual code changes: + ./buf.gen.yaml:3:1: buf.build/connectrpc/go:v2.0.0 is not published yet. Until connect-go v2.0.0 is released, generate with the local plugin instead: `go install connectrpc.com/connect/v2/cmd/protoc-gen-connect-go@latest` and a `local: protoc-gen-connect-go` entry. + +Scanned 1 Go file and 1 Buf template. 1 rewrite(s) ready (rerun with -w to apply). +Full migration guide: https://github.com/connectrpc/connect-go/blob/main/docs/v2-migration.md diff --git a/cmd/connect-go-v2-migrate/testdata/script/bufgen_remote.txtar b/cmd/connect-go-v2-migrate/testdata/script/bufgen_remote.txtar index 3add33e0..f1d697cf 100644 --- a/cmd/connect-go-v2-migrate/testdata/script/bufgen_remote.txtar +++ b/cmd/connect-go-v2-migrate/testdata/script/bufgen_remote.txtar @@ -32,5 +32,8 @@ Proposed rewrites (rerun with -w to apply): +The following issues require manual code changes: + ./buf.gen.yaml:3:1: buf.build/connectrpc/go:v2.0.0 is not published yet. Until connect-go v2.0.0 is released, generate with the local plugin instead: `go install connectrpc.com/connect/v2/cmd/protoc-gen-connect-go@latest` and a `local: protoc-gen-connect-go` entry. + Scanned 1 Go file and 1 Buf template. 1 rewrite(s) ready (rerun with -w to apply). Full migration guide: https://github.com/connectrpc/connect-go/blob/main/docs/v2-migration.md diff --git a/cmd/connect-go-v2-migrate/testdata/script/bufgen_remote_phase1.txtar b/cmd/connect-go-v2-migrate/testdata/script/bufgen_remote_phase1.txtar new file mode 100644 index 00000000..425fb79d --- /dev/null +++ b/cmd/connect-go-v2-migrate/testdata/script/bufgen_remote_phase1.txtar @@ -0,0 +1,70 @@ +# Regenerate-first with a remote plugin: the template is pinned to v2 and the +# report must still surface the not-published warning, because the steps below +# tell the user to run buf generate against that pin. +stubs v1generic +exec migrate +cmp stdout out.txt +stdout 'not published yet' +stdout 'no Go source changes are proposed yet' +stdout 'Proposed Buf template updates' +stdout 'no Go source changes are proposed yet' +exec go build ./... +-- service.go -- +package app + +import ( + "context" + + "connectrpc.com/connect" + pingv1 "example.com/app/gen/connect/ping/v1" + "example.com/app/gen/connect/ping/v1/pingv1connect" +) + +type pingServer struct { + pingv1connect.UnimplementedPingServiceHandler +} + +func (s *pingServer) Ping(ctx context.Context, req *connect.Request[pingv1.PingRequest]) (*connect.Response[pingv1.PingResponse], error) { + return connect.NewResponse(&pingv1.PingResponse{Number: req.Msg.Number, Text: req.Msg.Text}), nil +} +-- buf.gen.yaml -- +version: v2 +plugins: + - remote: buf.build/connectrpc/go:v1.18.1 + out: gen +-- out.txt -- +Scanned 1 Go file and 1 Buf template. The generated Connect code still targets +v1, so no Go source changes are proposed yet. + +Generated v1 Connect code: + ./gen/connect/ping/v1/pingv1connect + +Proposed Buf template updates (rerun with -w to apply): + ./buf.gen.yaml: bufgen_pin_remote_v2=1 +--- ./buf.gen.yaml ++++ ./buf.gen.yaml +@@ -1,5 +1,5 @@ + version: v2 + plugins: +- - remote: buf.build/connectrpc/go:v1.18.1 ++ - remote: buf.build/connectrpc/go:v2.0.0 + out: gen + + + +The following issues require a manual update: + ./buf.gen.yaml:3:1: buf.build/connectrpc/go:v2.0.0 is not published yet. Until connect-go v2.0.0 is released, generate with the local plugin instead: `go install connectrpc.com/connect/v2/cmd/protoc-gen-connect-go@latest` and a `local: protoc-gen-connect-go` entry. + +First, move the dependencies and generated code to v2: + + 1. connect-go-v2-migrate -w (applies the Buf template update above) + 2. go get -u \ + connectrpc.com/connect/v2 + (pulls the v2 core, generated SDKs, and ecosystem modules into go.mod) + 3. buf generate + +Then re-run connect-go-v2-migrate to work through the Go source changes: it +rewrites the call sites against the v2 stubs and reports anything that needs +a manual update. + +Full migration guide: https://github.com/connectrpc/connect-go/blob/main/docs/v2-migration.md diff --git a/cmd/connect-go-v2-migrate/testdata/script/bufgen_v1_remote.txtar b/cmd/connect-go-v2-migrate/testdata/script/bufgen_v1_remote.txtar index f4f59315..7f5110a5 100644 --- a/cmd/connect-go-v2-migrate/testdata/script/bufgen_v1_remote.txtar +++ b/cmd/connect-go-v2-migrate/testdata/script/bufgen_v1_remote.txtar @@ -49,5 +49,8 @@ Proposed rewrites (rerun with -w to apply): +The following issues require manual code changes: + ./buf.gen.yaml:8:1: buf.build/connectrpc/go:v2.0.0 is not published yet. Until connect-go v2.0.0 is released, generate with the local plugin instead: `go install connectrpc.com/connect/v2/cmd/protoc-gen-connect-go@latest` and a `local: protoc-gen-connect-go` entry. + Scanned 1 Go file and 1 Buf template. 1 rewrite(s) ready (rerun with -w to apply). Full migration guide: https://github.com/connectrpc/connect-go/blob/main/docs/v2-migration.md diff --git a/cmd/connect-go-v2-migrate/testdata/script/nested_module.txtar b/cmd/connect-go-v2-migrate/testdata/script/nested_module.txtar index 1a41181b..ce06153e 100644 --- a/cmd/connect-go-v2-migrate/testdata/script/nested_module.txtar +++ b/cmd/connect-go-v2-migrate/testdata/script/nested_module.txtar @@ -11,20 +11,6 @@ exec migrate ./child stdout 'client_construction' ! stdout 'does not cross module boundaries' -- child/client/main.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 ( @@ -37,20 +23,6 @@ func main() { _ = pingv1connect.NewPingServiceClient(http.DefaultClient, "http://localhost:8080/") } -- child/connectv2/connect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 connect is a minimal stand-in for connectrpc.com/connect/v2. package connect @@ -67,20 +39,6 @@ module connectrpc.com/connect/v2 go 1.25 -- child/gen/pingv1connect/ping.connect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - // Code generated by protoc-gen-connect-go. DO NOT EDIT. package pingv1connect diff --git a/cmd/connect-go-v2-migrate/testdata/script/partial_stub.txtar b/cmd/connect-go-v2-migrate/testdata/script/partial_stub.txtar index eedf4c2e..a634f0fe 100644 --- a/cmd/connect-go-v2-migrate/testdata/script/partial_stub.txtar +++ b/cmd/connect-go-v2-migrate/testdata/script/partial_stub.txtar @@ -7,20 +7,6 @@ stdout 'Deferred until their connect stubs are regenerated' stdout 'strip_new_request' ! stdout 'First, move the dependencies' -- connectv1/connect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 connect is a minimal stand-in for connectrpc.com/connect v1. package connect @@ -39,20 +25,6 @@ module connectrpc.com/connect go 1.25 -- connectv2/connect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 connect is a minimal stand-in for connectrpc.com/connect/v2. package connect @@ -68,20 +40,6 @@ module connectrpc.com/connect/v2 go 1.25 -- consumer_a.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 app import ( @@ -101,20 +59,6 @@ func echo(ctx context.Context) error { return err } -- consumer_b.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 app import ( @@ -134,20 +78,6 @@ func ping(ctx context.Context) error { return err } -- gen/av1/av1connect/echo.connect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - // Code generated by protoc-gen-connect-go. DO NOT EDIT. package av1connect @@ -170,20 +100,6 @@ func (c *AServiceClient) Echo(ctx context.Context, req *av1.EchoRequest) (*av1.E return nil, nil } -- gen/av1/echo.pb.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - // Code generated by protoc-gen-go. DO NOT EDIT. package av1 @@ -191,20 +107,6 @@ package av1 type EchoRequest struct{ Text string } type EchoResponse struct{ Text string } -- gen/bv1/bv1connect/ping.connect.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - // Code generated by protoc-gen-connect-go. DO NOT EDIT. package bv1connect @@ -227,20 +129,6 @@ func (c *BServiceClient) Ping(ctx context.Context, req *connect.Request[bv1.Ping return nil, nil } -- gen/bv1/ping.pb.go -- -// Copyright 2021-2026 The Connect Authors -// -// 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 -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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. - // Code generated by protoc-gen-go. DO NOT EDIT. package bv1 @@ -265,7 +153,7 @@ Proposed rewrites (rerun with -w to apply): ./consumer_a.go: client_construction=1 import_add_connecthttp=1 import_add_connectv2=1 import_drop_v1=1 strip_new_request=1 --- ./consumer_a.go +++ ./consumer_a.go -@@ -18,7 +18,8 @@ +@@ -4,7 +4,8 @@ "context" "net/http" @@ -275,7 +163,7 @@ Proposed rewrites (rerun with -w to apply): "example.com/app/gen/av1" "example.com/app/gen/av1/av1connect" -@@ -26,8 +27,8 @@ +@@ -12,8 +13,8 @@ // echo binds to service A, whose stub is already v2, so it migrates now. func echo(ctx context.Context) error { @@ -289,10 +177,10 @@ Proposed rewrites (rerun with -w to apply): The following issues require manual code changes: - ./consumer_b.go:21:2: connectrpc.com/connect (v1) import retained because it still uses connect.NewRequest. + ./consumer_b.go:7:2: connectrpc.com/connect (v1) import retained because it still uses connect.NewRequest. Deferred until their connect stubs are regenerated to v2: - ./consumer_b.go:29:12: stub-dependent rewrite (handler/client signatures, .Msg, NewRequest/NewResponse, streams, construction) + ./consumer_b.go:15:12: stub-dependent rewrite (handler/client signatures, .Msg, NewRequest/NewResponse, streams, construction) Regenerate those stubs (buf generate) and re-run connect-go-v2-migrate. Scanned 2 Go files and 0 Buf templates. 1 rewrite(s) ready (rerun with -w to apply). diff --git a/docs/v2-migration.md b/docs/v2-migration.md index 4d0fa2cb..e7a831dd 100644 --- a/docs/v2-migration.md +++ b/docs/v2-migration.md @@ -65,7 +65,13 @@ plugins: opt: paths=source_relative ``` -✅ `connect-go-v2-migrate` handles this. +✅ `connect-go-v2-migrate` handles this. It also replaces +`buf.build/connectrpc/gosimple`, since v2 makes the simple API the default +generator. + +> **Before v2.0.0 is released**, `buf.build/connectrpc/go:v2.0.0` is not +> published, so `buf generate` will fail against it. Use the local plugin until +> the release lands. The migration tool warns when it rewrites a remote entry. For local plugins (`local: protoc-gen-connect-go`), the `buf.gen.yaml` entry stays the same because the v1 and v2 plugins share the binary name. diff --git a/go.mod b/go.mod index 3f5171d2..450f83a1 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,5 @@ go 1.25.0 require ( github.com/google/go-cmp v0.7.0 - golang.org/x/mod v0.38.0 - golang.org/x/tools v0.48.0 google.golang.org/protobuf v1.36.11 ) - -require golang.org/x/sync v0.22.0 // indirect diff --git a/go.sum b/go.sum index f5caaf65..296be183 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,4 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= -golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= -golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=