-
Notifications
You must be signed in to change notification settings - Fork 24
204 lines (180 loc) · 8.02 KB
/
deploy-universal.yml
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
name: Deployment (Universal)
on:
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy to'
required: true
default: 'stage'
type: choice
options: ['stage', 'prod']
delete-volumes:
description: 'Delete volumes?'
type: boolean
default: false
restore-db:
description: 'Restore DB?'
type: boolean
default: false
manual-sql:
description: 'SQL intervention file path'
type: string
default: ''
reindex-elastic:
description: 'Reindex elasticsearch?'
type: boolean
default: false
flush-redis:
description: 'Clear redis?'
type: boolean
default: false
build-flag:
type: choice
description: docker compose additional build flag
default: "None"
options:
- "None"
- "--no-cache"
jobs:
info:
runs-on: ubuntu-latest
steps:
- name: Info
run: |
if [ "${{ github.event.inputs.environment }}" = "prod" ]; then
echo "::warning::Deploying to PRODUCTION!"
elif [ "${{ github.event.inputs.environment }}" = "stage" ]; then
echo "::notice::Deploying to STAGE"
fi
# warn if flags are set
if [ "${{ github.event.inputs.delete-volumes }}" = "true" ]; then
echo "::warning::Deleting volumes!"
fi
if [ "${{ github.event.inputs.restore-db }}" = "true" ]; then
echo "::warning::Restoring DB!"
fi
if [ "${{ github.event.inputs.manual-sql }}" != "" ]; then
echo "::warning::SQL to be run: ${{ github.event.inputs.manual-sql }}"
fi
if [ "${{ github.event.inputs.flush-redis }}" = "true" ]; then
echo "::warning::Flushing redis!"
fi
if [ "${{ github.event.inputs.reindex-elastic }}" = "true" ]; then
echo "::warning::Reindexing elasticsearch!"
fi
if [ "${{ github.event.inputs.build-flag }}" != "None" ]; then
echo "::notice::Build flag: ${{ github.event.inputs.build-flag }}"
fi
deployment:
needs: info
concurrency: ${{ github.event.inputs.environment }}
runs-on: [self-hosted, "${{ github.event.inputs.environment }}"]
environment: ${{ github.event.inputs.environment == 'stage' && 'Staging' || 'Production' }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Verify environment
run: |
(diff -wB <(grep -vE '^\s*#' /opt/deployment-specific-files/.env | cut -d '=' -f 1 | sort) \
<(grep -vE '^\s*#' .env.sample | cut -d '=' -f 1 | sort)) ||\
(echo "Environment variables mismatch" &&\
echo "Update /opt/deployment-specific-files/.env on the host or .env.sample in your branch" &&\
exit 1)
- name: Verify manual interventions
if: github.event.inputs.manual-sql != ''
run: |
if [ ! -r "${{ github.event.inputs.manual-sql }}" ]; then
echo "File ${{ github.event.inputs.manual-sql }} does not exist or is not readable"
exit 1
fi
- name: Copy configuration
run: |
cp -f /opt/deployment-specific-files/chain.pem ./caddy/certs
cp -f /opt/deployment-specific-files/priv.pem ./caddy/certs
cp -f /opt/deployment-specific-files/.env ./
# remove any FINGERPRINT= lines from .env
sed -i '/^FINGERPRINT=/d' .env
# add FINGERPRINT to .env
echo "FINGERPRINT=$(date +%s%N)$RANDOM" >> .env
- name: Build
env:
# replace None with an empty string
BUILD_FLAG: ${{ github.event.inputs.build-flag != 'None' && github.event.inputs.build-flag || '' }}
run: docker compose -f docker-compose.yml -f docker-compose.deploy.yml build $BUILD_FLAG
- name: Download DB dump
id: get-db
if: github.event.inputs.restore-db == 'true'
uses: ./.github/actions/get-db
with:
# taking the dump file from different workflows: full dump for prod and sanitized for stage
workflow: ${{ github.event.inputs.environment == 'stage' && 'restore-sanitized-db.yml' || 'backup-db.yml' }}
zip-password: ${{ github.event.inputs.environment == 'stage' && secrets.STAGING_BACKUP_PASSWORD || secrets.BACKUP_PASSWORD }}
- name: Copy everything to /orbitar
run: |
mkdir -p /orbitar
# Include dot files in *
shopt -s dotglob
rm -rf /orbitar/*
cp -r ./* /orbitar
shopt -u dotglob
- name: Delete volumes
if: github.event.inputs.delete-volumes == 'true'
working-directory: /orbitar
run: docker compose -f docker-compose.yml -f docker-compose.deploy.yml -f docker-compose.deploy.ssl.yml down -v
- name: Restore DB
if: github.event.inputs.restore-db == 'true'
working-directory: /orbitar
env:
MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }}
run: |
docker compose -f docker-compose.yml -f docker-compose.deploy.yml stop backend
docker compose -f docker-compose.yml -f docker-compose.deploy.yml up -d mysql --wait
docker compose -f docker-compose.yml -f docker-compose.deploy.yml exec -T mysql /usr/bin/mysql \
-u root --password=$MYSQL_ROOT_PASSWORD --default-character-set=utf8mb4 \
< ${{ steps.get-db.outputs.db-dump-file }}
- name: Run manual SQL interventions
working-directory: /orbitar
if: github.event.inputs.manual-sql != ''
env:
MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }}
run: |
set -ex
docker compose -f docker-compose.yml -f docker-compose.deploy.yml stop backend
docker compose -f docker-compose.yml -f docker-compose.deploy.yml up -d mysql --wait
docker compose -f docker-compose.yml -f docker-compose.deploy.yml exec -T mysql /usr/bin/mysql \
-u root --password=$MYSQL_ROOT_PASSWORD --default-character-set=utf8mb4 orbitar_db \
< ${{ github.event.inputs.manual-sql }}
- name: Reindex ElasticSearch
if: github.event.inputs.reindex-elastic == 'true'
working-directory: /orbitar
env:
MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }}
run: |
docker compose -f docker-compose.yml -f docker-compose.deploy.yml up -d mysql --wait
echo "update orbitar_db.content_source set indexed = 0;" | \
docker compose -f docker-compose.yml -f docker-compose.deploy.yml exec -T mysql /usr/bin/mysql -u root --password=$MYSQL_ROOT_PASSWORD
- name: Flush redis
if: github.event.inputs.flush-redis == 'true'
working-directory: /orbitar
env:
REDIS_PASSWORD: orbitar
run: |
docker compose -f docker-compose.yml -f docker-compose.deploy.yml stop backend
docker compose -f docker-compose.yml -f docker-compose.deploy.yml up -d redis --wait
docker compose -f docker-compose.yml -f docker-compose.deploy.yml exec -e REDISCLI_AUTH=$REDIS_PASSWORD redis redis-cli FLUSHALL
- name: Deploy
working-directory: /orbitar
run: docker compose -f docker-compose.yml -f docker-compose.deploy.yml -f docker-compose.deploy.ssl.yml up -d
- name: Purge Cloudflare Cache
env:
CLOUDFLARE_ZONE: ${{ secrets.CLOUDFLARE_ZONE }}
CLOUDFLARE_BEARER_TOKEN: ${{ secrets.CLOUDFLARE_BEARER_TOKEN }}
if: env.CLOUDFLARE_ZONE != '' && env.CLOUDFLARE_BEARER_TOKEN != ''
run: |
curl --request POST \
--url https://api.cloudflare.com/client/v4/zones/${{ secrets.CLOUDFLARE_ZONE }}/purge_cache \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ${{ secrets.CLOUDFLARE_BEARER_TOKEN }}' \
--data '{
"purge_everything": true
}'