Проблема
Займаючись розробкою пакету, який використовується клієнтами на різних версіях продукту та 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
до кожного GitHub репозиторію composer.json:
{
"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 репозиторій пакета, що тестується, і його залежностей.
Після цих змін 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
Якщо є ще якісь ідеї розв’язання цієї проблеми – пиши у коментарях.