10 Golang Dependency Management
10.1 Git Tagging
Go has no central repository for packages. Instead, you include remote packages in your code by importing a URL that points to the package’s remote location. Usually, this is a GitHub, BitBucket, or Google Code URL:
import "github.com/SatishTalim/redditnews"
^ ^ ^
| | |
| | `--------------- Package / Repo name
| `---------------------------- Author's handle
`-------------------------------------- Hosting site
Go doesn’t support any explicit method for versioning packages.
10.2 Versioning your package
Gustavo Niemeyer has come out with a package gopkg.in for stable APIs for the Go language, which we shall use here.
The advantage of using gopkg.in is that the URL is cleaner, shorter, redirects to the package documentation at godoc.org when opened with a browser, handles git branches and tags for versioning, and most importantly encourages the adoption of stable versioned package APIs.
Note that gopkg.in does not hold the package code. Instead, the go tool is redirected and obtains the code straight from the respective GitHub repository.
Here’s the gopkg.in URL for my repo.
GitHub repositories that have no version tags or branches are considered unstable, and thus in “v0”. What we had uploaded to GitHub was “v0”.
Version zero (v0) is reserved for packages that are so immature that offering any kind of API stability guarantees would be unreasonable. This is equivalent to labeling the package as alpha or beta quality, and as such the use of these packages as dependencies of stable packages and applications is discouraged.
Packages should not remain in v0 for too long, as the lack of API stability hinders their adoption, and hurts the stability of packages and applications that depend on them.
Use the go tool to automatically check out and install my package:
$ go get -u gopkg.in/SatishTalim/redditnews.v0
The -u flag instructs get to use the network to update the named packages and their dependencies. By default, get uses the network to check out missing packages but does not use it to look for updates to existing packages.
The go get command checks out the repository to $GOPATH/src/github.com/SatishTalim/redditnews and installs the binary, if any, to $GOPATH/bin. The bin directory is in my PATH.
The go get command can fetch code from:
- Bitbucket
- GitHub
- Google Code
- Launchpad
as well as arbitrary Git, Mercurial, Subversion, and Bazaar repositories.
To import my package, add the following line to your code:
import "gopkg.in/SatishTalim/redditnews.v0"
Note: Although a version selector (v0) is provided as part of the import path, your code should refer to the Go package as redditnews.
10.3 When to change the version?
Examples of modifications that DO NEED a major version change are:
- Removing or renaming any exposed name (function, method, type, etc.)
- Adding, removing or renaming methods in an interface
- Adding a parameter to a function, method, or interface
- Changing the type of a parameter or result in a function, method, or interface
- Changing the number of results in a function, method, or interface
- Some struct changes: A struct consisting only of a few exported fields must not have fields added (exported or not) or repositioned without a major version change, as that will break code using such structs in literals with positional fields. Also, removing or renaming exported fields from an existing struct means a major version change.
On the other hand, the following modifications are FINE WITHOUT a major version change:
- Adding exposed names (function, method, type, etc)
- Renaming a parameter or result of a function, method, or interface
- Some struct changes: A struct containing non-exported fields may always receive new exported fields safely, as the language disallows code outside the package from using literals of these structs without naming the fields explicitly.
10.4 How to change the version?
Once our package is stable, we need to change the version number to say “v1”. Increasing the version number is done by creating a git tag or branch with the proper name and pushing it, as follows:
$ git add -A
$ git commit -m "commit"
$ git tag -a v1 -m 'my version 1.0'
The -m specifies a tagging message, which is stored with the tag. If you don’t specify a message for an annotated tag, Git launches your editor so you can type it in. Annotated tags are stored as full objects in the Git database. They’re checksummed; contain the tagger name, e-mail, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG). It’s generally recommended that you create annotated tags so you can have all this information.
By default, the git push command doesn’t transfer tags to remote servers. You will have to explicitly push tags to a shared server after you have created them. Thus:
$ git push origin v1
10.5 What next?
We have seen the mechanics of building a bare-bones redditnews package. You can build further upon this:
- Expand the reddit package to support more of the Reddit API.
- Learn about Go’s concurrency primitives and perform multiple requests in parallel.
That’s it, have fun!