-
Notifications
You must be signed in to change notification settings - Fork 0
221 lines (190 loc) · 6.83 KB
/
Copy pathCI-CD.yml
File metadata and controls
221 lines (190 loc) · 6.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
name: CI-CD
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
concurrency:
group: ci-cd-${{ github.ref }}
cancel-in-progress: true
env:
PYTHON_VERSION: "3.14"
DOCKER_REPOSITORY: fastapi
DOCKER_SERVER_TAG: myapp-wsl-api
jobs:
test:
runs-on: ubuntu-latest
environment:
name: tests
env:
ACCESS_TOKEN_EXPIRE_MINUTES: ${{ secrets.ACCESS_TOKEN_EXPIRE_MINUTES }}
ALGORITHM: ${{ secrets.ALGORITHM }}
DATABASE_HOSTNAME: localhost
DATABASE_PORT: "5432"
DATABASE_NAME: ${{ secrets.DATABASE_NAME }}
DATABASE_USERNAME: ${{ secrets.DATABASE_USERNAME }}
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
TESTING: "true"
services:
postgres:
image: postgres:16-bookworm
env:
POSTGRES_USER: ${{ secrets.DATABASE_USERNAME }}
POSTGRES_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
POSTGRES_DB: "${{ secrets.DATABASE_NAME }}_test"
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: pip
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python -m pip install pytest
- name: Run Alembic migrations
run: alembic upgrade head
- name: Run tests
run: pytest --disable-warnings -v -s -x
validate_compose_dev:
needs: test
runs-on: ubuntu-latest
environment: tests
steps:
- uses: actions/checkout@v5
- name: Create temporary .env.docker from test environment secrets
run: |
cat > .env.docker <<EOF
DATABASE_HOSTNAME=postgres
DATABASE_PORT=5432
DATABASE_NAME=${{ secrets.DATABASE_NAME }}
DATABASE_USERNAME=${{ secrets.DATABASE_USERNAME }}
DATABASE_PASSWORD=${{ secrets.DATABASE_PASSWORD }}
SECRET_KEY=${{ secrets.SECRET_KEY }}
ALGORITHM=${{ secrets.ALGORITHM }}
ACCESS_TOKEN_EXPIRE_MINUTES=${{ secrets.ACCESS_TOKEN_EXPIRE_MINUTES }}
POSTGRES_USER=${{ secrets.DATABASE_USERNAME }}
POSTGRES_PASSWORD=${{ secrets.DATABASE_PASSWORD }}
POSTGRES_DB=${{ secrets.DATABASE_NAME }}
EOF
- name: Validate docker-compose-dev.yml
run: docker compose -f docker-compose-dev.yml config
docker_wsl:
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment:
name: ubuntu-server
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Extract Docker image metadata
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_REPOSITORY }}
tags: |
type=raw,value=${{ env.DOCKER_SERVER_TAG }}
type=sha,prefix=sha-
- name: Log in to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build and push Docker image
id: docker_build
uses: docker/build-push-action@v7
with:
context: .
pull: true
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
provenance: true
sbom: true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Image digest
run: echo "digest=${{ steps.docker_build.outputs.digest }}"
deploy_render:
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment:
name: production
steps:
- name: Trigger Render deploy
run: curl -fsS -X POST "$RENDER_DEPLOY_HOOK_URL"
env:
RENDER_DEPLOY_HOOK_URL: ${{ secrets.RENDER_DEPLOY_HOOK_URL }}
deploy_ubuntu:
needs: docker_wsl
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: [self-hosted, linux, x64, ubuntu-wsl]
environment:
name: tests
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Create .env.docker for Ubuntu deploy
run: |
cat > .env.docker <<EOF
DATABASE_HOSTNAME=postgres
DATABASE_PORT=5432
DATABASE_NAME=${{ secrets.DATABASE_NAME }}
DATABASE_USERNAME=${{ secrets.DATABASE_USERNAME }}
DATABASE_PASSWORD=${{ secrets.DATABASE_PASSWORD }}
SECRET_KEY=${{ secrets.SECRET_KEY }}
ALGORITHM=${{ secrets.ALGORITHM }}
ACCESS_TOKEN_EXPIRE_MINUTES=${{ secrets.ACCESS_TOKEN_EXPIRE_MINUTES }}
POSTGRES_USER=${{ secrets.DATABASE_USERNAME }}
POSTGRES_PASSWORD=${{ secrets.DATABASE_PASSWORD }}
POSTGRES_DB=${{ secrets.DATABASE_NAME }}
EOF
- name: Deploy on Ubuntu machine
working-directory: ${{ github.workspace }}
run: |
set -euo pipefail
docker compose -f docker-compose-wsl.yml up -d postgres
docker compose -f docker-compose-wsl.yml pull api
docker compose -f docker-compose-wsl.yml run --rm --no-deps api alembic upgrade head
docker compose -f docker-compose-wsl.yml up -d --no-deps api
# deploy_ubuntu:
# needs: docker_wsl
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
# runs-on: ubuntu-latest
# environment:
# name: ubuntu-server
# steps:
# - name: Set up SSH
# run: |
# install -m 700 -d ~/.ssh
# printf '%s\n' "${{ secrets.PROD_SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
# chmod 600 ~/.ssh/id_ed25519
# ssh-keyscan -p "${{ secrets.PROD_SSH_PORT }}" -H "${{ secrets.PROD_HOST }}" >> ~/.ssh/known_hosts
# - name: Deploy to Ubuntu server
# run: |
# ssh -p "${{ secrets.PROD_SSH_PORT }}" "${{ secrets.PROD_USERNAME }}@${{ secrets.PROD_HOST }}" <<'EOF'
# set -euo pipefail
# cd app/src
# git pull --ff-only origin main
# docker compose -f docker-compose-wsl.yml up -d postgres
# docker compose -f docker-compose-wsl.yml pull api
# docker compose -f docker-compose-wsl.yml run --rm --no-deps api alembic upgrade head
# docker compose -f docker-compose-wsl.yml up -d --no-deps api
# EOF