• Bryan C. Mills's avatar
    cmd/go: validate pseudo-versions against module paths and revision metadata · 1803ab1e
    Bryan C. Mills authored
    Previously, most operations involving pseudo-versions allowed any
    arbitrary combination of version string and date, and would resolve to
    the underlying revision (typically a Git commit hash) as long as that
    revision existed.
    
    There are a number of problems with that approach:
    
    • The pseudo-version participates in minimal version selection. If its
      version prefix is inaccurate, the pseudo-version may appear to have
      higher precedence that the releases that follow it, effectively
      “pinning” the module to that commit. For release tags, module
      authors are the ones who make the decision about release tagging;
      they should also have control over the pseudo-version precedence
      within their module.
    
    • The commit date within the pseudo-version provides a total order
      among pseudo-versions. If it is not accurate, the pseudo-version
      will sort into the wrong place relative to other commits with the
      same version prefix.
    
    To address those problems, this change restricts the pseudo-versions
    that the 'go' command accepts, rendering some previously
    accepted-but-not-canonical versions invalid. A pseudo-version is now
    valid only if all of:
    
    1. The tag from which the pseudo-version derives points to the named
       revision or one of its ancestors as reported by the underlying VCS
       tool, or the pseudo-version is not derived from any tag (that is,
       has a "vX.0.0-" prefix before the date string and uses the lowest
       major version appropriate to the module path).
    
    2. The date string within the pseudo-version matches the UTC timestamp
       of the revision as reported by the underlying VCS tool.
    
    3. The short name of the revision within the pseudo-version (such as a
       Git hash prefix) is the same as the short name reported by the
       underlying cmd/go/internal/modfetch/codehost.Repo. Specifically, if
       the short name is a SHA-1 prefix, it must use the same number of
       hex digits (12) as codehost.ShortenSHA1.
    
    4. The pseudo-version includes a '+incompatible' suffix only if it is
       needed for the corresponding major version, and only if the
       underlying module does not have a go.mod file.
    
    We believe that all releases of the 'go' tool have generated
    pseudo-versions that meet these constraints. However, a few
    pseudo-versions edited by hand or generated by third-party tools do
    not. If we discover invalid-but-benign pseudo-versions in widely-used
    existing dependencies, we may choose to add a whitelist for those
    specific path/version combinations.
    
    ―
    
    To work around invalid dependencies in leaf modules, users may add a
    'replace' directive from the invalid version to its valid equivalent.
    Note that the go command's go.mod parser automatically resolves commit
    hashes found in 'replace' directives to the appropriate
    pseudo-versions, so in most cases one can write something like:
    
    	replace github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c => github.com/docker/docker e7b5f7dbe98c
    
    and then run any 'go' command (such as 'go list' or 'go mod tidy') to
    resolve it to an appropriate pseudo-version. Note that the invalid
    version will still be used in minimal version selection, so this use
    of 'replace' directives is an incomplete workaround.
    
    ―
    
    One of the common use cases for higher-than-tagged pseudo-versions is
    for projects that do parallel development on release branches. For
    example, if a project cuts a 'v1.2' release branch at v1.2.0, they may
    want future commits on the main branch to show up as pre-releases for
    v1.3.0 rather than for v1.2.1 — especially if v1.2.1 is already tagged
    on the release branch. (On the other hand, a backport of a patch to
    the v1.2 branch should not show up as a pre-release for v1.3.0.)
    
    To address this use-case, module authors can make use of our existing
    support for pseudo-versions derived from pre-release tags: if the
    author adds an explicit pre-release tag (such as 'v1.3.0-devel') to
    the first commit after the branch, then the pseudo-versions for that
    commit and its descendents will be derived from that tag and will sort
    appropriately in version selection.
    
    ―
    
    Updates #27171
    Fixes #29262
    Fixes #27173
    Fixes #32662
    Fixes #32695
    
    Change-Id: I0d50a538b6fdb0d3080aca9c9c3df1040da1b329
    Reviewed-on: https://go-review.googlesource.com/c/go/+/181881
    Run-TryBot: Bryan C. Mills <bcmills@google.com>
    Reviewed-by: default avatarJay Conrod <jayconrod@google.com>
    1803ab1e
go1.13.html 26.2 KB