27 фСвраля 2022

πŸƒ Continuous Integration (CI): ΠΊΠ°ΠΊ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈ ΠΊΠ°ΠΊΡƒΡŽ Ρ€ΠΎΠ»ΡŒ ΠΎΠ½Π° ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π² Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

Π’Π΅Π»Π΅Π³Ρ€Π°ΠΌ @Andrey_Totshin
Π Π°Π·Π±Π΅Ρ€Π΅ΠΌ Ρ€ΠΎΠ»ΡŒ CI Π² ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠΌ Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ (Ρ‡Ρ‚ΠΎ Π² сСбя Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ эта Ρ‡Π°ΡΡ‚ΡŒ процСсса, ΠΊΠ°ΠΊΠΈΠ΅ Π·Π°Π΄Π°Ρ‡ΠΈ Ρ€Π΅ΡˆΠ°Π΅Ρ‚) ΠΈ Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅ настроим CI для прилоТСния API сСрвСра.
πŸƒ Continuous Integration (CI): ΠΊΠ°ΠΊ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈ ΠΊΠ°ΠΊΡƒΡŽ Ρ€ΠΎΠ»ΡŒ ΠΎΠ½Π° ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π² Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

Π’ ΠΏΡ€ΠΎΡˆΠ»ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠ΅ πŸƒ Π Π°Π±ΠΎΡ‚Π°Π΅ΠΌ Π½ΠΎΠ½-стоп: нСпрСрывная интСграция ΠΈ Π½Π΅ΠΏΡ€Π΅Ρ€Ρ‹Π²Π½ΠΎΠ΅ Ρ€Π°Π·Π²Π΅Ρ€Ρ‚Ρ‹Π²Π°Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π° (CI/CD) ΠΌΡ‹ ΠΎΠ±Π·ΠΎΡ€Π½ΠΎ познакомились с процСссом CI\CD. Настало врСмя ΡƒΠ³Π»ΡƒΠ±ΠΈΡ‚ΡŒΡΡ ΠΈ Ρ€Π°ΡΡˆΠΈΡ€ΠΈΡ‚ΡŒΡΡ Π² Π΄Π΅Ρ‚Π°Π»ΠΈ. НачнСм с Ρ€Π°Π·Π±ΠΎΡ€Π° ΠΏΠ΅Ρ€Π²ΠΎΠΉ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Ρ‹ процСсса – это CI (Continuous Deployment). Π Π°Π·Π±Π΅Ρ€Π΅ΠΌ Ρ†Π΅Π»ΠΈ этого процСсса, инструмСнты ΠΈ Π½Π° практичСском ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ кСйс.

Роль CI Π² ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠΌ Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

Вспомним ΠΊΠ°ΠΊ выглядит процСсс CI.

πŸƒ Continuous Integration (CI): ΠΊΠ°ΠΊ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈ ΠΊΠ°ΠΊΡƒΡŽ Ρ€ΠΎΠ»ΡŒ ΠΎΠ½Π° ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π² Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

Π¦Π΅Π»ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ прСслСдуСт этот процСсс ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅:

  1. Ѐиксация всСх ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ вСрсий Ρ‡Π΅Ρ€Π΅Π· систСму контроля вСрсий.
  2. ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡ ΠΊΠΎΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок ΠΏΡ€ΠΈ компиляции.
  3. АвтоматичСскоС тСстированиС выполнСния ΠΊΠΎΠ΄Π°.
  4. Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π°Ρ€Ρ‚Π΅Ρ„Π°ΠΊΡ‚ΠΎΠ² (оповСщСния, докумСнтация ΠΈ Ρ‚. Π΄.).

