Repository navigation
go_modules: run go list -m all after workspace updates to stabilize committed go.work.sum on Go < 1.28 #16518
Description
Is there an existing issue for this?
- I have searched the existing issues
Package ecosystem
gomod
Package manager version
Go command 1.27.1
Language version
The workspace declares:
go 1.27.0
toolchain go1.27.1Manifest location and content before the Dependabot update
This repository commits both go.work and go.work.sum:
Base commit used by both reproducing PRs:
kubernetes-sigs/kustomize@0b060a1
The workspace contains multiple modules. Their go.mod and go.sum files are also committed.
dependabot.yml content
Full file:
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10Updated dependency
Two public Dependabot PRs reproduce the problem:
k8s.io/cli-runtime0.37.0 -> 0.37.1- Head commit:
7687fd72f8ec4196de6ede1bf2a8068404d2a25e
- Head commit:
k8s.io/apimachinery0.37.0 -> 0.37.1- Head commit:
62a15c17c2fc23b0c6a1bd8ef647ea67ccabaef9
- Head commit:
What you expected to see, versus what you actually saw
Expected
For a repository that commits go.work and go.work.sum, a Dependabot workspace update should include the go.work.sum entries needed to load the complete updated workspace module graph.
After checking out a generated PR, the following should be a no-op:
go list -m all > /dev/null
git diff --exit-codeActual
Both Dependabot PRs leave go.work.sum incomplete.
The repository's CI runs make workspace-sync, which performs:
go work sync
./hack/doGoMod.sh tidy
go list -m all > /dev/nullgo work sync followed by go mod tidy for every workspace module produces no diff. The final go list -m all command is the command that modifies go.work.sum.
For PR #6297, it adds:
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+k8s.io/streaming v0.37.1/go.mod h1:APlJR26ZWRcVy5bIEj0QRrKUXROtBHPcxl2NT7EAzPU=For PR #6298, it adds:
+k8s.io/streaming v0.37.1/go.mod h1:APlJR26ZWRcVy5bIEj0QRrKUXROtBHPcxl2NT7EAzPU=As a result, the check-synced-go-modules CI job fails even though the other Go test jobs pass.
This is the behavior described by golang/go#63901. The Go fix, CL 815760, is targeted at Go 1.28. Its regression test verifies that go list -m all no longer changes go.work.sum after go work sync.
Repositories and Dependabot updates using Go 1.27 and earlier still need compatibility behavior.
Dependabot's current workspace updater runs go work sync, optionally tidies the workspace modules, and then collects their files and go.work.sum, but it does not load the complete module list before collecting the result:
dependabot-core/go_modules/lib/dependabot/go_modules/file_updater/go_mod_updater.rb
Lines 233 to 328 in b4b31b9
| sig { returns(T::Hash[String, String]) } | |
| def update_workspace_files | |
| in_repo_path do | |
| dependency_files.each do |file| | |
| path = Pathname.new(file.name).expand_path | |
| FileUtils.mkdir_p(path.dirname) | |
| File.write(path, file.content) | |
| end | |
| # Run `go get dep@version` in each module directory so every go.mod | |
| # that requires the dependency gets the version bump, not just the first. | |
| # Follow with a bare `go get` validation pass per module, matching the | |
| # single-module update path's intent (see run_go_get comment). | |
| workspace_module_paths.each do |mod_dir| | |
| Dir.chdir(mod_dir) do | |
| run_go_get(dependencies) | |
| run_go_get | |
| end | |
| end | |
| run_go_work_sync | |
| run_workspace_tidy | |
| collect_workspace_file_contents | |
| end | |
| end | |
| sig { void } | |
| def run_go_work_sync | |
| command = "go work sync" | |
| _, stderr, status = Open3.capture3(command) | |
| return if status.success? | |
| handle_subprocess_error(stderr) | |
| end | |
| sig { void } | |
| def run_workspace_tidy | |
| return unless tidy? | |
| workspace_module_paths.each do |mod_path| | |
| Dir.chdir(mod_path) do | |
| run_go_mod_tidy(context: mod_path) | |
| end | |
| end | |
| end | |
| sig { returns(T::Array[String]) } | |
| def workspace_module_paths | |
| go_work_file = dependency_files.find { |f| f.name.end_with?("go.work") } | |
| return ["."] unless go_work_file | |
| fetched_mod_names = dependency_files.select { |f| f.name.end_with?("go.mod") } | |
| .to_set(&:name) | |
| GoWorkParser.use_paths(T.must(go_work_file.content)) | |
| .select { |p| valid_workspace_path?(p) && fetched_mod_names.include?(workspace_mod_name(p)) } | |
| .map { |p| p == "." ? "." : "./#{p}" } | |
| end | |
| sig { params(path: String).returns(T::Boolean) } | |
| def valid_workspace_path?(path) | |
| return false if Pathname.new(path).absolute? | |
| !Pathname.new(path).cleanpath.to_s.start_with?("../") | |
| end | |
| sig { params(use_path: String).returns(String) } | |
| def workspace_mod_name(use_path) | |
| use_path == "." ? "go.mod" : "#{use_path}/go.mod" | |
| end | |
| sig { returns(T::Hash[String, String]) } | |
| def collect_workspace_file_contents | |
| results = T.let({}, T::Hash[String, String]) | |
| workspace_module_paths.each do |mod_path| | |
| relative_base = mod_path.delete_prefix("./") | |
| mod_file = File.join(mod_path, "go.mod") | |
| if File.exist?(mod_file) | |
| key = relative_base.empty? || relative_base == "." ? "go.mod" : "#{relative_base}/go.mod" | |
| results[key] = File.read(mod_file) | |
| end | |
| sum_file = File.join(mod_path, "go.sum") | |
| next unless File.exist?(sum_file) | |
| key = relative_base.empty? || relative_base == "." ? "go.sum" : "#{relative_base}/go.sum" | |
| results[key] = File.read(sum_file) | |
| end | |
| results["go.work.sum"] = File.read("go.work.sum") if File.exist?("go.work.sum") | |
| results | |
| end |
Suggested compatibility fix
After the workspace modules have been updated and tidied, and before collecting the resulting files, run at the workspace root:
go list -m allThe output can be discarded, but any resulting go.work.sum update should be included in the Dependabot PR. At minimum, this should be done when an existing go.work.sum was fetched as a committed dependency file.
The order is important: this should be the final Go operation after workspace tidy, so it records checksums for the final workspace module graph.
On Go 1.28 and later, this should be a no-op after the fixed go work sync, so keeping it as compatibility behavior would also avoid version-detection logic.
This is not a request to restore go list -m -json all during dependency discovery for every Go project, which was removed in #2880. The proposed scope is the post-update path for an already detected workspace with a committed go.work.sum.
Native package manager behavior
Using either Dependabot PR head with Go 1.27.1:
go work sync
./hack/doGoMod.sh tidy
git diff --exit-codeThis succeeds with no diff.
Then:
go list -m all > /dev/null
git diff --exit-codeThis fails because only go.work.sum has changed. Re-running go list -m all after applying those checksum entries is stable.
Images of the diff or a link to the PR, issue, or logs
- PR Switch to
repo.packagist.orgto allow mirrors #6297: build(deps): bump k8s.io/cli-runtime from 0.37.0 to 0.37.1 kubernetes-sigs/kustomize#6297 - Failing Switch to
repo.packagist.orgto allow mirrors #6297 job: https://github.com/kubernetes-sigs/kustomize/actions/runs/37086349710/job/111097361903 - PR Drop support for PHP Composer v1 #6298: build(deps): bump k8s.io/apimachinery from 0.37.0 to 0.37.1 kubernetes-sigs/kustomize#6298
- Failing Drop support for PHP Composer v1 #6298 job: https://github.com/kubernetes-sigs/kustomize/actions/runs/37086359980/job/111097388433
- Related Go bug: cmd/go: go.work.sum after
go work syncis missing entries needed bygo listgolang/go#63901 - Go 1.28 fix: https://go.dev/cl/815760
Smallest manifest that reproduces the issue
The two public PR heads above provide deterministic Dependabot reproductions.
The Go issue also contains a reduced testscript reproducer:
The Go 1.28 change includes a focused regression test:
https://go.googlesource.com/go/+/b614756d7b7e663f950de75d502462277785a635
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity