Skip to content

Commit 4768209

Browse files
authored
Merge pull request #12 from newfatto/feature/hw_34_2
Настроена конфигурация CI/CD
2 parents 26e79ab + 2ef7683 commit 4768209

66 files changed

Lines changed: 427 additions & 9302 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.git
2+
.github
3+
.env
4+
.venv
5+
venv
6+
__pycache__
7+
*.pyc
8+
.pytest_cache
9+
htmlcov
10+
media
11+
staticfiles
12+
.idea
13+
.vscode

.env.example

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
1-
SECRET_KEY=yoursecretkey
2-
DEBUG=True|False
3-
DATABASE_NAME=yourdbname
4-
DATABASE_USER=yourdbuser
5-
DATABASE_PASSWORD=yourdbpassword
6-
DATABASE_HOST=yourlhost
7-
DATABASE_PORT=yourport
1+
SECRET_KEY=
2+
DEBUG=False
83

9-
POSTGRES_DB=yourdbname
10-
POSTGRES_USER=yourdbuser
11-
POSTGRES_PASSWORD=yourdbpassword
4+
DATABASE_NAME=
5+
DATABASE_USER=
6+
DATABASE_PASSWORD=
7+
DATABASE_HOST=db
8+
DATABASE_PORT=5432
129

13-
STRIPE_API_KEY=yourstripeapikey
10+
ALLOWED_HOSTS=
11+
CSRF_TRUSTED_ORIGINS=
1412

15-
CELERY_BROKER_URL=yourbrockerurl
16-
CELERY_RESULT_BACKEND=yourresultbackend
13+
POSTGRES_DB=
14+
POSTGRES_USER=
15+
POSTGRES_PASSWORD=
1716

18-
EMAIL_HOST=smtp.gmail.com
19-
EMAIL_PORT=yourport
20-
EMAIL_HOST_USER=your_email@gmail.com
21-
EMAIL_HOST_PASSWORD=your_password
22-
EMAIL_USE_TLS=True
23-
DEFAULT_FROM_EMAIL=your_email@gmail.com
17+
STRIPE_API_KEY=
18+
19+
CELERY_BROKER_URL=redis://redis:6379/0
20+
CELERY_RESULT_BACKEND=redis://redis:6379/0
21+
CELERY_TASK_ALWAYS_EAGER=False
22+
CELERY_TASK_EAGER_PROPAGATES=False
23+
24+
EMAIL_HOST=
25+
EMAIL_PORT=465
26+
EMAIL_HOST_USER=
27+
EMAIL_HOST_PASSWORD=
28+
EMAIL_USE_TLS=False
29+
EMAIL_USE_SSL=True
30+
DEFAULT_FROM_EMAIL=

.flake8

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[flake8]
2+
max-line-length = 120
3+
ignore = E203, W503
4+
exclude = .git, __pycache__, venv, .venv, migrations

