-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathaction.yml
More file actions
357 lines (310 loc) · 14.3 KB
/
action.yml
File metadata and controls
357 lines (310 loc) · 14.3 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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
name: 'Deploy Mautic to DigitalOcean'
description: 'Deploy Mautic 6 with Docker Compose to a DigitalOcean VPS with automated SSL and monitoring'
author: 'escopecz'
branding:
icon: 'cloud'
color: 'blue'
inputs:
# DigitalOcean Configuration
digitalocean-token:
description: 'DigitalOcean API access token'
required: true
ssh-private-key:
description: 'SSH private key for VPS access'
required: true
# Mautic Configuration
email:
description: 'Admin email address for Mautic and SSL certificates'
required: true
mautic-password:
description: 'Admin password for Mautic'
required: true
mautic-version:
description: 'Mautic Docker image version'
required: false
default: '6.0.7-apache'
mautic-port:
description: 'Port for Mautic instance'
required: false
default: '8001'
# Optional Configuration
domain:
description: 'Domain name for your Mautic instance (optional, will use IP if not provided)'
required: false
vps-name:
description: 'Name for the DigitalOcean droplet'
required: false
default: 'mautic-vps'
vps-size:
description: 'DigitalOcean droplet size - Minimum s-1vcpu-2gb recommended for MySQL 8.0 + Mautic (s-1vcpu-2gb, s-2vcpu-2gb, s-2vcpu-4gb, s-4vcpu-8gb)'
required: false
default: 's-1vcpu-2gb'
vps-region:
description: 'DigitalOcean region'
required: false
default: 'nyc1'
# Mautic Packages
themes:
description: |
List of Mautic theme packages from Packagist or GitHub (one per line).
Packagist packages:
vendor/theme-name:^1.0
another-vendor/custom-theme:dev-main
GitHub URLs (public repositories):
https://github.com/user/theme-repo/archive/refs/heads/main.zip
GitHub URLs with custom directory and authentication:
https://github.com/company/private-theme/archive/main.zip?directory=MyCustomTheme&token=ghp_xxxxxxxxxxxxxxxxxxxx
https://github.com/vendor/premium-theme/archive/v2.1.0.zip?directory=PremiumTheme&token=ghp_yyyyyyyyyyyyyyyyyyyy
required: false
plugins:
description: |
List of Mautic plugin packages from Packagist or GitHub (one per line).
Packagist packages:
vendor/plugin-name:^2.0
another-vendor/custom-plugin:^1.5
GitHub URLs (public repositories):
https://github.com/user/plugin-repo/archive/refs/heads/main.zip
GitHub URLs with custom directory and authentication:
https://github.com/company/private-plugin/archive/main.zip?directory=CompanyPlugin&token=ghp_xxxxxxxxxxxxxxxxxxxx
https://github.com/vendor/premium-plugin/archive/v2.1.0.zip?directory=PremiumPlugin&token=ghp_yyyyyyyyyyyyyyyyyyyy
required: false
# Database Configuration
mysql-database:
description: 'MySQL database name'
required: false
default: 'mautic_db'
mysql-user:
description: 'MySQL user name'
required: false
default: 'mautic_db_user'
mysql-password:
description: 'MySQL password'
required: false
default: 'mautic_db_pwd'
mysql-root-password:
description: 'MySQL root password'
required: false
default: 'changeme'
outputs:
vps-ip:
description: 'IP address of the created VPS'
value: ${{ steps.deploy.outputs.vps-ip }}
mautic-url:
description: 'URL to access your Mautic instance'
value: ${{ steps.deploy.outputs.mautic-url }}
deployment-log:
description: 'Path to the deployment log artifact'
value: ${{ steps.deploy.outputs.deployment-log }}
runs:
using: 'composite'
steps:
- name: Validate inputs
shell: bash
run: |
echo "🔍 Validating required inputs..."
if [ -z "${{ inputs.digitalocean-token }}" ]; then
echo "❌ Error: digitalocean-token is required"
exit 1
fi
if [ -z "${{ inputs.ssh-private-key }}" ]; then
echo "❌ Error: ssh-private-key is required"
exit 1
fi
if [ -z "${{ inputs.email }}" ]; then
echo "❌ Error: email is required"
exit 1
fi
if [ -z "${{ inputs.mautic-password }}" ]; then
echo "❌ Error: mautic-password is required"
exit 1
fi
# Validate email format
if ! echo "${{ inputs.email }}" | grep -E '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$' > /dev/null; then
echo "❌ Error: Invalid email format"
exit 1
fi
echo "✅ All required inputs validated"
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ inputs.digitalocean-token }}
- name: Create and configure VPS
id: deploy
shell: bash
run: |
# Debug: Show what environment variables are actually set
echo "🐛 DEBUG: Environment variables:"
echo " INPUT_MAUTIC_VERSION='${INPUT_MAUTIC_VERSION}'"
echo " mautic-version input='${{ inputs.mautic-version }}'"
echo ""
# Run the main deployment script
${{ github.action_path }}/scripts/deploy.sh
# Fail-fast validation: Check if deployment outputs were created
echo ""
echo "🔍 Validating deployment..."
# Extract VPS IP from deployment outputs immediately
VPS_IP=$(grep "vps-ip=" "$GITHUB_OUTPUT" | cut -d'=' -f2-)
# Fail fast if no VPS IP found
if [ -z "$VPS_IP" ] && [ -z "$INPUT_DOMAIN" ]; then
echo "❌ FATAL: VPS IP not found in deployment outputs"
echo "🔍 Deployment appears to have failed - no VPS was created"
echo "📋 GitHub outputs content:"
cat "$GITHUB_OUTPUT" 2>/dev/null || echo "No GitHub outputs file found"
exit 1
fi
# Set the URL based on domain or IP
if [ -n "$INPUT_DOMAIN" ]; then
MAUTIC_URL="https://${INPUT_DOMAIN}"
echo "VPS IP: ${VPS_IP}"
echo "Mautic URL: ${MAUTIC_URL} (using domain)"
else
MAUTIC_PORT=${INPUT_MAUTIC_PORT:-8001}
MAUTIC_URL="http://${VPS_IP}:${MAUTIC_PORT}"
echo "VPS IP: ${VPS_IP}"
echo "Mautic URL: ${MAUTIC_URL}"
fi
# Fail fast if URL construction failed
if [ -z "$MAUTIC_URL" ]; then
echo "❌ FATAL: Could not construct Mautic URL"
exit 1
fi
echo "⏳ Waiting for Mautic to be ready..."
# Enhanced validation with better timeout and debugging
MAX_ATTEMPTS=8
ATTEMPT=1
while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
echo "Attempt $ATTEMPT: Testing Mautic login page..."
# Test the login endpoint directly - should return HTTP 200
LOGIN_URL="${MAUTIC_URL}/s/login"
# Enhanced curl with better error handling
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
--connect-timeout 15 \
--max-time 45 \
--retry 2 \
--retry-delay 5 \
--retry-connrefused \
"$LOGIN_URL" 2>/dev/null || echo "000")
# If we get a redirect, let's see where it goes
if [ "$HTTP_CODE" = "302" ] || [ "$HTTP_CODE" = "301" ]; then
REDIRECT_URL=$(curl -s -I --connect-timeout 10 --max-time 30 "$LOGIN_URL" 2>/dev/null | grep -i "location:" | cut -d' ' -f2- | tr -d '\r\n')
echo "📋 Login page returned HTTP $HTTP_CODE, redirecting to: $REDIRECT_URL"
# Follow the redirect to see the final response
if [ -n "$REDIRECT_URL" ]; then
FINAL_HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
--connect-timeout 15 \
--max-time 30 \
"$REDIRECT_URL" 2>/dev/null || echo "000")
echo "📋 Redirect destination returned HTTP $FINAL_HTTP_CODE"
# Accept 200 after redirect (successful page load)
if [ "$FINAL_HTTP_CODE" = "200" ]; then
echo "✅ Mautic is responding correctly (redirected to working page)"
echo "🎉 Deployment validation successful!"
break
elif echo "$REDIRECT_URL" | grep -q "/installer"; then
echo "⚠️ Mautic is redirecting to installer - installation incomplete"
echo "📋 Will continue trying as installation may still be in progress"
fi
fi
else
echo "📋 Login page returned HTTP $HTTP_CODE"
fi
# Accept 200 (direct success) or 503 (temporary unavailable during startup)
if [ "$HTTP_CODE" = "200" ]; then
echo "✅ Mautic login page loaded successfully (HTTP 200)"
echo "🎉 Deployment validation successful!"
break
elif [ "$HTTP_CODE" = "503" ]; then
echo "📋 Service temporarily unavailable (HTTP 503) - Mautic may still be starting up"
echo "⏳ Will retry in 45 seconds..."
elif [ "$HTTP_CODE" = "000" ]; then
echo "📋 Connection failed - checking if containers and port are accessible..."
# Enhanced debugging for connection failures
if [ $ATTEMPT -eq 1 ] || [ $ATTEMPT -eq 4 ]; then
echo "🔍 Detailed debugging for attempt $ATTEMPT:"
# Check if port is accessible from outside
echo "📡 Testing port connectivity..."
if [ -n "$INPUT_DOMAIN" ]; then
echo " - Testing HTTPS (443): $(nc -z -w5 ${INPUT_DOMAIN} 443 && echo 'OPEN' || echo 'CLOSED')"
echo " - Testing HTTP (80): $(nc -z -w5 ${INPUT_DOMAIN} 80 && echo 'OPEN' || echo 'CLOSED')"
else
MAUTIC_PORT=${INPUT_MAUTIC_PORT:-8001}
echo " - Testing Mautic port ($MAUTIC_PORT): $(nc -z -w5 ${VPS_IP} ${MAUTIC_PORT} && echo 'OPEN' || echo 'CLOSED')"
fi
# Check container status remotely with shorter timeout
echo "📊 Remote container status check:"
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=15 -i ~/.ssh/id_rsa root@${VPS_IP} "
cd /var/www 2>/dev/null || cd /
echo ' - Docker service:' \$(systemctl is-active docker 2>/dev/null || echo 'unknown')
echo ' - Container status:'
docker ps --filter 'name=mautic' --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' 2>/dev/null || echo ' Could not get container status'
echo ' - Recent Mautic logs:'
docker logs mautic_app --tail 5 --since 60s 2>/dev/null || echo ' No recent logs available'
" 2>/dev/null || echo " Could not connect to server for debugging"
fi
else
echo "📋 Unexpected HTTP response: $HTTP_CODE (expected 200)"
fi
if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
echo "⏳ Waiting 45 seconds before retry..."
sleep 45
else
echo "❌ Mautic failed to respond properly after $MAX_ATTEMPTS attempts"
echo "� Final troubleshooting information:"
echo " - VPS IP: ${VPS_IP}"
echo " - Mautic URL: ${MAUTIC_URL}"
echo " - Login URL: ${LOGIN_URL}"
echo " - Last HTTP response: ${HTTP_CODE}"
# Final comprehensive debugging
echo "� Final container debugging:"
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=30 -i ~/.ssh/id_rsa root@${VPS_IP} "
cd /var/www 2>/dev/null || cd /
echo 'Container status:'
docker ps -a --filter 'name=mautic' 2>/dev/null || echo 'Could not get container status'
echo 'Compose services:'
docker compose ps 2>/dev/null || echo 'Could not get compose status'
echo 'Mautic app logs (last 20 lines):'
docker logs mautic_app --tail 20 2>/dev/null || echo 'No Mautic logs available'
echo 'MySQL logs (last 10 lines):'
docker logs mautic_mysql --tail 10 2>/dev/null || echo 'No MySQL logs available'
" 2>/dev/null || echo "Could not connect for final debugging"
exit 1
fi
ATTEMPT=$((ATTEMPT + 1))
done
env:
INPUT_DIGITALOCEAN_TOKEN: ${{ inputs.digitalocean-token }}
INPUT_SSH_PRIVATE_KEY: ${{ inputs.ssh-private-key }}
INPUT_EMAIL: ${{ inputs.email }}
INPUT_MAUTIC_PASSWORD: ${{ inputs.mautic-password }}
INPUT_MAUTIC_VERSION: ${{ inputs.mautic-version }}
INPUT_MAUTIC_PORT: ${{ inputs.mautic-port }}
INPUT_DOMAIN: ${{ inputs.domain }}
INPUT_VPS_NAME: ${{ inputs.vps-name }}
INPUT_VPS_SIZE: ${{ inputs.vps-size }}
INPUT_VPS_REGION: ${{ inputs.vps-region }}
INPUT_THEMES: ${{ inputs.themes }}
INPUT_PLUGINS: ${{ inputs.plugins }}
INPUT_MYSQL_DATABASE: ${{ inputs.mysql-database }}
INPUT_MYSQL_USER: ${{ inputs.mysql-user }}
INPUT_MYSQL_PASSWORD: ${{ inputs.mysql-password }}
INPUT_MYSQL_ROOT_PASSWORD: ${{ inputs.mysql-root-password }}
ACTION_PATH: ${{ github.action_path }}
- name: Generate unique artifact ID
shell: bash
id: artifact-id
if: always()
run: echo "id=$(date +%s)-$$-$RANDOM" >> $GITHUB_OUTPUT
- name: Upload deployment log
uses: actions/upload-artifact@v4
if: always()
with:
name: mautic-deployment-log-${{ steps.artifact-id.outputs.id }}
path: ./setup-dc.log
- name: Cleanup
shell: bash
if: always()
run: |
echo "🧹 Cleaning up SSH keys and temporary files..."
rm -f ~/.ssh/id_rsa
rm -f ~/.ssh/id_rsa.pub
echo "✅ Cleanup completed"