github.com/GoogleContainerTools/skaffold@v1.39.18/DEVELOPMENT.md (about) 1 # Development 2 3 This doc explains the development workflow so you can get started 4 [contributing](CONTRIBUTING.md) to Skaffold! 5 6 7 ## Requirements 8 9 You must install these tools: 10 11 1. [`go`](https://golang.org/doc/install): The language skaffold is 12 built in (version >= go 1.19) 13 1. [`git`](https://help.github.com/articles/set-up-git/): For source control 14 1. [`make`](https://www.gnu.org/software/make/): For building skaffold. 15 16 ## Getting started 17 18 First you will need to setup your GitHub account and create a fork: 19 20 1. Create [a GitHub account](https://github.com/join) 21 1. Setup [GitHub access via SSH](https://help.github.com/articles/connecting-to-github-with-ssh/) 22 1. [Create and checkout a repo fork](#checkout-your-fork) 23 24 Once you have those, you can iterate on skaffold: 25 26 1. [Build your dev version of skaffold](#building-skaffold) 27 1. [Verify changes locally](#verifying-local-changes) 28 1. [Run skaffold tests](#testing-skaffold) 29 1. [Build docs](#building-skaffold-docs) if you are making doc changes 30 31 When you're ready, you can [create a PR](#creating-a-pr)! 32 33 ## Checkout your fork 34 35 To make local changes to skaffold and eventually submit a pull request to the repo, 36 we recommend [creating your own fork](https://help.github.com/articles/fork-a-repo/). 37 38 Once you've done this, clone your fork to your local machine: 39 40 ```shell 41 git clone git@github.com:${YOUR_GITHUB_USERNAME}/skaffold.git 42 cd skaffold 43 git remote add upstream git@github.com:GoogleContainerTools/skaffold.git 44 git remote set-url --push upstream no_push 45 ``` 46 47 _Adding the `upstream` remote sets you up nicely for regularly [syncing your fork](https://help.github.com/articles/syncing-a-fork/)._ 48 49 ## Creating a PR 50 51 When you have changes you would like to propose to skaffold, you will need to: 52 53 1. Ensure the commit message(s) follow the [conventional commits guidelines](https://www.conventionalcommits.org/en/v1.0.0/). The Skaffold repo has a bot to check that commit messages follow this style. 54 2. Ensure the PR description describes what issue you are fixing and how you are fixing it 55 (include references to [issue numbers](https://help.github.com/articles/closing-issues-using-keywords/) 56 if appropriate) 57 3. Add unit tests. Unit test coverage should increase or stay the same with every PR. 58 4. Add integration test if applicable 59 5. [Create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) 60 61 Please follow our [small Pull Requests guidelines](./docs/community/small-prs.md) for quicker response time. 62 63 ### Reviews 64 65 Each PR must be reviewed by a maintainer. This maintainer will add the `kokoro:run` label 66 to a PR to kick off [the integration tests](#integration-tests), which must pass for the PR 67 to be submitted. 68 69 ## Making a config change 70 71 Some changes to the skaffold code require a change to the skaffold config. These changes require a few extra steps: 72 73 * Open the latest Config at [pkg/skaffold/schema/latest/config.go](https://github.com/GoogleContainerTools/skaffold/blob/main/pkg/skaffold/schema/latest/config.go) and inspect the comment at [L28](https://github.com/GoogleContainerTools/skaffold/blob/main/pkg/skaffold/schema/latest/config.go#L28) 74 * If the line mentions the config version is not released, proceed making your changes. 75 ``` 76 // This config version is not yet released, it is SAFE TO MODIFY the structs in this file. 77 ``` 78 79 * **If the line mentions** the config version is released then, 80 ``` 81 // !!! WARNING !!! This config version is already released, please DO NOT MODIFY the structs in this file. 82 ``` 83 84 * Run `./hack/new-version.sh` to create a new version. 85 86 * Run `make test` to verify changes. 87 88 * Commit these generated changes, and submit a PR. 89 90 Once you've done this, merge or rebase your development branch with config changes, including the new config change. 91 **Any new config changes belong in pkg/skaffold/schema/latest/config.go. Do not edit the older config versions.** 92 93 * Be sure and update the documentation in `pkg/skaffold/schema/<previous_config_version>/upgrade.go` with any additions, removals, or updates you make to the config. 94 95 * In case of backwards compatibility issues, update the `Upgrade()` method from the previous config version appropriately. This is usually required when a previously existing field in the config is changed, but **not** when a new field is added. 96 97 *Note: the Upgrade() method is called by skaffold automatically for older config versions. This can also be done manually by users by running `skaffold fix`.* 98 99 * Finally, before committing your final changes and opening your pull request, be sure and run `make test` locally. This will regenerate the JSON schemas for the skaffold config with your new changes. Commit the resulting changes autogenerated by the scripts. 100 101 For more details behind the logic of config changes see [the Skaffold config management doc](https://docs.google.com/document/d/e/2PACX-1vRIjLuHL2uZ1OXcV9ZXbOQ7ijmqmeCeOZroCGBGTgstuNaZqoKXwg0KLGt_M-PHBwoVpnsKUhHxJ3Jc/pub). 102 103 ## Making changes to the Skaffold API 104 105 We build the API directly through gRPC, which gets translated into REST API through a reverse proxy gateway library. When adding new message types, make changes to [proto/v2/skaffold.proto](https://github.com/GoogleContainerTools/skaffold/blob/main/proto/v2/skaffold.proto), and when adding new enum types, make changes to [proto/enums/enums.proto](https://github.com/GoogleContainerTools/skaffold/blob/main/proto/enums/enums.proto). When changing either of these files, you can run `./hack/generate-proto.sh` to generate the equivalent Go code. 106 107 ## Adding actionable error messages to code. 108 Skaffold has a built-in framework to provide actionable error messages for user to help bootstrap skaffold errors. 109 110 Also, [v1.19.0](https://github.com/GoogleContainerTools/skaffold/releases/tag/v1.19.0) onwards, skaffold is collecting failure error codes to help the team get more insights into common failure scenarios. 111 112 To take advantage of this framework, contributors can simply use the [`ErrDef`](https://github.com/GoogleContainerTools/skaffold/blob/main/pkg/skaffold/errors/err_def.go#L32) struct to throw meaningful actionable error messages and 113 improve user experience. 114 115 e.g In this example [PR](https://github.com/GoogleContainerTools/skaffold/pull/5953), 116 1. The contributor created distinct error codes in [enums.proto](https://github.com/GoogleContainerTools/skaffold/commit/59edbda57ae7d2f5d0b53c075497bca480f555f5#diff-b9c28b2c93efad2841c587b3e93d2d83722c9ae26f5f9c961f87e1ca716b0e69R388) 117 ``` 118 // The Kptfile cannot be created via `kpt pkg init`. 119 RENDER_KPTFILE_INIT_ERR = 1501; 120 // The Kptfile is not a valid yaml file 121 RENDER_KPTFILE_INVALID_YAML_ERR = 1401; 122 // The Kptfile is not a valid API schema 123 RENDER_KPTFILE_INVALID_SCHEMA_ERR = 1402; 124 ``` 125 The `INIT` in this case stands for skaffold `INIT` phase which includes, parsing of skaffold config and creating a skaffold runner. 126 The other valid phases are `BUILD`, `DEPLOY`, `STATUSCHECK`. Complete list [here](https://skaffold.dev/docs/references/api/grpc/#statuscode) 127 2. Run `hack/generate-proto.sh`. These will generate go code and structs for the newly added proto fields. 128 ```shell script 129 git status 130 modified: docs/content/en/api/skaffold.swagger.json 131 modified: docs/content/en/docs/references/api/grpc.md 132 modified: proto/enums/enums.pb.go 133 modified: proto/enums/enums.proto 134 ``` 135 3. The contributor then used these error codes when creating an error in their [proposed code change](https://github.com/GoogleContainerTools/skaffold/pull/5953/files#diff-4d18270998dbca6b8378ad2e7720a797044d1357d2c5a7a61f2af56b9f2d1a5dR152). 136 They used the constructor `sErrors.NewErrorWithStatusCode` in [pkg/skaffold/errors](https://github.com/GoogleContainerTools/skaffold/blob/54466ff6983e9fcf977d6e549119b4c1c4dc9e2b/pkg/skaffold/errors/err_def.go#L65) to instantiate an object of struct `ErrDef`. 137 `ErrDef` implements the golang `error` interface. 138 ``` 139 err := sErrors.NewErrorWithStatusCode( 140 proto.ActionableErr{ 141 Message: fmt.Sprintf("unsupported validator %q", c.Name), 142 ErrCode: proto.StatusCode_CONFIG_UNKNOWN_VALIDATOR, 143 Suggestions: []*proto.Suggestion{ 144 { 145 SuggestionCode: proto.SuggestionCode_CONFIG_ALLOWLIST_VALIDATORS, 146 Action: fmt.Sprintf( 147 "please only use the following validators in skaffold-managed mode: %v. "+ 148 "to use custom validators, please use kpt-managed mode.", AllowlistedValidators), 149 }, 150 }, 151 }) 152 ``` 153 154 With above two changes, skaffold will now show a meaning full error message when this error condition is met. 155 ```shell 156 skaffold dev 157 unsupported validator "foo" please only use the following validators in skaffold-managed mode: [kubeval]. 158 To use custom validators, please use kpt-managed mode. 159 ``` 160 161 ## Building skaffold 162 163 To build with your local changes you have two options: 164 165 1. Build the skaffold binary: 166 167 ```shell 168 make 169 ./out/skaffold version 170 ``` 171 172 You can then run this binary directly, or copy/symlink it into your path. 173 174 1. Build and install the skaffold binary: 175 176 ```shell 177 make install 178 skaffold version 179 ``` 180 181 This will install skaffold via `go install` (note that if you have [manually downloaded 182 and installed skaffold to `/usr/local/bin`](README.md#install), this will probably 183 take precedence in your path over your `$GOPATH/bin`). 184 185 _If you are unsure if you are running a released or locally built version of skaffold, you 186 can run `skaffold version` - output which includes `dirty` indicates you have built the 187 binary locally._ 188 189 ## Verifying local changes 190 191 If you are iterating on skaffold and want to see your changes in action, you can: 192 193 1. [Build skaffold](#building-skaffold) 194 2. [Use the quickstart example](examples/getting-started) 195 196 ## Testing skaffold 197 198 skaffold has both [unit tests](#unit-tests) and [integration tests](#integration-tests). 199 200 ### Unit Tests 201 202 The unit tests live with the code they test and can be run with: 203 204 ```shell 205 make quicktest 206 ``` 207 208 You can also run a larger suite of tests/checks (unit tests, docs check, linters check) using: 209 210 ```shell 211 make test 212 ``` 213 214 In case you see a linter error such as: 215 216 ```shell 217 make test 218 RUN hack/linter.sh 219 ERRO Running error: no such linter "gocritic" 220 ``` 221 222 re-run the `hack/install-golint.sh` script to upgrade `golangci-lint`. 223 224 ### Integration tests 225 226 The integration tests live in [`integration`](./integration). They can be run with: 227 228 ```shell 229 make integration 230 ``` 231 232 _These tests require a Docker daemon, a Kubernetes cluster and all the tools 233 used by every Builder and Deployer, such as kubectl, bazel, java, kustomize..._ 234 235 A way to run the integration tests without installing those tools 236 and without depending on a Kubernetes cluster is to install 237 [kind](https://github.com/kubernetes-sigs/kind#installation-and-usage) 238 and run: 239 240 ```shell 241 make integration-in-kind 242 ``` 243 244 ### Running a subset of integration tests 245 246 You can select specific integration tests to run via the `INTEGRATION_TEST_ARGS` env var: 247 248 ```shell 249 INTEGRATION_TEST_ARGS="-run=TestDev/" make integration 250 ``` 251 252 ### Running GCP specific integration tests 253 254 Another set of the integration tests require a GCP project because they will 255 push to a GCR registry or use Cloud Build to build artifacts. Those tests 256 can be run with: 257 258 ```shell 259 GCP_ONLY=true make integration 260 ``` 261 262 _These tests will be kicked off by [reviewers](#reviews) for submitted PRs._ 263 264 ## Building skaffold docs 265 266 The latest version of the skaffold site is based on the Hugo theme of the github.com/google/docsy template. 267 268 ### Testing docs locally 269 270 Before [creating a PR](#creating-a-pr) with doc changes, we recommend that you locally verify the 271 generated docs with: 272 273 ```shell 274 make preview-docs 275 ``` 276 Once PRs with doc changes are merged, they will get automatically published to the docs 277 for the latest build to https://skaffold-latest.firebaseapp.com. 278 which at release time will be published with the latest release to https://skaffold.dev. 279 280 ### Previewing the docs on the PR 281 282 Mark your PR with `docs-modifications` label. Our PR review process will answer in comments in ~5 minutes with the URL of your preview and will remove the label. 283 284 ## Testing the Skaffold release image building process 285 286 Skaffold's release image build process works with Google Cloud Build within our own project `k8s-skaffold`. 287 288 In order to be able to iterate/fix the release process you can pass in your own project as a parameter to the build. 289 290 We continuously release edge images under `gcr.io/k8s-skaffold/skaffold:edge`. This is done by triggering `cloudbuild.yaml` on every push to `main`. 291 292 To run a build on your own project: 293 294 ``` 295 gcloud builds submit --config deploy/cloudbuild.yaml --substitutions=COMMIT_SHA=$(git rev-parse HEAD) --project <personal_project> 296 ``` 297 298 We build the latest stable release image under `gcr.io/k8s-skaffold/skaffold:latest`. This is done by triggering `cloudbuild-release.yaml` on every new tag in our Github repo. 299 300 To test a release on your own project: 301 302 ``` 303 gcloud builds submit --config deploy/cloudbuild-release.yaml --substitutions=TAG_NAME=<release_tag> --project <personal_project> 304 ``` 305 306 To just run a release image build without Google Cloud Build only using your local Docker daemon, you can run: 307 308 ``` 309 make -j release GCP_PROJECT=<personalproject> 310 ```