Проблема
Займаючись розробкою пакету, який використовується клієнтами на різних версіях продукту та PHP, зіткнувся з проблемою лімітів GitHub API під час функціонального тестування.
Для тестування змін у пул-реквестах використовується Jenkins з великою матрицею тестів. Кількість тестів, різні версії продукту плюс різні версії PHP - отримуємо дійсно велику матрицю функціональних тестів.
Після чергового додавання нової версії продукту в матрицю, тести почали падати у випадковому порядку з помилкою “Could not authenticate against github.com”.
Чому так відбувається?
Річ у тому, що я тягну пакет і деякі його залежності з GitHub.
Jenkins на одному з етапів генерує такий composer.json
, підставляючи потрібну версію продукту та PHP:
{
"name": "vendor/tested-package",
"description": "The example",
"version": "1.2.3",
"repositories": {
"tested-package-repo": {
"type": "vcs",
"url": "https://github.com/vendor/tested-package.git"
},
"dependency-1": {
"type": "vcs",
"url": "https://github.com/vendor/dependency-1.git"
},
"dependency-2": {
"type": "vcs",
"url": "https://github.com/vendor/dependency-2.git"
},
"dependency-3": {
"type": "vcs",
"url": "https://github.com/vendor/dependency-3.git"
},
"composer-repo.vendor.org": {
"type": "composer",
"url": "composer-repo.vendor.org"
}
},
"require": {
"php": "7.2",
"vendor/product": "1.10.22",
"vendor/tested-package": "dev-develop as 1.2.3",
"vendor/dependency-1": "dev-develop as 2.0.1",
"vendor/dependency-2": "dev-develop as 2.0.2",
"vendor/dependency-3": "dev-develop as 2.0.3"
}
}
На наступному етапі Jenkins виконує composer update
, а потім запускає функціональний тест.
Composer для отримання інформації з репозиторіїв використовує GitHub API. Мій ліміт запитів до API становить 5000 за годину. Але, враховуючи кількість тестів, версій продукту та PHP, я почав вилазити за рамки цього ліміту.
Як перевірити GitHub API ліміти?
Щоб перевірити, скільки у тебе залишилося запитів до GitHub API, можна виконати наступну команду в терміналі:
curl -H "Accept: application/vnd.github+json" -H "Authorization: token <your-token>" https://api.github.com/rate_limit
<your-token>
потрібно замінити на твій GitHub токен, який ти використовуєш у auth.json
Приклад відповіді від GitHub:
{
"resources": {
"core": {
"limit": 5000,
"used": 5001,
"remaining": 0,
"reset": 1662134609
},
"search": {
"limit": 30,
"used": 0,
"remaining": 30,
"reset": 1662133328
},
"graphql": {
"limit": 5000,
"used": 0,
"remaining": 5000,
"reset": 1662136868
},
"integration_manifest": {
"limit": 5000,
"used": 0,
"remaining": 5000,
"reset": 1662136868
},
"source_import": {
"limit": 100,
"used": 0,
"remaining": 100,
"reset": 1662133328
},
"code_scanning_upload": {
"limit": 1000,
"used": 0,
"remaining": 1000,
"reset": 1662136868
},
"actions_runner_registration": {
"limit": 10000,
"used": 0,
"remaining": 10000,
"reset": 1662136868
},
"scim": {
"limit": 15000,
"used": 0,
"remaining": 15000,
"reset": 1662136868
},
"dependency_snapshots": {
"limit": 100,
"used": 0,
"remaining": 100,
"reset": 1662133328
}
},
"rate": {
"limit": 5000,
"used": 5001,
"remaining": 0,
"reset": 1662134609
}
}
Нас цікавить ось ця частина:
...
"rate": {
"limit": 5000,
"used": 5001,
"remaining": 0,
"reset": 1662134609
}
...
limit
- скільки всього дається запитів на годинуused
- скільки використано запитівremaining
- скільки залишилося запитівreset
- час, коли відбудеться скидання
У цьому прикладі можна побачити, що ліміт вичерпано.
Вирішення проблеми з GitHub API
Використання no-api
Один з варіантів - додавання опції no-api
до кожного composer.json
репозиторію на GitHub
{
"name": "vendor/tested-package",
"description": "The example",
"version": "1.2.3",
"repositories": {
"tested-package-repo": {
"type": "vcs",
"url": "https://github.com/vendor/tested-package.git",
"no-api": true
},
"dependency-1": {
"type": "vcs",
"url": "https://github.com/vendor/dependency-1.git",
"no-api": true
},
"dependency-2": {
"type": "vcs",
"url": "https://github.com/vendor/dependency-2.git",
"no-api": true
},
"dependency-3": {
"type": "vcs",
"url": "https://github.com/vendor/dependency-3.git",
"no-api": true
},
"composer-repo.vendor.org": {
"type": "composer",
"url": "composer-repo.vendor.org"
}
},
"require": {
"php": "7.2",
"vendor/product": "1.10.22",
"vendor/tested-package": "dev-develop as 1.2.3",
"vendor/dependency-1": "dev-develop as 2.0.1",
"vendor/dependency-2": "dev-develop as 2.0.2",
"vendor/dependency-3": "dev-develop as 2.0.3"
}
}
Використовуючи цю опцію, Composer не використовує GitHub API для отримання інформації з репозиторію, а замість цього клонує репозиторій та читає потрібну інформацію з локального репозиторію.
Цей підхід дозволяє уникнути проблем з API лімітами, але виконання тестів може зайняти в 2-3 рази більше часу, оскільки клонування повільніше, ніж використання API.
Використання власного репозиторію composer
Можна підняти на машині з Jenkins свій репозиторій composer і використовувати його для зберігання пакетів, які тестуються, та їх залежностей.
Що я і зробив.
Перед етапом генерації composer.json
, я додав ще один етап - це упаковка та публікація пакета, який тестується, та його залежностей у мій репозиторій composer.
Після цих змін composer.json
має наступний вигляд:
{
"name": "vendor/tested-package",
"description": "The example",
"version": "1.2.3",
"repositories": {
"test-repo": {
"type": "composer",
"url": "127.0.0.1"
}
"composer-repo.vendor.org": {
"type": "composer",
"url": "composer-repo.vendor.org"
}
},
"require": {
"php": "7.2",
"vendor/product": "1.10.22",
"vendor/tested-package": "1.2.3",
"vendor/dependency-1": "2.0.1",
"vendor/dependency-2": "2.0.2",
"vendor/dependency-3": "2.0.3"
}
}
Проблему з GitHub API лімітами було вирішено без шкоди для швидкості виконання тестів.
Для підняття власного репозиторію composer ти можеш використовувати, наприклад, Satis
Якщо є ще якісь ідеї розв’язання цієї проблеми – пиши у коментарях.