🏃 Continuous Integration (CI): как настроить и какую роль она играет в цикле разработки
Телеграм @Andrey_Totshin Разберем роль CI в жизненном цикле разработки (что в себя включает эта часть процесса, какие задачи решает) и на практике настроим CI для приложения API сервера. В прошлой статье 🏃 Работаем нон-стоп: непрерывная интеграция и непрерывное развертывание кода (CI/CD) мы обзорно познакомились с процессом CICD. Настало время углубиться и расшириться в детали. Начнем с разбора первой половины процесса – это CI (Continuous Deployment). Разберем цели этого процесса, инструменты и на практическом примере реализуем кейс. Вспомним как выглядит процесс CI. Цели, которые преследует этот процесс следующие: Самое главное – это все выполняется полностью в автоматическом режиме. Человек участвует только в первоначальной настройке процесса, то есть при создании unit-тестов. Такой подход гораздо быстрее ручного тестирования, так как позволяет максимально избежать ошибок по вине человека. В итоге внесенное изменение проходит через тесты и если тесты не прошли, всегда можно вернуться на предыдущий коммит в системе контроля версии. В общем-то и все, предлагаю приступить к реализации этого процесса. Нам потребуется система СКВ (система контроля версий), а также среда, где будет компилироваться наш код и запускаться тесты. Все эти задачи (и еще много чего интересного) полностью предоставляет сервис GitHub. Кейс: Настроить CI с помощью функционала сервиса GitHub для API сервера написанного на Python. Подробно описывать код самого сервера и как залить его на git не буду. Тема статьи о другом. Имеем в репозитории Git следующую структуру файлов: Цветом выделены файлы, с которыми будем работать. Разберем для чего каждый файл. app.py Это основной файл нашего приложения (API сервера). Сервер имеет три endpoint. Мы будем работать с Пройдемся по основному функционалу приложения. Метод Endpoint – это точки входа для API обращений. Когда у нас будут отрабатывать автоматические тесты, мы постучимся Следующий у нас файл requirements.txt Тут перечислены зависимости по библиотекам для запуска нашего приложения. Если мы в дальнейшем захотим использовать дополнительный функционал из внешней библиотеке, необходимо добавить имя и версию. Makefile Этот файл интереснее. В нем прописаны команды для сборки нашего приложения. Видим, что сначала устанавливаются все библиотеки и вторым шагом запускается файл test_hello.py Собственно через get стучимся на эндпоинт В итоге у нас есть файл с приложением, файл с необходимыми зависимостями, файл с тестами и Если вспомнить цели, которых добивается процесс CI (там было что-то про автоматический запуск), то все это делается через описание Обратите внимание на расположение этого файла. Корень вашего репозитория, в нем директория main.yaml На языке YAML описывается: если у нас есть новый коммит в ветке Если на всем этом длинном пути нашего Если провалиться в детали – то можно посмотреть логи каждого шага Поздравляю, тесты прошли успешно – код успешно запускается без привязки к прод. окружению. И теперь запуск всей цепочки действий (наш PipeLine) будет происходить при каждом коммите в репозиторий. *** Андрей Трошин
Роль CI в жизненном цикле разработки
Настраиваем CI в GitHub
from fastapi import FastAPI import uvicorn from typing import Optional from pydantic import BaseModel import secrets from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import HTTPBasic, HTTPBasicCredentials class Item(BaseModel): name: str description: Optional[str] = None price: int tax: Optional[float] = None app = FastAPI() security = HTTPBasic() def get_current_username(credentials: HTTPBasicCredentials = Depends(security)): correct_username = secrets.compare_digest(credentials.username, "test") correct_password = secrets.compare_digest(credentials.password, "test") if not (correct_username and correct_password): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect email or password", headers={"WWW-Authenticate": "Basic"}, ) return credentials.username @app.get("/") def read_root(credentials: HTTPBasicCredentials = Depends(get_current_username)): return {"Hi": "from API Server)"} @app.get("/test/{item_id}") async def read_item(item_id: int, credentials: HTTPBasicCredentials = Depends(get_current_username)): print(item_id) return {"item_id": item_id} @app.get("/check") def hello(): return "Hello World" @app.post("/items/") async def create_item(item: Item, credentials: HTTPBasicCredentials = Depends(get_current_username)): return item
/
и check
. Endpoint /check
необходим как раз для тестов. get_current_username
необходим для базовой аутентификации по логину и паролю. Далее у нас идут четыре endpoint
:/chek
и если получим код возврата 200
, значит все хорошо и сервис работает.requirements.txt
:
uvicorn==0.14.0 pydantic==1.8.2 fastapi==0.66.1 requests==2.26.0 pytest==6.2.5
install: pip install --upgrade pip && pip install -r requirements.txt test: python -m pytest -vv test_hello.py
test_hello.py
– это наши тесты.
from fastapi.testclient import TestClient from app import app client = TestClient(app) def test_valid_id(): response = client.get("/check") assert response.status_code == 200
/check
и если код возврата 200
, то все ок – наш сервер как минимум отвечает по этому эндпоинту. Это минимальный вариант теста, можно его расширить и настроить под свое приложение. Смотрим в документацию Makefile
для последовательности запуска этого хозяйства. Вопрос на внимательность: чего не хватает?PipeLine
в файле main.yaml
..github/workflows/
.
name: Run Test on: push: branches: - main jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python 3.10.1 uses: actions/setup-python@v1 with: python-version: 3.10.1 - name: Install dependencies run: | make install - name: Test run: | make test
main
, необходимо выполнить Job
c шагами 1-3.install
файла Makefile
.test
файла Makefile
.PipeLine
не возникнет ошибок, то у нас соберется наше приложение, запустятся тесты. Проследить это можно на вкладке Action вашего репозитория.Материалы по теме
- 0 views
- 0 Comment
Свежие комментарии