Π‘Π°ΠΌΠΎΠ΅ Π³Π»Π°Π²Π½ΠΎΠ΅ – это всС выполняСтся ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π² автоматичСском Ρ€Π΅ΠΆΠΈΠΌΠ΅. Π§Π΅Π»ΠΎΠ²Π΅ΠΊ участвуСт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² ΠΏΠ΅Ρ€Π²ΠΎΠ½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎΠΉ настройкС процСсса, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈ создании unit-тСстов. Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Π³ΠΎΡ€Π°Π·Π΄ΠΎ быстрСС Ρ€ΡƒΡ‡Π½ΠΎΠ³ΠΎ тСстирования, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ позволяСт максимально ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ ошибок ΠΏΠΎ Π²ΠΈΠ½Π΅ Ρ‡Π΅Π»ΠΎΠ²Π΅ΠΊΠ°. Π’ ΠΈΡ‚ΠΎΠ³Π΅ внСсСнноС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ Ρ‡Π΅Ρ€Π΅Π· тСсты ΠΈ Ссли тСсты Π½Π΅ ΠΏΡ€ΠΎΡˆΠ»ΠΈ, всСгда ΠΌΠΎΠΆΠ½ΠΎ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ Π½Π° ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ ΠΊΠΎΠΌΠΌΠΈΡ‚ Π² систСмС контроля вСрсии. Π’ ΠΎΠ±Ρ‰Π΅ΠΌ-Ρ‚ΠΎ ΠΈ всС, ΠΏΡ€Π΅Π΄Π»Π°Π³Π°ΡŽ ΠΏΡ€ΠΈΡΡ‚ΡƒΠΏΠΈΡ‚ΡŒ ΠΊ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ этого процСсса.

НастраиваСм CI Π² GitHub

Нам потрСбуСтся систСма Π‘ΠšΠ’ (систСма контроля вСрсий), Π° Ρ‚Π°ΠΊΠΆΠ΅ срСда, Π³Π΄Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ наш ΠΊΠΎΠ΄ ΠΈ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ тСсты. ВсС эти Π·Π°Π΄Π°Ρ‡ΠΈ (ΠΈ Π΅Ρ‰Π΅ ΠΌΠ½ΠΎΠ³ΠΎ Ρ‡Π΅Π³ΠΎ интСрСсного) ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ прСдоставляСт сСрвис GitHub.

КСйс: ΠΠ°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ CI с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»Π° сСрвиса GitHub для API сСрвСра написанного Π½Π° Python.

ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ самого сСрвСра ΠΈ ΠΊΠ°ΠΊ Π·Π°Π»ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π½Π° git Π½Π΅ Π±ΡƒΠ΄Ρƒ. Π’Π΅ΠΌΠ° ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΎ Π΄Ρ€ΡƒΠ³ΠΎΠΌ.

ИмССм Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ Git ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ структуру Ρ„Π°ΠΉΠ»ΠΎΠ²:

πŸƒ Continuous Integration (CI): ΠΊΠ°ΠΊ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈ ΠΊΠ°ΠΊΡƒΡŽ Ρ€ΠΎΠ»ΡŒ ΠΎΠ½Π° ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π² Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

Π¦Π²Π΅Ρ‚ΠΎΠΌ Π²Ρ‹Π΄Π΅Π»Π΅Π½Ρ‹ Ρ„Π°ΠΉΠ»Ρ‹, с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ Π±ΡƒΠ΄Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ. Π Π°Π·Π±Π΅Ρ€Π΅ΠΌ для Ρ‡Π΅Π³ΠΎ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ„Π°ΠΉΠ».

app.py
        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


    

Π­Ρ‚ΠΎ основной Ρ„Π°ΠΉΠ» нашСго прилоТСния (API сСрвСра). Π‘Π΅Ρ€Π²Π΅Ρ€ ΠΈΠΌΠ΅Π΅Ρ‚ Ρ‚Ρ€ΠΈ endpoint. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с / ΠΈ check. Endpoint /check Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌ ΠΊΠ°ΠΊ Ρ€Π°Π· для тСстов.

