| # Gopls: Documentation for contributors |
| |
| This documentation augments the general documentation for contributing to the |
| x/tools repository, described at the [repository root](../../CONTRIBUTING.md). |
| |
| Contributions are welcome, but since development is so active, we request that |
| you file an issue and claim it before starting to work on something. Otherwise, |
| it is likely that we might already be working on a fix for your issue. |
| |
| ## Finding issues |
| |
| All `gopls` issues are labeled as such (see the [`gopls` label][issue-gopls]). |
| Issues that are suitable for contributors are additionally tagged with the |
| [`help-wanted` label][issue-wanted]. |
| |
| Before you begin working on an issue, please leave a comment that you are |
| claiming it. |
| |
| ## Getting started |
| |
| Most of the `gopls` logic is in the `golang.org/x/tools/gopls/internal` |
| directory. See [design/implementation.md] for an overview of the code organization. |
| |
| ## Build |
| |
| To build a version of `gopls` with your changes applied: |
| |
| ```bash |
| cd /path/to/tools/gopls |
| go install |
| ``` |
| |
| To confirm that you are testing with the correct `gopls` version, check that |
| your `gopls` version looks like this: |
| |
| ```bash |
| $ gopls version |
| golang.org/x/tools/gopls master |
| golang.org/x/tools/gopls@(devel) |
| ``` |
| |
| ## Getting help |
| |
| The best way to contact the gopls team directly is via the |
| [#gopls-dev](https://app.slack.com/client/T029RQSE6/CRWSN9NCD) channel on the |
| gophers slack. Please feel free to ask any questions about your contribution or |
| about contributing in general. |
| |
| |
| ## Error handling |
| |
| It is important for the user experience that, whenever practical, |
| minor logic errors in a particular feature don't cause the server to |
| crash. |
| |
| The representation of a Go program is complex. The import graph of |
| package metadata, the syntax trees of parsed files, and their |
| associated type information together form a huge API surface area. |
| Even when the input is valid, there are many edge cases to consider, |
| and this grows by an order of magnitude when you consider missing |
| imports, parse errors, and type errors. |
| |
| What should you do when your logic must handle an error that you |
| believe "can't happen"? |
| |
| - If it's possible to return an error, then use the `bug.Errorf` |
| function to return an error to the user, but also record the bug in |
| gopls' cache so that it is less likely to be ignored. |
| |
| - If it's safe to proceed, you can call `bug.Reportf` to record the |
| error and continue as normal. |
| |
| - If there's no way to proceed, call `bug.Fatalf` to record the error |
| and then stop the program with `log.Fatalf`. You can also use |
| `bug.Panicf` if there's a chance that a recover handler might save |
| the situation. |
| |
| - Only if you can prove locally that an error is impossible should you |
| call `log.Fatal`. If the error may happen for some input, however |
| unlikely, then you should use one of the approaches above. Also, if |
| the proof of safety depends on invariants broadly distributed across |
| the code base, then you should instead use `bug.Panicf`. |
| |
| Note also that panicking is preferable to `log.Fatal` because it |
| allows VS Code's crash reporting to recognize and capture the stack. |
| |
| Bugs reported through `bug.Errorf` and friends are retrieved using the |
| `gopls bug` command, which opens a GitHub Issue template and populates |
| it with a summary of each bug and its frequency. |
| The text of the bug is rather fastidiously printed to stdout to avoid |
| sharing user names and error message strings (which could contain |
| project identifiers) with GitHub. |
| Users are invited to share it if they are willing. |
| |
| ## Testing |
| |
| The normal command you should use to run the tests after a change is: |
| |
| ```bash |
| gopls$ go test -short ./... |
| ``` |
| |
| (The `-short` flag skips some slow-running ones. The trybot builders |
| run the complete set, on a wide range of platforms.) |
| |
| Gopls tests are a mix of two kinds. |
| |
| - [Marker tests](../internal/test/marker) express each test scenario |
| in a standalone text file that contains the target .go, go.mod, and |
| go.work files, in which special annotations embedded in comments |
| drive the test. These tests are generally easy to write and fast |
| to iterate, but have limitations on what they can express. |
| |
| - [Integration tests](../internal/test/integration) are regular Go |
| `func Test(*testing.T)` functions that make a series of calls to an |
| API for a fake LSP-enabled client editor. The API allows you to open |
| and edit a file, navigate to a definition, invoke other LSP |
| operations, and assert properties about the state. |
| |
| Due to the asynchronous nature of the LSP, integration tests make |
| assertions about states that the editor must achieve eventually, |
| even when the program goes wrong quickly, it may take a while before |
| the error is reported as a failure to achieve the desired state |
| within several minutes. We recommend that you set |
| `GOPLS_INTEGRATION_TEST_TIMEOUT=10s` to reduce the timeout for |
| integration tests when debugging. |
| |
| When they fail, the integration tests print the log of the LSP |
| session between client and server. Though verbose, they are very |
| helpful for debugging once you know how to read them. |
| |
| Don't hesitate to [reach out](#getting-help) to the gopls team if you |
| need help. |
| |
| ### CI |
| |
| When you mail your CL and you or a fellow contributor assigns the |
| `Run-TryBot=1` label in Gerrit, the |
| [TryBots](https://golang.org/doc/contribute.html#trybots) will run tests in |
| both the `golang.org/x/tools` and `golang.org/x/tools/gopls` modules, as |
| described above. |
| |
| Furthermore, an additional "gopls-CI" pass will be run by _Kokoro_, which is a |
| Jenkins-like Google infrastructure for running Dockerized tests. This allows us |
| to run gopls tests in various environments that would be difficult to add to |
| the TryBots. Notably, Kokoro runs tests on |
| [older Go versions](../README.md#supported-go-versions) that are no longer supported |
| by the TryBots. Per that that policy, support for these older Go versions is |
| best-effort, and test failures may be skipped rather than fixed. |
| |
| Kokoro runs are triggered by the `Run-TryBot=1` label, just like TryBots, but |
| unlike TryBots they do not automatically re-run if the "gopls-CI" result is |
| removed in Gerrit. To force a re-run of the Kokoro CI on a CL containing the |
| `Run-TryBot=1` label, you can reply in Gerrit with the comment "kokoro rerun". |
| |
| ## Debugging |
| |
| The easiest way to debug your change is to run a single `gopls` test with a |
| debugger. |
| |
| See also [Troubleshooting](troubleshooting.md#troubleshooting). |
| |
| <!--TODO(rstambler): Add more details about the debug server and viewing |
| telemetry.--> |
| |
| [issue-gopls]: https://github.com/golang/go/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Agopls "gopls issues" |
| [issue-wanted]: https://github.com/golang/go/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Agopls+label%3A"help+wanted" "help wanted" |
| |
| ## Documentation |
| |
| Each CL that adds or changes a feature should include, in addition to |
| a test that exercises the new behavior: |
| |
| - a **release note** that briefly explains the change, and |
| - **comprehensive documentation** in the [index of features](features/README.md). |
| |
| The release note should go in the file named for the forthcoming |
| release, for example [release/v0.16.0.md](release/v0.16.0.md). (Create |
| the file if your feature is the first to be added after a release.) |
| |
| |