.github/workflows/ci-cd.yml

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
name: DRF CI/CD
2+
3+
on:
4+
push:
5+
branches:
6+
- develop
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
services:
14+
postgres:
15+
image: postgres:16
16+
env:
17+
POSTGRES_DB: learning_machine
18+
POSTGRES_USER: postgres
19+
POSTGRES_PASSWORD: postgres
20+
ports:
21+
- 5432:5432
22+
options: >-
23+
--health-cmd="pg_isready -U postgres -d learning_machine"
24+
--health-interval=10s
25+
--health-timeout=5s
26+
--health-retries=5
27+
28+
redis:
29+
image: redis:7
30+
ports:
31+
- 6379:6379
32+
33+
env:
34+
SECRET_KEY: test-secret-key
35+
DEBUG: "True"
36+
ALLOWED_HOSTS: localhost,127.0.0.1
37+
38+
DATABASE_NAME: learning_machine
39+
DATABASE_USER: postgres
40+
DATABASE_PASSWORD: postgres
41+
DATABASE_HOST: localhost
42+
DATABASE_PORT: 5432
43+
44+
STRIPE_API_KEY: test-stripe-key
45+
46+
CELERY_BROKER_URL: redis://localhost:6379/0
47+
CELERY_RESULT_BACKEND: redis://localhost:6379/0
48+
CELERY_TASK_ALWAYS_EAGER: "False"
49+
CELERY_TASK_EAGER_PROPAGATES: "False"
50+
51+
EMAIL_HOST: smtp.example.com
52+
EMAIL_PORT: 465
53+
EMAIL_HOST_USER: test@example.com
54+
EMAIL_HOST_PASSWORD: test-password
55+
EMAIL_USE_TLS: "False"
56+
EMAIL_USE_SSL: "True"
57+
DEFAULT_FROM_EMAIL: test@example.com
58+
59+
steps:
60+
- name: Check out code
61+
uses: actions/checkout@v4
62+
63+
- name: Install Poetry
64+
run: pipx install poetry
65+
66+
- name: Set up Python
67+
uses: actions/setup-python@v4
68+
with:
69+
python-version: "3.10"
70+
cache: "poetry"
71+
72+
- name: Install dependencies
73+
run: poetry install --no-interaction --no-root
74+
75+
- name: Run migrations
76+
run: poetry run python manage.py migrate
77+
78+
- name: Run tests
79+
run: poetry run python manage.py test
80+
81+
lint:
82+
runs-on: ubuntu-latest
83+
needs: test
84+
85+
steps:
86+
- name: Check out code
87+
uses: actions/checkout@v4
88+
89+
- name: Install Poetry
90+
run: pipx install poetry
91+
92+
- name: Set up Python
93+
uses: actions/setup-python@v4
94+
with:
95+
python-version: "3.10"
96+
cache: "poetry"
97+
98+
- name: Install dependencies
99+
run: poetry install --no-interaction --no-root
100+
101+
- name: Run flake8
102+
run: poetry run flake8 . --exclude=.venv,venv,migrations,htmlcov --max-line-length=119
103+
104+
build:
105+
runs-on: ubuntu-latest
106+
needs: lint
107+
108+
steps:
109+
- name: Check out code
110+
uses: actions/checkout@v4
111+
112+
- name: Build Docker image
113+
run: docker build -t learning-machine:test .
114+
115+
deploy:
116+
runs-on: ubuntu-latest
117+
needs: build
118+
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
119+
120+
steps:
121+
- name: Check out code
122+
uses: actions/checkout@v4
123+
124+
- name: Set up SSH
125+
uses: webfactory/ssh-agent@v0.9.0
126+
with:
127+
ssh-private-key: ${{ secrets.SSH_KEY }}
128+
129+
- name: Add server to known hosts
130+
run: |
131+
mkdir -p ~/.ssh
132+
ssh-keyscan ${{ secrets.SERVER_IP }} >> ~/.ssh/known_hosts
133+
134+
- name: Create deploy directory on server
135+
run: |
136+
ssh ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP }} "mkdir -p ${{ secrets.DEPLOY_DIR }}"
137+
138+
- name: Copy project files to server
139+
run: |
140+
rsync -az --delete \
141+
--exclude '.git' \
142+
--exclude '.github' \
143+
--exclude '.env' \
144+
--exclude '.venv' \
145+
--exclude 'venv' \
146+
--exclude '__pycache__' \
147+
--exclude '.pytest_cache' \
148+
--exclude 'htmlcov' \
149+
--exclude 'media' \
150+
--exclude 'staticfiles' \
151+
./ ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP }}:${{ secrets.DEPLOY_DIR }}/
152+
153+
- name: Create .env on server
154+
run: |
155+
ssh ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP }} << EOF
156+
cd ${{ secrets.DEPLOY_DIR }}
157+
158+
cat > .env << 'ENVEOF'
159+
${{ secrets.ENV_FILE }}
160+
ENVEOF
161+
EOF
162+
163+
- name: Deploy with Docker Compose
164+
run: |
165+
ssh ${{ secrets.SSH_USER }}@${{ secrets.SERVER_IP }} << 'EOF'
166+
cd ${{ secrets.DEPLOY_DIR }}
167+
168+
docker compose -f docker-compose.prod.yml up -d db redis
169+
docker compose -f docker-compose.prod.yml build
170+
171+
docker compose -f docker-compose.prod.yml run --rm web python manage.py migrate
172+
docker compose -f docker-compose.prod.yml run --rm web python manage.py collectstatic --noinput
173+
174+
docker compose -f docker-compose.prod.yml up -d
175+
176+
docker image prune -f
177+
EOF

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pip-log.txt
3737
pip-delete-this-directory.txt
3838

3939
# Unit test / coverage reports
40-
#htmlcov/
40+
htmlcov/
4141
.tox/
4242
.nox/
4343
.coverage

Dockerfile

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
FROM python:3.10
1+
FROM python:3.10-slim
2+
3+
ENV PYTHONDONTWRITEBYTECODE=1
4+
ENV PYTHONUNBUFFERED=1
25

36
WORKDIR /app
47

5-
RUN apt-get update && apt-get install -y \
8+
RUN apt-get update && apt-get install -y --no-install-recommends \
69
gcc \
710
libpq-dev \
811
&& apt-get clean \
@@ -19,4 +22,4 @@ COPY . .
1922

2023
EXPOSE 8000
2124

22-
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
25+
CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"]

config/settings.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,17 @@
1212

1313
DEBUG = True if os.getenv("DEBUG") == "True" else False
1414

15-
ALLOWED_HOSTS = []
15+
ALLOWED_HOSTS = [
16+
host.strip()
17+
for host in os.getenv("ALLOWED_HOSTS", "localhost,127.0.0.1").split(",")
18+
if host.strip()
19+
]
20+
21+
CSRF_TRUSTED_ORIGINS = [
22+
origin.strip()
23+
for origin in os.getenv("CSRF_TRUSTED_ORIGINS", "").split(",")
24+
if origin.strip()
25+
]
1626

1727
INSTALLED_APPS = [
1828
"django.contrib.admin",
@@ -65,7 +75,7 @@
6575
"NAME": os.getenv("DATABASE_NAME"),
6676
"USER": os.getenv("DATABASE_USER"),
6777
"PASSWORD": os.getenv("DATABASE_PASSWORD"),
68-
"HOST": os.getenv("DATABASE_HOST"),
78+
"HOST": os.getenv("DATABASE_HOST", "db"),
6979
"PORT": os.getenv("DATABASE_PORT", default="5432"),
7080
}
7181
}
@@ -89,10 +99,10 @@
8999

90100
TIME_ZONE = "Europe/Moscow"
91101
USE_TZ = True
92-
93102
USE_I18N = True
94103

95104
STATIC_URL = "static/"
105+
STATIC_ROOT = BASE_DIR / "staticfiles"
96106

97107
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
98108

0 commit comments

Comments
 (0)