-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathdeploy.php.example
More file actions
180 lines (151 loc) · 7.19 KB
/
Copy pathdeploy.php.example
File metadata and controls
180 lines (151 loc) · 7.19 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
<?php
/**
* Gäld — Deployer configuration template for self-hosters.
*
* Copy this file to deploy.php and fill in your values,
* or set the equivalent environment variables in your CI/CD pipeline.
*
* Requires: composer require --dev deployer/deployer
* Usage: dep deploy
*/
namespace Deployer;
require 'recipe/laravel.php';
// --- Project ---
set('application', 'gaeld');
set('repository', getenv('DEPLOY_REPO') ?: 'git@github.com:Scanix/Gaeld.git');
set('keep_releases', 5);
set('deploy_ee_version', getenv('DEPLOY_EE_VERSION') ?: '');
set('deploy_ee_registry_url', getenv('DEPLOY_EE_COMPOSER_REGISTRY_URL') ?: '');
set('deploy_ee_registry_domain', getenv('DEPLOY_EE_COMPOSER_REGISTRY_DOMAIN') ?: '');
set('deploy_ee_registry_auth_file', getenv('DEPLOY_EE_COMPOSER_AUTH_FILE') ?: '');
set('deploy_ee_content_digest', getenv('DEPLOY_EE_CONTENT_DIGEST') ?: '');
// --- Shared files/dirs (persisted across releases) ---
add('shared_files', ['.env']);
add('shared_dirs', ['storage']);
// --- Writable dirs ---
add('writable_dirs', ['bootstrap/cache', 'storage']);
set('writable_mode', 'chmod');
set('writable_use_sudo', true);
// --- Host ---
// Set DEPLOY_HOST, DEPLOY_USER, DEPLOY_PATH in .env or as environment variables.
host('production')
->setLabels(['stage' => 'production'])
->setHostname(getenv('DEPLOY_HOST') ?: 'your-server-alias-or-ip')
->setRemoteUser(getenv('DEPLOY_USER') ?: 'deploy')
->set('branch', getenv('DEPLOY_BRANCH') ?: 'develop')
->set('http_user', 'www-data')
->setDeployPath(getenv('DEPLOY_PATH') ?: '/var/www/gaeld')
->setForwardAgent(true);
// --- Tasks ---
// Build assets locally to avoid CPU spikes on production.
task('assets:build', function () {
runLocally('pnpm install --frozen-lockfile');
runLocally('pnpm build');
})->desc('Build frontend assets locally');
task('assets:upload', function () {
upload(__DIR__.'/public/build/', '{{release_path}}/public/build/');
})->desc('Upload built assets to release path');
task('deploy:ee:artifact', function () {
$eeTag = (string) get('deploy_ee_version');
if ($eeTag === '') {
writeln('CE-only deployment: no EE artifact to install.');
return;
}
$registryUrl = (string) get('deploy_ee_registry_url');
$registryDomain = (string) get('deploy_ee_registry_domain');
$authFile = (string) get('deploy_ee_registry_auth_file');
$expectedDigest = (string) get('deploy_ee_content_digest');
if ($registryUrl === '' || $registryDomain === '' || $authFile === '' || $expectedDigest === '' || ! is_file($authFile)) {
throw new \RuntimeException('DEPLOY_EE_COMPOSER_REGISTRY_URL, DEPLOY_EE_COMPOSER_REGISTRY_DOMAIN, DEPLOY_EE_COMPOSER_AUTH_FILE, and DEPLOY_EE_CONTENT_DIGEST are required for EE deployment.');
}
$eeVersion = ltrim($eeTag, 'v');
if (! preg_match('/^\d+\.\d+\.\d+$/', $eeVersion)) {
throw new \RuntimeException('DEPLOY_EE_VERSION must be a semantic-version tag such as v2.9.18.');
}
$composerHome = '{{release_path}}/.deploy/composer';
$authDestination = $composerHome.'/auth.json';
$pluginDestination = '{{release_path}}/plugins/gaeld-ee';
run('mkdir -p {{release_path}}/.deploy/composer {{release_path}}/plugins');
upload($authFile, $authDestination);
run('chmod 600 '.escapeshellarg($authDestination));
run('COMPOSER_HOME='.escapeshellarg($composerHome).' {{bin/composer}} config --global gitlab-domains '.escapeshellarg($registryDomain));
run(
'COMPOSER_HOME='.escapeshellarg($composerHome)
.' {{bin/composer}} create-project --no-install --no-scripts --no-dev --prefer-dist --no-interaction'
.' --repository='.escapeshellarg($registryUrl)
.' '.escapeshellarg('gaeld/ee-plugin:'.$eeVersion)
.' '.escapeshellarg($pluginDestination),
);
run('test -f '.escapeshellarg($pluginDestination.'/plugin.json'));
run(
'actual_digest=$({{bin/php}} '.escapeshellarg($pluginDestination.'/scripts/content-digest.php')
.' '.escapeshellarg($pluginDestination).'); test "$actual_digest" = '.escapeshellarg($expectedDigest),
);
})->desc('Install and verify the immutable EE package from GitLab Composer');
task('deploy:ee:vendors', function () {
if ((string) get('deploy_ee_version') === '') {
return;
}
$composerHome = '{{release_path}}/.deploy/composer';
run('COMPOSER_HOME='.escapeshellarg($composerHome).' {{bin/composer}} install --working-dir='.escapeshellarg('{{release_path}}/plugins/gaeld-ee').' --no-dev --prefer-dist --no-interaction --optimize-autoloader');
run('rm -f '.escapeshellarg($composerHome.'/auth.json'));
})->desc('Install the immutable EE artifact dependencies');
task('deploy:ee:cleanup', function () {
run('rm -f {{release_path}}/.deploy/composer/auth.json');
})->desc('Remove temporary private registry credentials');
task('deploy:fpm:restart', function () {
// Adjust the PHP-FPM service name to match your server (e.g. php8.3-fpm).
run('sudo systemctl reload php8.4-fpm');
})->desc('Gracefully reload PHP-FPM workers');
task('deploy:permissions', function () {
run('sudo chown -R {{remote_user}}:{{http_user}} {{deploy_path}}/shared/storage');
run('sudo chmod -R 2775 {{deploy_path}}/shared/storage');
run('sudo chown -R {{remote_user}}:{{http_user}} {{release_path}}/bootstrap/cache');
run('sudo chmod -R 2775 {{release_path}}/bootstrap/cache');
})->desc('Fix storage & cache permissions');
task('deploy:storage:link', function () {
run('rm -f {{release_path}}/public/storage');
run('ln -s {{deploy_path}}/shared/storage/app/public {{release_path}}/public/storage');
})->desc('Symlink public/storage to shared storage');
task('deploy:worker:restart', function () {
run('sudo systemctl restart gaeld-worker');
})->desc('Restart gaeld-worker systemd service after deploy');
task('deploy:sync:permissions', function () {
run('cd {{release_path}} && {{bin/php}} artisan gaeld:sync-permissions');
})->desc('Sync RBAC permissions');
task('deploy:meilisearch:sync', function () {
run('cd {{release_path}} && {{bin/php}} artisan scout:sync-index-settings 2>/dev/null || true');
})->desc('Sync MeiliSearch index settings (skipped if driver is not meilisearch)');
task('deploy:verify:edition', function () {
$eeVersion = (string) get('deploy_ee_version');
if ($eeVersion === '') {
writeln('CE-only deployment: no EE compatibility gate required.');
return;
}
run('cd {{release_path}} && {{bin/php}} artisan edition:verify --ee-version='.escapeshellarg($eeVersion));
})->desc('Verify the CE/EE compatibility pair before activation');
// --- Deployment flow ---
task('deploy', [
'deploy:prepare',
'deploy:ee:artifact',
'deploy:ee:vendors',
'deploy:vendors',
'deploy:verify:edition',
'assets:build',
'assets:upload',
'deploy:storage:link',
'artisan:migrate',
'artisan:config:cache',
'artisan:route:cache',
'artisan:view:cache',
'artisan:event:cache',
'deploy:sync:permissions',
'deploy:meilisearch:sync',
'deploy:permissions',
'deploy:fpm:restart',
'deploy:publish',
'deploy:worker:restart',
])->desc('Deploy the application');
// --- Hooks ---
after('deploy:failed', 'deploy:unlock');
after('deploy:failed', 'deploy:ee:cleanup');