Автоматичний лінтинг коду в CI/CD: ESLint, Pylint, golangci-lint

Зауваження до стилю й типові помилки спливають уже перед випуском і гальмують роботу. Ми налаштовуємо автоматичний лінтинг у конвеєрі збирання під ключ: єдині правила, зрозумілі звіти й перевірка на кожній зміні. Аналіз коду прискорюється, а спірні правки вирішують за спільними правилами, а не в листуванні.
Часті запитання

Автоматичний лінтинг у конвеєрі: де ламається якість

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

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

Звідси й пізнє виявлення помилок: невикористовувана змінна, проковтнутий виняток, розбіжність у контракті між модулями спливають на ревью або на стенді.

Правка в цей момент іде по всьому ланцюжку — гілка, повторний прогін, повторне узгодження, — а не по одному рядку, який автор ще тримає в голові. Вартість виправлення зростає з кожним кроком, на якому його спіймали.

Ручні зауваження на ревью при цьому майже завжди про одне й те саме: форматування, іменування, порядок імпортів, забутий налагоджувальний вивід. Рев'юер розбирає стиль замість логіки, а суперечка про смаки займає місце обговорення архітектури.

Частина зауважень не доходить узагалі — правило ніде не зафіксоване, і в наступній гілці все повторюється.

Причина не в дисципліні, а в налаштуванні.

Лінтер (ESLint, Pylint або golangci-lint — за стеком проєкту) запускається по всьому дереву, на успадкованому коді висить кілька тисяч попереджень, рівень строгості виставлений у попередження замість помилки — і десяте зі сотні ніхто не помічає.

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

Що дає автоматичний лінтинг: ефект на збірку

Лінтер у конвеєрі дає ефект не сам по собі, а через те, які помилки перестають доходити до ревью та релізу. Налаштований набір правил зупиняє збірку на етапі статичного аналізу — за секунди, а не за годину в тестовому середовищі.

Рання діагностика помилок зміщує вартість виправлення: одруківка в імені змінної ловиться до того, як код покинув гілку розробника.

Час збірки при цьому не зростає: перевірки запускаються паралельно з тестами й кешують результат за хешем файлу, тому повторний прогін по незмінених модулях займає лічені секунди.

Основний виграш в іншому — падіння переноситься з етапу інтеграційних тестів на найраніший крок, і релізний конвеєр перестає простоювати на перезапусках.

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

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

Навантаження на ревью знижується тому, що рев'юер перестає бути фільтром форматування. Суперечки про довжину рядків, порядок імпортів і крапки з комою зникають з коментарів: правила задані в конфігурації на кшталт ESLint, Pylint або golangci-lint і застосовані автоматично.

Єдиний стиль коду перестає бути предметом усних домовленостей — новий інженер отримує його прямо з репозиторію.

Формати перевірки коду: локально, у збірці, на сервері

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

Нижче — за колонками «коли підходить» і «обмеження», щоб зіставити режим з розміром репозиторію та ритмом релізів.

Варіант Коли підходить Обмеження
Перевірка в редакторі щоденна робота, потрібен відгук на одруківку до збереження у кожного свої налаштування, на результат збірки не впливає
Передкомітні перевірки невеликі команди, важливо не пускати сміття в історію обходиться флагом, на великому наборі файлів помітно гальмує коміт
Шлюз якості у збірці обов'язковий поріг для всіх гілок і всіх авторів подовжує конвеєр, потребує кешу залежностей і запуску за зміненими файлами
Окремий сервер перевірок великий монорепозиторій, багато правил, потрібна історія звітів свій контур і черга завдань, звіт приходить із затримкою

Робоча зв'язка зазвичай така: передкомітні перевірки на змінених файлах плюс обов'язковий шлюз якості у збірці. Перевірка в редакторі прискорює правки, але не є порогом, а окремий сервер перевірок дає повноту по всьому дереву й графіки порушень у часі.

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

Як ми вибудовуємо перевірки: порядок робіт

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

  1. Аудит кодової бази. Рахуємо обсяг за мовами та спрацьовування за кожним правилом ESLint, Pylint і golangci-lint на актуальній гілці. На виході — перелік масових порушень і файлів, які правимо до ввімкнення суворого режиму.

  2. Набір правил. Ділимо правила на три групи: ті, що ловлять реальні дефекти — вмикаємо одразу; стильові — у міру правок; спірні — у винятки з позначкою причини. Конфігурація залишається читабельною, а не звалищем.

  3. Увімкнення суворих правил. Спершу режим звіту, потім група за групою переводимо в помилки — за каталогами й модулями, щоб не заблокувати всю команду одразу.

  4. Запуск у CI/CD. Лінтер перевіряє змінені рядки, а не весь репозиторій: збірка не подовжується, але нова невідповідність не проходить. Локальний прогін до надсилання дає ту саму перевірку за секунди.

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

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

Що команда отримує на руки після впровадження перевірок

