Gopls: Вклад в разработку
Вклад приветствуется! Однако разработка движется быстро, и у нас ограниченные возможности для проверки вкладов. Поэтому, прежде чем отправлять CL, пожалуйста, пожалуйста, пожалуйста:
-
создайте задачу для сообщения об ошибке или запроса функции, если такой ещё не существует. Это позволяет нам идентифицировать избыточные запросы, или объединить конкретную проблему с более общей, а также оценить важность проблемы.
-
заберите её на себя, оставив комментарий к задаче или, если это возможно, назначив её на себя. Это помогает нам избежать одновременной работы двух человек над одной проблемой.
-
предложите план реализации в трекере задач для CLs любой сложности. Гораздо эффективнее обсудить план на высоком уровне до того, как мы начнём углубляться в детали код-ревью.
При отправке CL он должен включать:
- описание CL, которое кратко описывает изменения, мотивирует необходимость внесения изменений, объясняет их на высоком уровне, противопоставляет их более очевидным или простым подходам и ссылается на соответствующие задачи;
- тесты (интеграционные тесты или маркерные тесты);
- документацию для новых или изменённых функций; и
- примечания к выпуску для новых функций или значительных изменений.
Во время код-ревью, пожалуйста, учитывайте все замечания рецензента. Некоторые замечания приводят к простым изменениям кода; другие требуют более сложного ответа. Когда рецензент задаёт вопрос, лучший ответ часто заключается не в прямом ответе на него, а в изменении кода, чтобы избежать возникновения вопроса, например, сделав код самопоясняющим. Можно не согласиться с комментарием, указать на ошибку рецензента, или предложить рассмотреть комментарий в последующем изменении, оставив TODO-комментарий в текущем CL. Но, пожалуйста, не игнорируйте или молча пропускайте комментарий без действий, так как это может привести к повторению замечаний со стороны рецензентов или к игнорированию серьёзных проблем.
Для получения дополнительной информации см. руководство по вкладу в проект Go: contribution guidelines.
Поиск задач
Все задачи gopls помечены соответствующей меткой (см. метку gopls).
Задачи, подходящие для участников, дополнительно помечены меткой
help-wanted.
Перед началом работы над задачей, пожалуйста, оставьте комментарий с указанием, что вы её_claiming_.
Начало работы
Большая часть логики gopls находится в каталоге golang.org/x/tools/gopls/internal.
См. design/implementation.md для обзора организации кода.
Сборка
Чтобы собрать версию gopls с вашими изменениями:
<code class="language-bash">cd /path/to/tools/gopls go install </code>
Чтобы убедиться, что вы тестируете корректную версию gopls, проверьте, чтобы версия
gopls выглядела следующим образом:
<code class="language-bash">$ gopls version golang.org/x/tools/gopls master golang.org/x/tools/gopls@(devel) </code>
Получение помощи
Лучший способ напрямую связаться с командой gopls — через канал #gopls-dev на Slack gophers. Пожалуйста, не стесняйтесь задавать любые вопросы о вашем вкладе или о внесении вклада в целом.
Обработка ошибок
Важно для пользовательского опыта, чтобы, когда это возможно, небольшие логические ошибки в определённой функции не приводили к сбою сервера.
Представление программы на Go является сложным. Граф импортов метаданных пакетов, синтаксические деревья разобранных файлов и связанная с ними информация о типах вместе формируют огромную поверхность API. Даже при корректном вводе существует множество граничных случаев, которые увеличиваются в разы, если учитывать отсутствующие импорты, ошибки разбора и ошибки типов.
Что следует делать, когда ваша логика должна обрабатывать ошибку, которую вы считаете «невозможной»?
-
Если возможно вернуть ошибку, то используйте функцию
bug.Errorfдля возврата ошибки пользователю, но также запишите ошибку в кэш gopls, чтобы она была менее подвержена игнорированию. -
Если безопасно продолжить выполнение, вы можете вызвать
bug.Reportfдля записи ошибки и продолжить работу как обычно. -
Если нет способа продолжить, вызовите
bug.Fatalfдля записи ошибки и затем остановите программу с помощьюlog.Fatalf. Также можно использоватьbug.Panicf, если существует шанс, что обработчик recover сможет спасти ситуацию. -
Только если локально можно доказать, что ошибка невозможна, следует вызывать
log.Fatal. Если же ошибка может возникнуть при некоторых входных данных, даже если маловероятно, тогда следует использовать один из вышеуказанных подходов. Также, если доказательство безопасности зависит от инвариантов, широко распространённых по кодовой базе, то вместо этого следует использоватьbug.Panicf.
Также следует отметить, что вызов panic предпочтительнее, чем log.Fatal, поскольку это позволяет VS Code распознавать и записывать стек вызовов при сбое.
Сообщения об ошибках, отправленные через bug.Errorf и аналогичные функции, извлекаются с помощью команды gopls bug, которая открывает шаблон задачи на GitHub и заполняет его сводкой по каждой ошибке и её частоте.
Текст ошибки выводится довольно тщательно в stdout, чтобы избежать передачи имён пользователей и строк сообщений об ошибках (которые могут содержать идентификаторы проектов) на GitHub.
Пользователям предлагается поделиться им, если они этого желают.
Тестирование
Обычной командой для запуска тестов после изменений является:
<code class="language-bash">gopls$ go test -short ./... </code>
(Флаг -short пропускает некоторые медленно выполняющиеся тесты. Trybot-сборщики
запускают полный набор тестов на широком диапазоне платформ.)
Тесты gopls представляют собой смесь двух видов.
-
Marker tests выражают каждый тестовый сценарий в отдельном текстовом файле, содержащем целевой .go, go.mod и go.work файлы, в которых специальные аннотации, встроенные в комментарии, управляют тестом. Эти тесты обычно просты в написании и быстро итерируются, но имеют ограничения по тому, что они могут выразить.
-
Интеграционные тесты являются обычными функциями Go
func Test(*testing.T), которые выполняют серию вызовов к API для имитации редактора с поддержкой LSP. API позволяет открывать и редактировать файл, переходить к определению, вызывать другие операции LSP и проверять свойства состояния.Из-за асинхронной природы LSP интеграционные тесты делают утверждения о состояниях, которые редактор должен достичь в конечном итоге, даже если программа падает сразу, может пройти некоторое время, прежде чем ошибка будет отображена как неудача в достижении требуемого состояния в течение нескольких минут. Рекомендуется установить
GOPLS_INTEGRATION_TEST_TIMEOUT=10sдля сокращения времени ожидания интеграционных тестов при отладке.При неудаче интеграционные тесты выводят журнал сеанса LSP между клиентом и сервером. Хотя он довольно подробный, он очень полезен для отладки, если вы знаете, как его читать.
Не стесняйтесь обратиться к команде gopls, если вам нужна помощь.
CI
Когда вы отправляете CL и вы или другой участник назначаете
метку Run-TryBot=1 в Gerrit,
TryBots запустят тесты в
модулях golang.org/x/tools и golang.org/x/tools/gopls, как описано выше.
Кроме того, дополнительный этап «gopls-CI» будет запускаться с помощью Kokoro, что является инфраструктурой Google, похожей на Jenkins, для запуска тестов в Docker-контейнерах. Это позволяет нам запускать тесты gopls в различных средах, которые было бы сложно добавить в TryBots. В частности, Kokoro запускает тесты на более старых версиях Go, которые больше не поддерживаются TryBots. Согласно этой политике, поддержка этих более старых версий Go осуществляется наилучшим образом, и сбои в тестах могут быть пропущены вместо того, чтобы их исправлять.
Запуски Kokoro инициируются меткой Run-TryBot=1, как и TryBots, но в отличие от TryBots они не перезапускаются автоматически, если результат «gopls-CI» будет удалён в Gerrit. Чтобы принудительно перезапустить Kokoro CI для CL, содержащего метку Run-TryBot=1, можно оставить комментарий в Gerrit со словами «kokoro rerun».
Отладка
Самый простой способ отладить изменения — это запустить один тест gopls с отладчиком.
См. также Устранение неполадок.
Документация
Каждый CL, добавляющий или изменяющий функциональность, должен включать, помимо теста, который проверяет новое поведение:
- примечание о выпуске, кратко объясняющее изменения, и
- полная документация в индексе функций.
Примечание о выпуске должно находиться в файле, названном в соответствии с предстоящим релизом, например release/v0.16.0.md. (Создайте файл, если ваша функция является первой, добавленной после релиза.)
Документация по архитектуре
Исходные файлы для этой документации можно найти в директории golang.org/x/tools/gopls/doc.