Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

short-term steps to improve using github.com/docker/docker for modules-based consumers (new tag? documentation? nested module?) #41503

Open
thepudds opened this issue Sep 29, 2020 · 2 comments

Comments

@thepudds
Copy link

thepudds commented Sep 29, 2020

An incomplete summary of some related facts about this repo:

  • github.com/docker/docker redirects to github.com/moby/moby
  • The canonical import path is github.com/docker/docker (e.g., github.com/moby/moby/client/client.go declares itself as package client // import "github.com/docker/docker/client").
  • The most recent (highest semver precedence) syntactically valid semver release tag is v1.13.1.
  • The most recent (highest semver precedence) syntactically valid semver pre-release tag is v17.12.1-ce-rc2
    • There are a dozen or so similar semver pre-release tags that all follow the pattern of v17.*.*-ce*, which I suspect are all 3 years old or so at this point given they seem to be following "CalVer".
  • There many other "CalVer" tags on the repo, but aside from the v17.* ones, none of the others are syntactically valid semver tags.
    • They are not syntactically valid semver tags primarily because of leading 0 (e.g., 03 for March), which are disallowed by semver. An example tag on this repo that is not a semver tag: v19.03.13
  • One consequence is github.com/docker/docker@latest resolves to v1.13.1, which is a release that is over 3 years old from early 2017.

Proposal

I think there are maybe 2-3 small near-term steps that could materially simplify importing docker for modules-based consumers, and I would like to focus this issue on discussing whether one or more short-term steps are feasible (whether from this list, or perhaps someone will suggest a better short-term step).

These near-term steps would not include adopting modules wholesale, which could be a separate discussion but which also could be made easier by adopting one or more of these near-term steps.

Suggestion 1: apply a v1.20.x tag or similar

Apply at least one syntactically valid semver release tag on a recent commit in moby/moby. This would materially improve things for modules-based consumers, even if this was done manually, and even if this was just done as a one time operation to start. A syntactically valid semver release tag would not include anything trailing hyphen such as -foo (which would make it a semver pre-release tag), and would not any leading 0 in any of the version strings.

For example, if you applied the tag v1.20.1903012 to the moby/moby commit that is currently tagged v19.03.12, then the go command would recognize v1.20.1903012 as a syntactically valid semver tag, and it would be considered greater than (more recent than) v1.13.1, which is ~3.5 years old at this point. In addition, all of the -ce tags (like v17.12.1-ce-rc2+incompatible) are semver pre-release tags, which the go command won't use by default when resolving @latest or when a client does an upgrade via something like go get -u ./....

In other words, at that point, go get github.com/docker/docker@latest would resolve to v1.20.1903012 as the highest available syntactically valid non-prerelease tag.

Of course, pick whatever commit makes the most sense, and once you see it work, you could choose to apply additional similar tags to other commits if that makes sense.

This would be a large step forward, and stop consumers from defaulting to the ~3.5 year old v1.13.1 release by default.

This would also be a step towards adopting modules for github.com/docker/docker, but it would be easier than fully adopting modules.

Suggestion 2: document how to use a replace

If you don't want to do Suggestion 1, you could official document how to set a replace directive for modules-based consumers of docker/docker. For example, #39302 (comment) could be a starting point. If I search docs.docker.com, I do not see anything along those lines currently.

Suggestion 3: document how modules-consumers can use moby/moby/vendor.conf

Slightly more nuanced, but one of the challenges is moby/moby does not itself use modules, which the means dependency info in moby/moby/vendor.conf does not get used by module consumers, which in turn means sometimes people can do the right replace (e.g., following item 2) but still end up with a bad total set of versions if for example the @latest version of some dependency of moby/moby is in fact incompatible with the selected version of moby/moby. There is a solution for that documented here:

https://github.com/golang/go/wiki/Modules#i-have-a-problem-with-a-complex-dependency-that-has-not-opted-in-to-modules-can-i-use-information-from-its-current-dependency-manager

It's a bit more nuanced, but you could document how to do that specifically with github.com/docker/docker as the non-module target, or maybe instead document a few lines of bash that do it automatically (or even create a small Go utility, though a handful of lines of bash might be easier).

Suggestion 4: consider one or more nested modules, such as docker/docker/client

You could partially adopt modules, for example starting with creating a go.mod at github.com/moby/moby/client/go.mod, the first line of which would read module github.com/docker/docker/client. You could then tag something like client/v0.1.0 or client/v0.2020.9 (note the leading client/ on the git tag). When you have a nested module within a repo (that is, when you have a go.mod in a subdirectory of a repo), you use the directory name as part of the VCS tag, which means you would be sidestepping your CalVer history of the main repo.

In other words, you would have more freedom about how you tag and version the nested module github.com/docker/docker/client because it would end up with its own "name space" from a VCS tag perspective as far as the go command was concerned.

To start, you wouldn't need to create a go.mod at the root of the repo, and you wouldn't need to start using /v20 in your import paths.

This is my least favorite option because nested modules present their own challenges, but I at least wanted to mention it.


A few more details about "Suggestion 1: apply a v1.20.x tag or similar".

The v17.*.*-ce* semver pre-release tags will not be used by default, including because cmd/go prefers semver release tags over semver pre-release tags. For example, from cmd/go doc:

https://golang.org/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them

For each named package or package pattern, get must decide which version of the corresponding module to use. By default, get looks up the latest tagged release version, such as v0.4.5 or v1.2.3. If there are no tagged release versions, get looks up the latest tagged pre-release version, such as v0.0.1-pre1. If there are no tagged versions at all, get looks up the latest known commit.

Pre-release version definition: https://semver.org/#spec-item-9

However, one non-default scenario where the v17.*.*-ce* semver pre-release tags could appear is possibly as the explicitly named version in another dependency in the same build as someone who is importing the (new) release tag created in suggestion 1.

For example, suppose in a single build module A is using the new release tag via require github.com/docker/docker v1.20.1903012, while module B in the same build has require github.com/docker/docker v17.12.1-ce-rc2 in module B's go.mod. In that case, cmd/go's version selection will pick v17.12.1-ce-rc2 over v1.20.1903012 because v17.12.1-ce-rc2 has higher semver precedence. That would not be desirable, because it would be favoring a 3 year old version over a 2019 release.

However, this is hopefully a fairly rare case -- those dozen or so v17.-ce pre-release tags are over three years old at this point, and won't be selected by default for new consumers, so it hopefully would be a relatively rare situation that an existing current user is using them in the same build as someone else who is using a more modern release tag.

Even if this does occur, it is still solvable with a replace in the top-level build, or by updating module B to not require a v17.*-c2 tag. Arguably, this no worse than the current situation.


This is a longer, more complete version of my suggestions from a year or so ago in #39302 (comment), but #39302 is very wide ranging, and I felt it better to attempt to split out a separate issue focused on simpler and possibly more actionable steps.

CC @thaJeztah @cpuguy83 @rogpeppe @bcmills for any comments, corrections, or additional ideas.

@thepudds
Copy link
Author

thepudds commented Sep 29, 2020

One other comment is that after Go 1.16 ships, potentially the v17.*-ce*pre-release tags could be retracted (golang/go#24031), but I'm not sure that would materially change things overall, and likely is not worth waiting for before trying to otherwise improve things.

Also, here is what the go command (version 1.15.2) currently reports as the syntactically valid semver tags on this repo:

$ go list -versions -m github.com/docker/docker
github.com/docker/docker v0.1.0 v0.1.1 v0.1.2 v0.1.3 v0.1.4 v0.1.5 v0.1.6 v0.1.7 v0.1.8 v0.2.0 v0.2.1 v0.2.2 v0.3.0 v0.3.1 v0.3.2 v0.3.3 v0.3.4 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.4.7 v0.4.8 v0.5.0 v0.5.1 v0.5.2 v0.5.3 v0.6.0 v0.6.1 v0.6.2 v0.6.3 v0.6.4 v0.6.5 v0.6.6 v0.6.7 v0.7.0-rc1 v0.7.0-rc2 v0.7.0-rc3 v0.7.0-rc4 v0.7.0-rc5 v0.7.0-rc6 v0.7.0-rc7 v0.7.0 v0.7.1 v0.7.2 v0.7.3 v0.7.4 v0.7.5 v0.7.6 v0.8.0 v0.8.1 v0.9.0 v0.9.1 v0.10.0 v0.11.0 v0.11.1 v0.12.0 v1.0.0 v1.0.1 v1.1.0 v1.1.1 v1.1.2 v1.2.0 v1.3.0 v1.3.1 v1.3.2 v1.3.3 v1.4.0 v1.4.1 v1.5.0-rc1 v1.5.0-rc2 v1.5.0-rc3 v1.5.0-rc4 v1.5.0 v1.6.0-rc1 v1.6.0-rc2 v1.6.0-rc3 v1.6.0-rc4 v1.6.0-rc5 v1.6.0-rc6 v1.6.0-rc7 v1.6.0 v1.6.1 v1.6.2 v1.7.0-rc1 v1.7.0-rc2 v1.7.0-rc3 v1.7.0-rc4 v1.7.0-rc5 v1.7.0 v1.7.1-rc1 v1.7.1-rc2 v1.7.1-rc3 v1.7.1 v1.8.0-rc1 v1.8.0-rc2 v1.8.0-rc3 v1.8.0 v1.8.1 v1.8.2-rc1 v1.8.2 v1.8.3 v1.9.0-rc1 v1.9.0-rc2 v1.9.0-rc3 v1.9.0-rc4 v1.9.0-rc5 v1.9.0 v1.9.1-rc1 v1.9.1 v1.10.0-rc1 v1.10.0-rc2 v1.10.0-rc3 v1.10.0-rc4 v1.10.0 v1.10.1-rc1 v1.10.1 v1.10.2-rc1 v1.10.2 v1.10.3-rc1 v1.10.3-rc2 v1.10.3 v1.11.0-rc1 v1.11.0-rc2 v1.11.0-rc3 v1.11.0-rc4 v1.11.0-rc5 v1.11.0 v1.11.1-rc1 v1.11.1 v1.11.2-rc1 v1.11.2 v1.12.0-rc1 v1.12.0-rc2 v1.12.0-rc3 v1.12.0-rc4 v1.12.0-rc5 v1.12.0 v1.12.1-rc1 v1.12.1-rc2 v1.12.1 v1.12.2-rc1 v1.12.2-rc2 v1.12.2-rc3 v1.12.2 v1.12.3-rc1 v1.12.3 v1.12.4-rc1 v1.12.4 v1.12.5-rc1 v1.12.5 v1.12.6 v1.13.0-rc1 v1.13.0-rc2 v1.13.0-rc3 v1.13.0-rc4 
v1.13.0-rc5 v1.13.0-rc6 v1.13.0-rc7 v1.13.0 v1.13.1-rc1 v1.13.1-rc2 v1.13.1 
v17.10.0-ce+incompatible
v17.10.0-ce-rc1+incompatible
v17.10.0-ce-rc2+incompatible
v17.11.0-ce+incompatible
v17.11.0-ce-rc1+incompatible
v17.11.0-ce-rc2+incompatible
v17.11.0-ce-rc3+incompatible
v17.11.0-ce-rc4+incompatible
v17.12.0-ce+incompatible
v17.12.0-ce-rc1+incompatible
v17.12.0-ce-rc2+incompatible
v17.12.0-ce-rc3+incompatible
v17.12.0-ce-rc4+incompatible
v17.12.1-ce+incompatible
v17.12.1-ce-rc1+incompatible
v17.12.1-ce-rc2+incompatible

@bcmills
Copy link

bcmills commented Sep 30, 2020

As of Go 1.16, it may be possible to add a go.mod file that retracts all of the v0, v1, and ambiguously-{Cal,Sem}Ver releases, which would cause go get github.com/docker/docker@latest to instead use a pseudo-version from the head of the default branch.

(See golang/go#24031.)

[Edit: oops, I should have refreshed the page before posting my comment, because I see that @thepudds gave the same suggestion above.]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants