Rewrite docs on godep

This commit is contained in:
Tim Hockin 2017-09-01 11:21:09 -07:00
parent b02edb9d2b
commit 42db070c3f
2 changed files with 137 additions and 98 deletions

View File

@ -152,24 +152,11 @@ images.
#### Dependency management
Kubernetes build/test scripts use [`godep`](https://github.com/tools/godep) to
manage dependencies.
```sh
go get -u github.com/tools/godep
```
The Godep version that Kubernetes is using is listed in `Godep/Godep.json` (in
the kubernetes repo root). See what version you are running with this command:
```sh
godep version
```
Developers planning to manage dependencies in the `vendor/` tree may want to
explore alternative environment setups. See [using godep to manage
dependencies](godep.md).
Kubernetes uses [`godep`](https://github.com/tools/godep) to manage
dependencies.
Developers who need to manage dependencies in the `vendor/` tree should read
the docs on [using godep to manage dependencies](godep.md).
## Build with Bazel/Gazel
@ -178,7 +165,6 @@ Building with Bazel is currently experimental. For more information,
see [Build with Bazel].
## Workflow
![Git workflow](git_workflow.png)

View File

@ -1,128 +1,181 @@
# Using godep to manage dependencies
This document is intended to show a way for managing `vendor/` tree dependencies
in Kubernetes. If you are not planning on managing `vendor` dependencies go here
[Godep dependency management](development.md#godep-dependency-management).
in Kubernetes. If you do not need to manage vendored dependencies, you probably
do not need to read this.
## Alternate GOPATH for installing and using godep
## Background
There are many ways to build and host Go binaries. Here is one way to get
utilities like `godep` installed:
As a tool, `godep` leaves much to be desired. It builds on `go get`, and adds
the ability to pin dependencies to exact git version. The `go get` tool itself
doesn't have any concept of versions, and tends to blow up if it finds a git
repo synced to anything but `master`, but that is exactly the state that
`godep` leaves repos. This is a recipe for frustration when people try to use
the tools.
Create a new GOPATH just for your go tools and install godep:
This doc will focus on predictability and reproducibility.
## Theory of operation
The `go` toolchain assumes a global workspace that hosts all of your Go code.
The `godep` tool operates by first "restoring" dependencies into your `$GOPATH`.
This reads the `Godeps.json` file, downloads all of the dependencies from the
internet, and syncs them to the specified revisions. You can then make
changes - sync to different revisions or edit Kubernetes code to use new
dependencies (and satisfy them with `go get`). When ready, you tell `godep` to
"save" everything, which it does by walking the Kubernetes code, finding all
required dependencies, copying them from `$GOPATH` into the `vendor/` directory,
and rewriting `Godeps.json`.
This does not work well, when combined with a global Go workspace. Instead, we
will set up a private workspace for this process.
The Kubernetes build process uses this same technique, and offers a tool called
`run-in-gopath.sh` which sets up and switches to a local, private workspace,
including setting up `$GOPATH` and `$PATH`. If you wrap commands with this
tool, they will use the private workspace, which will not conflict with other
projects and is easily cleaned up and recreated.
To see this in action, you can run an interactive shell in this environment:
```sh
export GOPATH=$HOME/go-tools
mkdir -p $GOPATH
go get -u github.com/tools/godep
# Run a shell, but don't run your own shell initializations.
hack/run-in-gopath.sh bash --norc --noprofile
```
Add this $GOPATH/bin to your path. Typically you'd add this to your ~/.profile:
## Restoring deps
To extract and download dependencies into `$GOPATH` we provide a script:
`hack/godep-restore.sh`. If you run this tool, it will restore into your own
`$GOPATH`. If you wrap it in `run-in-gopath.sh` it will restore into your
`_output/` directory.
```sh
export GOPATH=$HOME/go-tools
export PATH=$PATH:$GOPATH/bin
hack/run-in-gopath.sh hack/godep-restore.sh
```
## Using godep
This script will try to optimize what it needs to download, and if it seems the
dependencies are all present already, it will return very quickly.
Here's a quick walkthrough of one way to use godeps to add or update a
Kubernetes dependency into `vendor/`. For more details, please see the
instructions in [godep's documentation](https://github.com/tools/godep).
If there's every any doubt about the correctness of your dependencies, you can
simply `make clean` or `rm -rf _output`, and run it again.
1) Devote a directory to this endeavor:
Now you should have a clean copy of all of the Kubernetes dependencies.
_Devoting a separate directory is not strictly required, but it is helpful to
separate dependency updates from other changes._
## Making changes
The most common things people need to do with deps are add and update them.
These are similar but different.
### Adding a dep
For the sake of examples, consider that we have discovered a wonderful Go
library at `example.com/go/frob`. The first thing you need to do is get that
code into your workspace:
```sh
export KPATH=$HOME/code/kubernetes
mkdir -p $KPATH/src/k8s.io
cd $KPATH/src/k8s.io
git clone https://github.com/$YOUR_GITHUB_USERNAME/kubernetes.git # assumes your fork is 'kubernetes'
# Or copy your existing local repo here. IMPORTANT: making a symlink doesn't work.
hack/run-in-gopath.sh go get -d example.com/go/frob
```
2) Set up your GOPATH.
This will fetch, but not compile (omit the `-d` if you want to compile it now),
the library into your private `$GOPATH`. It will pull whatever the default
revision of that library is, typically the `master` branch for git repositories.
If this is not the revision you need, you can change it, for example to
`v1.0.0`:
```sh
# This will *not* let your local builds see packages that exist elsewhere on your system.
export GOPATH=$KPATH
hack/run-in-gopath.sh bash -c 'git -C $GOPATH/src/example.com/go/frob checkout v1.0.0'
```
3) Populate your new GOPATH.
Now that the code is present, you can start to use it in Kubernetes code.
Because it is in your private workspace's `$GOPATH`, it might not be part of
your own `$GOPATH`, so tools like `goimports` might not find it. This is an
unfortunate side-effect of this process. You can either add the whole private
workspace to your own `$GOPATH` or you can `go get` the library into your own
`$GOPATH` until it is properly vendored into Kubernetes.
Another possible complication is a dep that uses `gopdep` itself. In that case,
you need to restore its dependencies, too:
```sh
cd $KPATH/src/k8s.io/kubernetes
./hack/godep-restore.sh
hack/run-in-gopath.sh bash -c 'cd $GOPATH/src/example.com/go/frob && godep restore'
```
4) Next, you can either add a new dependency or update an existing one.
To add a new dependency is simple (if a bit slow):
If the transitive deps collide with Kubernetes deps, you may have to manually
resolve things. This is where the ability to run a shell in this environment
comes in handy:
```sh
cd $KPATH/src/k8s.io/kubernetes
DEP=example.com/path/to/dependency
godep get $DEP/...
# Now change code in Kubernetes to use the dependency.
./hack/godep-save.sh
hack/run-in-gopath.sh bash --norc --noprofile
```
To update an existing dependency is a bit more complicated. Godep has an
`update` command, but none of us can figure out how to actually make it work.
Instead, this procedure seems to work reliably:
### Updating a dep
Sometimes we already have a dep, but the version of it is wrong. Because of the
way that `godep` and `go get` interact (badly) it's generally easiest to hit it
with a big hammer:
```sh
cd $KPATH/src/k8s.io/kubernetes
DEP=example.com/path/to/dependency
# NB: For the next step, $DEP is assumed be the repo root. If it is actually a
# subdir of the repo, use the repo root here. This is required to keep godep
# from getting angry because `godep restore` left the tree in a "detached head"
# state.
rm -rf $KPATH/src/$DEP # repo root
godep get $DEP/...
# Change code in Kubernetes, if necessary.
rm -rf Godeps
rm -rf vendor
./hack/godep-save.sh
# Regenerate removed BUILD, licenses.
touch vendor/BUILD
./hack/update-bazel.sh
./hack/update-godep-licenses.sh
# If you haven't followed this doc step-by-step and haven't created a dedicated GOPATH,
# make sure there is no client-go or other staging repo in $GOPATH before running the next command.
./hack/update-staging-godeps.sh
git checkout -- $(git status -s | grep "^ D" | awk '{print $2}' | grep ^Godeps)
hack/run-in-gopath.sh bash -c 'rm -rf $GOPATH/src/example.com/go/frob'
hack/run-in-gopath.sh go get -d example.com/go/frob
hack/run-in-gopath.sh bash -c 'git -C $GOPATH/src/example.com/go/frob checkout v2.0.0'
```
_If `go get -u path/to/dependency` fails with compilation errors, instead try
`go get -d -u path/to/dependency` to fetch the dependencies without compiling
them. This is unusual, but has been observed._
This will remove the code, re-fetch it, and sync to your desired version.
### Removing a dep
This happens almost for free. If you edit Kubernetes code and remove the last
use of a given dependency, you only need to restore and save the deps, and the
`godep` tool will figure out that you don't need that dep any more:
## Saving deps
Now that you have made your changes - adding, updating, or removing the use of a
dep - you need to rebuild the dependency database and make changes to the
`vendor/` directory.
```sh
hack/run-in-gopath.sh hack/godep-save.sh
```
This will run through all of the primary targets for the Kubernetes project,
calculate which deps are needed, and rebuild the database. It will also
regenerate other metadata files which the project needs, such as BUILD files and
the LICENSE database.
After all of this is done, `git status` should show you what files have been
modified and added/removed. Make sure to `git add` and `git rm` them. It is
commonly advised to make one `git commit` which includes just the dependency
update and Godeps files, and another `git commit` that includes changes to
Kubernetes code to use the new/updated dependency. These commits can go into a
single pull request.
modified and added/removed. Make sure to sanity-check them with `git diff`, and
to `git add` and `git rm` them, as needed. It is commonly advised to make one
`git commit` which includes just the dependencies and Godeps files, and
another `git commit` that includes changes to Kubernetes code to use (or stop
using) the new/updated/removed dependency. These commits can go into a single
pull request.
5) Before sending your PR, it's a good idea to sanity check that your
Godeps.json file and the contents of `vendor/ `are ok by running `hack/verify-godeps.sh`
## Sanity checking
_If `hack/verify-godeps.sh` fails after a `godep update`, it is possible that a
transitive dependency was added or removed but not updated by godeps. It then
may be necessary to perform a `hack/godep-save.sh` to pick up the transitive
dependency changes._
Before sending your PR, it's a good idea to sanity check that your
Godeps.json file and the contents of `vendor/ `are ok:
It is sometimes expedient to manually fix the /Godeps/Godeps.json file to
minimize the changes. However without great care this can lead to failures
with `hack/verify-godeps.sh`. This must pass for every PR.
```sh
hack/run-in-gopath.sh hack/verify-godeps.sh
```
6) If you updated the Godeps, please also update `Godeps/LICENSES` by running
`hack/update-godep-licenses.sh`.
All this script will do is a restore, followed by a save, and then look for
changes. If you followed the above instructions, it should be clean. If it is
not, you get to figure out why.
## Manual updates
It is sometimes expedient to manually fix the `Godeps.json` file to
minimize the changes. However, without great care this can lead to failures
with the verifier scripts. The kubernetes codebase does "interesting things"
with symlinks between `vendor/` and `staging/` to allow multiple Go import
paths to coexist in the same git repo.
The verifiers, including `hack/verify-godeps.sh` *must* pass for every pull
request.
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->