Вітаю, колеги! Мене звати Назарій Мошенський. Я Senior Software Engineer у компанії Grid Dynamics. За більш ніж 5 років у цій сфері я працював на проєктах різного розміру і складності, проте найбільше мене захоплювали задачі з автоматизації процесів. Ця стаття буде цікавою для розробників, які хочуть покращити швидкість написання коду, його якість, а також формалізувати процеси і стандарти.

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

Більшість з цих речей можна автоматизувати, і далі ми поговоримо, як це зробити. Сенс статті — показати не набір команд, які можуть автоматизувати будь-який проект, а набір інструментів, які ви можете налаштувати під свої потреби.

Як має виглядати pull request

На мою думку, ідеальний пул-реквест має невеликий набір характеристик:

  1. Невеликий розмір

    Погодьтесь, що перевіряти дуже великі пул-реквести досить важко. Особливо, коли ви не до кінця володієте контекстом задачі. Зі збільшенням кількості змін в пул-реквесті зберігати фокус і тримати все в голові стає все важче. Тобто розмір пул-реквеста треба якось обмежити.

  2. Статичний аналізатор коду не видає помилок

    Ніхто не хоче перевіряти мінорні помилки чи помилки, які легко можна проаналізувати готовими інструментами. В Android ми можемо писати власні правила перевірки коду і використовувати вже готові, налаштовувати стиль написання коду і перевіряти, як він підтримується тощо. Тому треба якось вивести ці помилки в пул-реквесті. Якщо ми бачимо нові помилки, то перевіряти його поки немає сенсу.

  3. Видно контекст задачі

    Ми хочемо бачити, над яким тікетом проводилась робота і що саме було зроблено. Для цього було б зручно, якби ми могли фейлити пайплайн, якщо PR не має опису, в заголовку додавати номер тікета і його тайтл. В ідеалі ще додати скріншоти, щоб було наочно видно зміни.

  4. “Зелені” тести

    Ми покриваємо код тестами і якщо зміни в коді “ламають” тести, то, очевидно, що такий PR поки не готовий до рев’ю, бо всі тести мають успішно проходити. Тому було б зручно унеможливити мердж такого коду.

  5. Зрозумілі меседжі комітів

    Коли ми знайомимось з пул-реквестом, то дуже легко відстежити послідовність дій автора, коли він створює атомарні коміти, додаючи до них зрозумілі меседжі. В ідеалі треба нав’язати стиль написання таких меседжів.

  6. Автоматичне визначення рев’юерів

    Якщо у вас великий проєкт, на якому працює декілька команд, то було б зручно ділити код на зони відповідальності. Якщо ви робите зміни в репозиторії сусідньої команди, то було б зручно, якби неможливо було змерджити їх без апрува цієї команди.

  7. Pull request template (checklist)

    Перед тим, як передавати пул-реквест на перевірку, автор повинен переконатись, що він нічого не забув і виконав всі необхідні підготовчі дії. Для цього зручно мати список з чекбоксами, де автор повинен відмітити дії, які він виконав. Тоді рев’юер буде бачити, що пул-реквест дійсно готовий до перевірки.

Для всього цього є багато інструментів, які спростять нам життя і автоматизують це все.

Danger

Для автоматизації рутинних задач в процесі СІ ми використовуємо Danger. Він досить легко налаштовується і має багато плагінів, які вміють працювати з популярними інструментами. Також ви можете писати власні за потреби. Ось, наприклад, набір готових плагінів для ознайомлення — https://danger.systems/ruby/


Danger можна інтегрувати, наприклад, в GitHub Actions і видавати результати його роботи в pull request за допомогою бота.

Взагалі Danger — це інструмент, який заслуговує окремої серії статей. Ми розберемо базові можливості для розуміння, що можна з ним робити. Для детальнішого розбору можливостей раджу зазирнути на офіційний сайт — https://danger.systems/reference.html або безпосередньо в документацію до плагінів, які ви для нього обрали. 

Наприклад, вирішимо декілька проблем, які ми описували вище:

  1. Порожній description пул-реквеста

  2. Занадто великий пул-реквест

  3. Тести “падають”

  4. Lint warnings не видно

Ми використовуємо danger/ruby. Два основних файли, які нам потрібні,—- це Gemfile і Dangerfile.

В Gemfile ви додаєте danger плагіни, які ви плануєте використовувати, наприклад, danger-junit, danger-android_lint тощо.

