How to update a module's direct dependencies only

1,221 views
Skip to first unread message

mihaib...@gmail.com

unread,
Sep 4, 2019, 7:35:58 PM9/4/19
to golang-nuts
Hello,

I am looking for a way to regularly update my Go module's direct dependencies. Without specifying indirect dependencies myself: let my direct dependencies specify what they need in their own go.mod.

After reading relevant documentation, I could only come up with this partial workaround:

go list -m -u -f '{{if and (and (not .Indirect) (not .Main)) .Update}}{{.Path}}@{{.Update.Version}}{{end}}' all | xargs --no-run-if-empty go get

Suspecting this scenario is common and useful, I have prepared a minimal concrete example below (each module is a repository under github.com/MihaiB for now).
"X → Y" means "module X depends directly on module Y".
I have the following Go modules:

goMain → goA → goB
goMain's tests → goT

All modules have published versions v1.1.0, v1.2.0 and v2.0.0 (except goMain which has no version tags). All dependency arrows above (go.mod entries) specify v1.1.0, so all can be updated.

goMain's .go files are in a sub/dir/ to make sure the commands I type inspect all packages inside the module, but this isn't mandatory: I can also repeat a command in each package's directory if needed.

--------
In goMain:
$ cat go.mod 

go 1.13

require (
)
--------

1) How to find out if goA or goT have a newer v1 version, and update to it?
My 'go list … | xargs …' workaround above does this by listing the direct dependencies and passing them to 'go get'.
Would it make sense to support this functionality via a shorter command?
I cannot use 'go get -u -t -d ./...' here because that brings in the indirect dependency 'goB' into my go.mod.

2) How to find out if goA or goT have a newer major version (v2 or later)?
I know that v2 and later have a different import path (ending in "/v2"), so different major versions are different packages and they can be used together in my module.
But I would like a command which tells me if some of my direct dependencies have a newer major version, otherwise I would have to check each dependency by hand to find out.

Mihai

t hepudds

unread,
Sep 4, 2019, 9:33:28 PM9/4/19
to golang-nuts
Hello Mihai,

To upgrade your direct dependencies to their latest release (with your indirect dependencies using versions selected based on the requirements of your direct dependencies), this should work in most cases:

  go get $(go list -f '{{if not (or .Main .Indirect)}}{{.Path}}{{end}}' -m all)

Does that work for you?

There is an issue suggesting allowing this to be specified more easily:

    #28424 cmd/go: add 'go get' options to update direct and indirect dependencies separately
  
If interested, you could add a comment there briefly explaining your use case, or whatever other comment makes sense.

Regards,
thepudds

Mihai Borobocea

unread,
Sep 5, 2019, 3:17:51 AM9/5/19
to golang-nuts
On Thu, Sep 5, 2019 at 4:33 AM t hepudds <thepud...@gmail.com> wrote:
To upgrade your direct dependencies to their latest release (with your indirect dependencies using versions selected based on the requirements of your direct dependencies), this should work in most cases:

  go get $(go list -f '{{if not (or .Main .Indirect)}}{{.Path}}{{end}}' -m all)
Thank you for this shorter solution and its GitHub issue.
To run it on any module (including modules without dependencies and with no .go files in the module root) this checks that the list of dependencies isn't empty:

go list -f '{{if not (or .Main .Indirect)}}{{.Path}}{{end}}' -m all | xargs --no-run-if-empty go get

Then my remaining question is: How to find out if one of my dependencies has a newer major version?
Is there, or should there be, a way using the standard tools to query for this?
I found a couple of GitHub issues about upgrading to /v2+ (like changing the /vN import suffix automatically) once the user knows about a new major version. But I didn't find an issue about discovering that there is a new major version without manually checking.

Regards,
Mihai

Tamás Gulácsi

unread,
Sep 5, 2019, 8:28:20 AM9/5/19
to golang-nuts
Ain't Go 1.13's "go get -u" does exactly this?
And the old behaviour with "go get -u all" ?

"The -u flag instructs get to update modules providing dependencies of packages named on the command line to use newer minor or patch releases when available. Continuing the previous example, 'go get -u A' will use the latest A with B v1.3.1 (not B v1.2.3). If B requires module C, but C does not provide any packages needed to build packages in A (not including tests), then C will not be updated."

"With no package arguments, 'go get' applies to Go package in the current directory, if any. In particular, 'go get -u' and 'go get -u=patch' update all the dependencies of that package."

Mihai Borobocea

unread,
Sep 5, 2019, 8:45:32 AM9/5/19
to golang-nuts
On Thu, Sep 5, 2019 at 3:28 PM Tamás Gulácsi <tgula...@gmail.com> wrote:
Ain't Go 1.13's "go get -u" does exactly this?
And the old behaviour with "go get -u all" ?
Thanks for the input but:
I cannot use 'go get -u -t -d ./...' here because that brings in the indirect dependency 'goB' into my go.mod.
In my minimal concrete example at https://github.com/MihaiB/goMain and described in the first message in this thread.
Reply all
Reply to author
Forward
0 new messages