Keyboard Shortcuts

Close

Как внести свой вклад (ru)

Tags: open-source eosp


Это краткое руководство для начинающих, о том, как работать с открытым исходным кодом в рамках практик GitHub flow. Все примеры будут с платформой GitHub, но можно использовать и другие хостинги репозиториев, которые предоставляют необходимый функционал для реализации GitHub flow. Здесь вы можете найти классический способ внести свой вклад почти в любой проект. А так же узнать несколько советов и хаков.

Итак, с чего же начинается любой вклад. В идеале, с проблемы. Проблемой можно называть что угодно, в том числе нехватка каких-то новых фич, отсутствие либо неполнота страниц документации по определённому вопросу, какой-то вопрос, либо же банальные баги, которые есть везде. Лично вы проблему ни с чем не спутаете, ведь она обязательно будет сопровождать зудящим чувством, что “что-то подбешивает.” Но будет ли это проблемой для других пользователей и разработчиков? Для того, чтобы это понять и синхронизировать ваше представление с представлениями команды, и существует issue.

CONTRIBUTION.md

В каждом проекте есть свои собственные устоявшиеся правила того, как нужно в них участвовать. Эти правило описываются либо в README.md в отдельном параграфе “Contribution”, либо в специальном файле CONTRIBUTION.md. Обязательно прочитайте его в самом начале. Этот файл имеет первый приоритет. То есть даже если вы понимаете, что какие-то практики отходят от той правильной схемы, которую мы рассмотрим ниже, всё равно следуйте им. Некоторые крупные проекты, такие как Postgres или linux-kernel вообще до сих пор работает по mail-листам. Следует уважать те традиции, которые сложились в репозитории, даже если сейчас это выглядит как legacy.

# 1. Issue

Issue представляет из себя тикет, который хранится в репозитории. Создать его может любой человек, пришедший в репозиторий. Но я рекомендую вам, перед тем как бросаться описывать, вашу проблему, сделать несколько попыток по поиску подобных issue, чтобы не нагружать лишней работой мейнтейнеров репозитория. Давайте посмотрим как это можно сделать:

gh issue list --search "app crashed"

Этот и все дальнейшие примеры будут с использованием официальной утилиты gh. Она позволяет из консоли выполнять все базовые операции с GitHub. Рекомендую использовать её для простых операций, для ускорения работы.

Параметр search позволяет задавать прям в себе добавлять различные фильтры поиска. Давайте попробуем их добавить:

gh issue list --search "app crashed is:open label:bug created:>2024-01-01"

Вполне возможно, особенно в крупных проектах, что это позволит вам выйти на уже заведённый тикет по вашей проблеме и даже найти в нём решение или ответ. Если же нет, то не стесняйтесь открывать новый issue. Наилучшим образом его структурировать поможет схема:

  graph LR
    A[Excepted] ---> B("Action (run/click/etc)")
    B ---> C[Got]

В крупных проектах существуют issue templates, которые помогут вам оформить issue в соответствии с теми стандартными, которые приняты в этом проекте. Создать issue можно командой:

gh issue create

Так же отличной практикой является предоставление docker образа, в котором настроено все окружение, и проблема гарантированно воспроизводима. Либо хотя бы предоставить лог. Профессиональным подходом так же будет локализация проблемы, настолько насколько это возможно. Например, вы получили ошибку в таком файле:

import fruits
import logistic

a = fruits.Apple()
basket = fruits.MakeBasket()
basket.put(a)
logistic.send(basket)

Конечно, можно было бы так в issue и написать. Но еще лучше будет самостоятельно поэкспериментировать с этим кодом и понять, что именно не так. Например проверить удалось ли добавить яблоко в корзину:

basket.put(a)
print(basket.content())

Возможно проблема в том, что мы пытаемся отправить пустую корзину, что будет означать баг в методе put. Либо же все-таки проблема в методе send. Таким образом, мы срезаем лишнее, оставляя в сообщении issue суть проблемы.

Помните, о том, что даже факт заведения успешного issue, например, предложения ценной фичи или обнаружение реального бага или уязвимости — это уже вклад в проект, и это уже успех. А неуспехом будет создание дублирующего issue или перегрузка мейнтейнеров лишним контекстом.

# 2. Fork

Когда вы поняли какую проблемы вы решаете и убедились, что это реально проблема, можно переходить к её решению. Для этого стоит для начала сделать fork репозитория. Это будет, как ценным подспорьем для вас если вы, например, будете тестировать CI или просто сильно опережать оригинальный репозиторий, так и позволит отправлять pull request-ы, ведь вы, скорее всего, не имеете прав для внесения изменений в оригинальный репозиторий:

gh repo fork <OWNER>/<REPO>

Клонировав fork локально вносите изменения в отдельной ветке, которую будет удобнее назвать номером issue, который вы пытаетесь закрыть. Почему? Потому что в коротком лаконичном названии ветки далеко не всегда удастся выразить суть проблемы, на которую, возможно, ушло несколько месяцев обсуждения в тиките. Поэтому гораздо удобнее просто на него сослаться, через номер issue:

git switch -c 42

В GitHub flow мы не создаем сложную структуру из веток, где у каждой есть свое значение. Вместо этого у нас есть master-ветка в которую попадают только прошедшие все проверки изменения. А попадают они туда из множества, так называемых feature-веток, которые мы предлагаем тут привязывать к конкретным issue. А раз в какое-то время мы на master ветке выпускаем релиз. В итоге получается вполне лакончиная структура:

  %%{init: {
  "gitGraph": {
    "tagLabelColor": "#ffffff",
    "tagLabelBackground": "#d73a49"
  }
}}%%
gitGraph
    commit
    commit
    branch "42"
    checkout "42"
    commit
    commit
    checkout main
    merge "42"
    commit tag: "🚩 v1.1.23"

    branch "44"
    checkout "44"
    commit
    commit
    commit
    checkout main
    merge "44"
    commit tag: "🚩 v1.2.0"

Так же не забывайте синхронизировать ваш fork, чтобы не потерять связь с оригинальным проектом:

gh repo sync <your-username>/<fork-repo> --branch main

# 3. Pull request

Когда изменения внесены и закоммичены, то можно отправлять pull request. Удобнее всего просто остаться на вашей ветке и выполнить команду ниже. gh сам сформирует подходящий pull request:

gh pr create

После создания PR могут автоматически запуститься проверки, если в репозитории настроен CI. И это отлично. Потому что проверки упрощают и ускоряют процесс ревью. Вы сразу можете увидеть, что в вашем коде например не проходят проверки стилей, или, что вы не написали тесты на свой код и из-за этого упал code coverage. Не игнорируйте это, а делайте новой коммиты в той же ветки и после пуша они автоматически добавятся в PR и проверки будут перезапущены. Мейнтейнер репозитория даже не начнет ревью вашего PR, пока все проверки в нем не станут зелёными. Проверить статус pull request-а вы можете командой:

gh pr status

Так же старайтесь сделать аккуратную историю коммитов в pull request-е, чтобы упросить процесс review. В этом вам помогут squash коммиты.

Когда вы прорвались через все авто-проверки, не стесняйтесь обращаться к архитектору репозитория и просить его ревью. Он либо сам сделает ревью вашего PR, либо делегирует это кому-то из команды. На GitHub это делается просто через тег: @username. Часто уведомления о том, что пришёл новый pull request могут быть отключены, и тем более архитектор не узнает, когда вы внесете все правки, чтобы пройти CI. Поэтому скромность здесь может привести к тому, что ваш pull request просто никто не увидит. Тоже, кстати, касается и issue.

Если вы понимаете, что ваш pull request полностью закрывает тот issue, который вы решали, то в сообщениях PR можно указать Close \#49, тогда issue будет автоматически закрыт после слияния pull request-а.

# 4. Merge

Итак, когда вы прошли все авто-проверки и ручное ревью, то ваш код попадет в master-ветку репозитория и вы можете считать себя полноправным контрибьютором в этот проект. Так держать!

Обратите так же внимание на интересную практику, которая, на мой взгляд, очень профессиональна. Представим что вы обнаружили и доложили о каком-то баге в issue. Это уже вклад в репозиторий. Дальше предлагается создать pull request, в котором вы пишете тест, который воспроизводит этот баг. Тест конечно-же будет падать. Но вы присылать pull request, внося тем самым этот тест в состоянии disabled в кодовую базу. Так же можно оставить TODO метку. И это станет еще большим вкладом в репозиторий, поскольку вы добавили содержательный тест, а этом всегда очень полезно. И наконец вторым pull request-ом вы уже присылаете изменения, которые чинят код так, чтобы он проходил этот тест. И вновь увеличиваете ваш вклад. Таким образом вы оставили после себя массу артефактов в репозитории: issue, усиленная система тестов, и исправленный баг. Это будет отличным примером реализации TDD (Test Driven Development) подхода.




Таким образом мы с вами прошли полный цикл от проблемы до вклада в master-ветку:

  flowchart LR
    BUG["Find a bug / Need feature"] --> ISSUE["Create Issue"]
    ISSUE --> DISCUSS["Discussion / Planning"]
    DISCUSS --> PR["Open Pull Request"]
    PR --> CI["PR Checks with CI"]
    CI --> REVIEW["Reviewer Reviews PR"]
    REVIEW --> MERGE["Merge PR into main"]
    MERGE --> BUG

Вы можете проверить свои силы уже сейчас, найдя подходящий issue с помощью этих прекрасных сервисов:

Не забывайте, что вы и сами можете регистрировать свои проекты на этих ресурсах, чтобы привлекать к себе новых разработчиков!

GitHub CLI

Если вас заинтересовала продуктивная работа с GitHub из консоли с помощью утилиты gh, обратите внимание на её документацию. А так же на то, что gh поддерживает расширения, ознакомиться с которыми вы можете с помощью команды gh ext browse или написать своё!

Так же можно почитать по теме: