-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdeploy.php
More file actions
204 lines (167 loc) Β· 6.43 KB
/
deploy.php
File metadata and controls
204 lines (167 loc) Β· 6.43 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
<?php
namespace Deployer;
require 'recipe/laravel.php';
// Config
set('application', 'merchant-docs');
set('repository', 'https://github.com/magentoopensource/docs-website.git');
set('keep_releases', 5);
set('writable_mode', 'chmod');
// Hosts
host('production')
->setHostname('62.113.231.168')
->setRemoteUser('web-user')
->setDeployPath('~/docs.magento-opensource.com')
->setLabels(['stage' => 'production'])
->set('ssh_multiplexing', false)
->setSshArguments(['-o StrictHostKeyChecking=no']);
// Shared files/dirs
add('shared_files', [
'.env',
]);
add('shared_dirs', [
'storage',
'resources/docs/main',
]);
// Writable dirs
add('writable_dirs', [
'storage',
'storage/app',
'storage/app/public',
'storage/framework',
'storage/framework/cache',
'storage/framework/cache/data',
'storage/framework/sessions',
'storage/framework/views',
'storage/logs',
'bootstrap/cache',
]);
// Tasks
desc('Authenticate with maxcluster control plane');
task('deploy:cluster-auth', function () {
writeln('π Authenticating with cluster-control...');
// Get PAT from local environment (set in GitHub Actions)
// Note: This runs on the CI runner, not the remote server
$pat = getenv('MAXCLUSTER_PAT');
if (empty($pat)) {
throw new \Exception('β MAXCLUSTER_PAT environment variable not set!');
}
run("cluster-control login --pa_token=" . escapeshellarg($pat));
writeln('β
Cluster-control authentication successful');
});
desc('Install npm dependencies');
task('deploy:npm-install', function () {
cd('{{release_path}}');
run('npm ci --production=false');
});
desc('Build Vite assets');
task('deploy:build-assets', function () {
cd('{{release_path}}');
run('npm run build');
});
desc('Verify assets were built successfully');
task('deploy:verify-assets', function () {
cd('{{release_path}}');
// Check manifest exists
if (!test('[ -f public/build/manifest.json ]')) {
throw new \Exception('β Build verification failed: manifest.json not found!');
}
// Check at least one CSS file exists
$cssCount = run('find public/build/assets -name "*.css" -type f | wc -l');
if ((int)trim($cssCount) === 0) {
throw new \Exception('β Build verification failed: No CSS files found in build directory!');
}
// Check at least one JS file exists
$jsCount = run('find public/build/assets -name "*.js" -type f | wc -l');
if ((int)trim($jsCount) === 0) {
throw new \Exception('β Build verification failed: No JS files found in build directory!');
}
writeln('β
Build verification passed - all required assets exist');
});
desc('Sync external documentation');
task('deploy:sync-docs', function () {
run('cd {{release_path}} && DEPLOYER_ROOT={{deploy_path}} bash bin/checkout_latest_docs.sh');
});
desc('Ensure webhook secret is configured');
task('deploy:configure-webhook', function () {
$secret = getenv('DOCS_WEBHOOK_SECRET');
if (empty($secret)) {
writeln('β οΈ DOCS_WEBHOOK_SECRET not set in environment, skipping...');
return;
}
$sharedEnv = '{{deploy_path}}/shared/.env';
// Check if secret already exists in .env
$hasSecret = test("grep -q '^GITHUB_WEBHOOK_SECRET=' $sharedEnv");
if ($hasSecret) {
// Update existing value
run("sed -i 's/^GITHUB_WEBHOOK_SECRET=.*/GITHUB_WEBHOOK_SECRET=$secret/' $sharedEnv");
writeln('β
Updated GITHUB_WEBHOOK_SECRET in .env');
} else {
// Append new value
run("echo 'GITHUB_WEBHOOK_SECRET=$secret' >> $sharedEnv");
writeln('β
Added GITHUB_WEBHOOK_SECRET to .env');
}
});
desc('Clear and optimize Laravel caches');
task('deploy:optimize', function () {
cd('{{release_path}}');
run('php artisan cache:clear');
run('php artisan config:clear');
run('php artisan route:clear');
run('php artisan view:clear');
run('php artisan config:cache');
run('php artisan route:cache');
run('php artisan view:cache');
});
desc('Clear PHP OPcache by reloading PHP-FPM');
task('deploy:clear-opcache', function () {
writeln('π Reloading PHP-FPM to clear OPcache...');
// Use cluster-control to gracefully reload PHP-FPM
// This clears OPcache and allows running processes to complete (30s timeout)
run('cluster-control php:reload C-727 srv-a --no-interaction');
run('cluster-control logout');
writeln('β
PHP-FPM reloaded, OPcache cleared');
});
desc('Verify deployment health');
task('deploy:health-check', function () {
writeln('π Running post-deployment health checks...');
// Check if homepage loads
$response = run('curl -s -o /dev/null -w "%{http_code}" https://docs.magento-opensource.com/');
if (trim($response) !== '200') {
writeln('β οΈ Warning: Homepage returned HTTP ' . trim($response));
} else {
writeln('β
Homepage loads successfully (HTTP 200)');
}
// Fetch homepage HTML and check for Vite assets
$html = run('curl -s https://docs.magento-opensource.com/');
// Extract CSS filename from HTML
if (preg_match('/build\/assets\/app-([a-f0-9]+)\.css/', $html, $matches)) {
$cssFile = "build/assets/app-{$matches[1]}.css";
$cssResponse = run("curl -s -o /dev/null -w \"%{http_code}\" https://docs.magento-opensource.com/$cssFile");
if (trim($cssResponse) === '200') {
writeln("β
CSS file loads successfully: $cssFile");
} else {
throw new \Exception("β CSS file failed to load: $cssFile (HTTP " . trim($cssResponse) . ")");
}
} else {
writeln('β οΈ Warning: Could not find CSS reference in HTML');
}
writeln('β
All health checks passed');
});
// Hooks
after('deploy:prepare', 'deploy:cluster-auth');
after('deploy:vendors', 'deploy:npm-install');
after('deploy:npm-install', 'deploy:build-assets');
after('deploy:build-assets', 'deploy:verify-assets');
after('deploy:symlink', 'deploy:sync-docs');
after('deploy:sync-docs', 'deploy:configure-webhook'); // Set webhook secret if provided
after('deploy:configure-webhook', 'deploy:clear-opcache'); // Clear OPcache BEFORE rebuilding caches
after('deploy:clear-opcache', 'deploy:optimize'); // Rebuild Laravel caches with fresh PHP
after('deploy:optimize', 'deploy:health-check');
// Main deployment flow
desc('Deploy the application');
task('deploy', [
'deploy:prepare',
'deploy:vendors',
'deploy:publish',
]);
after('deploy:failed', 'deploy:unlock');