Виглядати він буде приблизно таким чином:

source 'https://rubygems.org'
gem 'danger'
gem 'danger-junit'
gem 'danger-android_lint'
gem 'danger-checkstyle_format'

В Dangerfile ви пишете скрипт за допомогою Ruby DSL, використовуючи Danger плагіни, які ви вказали в Gemfile.

Ось так в декілька рядків в Dangerfile ми можемо перевірити чи пул реквест не занадто великий і чи є в нього опис.

warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]"

# Warn when there is a big PR
warn("Big PR") if git.lines_of_code > 500

if github.pr_body.length < 5
  fail "Please provide a summary in the Pull Request description"
end

Щоб перевірити результати тестів, я встановлюю Danger-плагін JUnit. Він парсить звіти виконання юніт-тестів. Ви можете їх відформатувати, як вам зручно і вивести в ваш pull request.

У моєму проєкті декілька модулів, тому я створюю патерн обходу директорій і використовую методи parse & report:

###########################################
#                  JUnit                  #
###########################################

junit_tests_dir = "**/build/test-results/**/*.xml"
Dir[junit_tests_dir].each do |file_name|
  junit.parse file_name
  junit.report
end

Насправді це найбазовіший конфіг. Власне, сам плагін здатний на значно більше. 

Також ми можемо налаштувати Android Lint, який проаналізує код і виведе результати.

Так буде виглядати результат:

Це знову ж таки зроблено з мінімальними конфігураціями і без нічого особливого:

###########################################
#                   LINT                  #
###########################################

lint_dir = "**/build/reports/*.xml"
Dir[lint_dir].each do |file_name|
  android_lint.skip_gradle_task = true
  android_lint.filtering = false
  android_lint.report_file = file_name
  android_lint.lint
end

Ідея така ж — запускаємо Lint, він кладе результати своїх спостережень в папку, яку ми потім парсимо та відображаємо результати за допомогою Danger.

Ми можемо легко інтегрувати Danger з GitHub Actions, створивши подібний workflow:

name: Test,Verify,Report

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the main branch
  pull_request:
    types: [synchronize, opened, reopened, labeled, unlabeled, edited]

jobs:
  danger:
    runs-on: ubuntu-latest
    if: github.event_name  == 'pull_request' 
    steps:
    - uses: actions/checkout@v2
    - name: Set up Java SDK
      uses: actions/setup-java@v1
      with: {java-version: 1.8}
    - uses: ruby/setup-ruby@v1
      with:
        ruby-version: '3.0'
    - uses: actions/cache@v1
      with:
        path: vendor/bundle
        key: ${{ runner.os }}-gems-${{ hashFiles('Gemfile.lock') }} # change your gemfile path
        restore-keys: |
          ${{ runner.os }}-gems-
    - name: Run unit tests
      run: ./gradlew test
    - name: Run linter
      run: ./gradlew runChecksForDanger
    - name: danger
      env:
        DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
          bundle install
          bundle exec danger

Перед запуском Danger я запускаю команди ./gradlew test та ./gradlew runChecksForDanger. Перша генерує звіти юніт-тестів, а друга звіти лінтера. Вони будуть потрібні для того, щоб Danger їх розпарсив і вивів результати на екран.

Також потрібно додати токен, щоб бот міг виводити результати роботи Danger в ваш PR.

Commit messages

Для того, щоб коміт меседжі легко читались і було зрозуміло, що там було зроблено, пропоную розглянути ідею Conventional Commits.

Це ідеологія, яка формалізує структуру коміт меседжів. Детальніше про неї можна прочитати тут — https://www.conventionalcommits.org/en/v1.0.0/#summary

Її сенс полягає в тому, щоб у кожному коміті було вказано тип коміта, скоуп, до якого він відноситься, короткий опис. Також для читабельності визначені і вимоги до форматування таких меседжів.

Якщо ви, як і я, користуєтесь IntelliJ IDEA чи Android Studio, то хороша новина в тому, що є готовий плагін, який буде підсвічувати вам помилки в структурі та форматуванні коміт меседжів.

Conventional Commits Plugin
Приклад роботи плагіна

Також у нього є зручний Wizard, в якому ви просто вводите значення в поля вводу і він форматує код за вас.

Conventional Commits Wizards

Branch protection rules

Це дуже важлива частина PR, де ви можете налаштувати правила для різних гілок у вашому git репозиторії. А особливо нас будуть цікавити налаштування, які стосуються пул реквестів.

Code Owners

Якщо у вас досить великий проєкт і над ним одночасно працюють декілька команд, то скоріш за все кожна з них має свою зону відповідальності. Тому для того, щоб рев’ю обов’язково робили люди, які відповідають за компонент, в який ви вносите зміни, пропоную налаштувати Code Owners.

Це файл, в якому прописані користувачі чи групи користувачів, які відповідають за окремі частини системи. Також в branch protection rules ви можете встановити обов’язкову перевірку коду Code Owner’ами:


Ми можемо встановити, наприклад, 2 обов’язкових апрува і поставити галочку навпроти Require review from Code Owners. 

Pull request template (checklist)

Перед тим, як дивитись PR, було б зручно, щоб його автор спочатку перевірив сам себе. Для цього потрібно скласти список підготовчих дій, які повинен виконати кожен, хто створює пул реквест. В гуглі можна знайти безліч прикладів таких чеклістів. Вам треба обрати, що саме важливо для вас і вашого проєкту і внести це в список. Ось, наприклад, список з мого демо-проєкту: 

Шаблон такого чекліста пишеться за допомогою Markdown. Ось приклад мого:

## Checklist:

### Code quality
- [ ] My code follows the style guidelines of this project
- [ ] My changes generate no new warnings
- [ ] I have commented my code, particularly in hard-to-understand areas

### Testing
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] I have performed a self-review of my own code

### Merge conflicts
- [ ] Any dependent changes have been merged and published in downstream modules

Ви можете встановити додаток з маркетплейсу, який буде перевіряти, чи всі галочки проставлені, і відображати статус заповнення чекліста. У разі невиконання всіх умов змінить її колір з зеленого на сірий:

Як тільки всі умови з чекліста будуть виконані кнопка стане зеленою:

Насправді це не обов’язково повинен бути чеклист. Часто використовують шаблони формату “питання-відповідь” або змішаного:

Ось такі невеличкі поради щодо автоматизації перевірки pull requests. Надіюсь, вам було корисно. Буду радий прочитати в коментарях, що ви використовуєте на своїх проєктах, що працює для вас, а що ні.

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Назар Мошенський
Назар Мошенський@moshenskyi_n

58Прочитань
0Автори
5Читачі
Підтримати
На Друкарні з 15 квітня

Вам також сподобається

  • Шпаргалка по Kotlin ч. 1 Колекції

    Колеції та їх функції, які мало хто використовує, але можуть бути дуже корисними в написанні коду.

    Теми цього довгочиту:

    Kotlin
  • Restore Your Car’s Shine with Expert Dent Repair in Abu Dhabi

    Service My Car offers Paintless Dent Repair (PDR) and traditional dent repair to fix dents efficiently. Enjoy affordable pricing, skilled technicians, and doorstep service. Book now for a flawless finish!

    Публікація містить описи/фото насилля, еротики або іншого чутливого контенту.

    Теми цього довгочиту:

    Automation
  • Навчити — найкраще що я можу зробити як керівник

    Як керівник компанії я проходив декілька етапів розвитку щодо відношення до навчання співробітників: від "ви повинні самі" до розробки власних курсів та регулярних семінарів для співробітників.

    Теми цього довгочиту:

    Навчання

Коментарі (4)

Pull request template (checklist)

уявляю як ця штука дістане розробників за тиждень-два, особливо коли спрінт складається з маленьких багів

Вам також сподобається

  • Шпаргалка по Kotlin ч. 1 Колекції

    Колеції та їх функції, які мало хто використовує, але можуть бути дуже корисними в написанні коду.

    Теми цього довгочиту:

    Kotlin
  • Restore Your Car’s Shine with Expert Dent Repair in Abu Dhabi

    Service My Car offers Paintless Dent Repair (PDR) and traditional dent repair to fix dents efficiently. Enjoy affordable pricing, skilled technicians, and doorstep service. Book now for a flawless finish!

    Публікація містить описи/фото насилля, еротики або іншого чутливого контенту.

    Теми цього довгочиту:

    Automation
  • Навчити — найкраще що я можу зробити як керівник

    Як керівник компанії я проходив декілька етапів розвитку щодо відношення до навчання співробітників: від "ви повинні самі" до розробки власних курсів та регулярних семінарів для співробітників.

    Теми цього довгочиту:

    Навчання