Why Golang packages have to be v0 or v1 and not v2020

Viewed 3055

I read everywhere that packages have to have a tag of v0 or v1. Why can't a tag be v2020 or something other than v0 or v1. I have tried this personal and is get the following error with I use v2020.

Scotts-Mac-mini:seeding syacko$ go mod tidy
go: errors parsing go.mod:
/Users/syacko/workspace/sotesoft/src/utils/seeding/go.mod:10: require gitlab.com/soteapps/packages: version "v2020.2.0" invalid: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2020
Scotts-Mac-mini:seeding syacko$ 
2 Answers

It's a convention, a convenience for everyone. Go modules chose to use the widely accepted Semantic Versioning v2.

Go Modules Wiki:

What happens if I create a go.mod but do not apply semver tags to my repository?

semver is a foundation of the modules system. In order to provide the best experience for consumers, module authors are encouraged to apply semver VCS tags (e.g., v0.1.0 or v1.2.3-rc.1), but semver VCS tags are not strictly required:

  1. Modules are required to follow the semver specification in order for the go command to behave as documented. This includes following the semver specification regarding how and when breaking changes are allowed.

  2. Modules that do not have semver VCS tags are recorded by consumers using a semver version in the form of a pseudo-version. Typically this will be a v0 major version, unless the module author constructed a v2+ module following the "Major Subdirectory" approach.

  3. Therefore, modules that do not apply semver VCS tags and have not created a "Major Subdirectory" are effectively declaring themselves to be in the semver v0 major version series, and a module-based consumer will treat them as having a semver v0 major version.

An interesting and relevant blog post from Dave Cheney that predates Go modules: Gophers, please tag your releases

What do we want? Version management for Go packages! When do we want it? Yesterday!

[...] We want our Go build tool of choice to fetch the latest stable version when you start using the package in your project.[...]

But as it stands, today, in 2016, there is no way for a human, or a tool, to look at an arbitrary git (or mercurial, or bzr, etc) repository of Go code and ask questions like:

  • What versions of this project have been released?
  • What is the latest stable release of this software?
  • If I have version 1.2.3, is there a bugfix or security update that I should apply?

The reason for this is Go projects (repositories of Go packages) do not have versions, at least not in the way that our friends in other languages use that word. Go projects do not have versions because there is no formalised release process.

[...] I recommend that Go projects adopt SemVer 2.0.0. It’s a sound standard, it is well understood by many, not just Go programmers, and semantic versioning will let people write tools to build a dependency management ecosystem on top of a minimal release process.

After re-reading github.com/golang/go/wiki/…, I see the issue is not with the v2020.y.z, it is with the directory structure not matching the version number. path abc/def/v2020 v2020.y.z should work. Thank you for the various links. A good working example is github.com/jackc/pgx/v4

Here are the steps for the item you are going version: When you get to the point where you want to change the version to V2 or higher, these are the steps that need to be followed.

Sample go.mod file before version change
module gitlab.com/soteapps/packages

go 1.14

require (
    github.com/aws/aws-sdk-go v1.32.4
    github.com/jackc/pgconn v1.5.0
    github.com/jackc/pgx/v4 v4.6.0
    golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
    golang.org/x/text v0.3.3 // indirect
)
Sample go.mod file after version change
module gitlab.com/soteapps/packages/v2100

go 1.14

require (
    github.com/aws/aws-sdk-go v1.32.4
    github.com/jackc/pgconn v1.5.0
    github.com/jackc/pgx/v4 v4.6.0
    golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
    golang.org/x/text v0.3.3 // indirect
)
Sample Golang file import before change
package sDatabase

import (
    "context"
    "encoding/json"
    "fmt"
    "strings"

    "github.com/jackc/pgx/v4"
    "github.com/jackc/pgx/v4/pgxpool"
    "gitlab.com/soteapps/packages/sError"
    "gitlab.com/soteapps/packages/sLogger"
)

const (
Sample Golang file import after change
package sDatabase

import (
    "context"
    "encoding/json"
    "fmt"
    "strings"

    "github.com/jackc/pgx/v4"
    "github.com/jackc/pgx/v4/pgxpool"
    "gitlab.com/soteapps/packages/v2020/sError"
    "gitlab.com/soteapps/packages/v2020/sLogger"
)

const (
Item having a version v2+ number:
  1. Edit the go.mod module line to include the major version number at the end of the existing module path. So, the above module line module gitlab.com/soteapps/packages would change too module gitlab.com/soteapps/packages/v2100.
  2. All import references to gitlab.com/soteapps/packages in all the *.go files in the project must be updated to gitlab.com/soteapps/packages/{version}. In our example, this would the following, gitlab.com/soteapps/packages/v2100.
  3. Commit the change to source control.
    1. If you are using master, then commit to master.
      1. After you commit to master, create a branch from master with the version name. v2100 in the above example.
    2. If you are using branch, then commit to a branch with the version name. v2100 in the above example.
    3. The last step is to create a tag using semantic versioning format (vX.Y.Z) that point to the version branch. v2100.1.0 would be the tag for this example.
Related