ΠŸΡ€ΠΎΠΉΠ΄Π΅ΠΌΡΡ ΠΏΠΎ основному Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»Ρƒ прилоТСния. ΠœΠ΅Ρ‚ΠΎΠ΄ get_current_username Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌ для Π±Π°Π·ΠΎΠ²ΠΎΠΉ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΏΠΎ Π»ΠΎΠ³ΠΈΠ½Ρƒ ΠΈ ΠΏΠ°Ρ€ΠΎΠ»ΡŽ. Π”Π°Π»Π΅Π΅ Ρƒ нас ΠΈΠ΄ΡƒΡ‚ Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ endpoint:

  1. @app.get(β€œ/”)
  2. @app.get(β€œ/test”)
  3. @app.get(β€œ/items”)
  4. @app.get(β€œ/check”)

Endpoint – это Ρ‚ΠΎΡ‡ΠΊΠΈ Π²Ρ…ΠΎΠ΄Π° для API ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΉ. Когда Ρƒ нас Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ автоматичСскиС тСсты, ΠΌΡ‹ постучимся /check ΠΈ Ссли ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΠΊΠΎΠ΄ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° 200, Π·Π½Π°Ρ‡ΠΈΡ‚ всС Ρ…ΠΎΡ€ΠΎΡˆΠΎ ΠΈ сСрвис Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚.

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Ρƒ нас Ρ„Π°ΠΉΠ» requirements.txt:

requirements.txt
        uvicorn==0.14.0
pydantic==1.8.2
fastapi==0.66.1
requests==2.26.0
pytest==6.2.5
    

Π’ΡƒΡ‚ пСрСчислСны зависимости ΠΏΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌ для запуска нашСго прилоТСния. Если ΠΌΡ‹ Π² дальнСйшСм Π·Π°Ρ…ΠΎΡ‚ΠΈΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» ΠΈΠ· внСшнСй Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ имя ΠΈ Π²Π΅Ρ€ΡΠΈΡŽ.

Makefile
        install:
	pip install --upgrade pip &&\
		pip install -r requirements.txt

test:
	python -m pytest -vv test_hello.py


    

Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» интСрСснСС. Π’ Π½Π΅ΠΌ прописаны ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ для сборки нашСго прилоТСния. Π’ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ сначала ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°ΡŽΡ‚ΡΡ всС Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ ΠΈ Π²Ρ‚ΠΎΡ€Ρ‹ΠΌ шагом запускаСтся Ρ„Π°ΠΉΠ» 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


    

БобствСнно Ρ‡Π΅Ρ€Π΅Π· get стучимся Π½Π° эндпоинт /check ΠΈ Ссли ΠΊΠΎΠ΄ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° 200, Ρ‚ΠΎ всС ΠΎΠΊ – наш сСрвСр ΠΊΠ°ΠΊ ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ ΠΏΠΎ этому эндпоинту. Π­Ρ‚ΠΎ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ тСста, ΠΌΠΎΠΆΠ½ΠΎ Π΅Π³ΠΎ Ρ€Π°ΡΡˆΠΈΡ€ΠΈΡ‚ΡŒ ΠΈ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΏΠΎΠ΄ своС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. Π‘ΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ

Π’ ΠΈΡ‚ΠΎΠ³Π΅ Ρƒ нас Π΅ΡΡ‚ΡŒ Ρ„Π°ΠΉΠ» с ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ, Ρ„Π°ΠΉΠ» с Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹ΠΌΠΈ зависимостями, Ρ„Π°ΠΉΠ» с тСстами ΠΈ Makefile для ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ запуска этого хозяйства. Вопрос Π½Π° Π²Π½ΠΈΠΌΠ°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ: Ρ‡Π΅Π³ΠΎ Π½Π΅ Ρ…Π²Π°Ρ‚Π°Π΅Ρ‚?