Впровадження перевірок закінчується не «зеленою» збіркою, а набором артефактів, які команда веде далі сама.

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

  • Конфігурації правил для кожної мови з коментарями: що правило ловить, чому ввімкнене, як оформити хибне спрацьовування.
  • Спільні набори для репозиторіїв: базовий профіль як обов'язковий мінімум і підключувані модулі під сервіси, інтерфейс та інфраструктурні описи. Успадкування замість копіювання — правило змінюється в одному місці.
  • Схема запуску перевірок: хук перед комітом на змінених файлах, повний набір під час злиття гілки як блокуючий крок, нічний прогін по всьому коду — нові правила не руйнують старі файли раптово.
  • Порядок винятків: файл вимкнень з обґрунтуванням, власником і терміном перегляду в кожного запису. Тимчасове вимкнення правила відрізняється від постійного й видно у звіті.
  • Документація з якості коду: як додати або понизити правило, де дивитися звіт, що робити при червоній збірці.
  • Регламент реакції на порушення: що правиться в поточному завданні, що йде окремим пунктом, коли підключається ескалація. Правило, яке всі обходять, чесно вимикається або переводиться в попередження.
  • Набір метрик: частка перевірених шляхів, кількість вимкнень на репозиторій, час прогону — за ними видно, де набір почав заважати, а не допомагати.

Через місяць підтримки такий комплект дозволяє змінювати правила без нас, а розбір порушень стає частиною звичайного ревью.

Кейс: єдиний шлюз якості в монорепозиторії

Монорепозиторій на кілька десятків пакетів: частина правил лежала в локальних конфігураціях, частина — в окремих репозиторіях, підключених як залежності. Набори розходилися — ESLint, Pylint і golangci-lint запускалися з різними рівнями строгості. Той самий фрагмент проходив перевірку в одному пакеті й валив збірку в сусідньому.

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

Як влаштували єдиний шлюз

Усі правила переїхали до спільного пакета конфігурацій, який підключається в кожному пакеті й оновлюється централізовано. У CI з'явилася одна точка входу: спочатку швидкі перевірки змінених файлів, потім прогін заторкнутими пакетами, окремо — блокуючі та інформаційні рівні. Зміни правил проходять ревью як звичайний код.

Результат: відмови з причин, які ловляться статикою, скоротилися приблизно втричі, а розбіжності між командами зникли з регулярної роботи. Час перевірки гілки тримається в межах кількох хвилин завдяки прогону лише змінених пакетів. Новий пакет підключає шлюз одним рядком і одразу отримує актуальний набір правил.

Чим перевірка у збірці відрізняється від перевірки в редакторі

Локальна перевірка в редакторі відповідає на питання «чи не помилився я прямо зараз»: лінтер спрацьовує на збереженні файлу, підсвічує проблему за частки секунди й дає ту швидкість зворотного зв'язку, заради якої його ставлять.

Але гарантій вона не дає — розширення може бути вимкнене, набір правил відрізнятися від командного, а частина файлів у цій сесії взагалі не відкривалася.

Обов'язковий шлюз у збірці — єдине місце, де правило стає обов'язковим. Перевірка йде на тому самому коміті, який вирушає в основну гілку, і при порушенні злиття блокується. Тут же розбирається проєкт цілком, включно з кодом, який ніхто не чіпав руками.

Розподіл зон відповідальності звідси простий: локально — швидкий відгук за зміненими файлами, у конвеєрі — повний набір правил і остаточне рішення. Швидкість зворотного зв'язку забезпечує редактор, а не збірка, тому дорогі перевірки не потрібно тягнути в локальний цикл.

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

Тому набір підключається з одного файлу, який читають і ESLint-подібні інструменти, і крок збірки: локально — попередження, у шлюзі — помилка.

Технічні сумніви: питання про правила й підтримку

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

У проєкті багато успадкованого коду — невже доведеться лагодити все одразу?

Ні. Перший прогін іде в режимі попереджень: збірка не падає, звіт лише показує поточну кількість порушень за кожним правилом. Блокування вмикаємо тільки для нових і змінених рядків — правка старого файлу попутно чистить зауваження в заторкнутому фрагменті.

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

Чи не сповільнить автоматичний лінтинг збірку?

Перевірки йдуть паралельно з тестами та збіркою артефактів, тому до загального часу додаються секунди, а не хвилини.

Основна затримка — повторний розбір дерева залежностей, її знімає кеш між запусками: після прогріву лінтер коштує приблизно стільки ж, скільки встановлення залежностей. Для великих змін перевіряємо тільки заторкнуті файли, повний обхід залишаємо нічному прогону.

Хто підтримає набір правил після передачі проєкту?

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

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

Обговоримо задачу: що потрібно знати перед стартом

Оцінка виходить точною, коли ми бачимо проєкт, а не його опис у двох рядках. Перша розмова займає 30–40 хвилин і йде по суті: розбираємо репозиторії, поточні перевірки та те, що заважає їм працювати. Нижче — ввідні, після яких ми повертаємося з оцінкою та планом робіт.

  • репозиторії: скільки їх, якими мовами написаний код, чи є спільні бібліотеки зі своїми правилами;
  • поточні перевірки: які лінтери вже підключені, якими наборами правил, що і як часто ламається;
  • збірка: де йде конвеєр, на якому етапі запускаються перевірки, скільки займає повний прогін;
  • політика якості: що блокує злиття, що залишається попередженням і кому йдуть повідомлення;
  • доступи: права на репозиторії, агенти збірки, можливість прогоняти перевірки на кожному запиті на злиття;
  • болі: які помилки спливають найпізніше і на яких ділянках частіше відкочують зміни;
  • з вашого боку: хто ухвалює рішення щодо правил і хто залишається на зв'язку з інфраструктури.

Склад команди називаємо одразу: інженер зі збірки та перевірок, інженер з інфраструктури, плюс той, хто веде документацію та передачу правил вашій команді.

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

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1141