Skip to content

Commit 687d8e6

Browse files
authored
ci: stabilize pipeline, fix integration tests and docker builds
- CI/CD: Resolved "no space left on device" error by cleaning up runner disk space. - Tests: Fixed integration tests by mocking Airflow, MLflow, and API startup events. - Dependencies: Added missing packages (dill, prometheus-client) to requirements.txt. - Quality: Applied formatting (Black, Isort) and fixed Flake8/MyPy errors. - Security: Configured correct permissions for Trivy and CodeQL scans.
1 parent 680332b commit 687d8e6

19 files changed

+390
-612
lines changed

.coverage

0 Bytes
Binary file not shown.

.github/workflows/cd.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CD Pipeline
22

33
on:
44
push:
5-
branches: [ main ]
5+
branches: [ main, 'feature/CI-CD-improve' ]
66
tags:
77
- 'v*.*.*'
88

@@ -26,13 +26,23 @@ jobs:
2626
- name: Checkout code
2727
uses: actions/checkout@v3
2828

29+
- name: Downcase REPO NAME
30+
run: |
31+
echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV}
32+
2933
- name: Log in to Container Registry
3034
uses: docker/login-action@v2
3135
with:
3236
registry: ${{ env.REGISTRY }}
3337
username: ${{ github.actor }}
3438
password: ${{ secrets.GITHUB_TOKEN }}
3539

40+
- name: Set up Docker Buildx
41+
uses: docker/setup-buildx-action@v2
42+
with:
43+
driver: docker-container
44+
driver-opts: network=host
45+
3646
- name: Extract metadata
3747
id: meta
3848
uses: docker/metadata-action@v4
@@ -72,12 +82,10 @@ jobs:
7282
run: |
7383
echo "Deploying to staging environment..."
7484
# Add your deployment commands here
75-
# Example: kubectl apply -f k8s/staging/
7685
7786
- name: Run smoke tests
7887
run: |
7988
echo "Running smoke tests..."
80-
# Add smoke test commands
8189
8290
deploy-production:
8391
name: Deploy to Production
@@ -95,7 +103,6 @@ jobs:
95103
- name: Deploy to production
96104
run: |
97105
echo "Deploying to production environment..."
98-
# Add your production deployment commands
99106
100107
- name: Create GitHub Release
101108
uses: actions/create-release@v1

.github/workflows/ci.yml

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CI Pipeline
22

33
on:
44
push:
5-
branches: [ main, develop ]
5+
branches: [ main, develop, 'feature/CI-CD-improve' ]
66
pull_request:
77
branches: [ main ]
88

@@ -16,18 +16,18 @@ jobs:
1616

1717
steps:
1818
- name: Checkout code
19-
uses: actions/checkout@v3
19+
uses: actions/checkout@v4
2020

2121
- name: Set up Python
22-
uses: actions/setup-python@v4
22+
uses: actions/setup-python@v5
2323
with:
2424
python-version: ${{ env.PYTHON_VERSION }}
2525
cache: 'pip'
2626

2727
- name: Install dependencies
2828
run: |
2929
python -m pip install --upgrade pip
30-
pip install black flake8 mypy isort
30+
pip install black flake8 mypy isort types-PyYAML
3131
pip install -r requirements.txt
3232
3333
- name: Run Black (code formatting)
@@ -63,10 +63,10 @@ jobs:
6363
6464
steps:
6565
- name: Checkout code
66-
uses: actions/checkout@v3
66+
uses: actions/checkout@v4
6767

6868
- name: Set up Python
69-
uses: actions/setup-python@v4
69+
uses: actions/setup-python@v5
7070
with:
7171
python-version: ${{ env.PYTHON_VERSION }}
7272
cache: 'pip'
@@ -94,15 +94,16 @@ jobs:
9494
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
9595

9696
- name: Upload coverage to Codecov
97-
uses: codecov/codecov-action@v3
97+
uses: codecov/codecov-action@v4
9898
with:
9999
file: ./coverage.xml
100100
flags: unittests
101101
name: codecov-umbrella
102102
fail_ci_if_error: true
103+
token: ${{ secrets.CODECOV_TOKEN }}
103104

104105
- name: Upload coverage report as artifact
105-
uses: actions/upload-artifact@v3
106+
uses: actions/upload-artifact@v4
106107
with:
107108
name: coverage-report
108109
path: htmlcov/
@@ -114,10 +115,20 @@ jobs:
114115

115116
steps:
116117
- name: Checkout code
117-
uses: actions/checkout@v3
118+
uses: actions/checkout@v4
119+
120+
# 👇 РУЧНЕ ОЧИЩЕННЯ ДИСКА (ПРАЦЮЄ ЗАВЖДИ) 👇
121+
- name: Free Disk Space (Manual)
122+
run: |
123+
sudo rm -rf /usr/share/dotnet
124+
sudo rm -rf /usr/local/lib/android
125+
sudo rm -rf /opt/ghc
126+
sudo rm -rf /opt/hostedtoolcache/CodeQL
127+
sudo docker image prune --all --force
128+
# 👆 КІНЕЦЬ БЛОКУ 👆
118129

119130
- name: Set up Docker Buildx
120-
uses: docker/setup-buildx-action@v2
131+
uses: docker/setup-buildx-action@v3
121132

122133
- name: Build Airflow image
123134
run: |
@@ -144,10 +155,14 @@ jobs:
144155
name: Security Scanning
145156
runs-on: ubuntu-latest
146157
needs: lint
158+
permissions:
159+
contents: read
160+
security-events: write
161+
actions: read
147162

148163
steps:
149164
- name: Checkout code
150-
uses: actions/checkout@v3
165+
uses: actions/checkout@v4
151166

152167
- name: Run Trivy vulnerability scanner
153168
uses: aquasecurity/trivy-action@master
@@ -158,7 +173,7 @@ jobs:
158173
output: 'trivy-results.sarif'
159174

160175
- name: Upload Trivy results to GitHub Security
161-
uses: github/codeql-action/upload-sarif@v2
176+
uses: github/codeql-action/upload-sarif@v3
162177
with:
163178
sarif_file: 'trivy-results.sarif'
164179

@@ -168,7 +183,7 @@ jobs:
168183
bandit -r src/ -f json -o bandit-report.json || true
169184
170185
- name: Upload Bandit report
171-
uses: actions/upload-artifact@v3
186+
uses: actions/upload-artifact@v4
172187
with:
173188
name: bandit-security-report
174189
path: bandit-report.json

.github/workflows/scheduled.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Scheduled Tests
2+
3+
on:
4+
schedule:
5+
- cron: '0 2 * * *'
6+
workflow_dispatch:
7+
8+
jobs:
9+
integration-tests:
10+
name: Full Integration Tests
11+
runs-on: ubuntu-latest
12+
13+
# FIX: Removed 'services' block entirely.
14+
# We are using docker-compose below, which will start Postgres, MinIO, etc.
15+
# Defining it here causes a port 5432/9000 conflict.
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v3
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v4
23+
with:
24+
python-version: '3.10'
25+
26+
- name: Start all services
27+
run: |
28+
docker compose up -d
29+
sleep 60 # Wait for services to be ready
30+
31+
- name: Run full test suite
32+
run: |
33+
pip install pytest pytest-cov
34+
pip install -r requirements.txt
35+
# Using localhost because docker-compose mapped ports to host
36+
pytest tests/ -v --cov=src --cov-report=xml
37+
38+
- name: Check service health
39+
run: |
40+
curl -f http://localhost:8000/health || exit 1
41+
curl -f http://localhost:5000/health || exit 1
42+
# curl -f http://localhost:8080/health || exit 1 # Airflow might take longer
43+
44+
- name: Cleanup
45+
if: always()
46+
run: docker compose down -v

docker-compose.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ services:
7575
networks:
7676
- churn-network
7777

78-
# MLflow Server (ТЕПЕР НА SQLITE, ЩОБ НЕ КОНФЛІКТУВАТИ)
78+
# MLflow Server
7979
mlflow:
8080
build:
8181
context: .
@@ -91,7 +91,6 @@ services:
9191
ports:
9292
- "5000:5000"
9393
volumes:
94-
# Зберігаємо файл бази даних
9594
- mlflow_data:/mlflow
9695
command: >
9796
mlflow server

requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,7 @@ python-dateutil
3636
matplotlib
3737
cryptography
3838
dill==0.3.7
39+
seaborn
40+
prometheus-client
41+
prometheus-client
42+
dill

scripts/create_test_data.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,61 +6,57 @@
66
url = "http://localhost:8000/predict"
77

88

