fix: hybrid deploy without OPcache tool, tolerant of missing secrets
- No cachetool: its web adapter needs PHP below www.ep-reisen.de/typo3temp, which is the static docroot in the hybrid setup (blocked, and not the release's typo3temp). Not needed: the exporter's front controller stubs resolve the "current" symlink with readlink() on every request. - additional.php only merges secrets.php when it returns an array: Deployer creates an empty shared file on the first deploy. - public/.htaccess sets TYPO3_CONTEXT=Production/Staging for staging.ep-reisen.de, the smoke-test vhost. - dep host:check: read-only checks of the host before the first deploy. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
67c32802dc
commit
f6307d7552
3 files changed
+41
-11
No files matched your search
@@ -61,7 +61,9 @@ if (getenv('IS_DDEV_PROJECT') == 'true') {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_file(__DIR__ . '/secrets.php')) {
|
// Deployer creates an empty secrets.php if none exists yet: only an array counts
|
||||||
|
$secrets = is_file(__DIR__ . '/secrets.php') ? require __DIR__ . '/secrets.php' : null;
|
||||||
|
if (is_array($secrets)) {
|
||||||
$withoutEmptyValues = static function (array $values) use (&$withoutEmptyValues): array {
|
$withoutEmptyValues = static function (array $values) use (&$withoutEmptyValues): array {
|
||||||
foreach ($values as $key => $value) {
|
foreach ($values as $key => $value) {
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
@@ -74,7 +76,8 @@ if (is_file(__DIR__ . '/secrets.php')) {
|
|||||||
};
|
};
|
||||||
$GLOBALS['TYPO3_CONF_VARS'] = array_replace_recursive(
|
$GLOBALS['TYPO3_CONF_VARS'] = array_replace_recursive(
|
||||||
$GLOBALS['TYPO3_CONF_VARS'],
|
$GLOBALS['TYPO3_CONF_VARS'],
|
||||||
$withoutEmptyValues(require __DIR__ . '/secrets.php')
|
$withoutEmptyValues($secrets)
|
||||||
);
|
);
|
||||||
unset($withoutEmptyValues);
|
unset($withoutEmptyValues);
|
||||||
}
|
}
|
||||||
|
unset($secrets);
|
||||||
+32
-7
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Deployer;
|
namespace Deployer;
|
||||||
|
|
||||||
// Run inside DDEV after "ddev auth ssh": ddev exec vendor/bin/dep deploy
|
// Run inside DDEV after "ddev auth ssh": ddev exec vendor/bin/dep deploy
|
||||||
@@ -6,9 +7,8 @@ namespace Deployer;
|
|||||||
|
|
||||||
require 'recipe/typo3.php';
|
require 'recipe/typo3.php';
|
||||||
require 'contrib/rsync.php';
|
require 'contrib/rsync.php';
|
||||||
require 'contrib/cachetool.php';
|
|
||||||
|
|
||||||
set('application', 'ep-reisen-13');
|
set('application', 'ep-reisen-typo3-13');
|
||||||
set('keep_releases', 3);
|
set('keep_releases', 3);
|
||||||
|
|
||||||
// The release is built locally from the committed state, so nothing uncommitted is ever deployed
|
// The release is built locally from the committed state, so nothing uncommitted is ever deployed
|
||||||
@@ -75,10 +75,6 @@ host('prod')
|
|||||||
// Verify on the host once Hetzner has installed it
|
// Verify on the host once Hetzner has installed it
|
||||||
->set('bin/php', '/usr/bin/php85')
|
->set('bin/php', '/usr/bin/php85')
|
||||||
->set('http_user', 'eptypo3')
|
->set('http_user', 'eptypo3')
|
||||||
// The temp script goes into the shared typo3temp, which resolves to the same directory from every
|
|
||||||
// release: PHP workers with a stale realpath cache still map "current" to the previous release and
|
|
||||||
// would 404 on a script placed inside the new one.
|
|
||||||
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{deploy_path}}/shared/{{typo3/public_dir}}/typo3temp/assets/ --web-url=https://www.ep-reisen.de/typo3temp/assets')
|
|
||||||
;
|
;
|
||||||
|
|
||||||
desc('Build the release locally: committed state, production dependencies, theme assets');
|
desc('Build the release locally: committed state, production dependencies, theme assets');
|
||||||
@@ -89,6 +85,33 @@ task('build', function () {
|
|||||||
runLocally('cd {{build_dir}} && npm ci --no-audit --no-fund && npm run build');
|
runLocally('cd {{build_dir}} && npm ci --no-audit --no-fund && npm run build');
|
||||||
})->once();
|
})->once();
|
||||||
|
|
||||||
|
desc('Read-only checks of the host before the first deploy (see .ddev/plans/TYPO3-13-GO-LIVE.md)');
|
||||||
|
task('host:check', function () {
|
||||||
|
$checks = [
|
||||||
|
'PHP CLI 8.5.12+' => '{{bin/php}} -r \'exit(version_compare(PHP_VERSION, "8.5.12", ">=") ? 0 : 1);\' && {{bin/php}} -v | head -1',
|
||||||
|
'PHP extensions' => '{{bin/php}} -r \'$m = array_diff(["mysqli", "pdo_mysql", "intl", "mbstring", "xml", "zip", "gd", "fileinfo", "openssl", "curl", "zlib"], get_loaded_extensions()); echo $m ? "missing: " . implode(", ", $m) : "ok"; exit($m ? 1 : 0);\'',
|
||||||
|
'image processor (GraphicsMagick)' => 'test -x /usr/bin/gm && /usr/bin/gm version | head -1',
|
||||||
|
'production fileadmin' => 'test -d {{fileadmin_path}} && du -sh {{fileadmin_path}} 2>/dev/null | cut -f1',
|
||||||
|
'static/ep-reisen/fileadmin links there' => 'test "$(readlink -f /usr/home/eptypo3/public_html/static/ep-reisen/fileadmin)" = "$(readlink -f {{fileadmin_path}})" && echo yes',
|
||||||
|
'free disk space' => 'df -h /usr/home/eptypo3 | tail -1',
|
||||||
|
'secrets.php in place' => 'test -s {{deploy_path}}/shared/config/system/secrets.php && {{bin/php}} -r \'exit(is_array(require "{{deploy_path}}/shared/config/system/secrets.php") ? 0 : 1);\' && echo yes',
|
||||||
|
'MyE&P reachable' => 'curl -s -o /dev/null -w "%{http_code}" --max-time 10 https://my.ep-reisen.de/api/last-update',
|
||||||
|
];
|
||||||
|
$failed = false;
|
||||||
|
foreach ($checks as $label => $command) {
|
||||||
|
try {
|
||||||
|
writeln(sprintf('<info>✔</info> %s: %s', $label, trim(run($command))));
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
writeln(sprintf('<error>✘</error> %s', $label));
|
||||||
|
$failed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln('Not checkable from the CLI: open_basedir and PHP 8.5.12 (FPM) of the static vhosts, see the go-live plan.');
|
||||||
|
if ($failed) {
|
||||||
|
throw new \RuntimeException('Host checks failed');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
desc('Link the production fileadmin into the release');
|
desc('Link the production fileadmin into the release');
|
||||||
task('typo3:fileadmin', function () {
|
task('typo3:fileadmin', function () {
|
||||||
run('test -d {{fileadmin_path}}');
|
run('test -d {{fileadmin_path}}');
|
||||||
@@ -116,7 +139,9 @@ task('deploy', [
|
|||||||
// Caches belong to the release that goes live, so they are cleared after the symlink flip. Hooking
|
// Caches belong to the release that goes live, so they are cleared after the symlink flip. Hooking
|
||||||
// into deploy:symlink rather than appending to the list above keeps them inside deploy:publish, ahead
|
// into deploy:symlink rather than appending to the list above keeps them inside deploy:publish, ahead
|
||||||
// of deploy:unlock and deploy:success - a failing cache task must not follow a declared success.
|
// of deploy:unlock and deploy:success - a failing cache task must not follow a declared success.
|
||||||
after('deploy:symlink', 'cachetool:clear:opcache');
|
// No OPcache reset (cachetool): its web adapter would need PHP under www.ep-reisen.de/typo3temp, which
|
||||||
|
// is the static docroot. Not needed either: the front controller stubs in the static docroots resolve
|
||||||
|
// "current" with readlink() on every request, so a new release is always loaded under new paths.
|
||||||
after('deploy:symlink', 'typo3:cache:flush');
|
after('deploy:symlink', 'typo3:cache:flush');
|
||||||
|
|
||||||
after('deploy:failed', 'deploy:unlock');
|
after('deploy:failed', 'deploy:unlock');
|
||||||
+4
-2
@@ -296,8 +296,10 @@ AddDefaultCharset utf-8
|
|||||||
# Rules to set ApplicationContext based on hostname
|
# Rules to set ApplicationContext based on hostname
|
||||||
#RewriteCond %{HTTP_HOST} ^dev\.example\.com$
|
#RewriteCond %{HTTP_HOST} ^dev\.example\.com$
|
||||||
#RewriteRule .? - [E=TYPO3_CONTEXT:Development]
|
#RewriteRule .? - [E=TYPO3_CONTEXT:Development]
|
||||||
#RewriteCond %{HTTP_HOST} ^staging\.example\.com$
|
# Test vhost of the hybrid go-live (base variant in config/sites/ep-reisen); production
|
||||||
#RewriteRule .? - [E=TYPO3_CONTEXT:Production/Staging]
|
# traffic never reaches this file, the static docroots have their own .htaccess
|
||||||
|
RewriteCond %{HTTP_HOST} ^staging\.ep-reisen\.de$
|
||||||
|
RewriteRule .? - [E=TYPO3_CONTEXT:Production/Staging]
|
||||||
#RewriteCond %{HTTP_HOST} ^www\.example\.com$
|
#RewriteCond %{HTTP_HOST} ^www\.example\.com$
|
||||||
#RewriteRule .? - [E=TYPO3_CONTEXT:Production]
|
#RewriteRule .? - [E=TYPO3_CONTEXT:Production]
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user