Если Π²ΡΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ Ρ†Π΅Π»ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… добиваСтся процСсс CI (Ρ‚Π°ΠΌ Π±Ρ‹Π»ΠΎ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΠΏΡ€ΠΎ автоматичСский запуск), Ρ‚ΠΎ всС это дСлаСтся Ρ‡Π΅Ρ€Π΅Π· описаниС PipeLine Π² Ρ„Π°ΠΉΠ»Π΅ main.yaml.

πŸƒ Continuous Integration (CI): ΠΊΠ°ΠΊ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈ ΠΊΠ°ΠΊΡƒΡŽ Ρ€ΠΎΠ»ΡŒ ΠΎΠ½Π° ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π² Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° располоТСниС этого Ρ„Π°ΠΉΠ»Π°. ΠšΠΎΡ€Π΅Π½ΡŒ вашСго рСпозитория, Π² Π½Π΅ΠΌ дирСктория .github/workflows/.

main.yaml
        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


    

На языкС YAML описываСтся: Ссли Ρƒ нас Π΅ΡΡ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ ΠΊΠΎΠΌΠΌΠΈΡ‚ Π² Π²Π΅Ρ‚ΠΊΠ΅ main, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ Job c шагами 1-3.

  1. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Python 3.10.1
  2. Π’Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ ΠΈΠ· Π±Π»ΠΎΠΊΠ° install Ρ„Π°ΠΉΠ»Π° Makefile.
  3. Π’Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ ΠΈΠ· Π±Π»ΠΎΠΊΠ° test Ρ„Π°ΠΉΠ»Π° Makefile.

Если Π½Π° всСм этом Π΄Π»ΠΈΠ½Π½ΠΎΠΌ ΠΏΡƒΡ‚ΠΈ нашСго PipeLine Π½Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ½Π΅Ρ‚ ошибок, Ρ‚ΠΎ Ρƒ нас собСрСтся нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, запустятся тСсты. ΠŸΡ€ΠΎΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ это ΠΌΠΎΠΆΠ½ΠΎ Π½Π° Π²ΠΊΠ»Π°Π΄ΠΊΠ΅ Action вашСго рСпозитория.

πŸƒ Continuous Integration (CI): ΠΊΠ°ΠΊ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈ ΠΊΠ°ΠΊΡƒΡŽ Ρ€ΠΎΠ»ΡŒ ΠΎΠ½Π° ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π² Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

Если ΠΏΡ€ΠΎΠ²Π°Π»ΠΈΡ‚ΡŒΡΡ Π² Π΄Π΅Ρ‚Π°Π»ΠΈ – Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π»ΠΎΠ³ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ шага

πŸƒ Continuous Integration (CI): ΠΊΠ°ΠΊ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈ ΠΊΠ°ΠΊΡƒΡŽ Ρ€ΠΎΠ»ΡŒ ΠΎΠ½Π° ΠΈΠ³Ρ€Π°Π΅Ρ‚ Π² Ρ†ΠΈΠΊΠ»Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ

ΠŸΠΎΠ·Π΄Ρ€Π°Π²Π»ΡΡŽ, тСсты ΠΏΡ€ΠΎΡˆΠ»ΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ – ΠΊΠΎΠ΄ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ запускаСтся Π±Π΅Π· привязки ΠΊ ΠΏΡ€ΠΎΠ΄. ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΡŽ. И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ запуск всСй Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠΈ дСйствий (наш PipeLine) Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΠΊΠΎΠΌΠΌΠΈΡ‚Π΅ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ.

***

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ ΠΏΠΎ Ρ‚Π΅ΠΌΠ΅

ΠœΠ•Π ΠžΠŸΠ Π˜Π―Π’Π˜Π―

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

Π’ΠΠšΠΠΠ‘Π˜Π˜

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ вакансию
Senior Java Developer
Москва, ΠΏΠΎ ΠΈΡ‚ΠΎΠ³Π°ΠΌ собСсСдования
Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π‘#
ΠΎΡ‚ 200000 RUB Π΄ΠΎ 400000 RUB

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•