Major Versions in Go Modules Explained

 4 years ago
source link: https://www.tuicool.com/articles/hit/IF3aauq
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Go Modules is still a relatively new feature and some of the documentation surrounding it is detailed and technical, but not easily digestible as a quick start.

One issue I ran into is dealing with packages that have a version of2.x.xor higher. It’s not immediately obvious but Go modules handles packages that have a major version that is notv0.x.xorv1.x.xin a special way.

I won’t go into why this is so. The bottom line is that if you publish a package with a version ofv2.0.0+or publish a new major version there are some extra steps in your package and the packages that depend on it.

In this example I will be publishing v7.0.0 of github.com/kounta/luigi (one of our private repositories, but you can substitute the name with your own). It already uses go modules, but it has never had its major version taken into special consideration. This causes packages that depend on it to force a specific version in theirgo.mod:

github.com/kounta/luigi v0.0.0-20190328234950-d6354a0da43d

We would rather have the tagged version, like:

github.com/kounta/luigi v7.0.1

The odd thing is that if I change the version manually (ingo.mod), Go will just revert it back to the specific hash and checksum. What's going on!?

Before we start there is an important consideration here. If you want to support multiple major versions or not. In my case we only want to support the current major version since it is an internal library. Any projects that depend on it will eventually need to update their dependencies which will trigger them to updateluigito the latest version.

However, if you need to support multiple major versions at the same time I will explain this separately later in Maintaining Multiple Major Versions .

Updating the Package

We already have ago.modfile. We have to modify the first line ofgo.modto include the major version (notice we do not care about the minor or patch):

module github.com/kounta/luigi/v7

This may seem obscure at right now. The next step will show why this is needed.

Rungo build(orgo testif you have tests) and you will receive errors like:

./log_entry_test.go:14:14: undefined: luigi.NewLogEntry

./log_http_test.go:15:78: undefined: luigi.Environment

This is because we have changed the name of the current package. Technically Go is giving these errors because there is no longer [email protected]@v1.0.0available.

We will need to update our imports to the new package name (including test files):

import "github.com/kounta/luigi/v7"

My first through was, "Oh, no! Will I have to referencev7.xinstead ofluigi.xeverywhere?" Actually, no. Only the import name changes, and Go understands we are talking about the version on the end. Phew.

It could be painful if you have many imports to update. A global search and replace might be necessary.

Oncego build/testpasses you should rungo mod tidy, not only because it’s a good idea but also because it will remove any references to the old version of this package that might have been added from ago build/testwhile refactoring.

Now commit all changes including thego.modandgo.sum.

Updating The Packages That Depend On Luigi

For any packages that rely onluigi, we have to update them to point tov7explicitly.

There are two ways to do this:

  1. Simply run (notice the version is now in the package name):

    go get github.com/kounta/luigi/[email protected]

  2. Or, edit thego.modmanually and change the version and package name, from:

github.com/kounta/luigi v0.0.0-20190328234950-d6354a0da43d


github.com/kounta/luigi/v7 v7.0.1

When you rungo build/testyou will get the same kind of error as before. It requires the same fix. That is, changing the import names to include the version number on the end.

Finally, rungo mod tidyfor good measure. You are done!

Maintaining Multiple Major Versions

If you need to support multiple major versions at the same time you will need to use multiplego.modfiles.

Let’s say I had to manage bothv6andv7(the latest) ofluigi. Before embarking on the changes above you should copy thego.modandgo.suminto a folder calledv6:

mkdir v6

cp go.mod go.sum v6

Any consumers that wish to remain onv6can with the import:

import "github.com/kounta/luigi/v6"

Go will automatically resolve this to the versioned folder in the repository. Easy. It's also a nice way to indicate how many major versions back your package officially supports.

About Joyk

Aggregate valuable and interesting links.
Joyk means Joy of geeK