jesselang.com | @jesselang
And it worked.
$GOPATH
bin/
helloworld
src/
github.com/
go-training/
helloworld/
LICENCE
README.md
main.go
main_test.go
# Get and test the latest version of a Hello World app
# and then run it!
% go get -u github.com/go-training/helloworld
% go test -v github.com/go-training/helloworld
=== RUN TestHelloWorld
--- PASS: TestHelloWorld (0.00s)
PASS
ok github.com/go-training/helloworld 0.003s
% go run github.com/go-training/helloworld
Hello World!!
# See the documentation for Cobra
% go doc github.com/spf13/cobra
Software is complex, and can be volatile as it moves quickly. The Go committee encouraged us to write backward-compatible code, but we all know there are limits to that ideal.
Six months from now, when your company is suffering an outage and you need to push a critical fix, your app will inevitably fail to build unless...
... you can identify and retrieve the
exact same packages
that you built your app with when you last deployed it.
(╯°□°)╯︵ ┻━┻
Easy! There are plenty of ways to solve this.
No silver bullets though.
- GOPATH per app, per app version (please don't do this)
- Vendor your dependencies (not fun to manage, makes for messy PRs)
- Track which git commits of your dependencies were used
- Use tools to automate vendoring or pinning
- 2015: Go 1.5 introduced
vendor
directory support,govendor
tool - Feb 2016: Go 1.6 released with
vendor
support enabled by default - And then: glide, godep, dep, then vgo.
- Blah, blah, blah, I didn't get into this deep enough to say enough smart things
OK Jesse. Enough details already.
How can I effectively use Go modules?
I'm so glad you asked!
Let's talk about modules.
A module is a group of Go packages that share a versioning and release lifecycle.
Modules record precise dependency requirements and create reproducible builds.
Go prefers that modules use Semantic Versioning.
That is deceptively simple.
Your app requires Modules A and B. Module A requires Module [email protected], and Module B requires Module [email protected]. Module C just released v1.3.3 today. Go will choose the minimum required version, favoring fully reproducible builds, instead of selecting the latest minor version.
% go get -u github.com/spf13/cobra/cobra
% cobra init \
--pkg-name github.com/jesselang/go-module-example/foocli
% go mod init github.com/jesselang/go-module-example/foocli
# get all dependencies and build
% go build
% go test all
% go mod tidy
% git commit ...
# The "v" prefix on the tag is really important.
% git tag -am "Version 1.2.14" v1.2.14
% git push && git push --tags
go mod init
Works with vgo, dep, godep, glide, govendor, etc.
# package-building commands add new dependencies
# to go.mod as needed.
% go build
% go test
% go get github.com/spf13/cobra/[email protected] # downgrade a module
% go list -m all # prints the current module’s dependencies.
% go mod tidy # removes unused dependencies.
When hacking on a dependent module, you can use local modifications by adding
the replace
directive to your go.mod
to point to an on-disk path:
replace example.com/project/foo => ../foo
# Retrieves all dependencies from go.mod and puts them
# in the vendor/ directory. You can commit those dependencies in your repo
# if you need that guarantee.
% go mod vendor
@jesselang on Twitter