[3.0][Testing] Add a Docker development environment for MySQL and PostgreSQL - #9317
Conversation
Provides a reproducible local stack so contributors can work on SMF without installing PHP, Composer or PostgreSQL on the host: - PHP 8.4 on Apache, with every extension other/requirements.md lists as required (mbstring, fileinfo, pgsql, mysqli) or recommended (gd, intl, curl, exif, ftp, xsl, zip). - PostgreSQL 17, with standard_conforming_strings forced on at database level as SMF requires. - Mailpit, so mail() is captured locally and nothing can be sent out. - Adminer, for browsing the database. The entrypoint runs composer install, waits for the database, generates a Settings.php pointed at the db service and drops install.php into place, so a fresh checkout is ready to install on first boot. Everything lives under .docker/ because check-smf-index.php and check-smf-license.php skip dot directories, so the environment cannot break the file integrity checks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
SMF supports MySQL and PostgreSQL, and until now this environment only offered one of them. Both database services now start, and SMF_DB_TYPE decides which one the generated Settings.php points at. It defaults to mysql, since that is what the great majority of installs run on. The two engines keep separate volumes, so a forum can be installed on each and switched between by deleting Settings.php and restarting. Settings.php wins over SMF_DB_TYPE once it exists, and the entrypoint says so rather than silently ignoring the variable. The postgres service is renamed from `db` to say what it is, and keeps `db` as a network alias so Settings.php files written by the previous version still resolve. Engine settings are pinned the same way the postgres side already pinned standard_conforming_strings: utf8mb4 and InnoDB, matching SMF's own table DDL. The collation is deliberately left at the charset default, because SMF sets CHARSET without COLLATE, and forcing one here would diverge from the tables it creates. Also corrects the everyday-use notes: php.ini, the vhost and the entrypoint are copied into the image, so editing them needs a rebuild rather than a restart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PostgreSQL logs every statement that errors together with the SQL that caused it, with no configuration needed, and the log is only on the container stderr. That makes `docker compose logs postgres` the most useful debugging tool in the stack, and nothing said so. MySQL logs server errors only, never the client statement that failed, so the note points out the asymmetry: now that mysql is the default engine, a suspected SQL problem is worth reproducing on postgres. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
| -e "s|^\$db_user = 'root';|\$db_user = '${SMF_DB_USER}';|" \ | ||
| -e "s|^\$db_passwd = '';|\$db_passwd = '${SMF_DB_PASSWD}';|" \ | ||
| -e "s|^\$boardurl = 'http://127.0.0.1/smf';|\$boardurl = '${SMF_BOARDURL}';|" \ | ||
| -e "s|^\$mbname = 'My Community';|\$mbname = 'SMF Dev';|" \ |
There was a problem hiding this comment.
Why do we set the forum name here?
I am questioning:
- Why set it at all
- Why not set it to something like "SMF Dev - {GIT Revision}" and then update it on refresh, using the else statement?
There was a problem hiding this comment.
Good question, and digging into it the answer to (1) is that we should not set it at all. I will drop the line.
It never reaches the finished forum. The installer's forum-name field does not read Settings.php — its value is a constant:
// Themes/default/InstallTemplate.php:314
value="', Lang::getTxt('install_settings_name_default', file: 'Maintenance'), '"which is 'My Community', and Install.php:668 writes $_POST['mbname'] back unconditionally. So anyone installing through the browser ends up with My Community whatever the entrypoint wrote, and before the install finishes Settings.php just redirects to install.php, so the name is never on screen either. It is write-only. (Whether the installer should honour a prepared $mbname is a separate question, so I have raised it separately as #9546 rather than smuggle a behaviour change in here.)
It is redundant from the other direction too: in #9344 install-forum.sh passes --mbname="$SMF_MBNAME", defaulting to SMF Dev in lib.sh, which is what actually names the forum you get. So the sed line is dead in both worlds.
On (2) — I like the goal, but I do not think $mbname is the right carrier, for four reasons:
- It would fight the developer.
$mbnameis editable in Admin → Server Settings. Rewriting it from theelsebranch on everydocker compose upsilently reverts that, and the header of this file promises the opposite: "Everything here is idempotent: it is safe to restart the container at any time." - It would go stale, which is worse than absent. The checkout is bind-mounted live, so you can
git switchon the host without restarting the container. The name would then name a commit you are not running. A restart-time snapshot of a live tree is a claim that quietly turns false. - It leaks well past the page header.
$mbnameis the outgoing-mail identity: digest subjects (SendDigests.php:225), database-error alert mail (ErrorHandlerService.php:510), warning PMs (IssueWarning.php:309), the export author field (ExportProfileData.php:1229). A revision string through all of that makes Mailpit output churn between runs, so you cannot diff it. - Portability.
gitis in the image and the entrypoint runs as root, so it does work here —git describe --tags --always --dirtygivesv3.0-alpha.4-1217-g0ae132e78. But aswww-datathe same call fails withdetected dubious ownership in repository at '/var/www/html', and on a Linux host, where the bind mount carries the developer's own uid rather than root's, that will bite too. Workable withsafe.directory, but it is another moving part.
What I would suggest instead is to serve the same purpose where it cannot lie or leak — the entrypoint already logs a few lines at startup, and one more is accurate at the moment it prints, touches no state and reaches no mail:
log "checkout is at $(git -c safe.directory='*' -C "$BOARD_DIR" describe --tags --always --dirty 2>/dev/null || echo unknown)"Happy to add that here if you think it earns its place, or leave it out and keep this PR to the environment itself. And if you do want the forum to announce it is a dev instance, SMF_MBNAME from #9344 is the honest way to do it.
There was a problem hiding this comment.
Nope, let's drop setting it here.
There was a problem hiding this comment.
Dropped in ed38bc2 — the entrypoint no longer touches $mbname, so the generated Settings.php keeps the stock My Community, which is what the installer writes back anyway.
Nothing else referenced it: the README never mentioned a forum name, and the generated Settings.php is otherwise unchanged (verified by running the same sed block against other/Settings.php — every database value and $boardurl still substitute, and the result passes php -l).
The generated Settings.php had $mbname rewritten to 'SMF Dev', which never reached the finished forum. The installer's forum-name field does not read Settings.php -- it defaults to the 'install_settings_name_default' string and writes $_POST['mbname'] back unconditionally -- so a browser install always ends up with 'My Community' whatever was written here, and before the install finishes Settings.php only redirects to install.php, so the name is never on screen either. The line was write-only. Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
The Docker environment this branch was built on has landed upstream in SimpleMachines#9317, so the copies of compose.yaml and most of .docker/ that were riding along in this diff are now the same files release-3.0 already has. Merging drops them from the diff and leaves the install tooling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
The Docker environment this branch was built on has landed upstream in SimpleMachines#9317, so the copies of compose.yaml and most of .docker/ that were riding along in this diff are now the same files release-3.0 already has. Merging drops them from the diff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
SimpleMachines#9317 put the Docker environment upstream, so the copies of compose.yaml and most of .docker/ that this branch was carrying are now identical to what release-3.0 has. Merging drops them from the diff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
SimpleMachines#9317 put the Docker environment upstream, so the copies of compose.yaml and most of .docker/ that this branch was carrying are now identical to what release-3.0 has. Merging drops them from the diff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
SimpleMachines#9317 put the Docker environment upstream, so the copies of compose.yaml and most of .docker/ that this branch was carrying are now identical to what release-3.0 has. Merging drops them from the diff. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
Note
This change was produced by an LLM. The code, the commit messages and this
description were all written by Claude (Anthropic), driven by @albertlast. It has
not yet had human code review.
Everything stated below was verified by actually running it — a full install from
an empty database on each engine — rather than only reasoned about. Even so, please
review it as untrusted work: it may be right about what it does while not being
what SMF would prefer stylistically or architecturally.
Description
This one is a proposal rather than a fix — please close it if a bundled dev
environment is not wanted in the repository. It adds tooling only and changes no
forum code. It is the environment the other PRs in this batch were found and verified
in, so it is offered mainly so that work is reproducible.
docker compose up -d --buildgives a working 3.0 checkout with no local PHP,Composer, MySQL or PostgreSQL install:
mail(), nothing can be sentlocalhost:3307localhost:5433Both engines SMF supports are in the stack, and MySQL is the default. Both
services always start, on separate volumes, so a forum can be installed on each and
switched between.
SMF_DB_TYPEdecides which one the generatedSettings.phppointsat:
Once the forum is installed
Settings.phpis what counts, and the variable no longerhas any effect. The entrypoint detects that case and says so in the log rather than
appearing to ignore the setting.
Built to match
other/requirements.md: the required extensions (mbstring,fileinfo, and bothmysqliandpgsql, since SMF checks forpg_connect) and therecommended ones (
gd,intl,curl,exif,ftp,xsl,zip). The enginesettings SMF asks for are pinned at server level rather than left to whatever the
images happen to ship:
standard_conforming_strings = on, asrequirements.mdrequires.utf8mb4and InnoDB, matching SMF's own table DDL. The collation isdeliberately left at the charset default — SMF writes
CHARSET=utf8mb4with noCOLLATE, so its tables come oututf8mb4_0900_ai_cion MySQL 8.4, and forcing adifferent server collation would only apply to objects SMF did not create and make
the two diverge.
The entrypoint runs
composer install, waits for whichever database was selected,generates a
Settings.phppointed at it and putsinstall.phpin place, so a freshcheckout is ready to install on first boot.
The PostgreSQL service is named
postgresrather thandb, and keepsdbas anetwork alias so a
Settings.phpwritten by an earlier revision of this branch stillresolves.
It does not disturb the existing CI checks
Everything lives under
.docker/on purpose.check-smf-index.phprequires anindex.phpin every directory but skips dot directories (that is how.githubpasses today), and
check-smf-license.phponly inspects.phpfiles —.docker/contains none. Re-confirmed after adding the MySQL side: all four integrity scripts
in the
buildjob exit 0 with this branch checked out.The only tracked file outside
.docker/andcompose.yamlis.gitignore, to add/install.php(next to the existing/upgrade.php),/.envand the compose overridefilenames.
Notes for review
smf/smf/smfon both engines and are deliberatelycommitted — this is a throwaway local environment, not something with secrets worth
protecting.
compose.yamlworks with no.envfile;.docker/env.exampleis there foroverriding ports, versions, credentials and the engine.
.docker/README.md: the installer does not take its formdefaults from
Settings.php, it uses the hardcoded ones in the database API class,so the database step still has to be filled in by hand. The README lists the exact
values for both engines.
php.ini, the vhost and the entrypoint are copied into the image rather thanbind-mounted, so editing them needs
docker compose up -d --build web, not arestart. An earlier revision of the README said restart, which was wrong.
UpdateUnicodescheduled taskregenerates
Sources/Unicode/*.phpin place viafile_put_contents(), and itsoutput differs from what is committed by a handful of blank lines, so the working
tree goes dirty on its own. Not caused by this PR, but it will be noticed by anyone
using it.
How this was verified
PostgreSQL side: full teardown and rebuild (
docker compose down -v, deleteSettings.php, up again) followed by a complete install from an empty database,repeated several times while finding the other issues in this batch.
MySQL side: same, driven through every installer step against an empty database.
database population) all return HTTP 200.
utf8mb4.install.phpremoved, andindex.phpthenserves the new forum at HTTP 200.
engines do not interfere.
docker compose configvalidates, and all fourbuildjob integrity scripts pass.One thing found while verifying, which this PR depends on
The installer cannot finish on this branch without #9316. Step 6, the admin
account step, dies with:
which is exactly what #9316 fixes. Merging that branch in locally was what allowed the
MySQL install above to complete, and it was then dropped again so this PR stays
tooling-only. The code involved is in
Sources/Maintenance/Tools/Install.phpand isnot engine-specific, so it should affect a PostgreSQL install equally; it was only
observed here on MySQL.
This branch has also been brought up to date with
release-3.0, which it was tencommits behind.
Issues References (Fixes|Related|Closes)