Налаштування безперервної інтеграції (CI) для треку дуже важливе, адже це допомагає виявляти помилки.
Репозиторії Exercism (зокрема репозиторії треків) використовують GitHub Actions для запуску свого CI. GitHub Actions ґрунтується на робочих процесах, які визначають скрипти для автоматичного запуску щоразу, коли відбувається певна подія (наприклад, надсилання коміту). Докладніше про робочі процеси GitHub Actions можна дізнатися з документації про робочі процеси.
Треки постачаються з кількома попередньо встановленими робочими процесами, більшість з яких не варто змінювати (їх називають спільними робочими процесами).
Але є один робочий процес, який варто змінити, а саме робочий процес test.yml.
Мета робочого процесу test.yml - перевірити, що вправи треку перебувають у належному стані.
Робочий процес налаштований на автоматичний запуск (термінологія GitHub Actions: запускається) під час надсилання змін до гілки main або до гілки пул-реквесту.
Сам робочий процес не повинен робити багато чого, крім:
Як уже згадувалося, вправи перевіряються за допомогою скрипта, а саме скрипта bin/verify-exercises (bash).
Цей скрипт майже готовий і робить таке:
unskip_tests, у якій можна зняти пропуски з тестів у тестових файлах (необовʼязково)run_tests, у якій потрібно запустити тести (обовʼязково)Функції run_tests й unskip_tests - це єдине, що потрібно реалізувати.
Якщо трек підтримує пропуск тестів, ми маємо переконатися, що під час перевірки зразкового рішення вправи жоден тест не пропускається. Загалом є два способи, якими треки підтримують «зняття пропусків» з тестів:
test.skip на test.SKIP_TESTS=false.Якщо пропуск тестів ґрунтується на файлах (перший варіант, згаданий вище), відредагуйте функцію unskip_tests, щоб змінити тестові файли (наявний код уже виконує прохід циклом по тестових файлах).
Функція unskip_test працює з копією каталогу вправи, тож сміливо змінюйте файли на свій розсуд.
bin/verify-exercises file треку Arturo використовує sed, щоб зняти пропуски з тестів у тестових файлах:
unskip_tests() {
jq -r '.files.test[]' .meta/config.json | while read -r test_file; do
sed -i 's/test.skip/test/g' "${test_file}"
done
}
Якщо для зняття пропусків з тестів потрібно встановити змінну середовища, переконайтеся, що її встановлено у функції run_tests.
Функція run_tests відповідає за запуск тестів вправи.
Коли функцію викликають, зразкові файли вже скопійовано у файли рішення (заготовки), тож потрібно лише викликати правильну команду для запуску тестів.
Функція повинна повернути нуль як код виходу, якщо всі тести проходять, або ненульовий код виходу в іншому разі.
Функція run_tests працює з копією каталогу вправи, тож сміливо змінюйте файли на свій розсуд.
Типовий варіант для скрипта перевірки вправ - використовувати інструментарій мови (SDK/бінарний файл/тощо), і саме так робить більшість треків. Кожен трек матиме власний спосіб запуску тестів, але зазвичай це лише одна команда.
bin/verify-exercises file треку Arturo змінює функцію run_tests, щоб просто викликати команду arturo для тестового файлу:
run_tests() {
arturo tester.art
}
Другий варіант - перевіряти вправи, запускаючи тест-раннер треку. Це, звісно, залежить від того, чи має трек робочий тест-раннер.
Якщо у треку ще немає тест-раннера, можна або:
До типового скрипта bin/verify-exercises потрібно внести такі зміни:
docker доступнаdocker run, щоб запустити Docker-образ тест-раннера для кожної вправиjq, щоб перевірити, що файл results.json, який повертає Docker-контейнер, указує на те, що всі тести пройденоunskip_test і виклик цієї функціїГоловна перевага цього підходу в тому, що він найкраще відтворює те, як тести запускаються в продакшені (на сайті). За такого підходу менш імовірно, що в продакшені не спрацює те, що пройшло в CI. Недолік цього підходу в тому, що він зазвичай повільніший через потребу завантажувати Docker-образ і через накладні витрати Docker.
bin/verify-exercises file треку Unison додає перевірку того, що команда docker також встановлена:
required_tool docker
Потім він завантажує образ тест-раннера треку:
docker pull exercism/unison-test-runner
Далі він змінює функцію run_tests, щоб використати docker run для запуску тест-раннера поточної вправи (яка перебуває в робочому каталозі), а потім команду jq для перевірки належного статусу:
run_tests() {
local slug
slug="${1}"
docker run \
--rm \
--network none \
--mount type=bind,src="${PWD}",dst=/solution \
--mount type=bind,src="${PWD}",dst=/output \
--tmpfs /tmp:rw \
exercism/unison-test-runner "${slug}" "/solution" "/output"
jq -e '.status == "pass"' "${PWD}/results.json" >/dev/null 2>&1
}
Нарешті, потрібно змінити виклик функції run_tests, бо тепер вона потребує слага:
run_tests "${slug}"
Тепер, коли скрипт verify-exercises готовий, час завершити робочий процес test.yml.
Те, як це зробити, залежить від того, який варіант реалізації скрипта verify-exercises обрано.
Якщо скрипт verify-exercises безпосередньо використовує інструментарій мови, робочому процесу тестування потрібно буде встановити:
Щойно це буде зроблено, verify-exercises працюватиме як слід, і безперервну інтеграцію успішно налаштовано!
Наприклад, дивіться робочий процес test.yml треку Arturo:
name: Test
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
ci:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install libgtk-3-dev libwebkit2gtk-4.0-dev libmpfr-dev
- name: Install Arturo
run: bin/install-arturo
env:
GH_TOKEN: ${{ github.token }}
- name: Verify all exercises
run: bin/verify-exercises
Другий варіант - перевіряти вправи, запускаючи тест-раннер треку. Цей варіант вимагає виконання двох умов:
verify-exercises використовує Docker-образ тест-раннера для запуску тестів вправиЯкщо у треку ще немає тест-раннера, можна або:
Цей підхід має кілька переваг:
Головний недолік у тому, що він, імовірно, повільніший через потребу завантажувати Docker-образ і через накладні витрати Docker.
Є кілька способів завантажити Docker-образ тест-раннера:
verify-exercises.
Цей підхід використовує трек Unison.То який підхід обрати?
Ми радимо принаймні реалізувати варіант номер 1, щоб скрипт verify-exercises став самодостатнім.
Якщо образ особливо великий, може бути корисно також реалізувати варіант 3, який збереже зібраний Docker-образ у кеші GitHub Actions.
Наступні запуски зможуть просто читати Docker-образ із кешу замість завантаження, що може бути краще для продуктивності (будь ласка, виміряйте, щоб переконатися).
Третій, альтернативний варіант - це гібрид двох попередніх варіантів.
Тут ми також використовуємо Docker-образ тест-раннера, але цього разу запускаємо скрипт verify-exercises усередині цього Docker-образу.
Щоб увімкнути цей варіант, потрібно встановити контейнер робочого процесу як тест-раннер:
container:
image: exercism/vimscript-test-runner
Тоді ми можемо пропустити кроки встановлення залежностей та інструментарію (їх буде встановлено всередині Docker-образу тест-раннера) і перейти до запуску скрипта bin/verify-exercises.
Робочий процес test.yml треку vimscript використовує цей варіант:
name: Verify Exercises
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
jobs:
ci:
runs-on: ubuntu-24.04
container:
image: exercism/vimscript-test-runner
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Verify all exercises
run: bin/verify-exercises