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  ```