9-
# 🔴 Генерируем клиента, который ГАРАНТИРОВАННО должен уйти
10-
# (Максимально плохие условия для удержания)
119
def generate_toxic_customer():
1210
return {
1311
"gender": "Female",
14-
"SeniorCitizen": 1, # Пенсионеры чаще уходят
15-
"Partner": "No", # Нет привязки к семье
12+
"SeniorCitizen": 1,
13+
"Partner": "No",
1614
"Dependents": "No",
17-
"tenure": 1, # Только пришел (1 месяц)
15+
"tenure": 1,
1816
"PhoneService": "Yes",
1917
"MultipleLines": "Yes",
20-
"InternetService": "Fiber optic", # Самый дорогой и проблемный инет
18+
"InternetService": "Fiber optic",
2119
"OnlineSecurity": "No",
2220
"OnlineBackup": "No",
2321
"DeviceProtection": "No",
24-
"TechSupport": "No", # Никакой поддержки
25-
"StreamingTV": "Yes", # Набрал услуг...
26-
"StreamingMovies": "Yes", # ...чтобы чек был огромным
27-
"Contract": "Month-to-month", # Никаких обязательств
22+
"TechSupport": "No",
23+
"StreamingTV": "Yes",
24+
"StreamingMovies": "Yes",
25+
"Contract": "Month-to-month",
2826
"PaperlessBilling": "Yes",
29-
"PaymentMethod": "Electronic check", # Самый "ненадежный" метод
30-
"MonthlyCharges": 118.75, # МАКСИМАЛЬНО возможная цена в датасете
31-
"TotalCharges": 118.75, # Равно месячной, так как 1й месяц
27+
"PaymentMethod": "Electronic check",
28+
"MonthlyCharges": 118.75,
29+
"TotalCharges": 118.75,
3230
}
3331

3432

35-
# 🟢 Идеальный клиент (Лояльный)
3633
def generate_loyal_customer():
3734
return {
3835
"gender": "Male",
3936
"SeniorCitizen": 0,
4037
"Partner": "Yes",
4138
"Dependents": "Yes",
42-
"tenure": 72, # С нами 6 лет (максимум)
39+
"tenure": 72,
4340
"PhoneService": "Yes",
4441
"MultipleLines": "No",
45-
"InternetService": "No", # Нет интернета - нет проблем
42+
"InternetService": "No",
4643
"OnlineSecurity": "No internet service",
4744
"OnlineBackup": "No internet service",
4845
"DeviceProtection": "No internet service",
4946
"TechSupport": "No internet service",
5047
"StreamingTV": "No internet service",
5148
"StreamingMovies": "No internet service",
52-
"Contract": "Two year", # Контракт на 2 года
49+
"Contract": "Two year",
5350
"PaperlessBilling": "No",
5451
"PaymentMethod": "Mailed check",
55-
"MonthlyCharges": 20.0, # Минимальная цена
52+
"MonthlyCharges": 20.0,
5653
"TotalCharges": 1400.0,
5754
}
5855

5956

6057
print("🚀 Starting EXTREME Load Test...")
6158

6259
while True:
63-
# Чередуем: Плохой -> Хороший
6460
if random.random() > 0.5:
6561
data = generate_toxic_customer()
6662
type_cust = "🤬 TOXIC"
@@ -84,4 +80,4 @@ def generate_loyal_customer():
8480
except Exception as e:
8581
print(f"🚨 Connection error: {e}")
8682

87-
time.sleep(0.2) # Шлем быстро, чтобы забить графики
83+
time.sleep(0.2)

scripts/evaluate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def plot_confusion_matrix(y_true, y_pred, save_path):
5757
plt.text(
5858
j + 0.5,
5959
i + 0.7,
60-
f"{cm[i, j]/total*100:.1f}%", # ВИПРАВЛЕНО ТУТ: додано пробіл після коми [i, j]
60+
f"{cm[i, j]/total*100:.1f}%",
6161
ha="center",
6262
va="center",
6363
fontsize=10,

scripts/setup_monitoring.sh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ set -e
33

44
echo "📊 Setting up monitoring stack..."
55

6-
# 1. Проверяем наличие сети (она должна быть создана основным компоузом)
76
NETWORK_NAME="churn-pipeline_churn-network"
87

98
if [ -z "$(docker network ls --filter name=^${NETWORK_NAME}$ -q)" ]; then
@@ -14,15 +13,12 @@ else
1413
echo "✅ Network '${NETWORK_NAME}' found."
1514
fi
1615

17-
# 2. Удаляем старые контейнеры мониторинга (чтобы избежать конфликтов)
1816
echo "🧹 Cleaning up old monitoring containers..."
1917
docker rm -f churn-prometheus churn-grafana churn-alertmanager churn-node-exporter 2>/dev/null || true
2018

21-
# 3. Запускаем
2219
echo "🚀 Starting monitoring services..."
2320
docker compose -f monitoring/docker-compose.monitoring.yml up -d
2421

25-
# 4. Ждем
2622
echo "⏳ Waiting for services to initialize..."
2723
sleep 10
2824

0 commit comments

Comments
 (0)