Skip to content

Latest commit

 

History

History
227 lines (182 loc) · 11.7 KB

File metadata and controls

227 lines (182 loc) · 11.7 KB

Contributing

Thank you for helping maintain this tModLoader container. Contributions should focus on container behavior, deployment, Workshop management, automation, documentation, or fixes that make the dedicated server more reliable.

This project is independently maintained. Submit issues and pull requests here; its features, fixes, and releases are managed in this repository.

Before starting

  • Read and follow the Code of Conduct.
  • Search existing issues and pull requests for related work.
  • Use a normal issue for bugs and feature requests.
  • Use the private process in SECURITY.md for vulnerabilities.
  • Discuss large behavior or compatibility changes before implementing them.

Development environment

Start with the code and process map to trace startup, dashboard requests, staged settings, and background operations. It also records the remaining maintainability hotspots and their regression coverage.

Install Git, Docker Engine or Docker Desktop, and Bash. ShellCheck and actionlint are recommended; both can also be run from containers. On Windows, Git Bash is the simplest way to run the repository's Bash tests.

Build both linux/amd64 and linux/arm64 when changing image dependencies or Workshop handling. ARM64 uses native DepotDownloader; AMD64 uses SteamCMD. The CI matrix runs on native runners for both architectures. Docker Desktop can test an ARM64 image on AMD64 via its built-in emulation, but those tests do not measure native ARM performance.

For each image, run tests/architecture-test.sh and tests/workshop-download-test.sh inside the container as tml, with the repository mounted read-only at /repo. The latter downloads Recipe Browser anonymously into a temporary directory and verifies that a second run reuses the cache. Also run python3 -m unittest discover -s tests -p 'test_workshop_download.py' -v for download failure and cache replacement safety.

Create a branch from the current master, make focused changes, and preserve backward compatibility unless the pull request clearly documents a necessary breaking change.

Required validation

For local Python tests, install argon2-cffi, waitress, cryptography, and PyYAML. Also run admin tests inside the built image to verify compatibility with Ubuntu's packaged Argon2 library.

For the administration page, run python3 -m unittest discover -s tests -p 'test_admin.py' -v, node --check web/app.js, and node --check web/setup.js. Test the default WebUI-enabled container with disposable volumes and a test token: first-run setup, saved-hash restart, authentication rejection, stage without apply, confirmed apply/restart, backup/verify, and environment-mode read-only behavior. Live Workshop search requires a separately supplied Steam API key; mocked API tests do not establish live key access.

For setup field validation, run node tests/setup-ui-test.cjs with Playwright installed. Set SETUP_TEST_URL and SETUP_TEST_CODE for a disposable first-run server; this test creates its admin credential. Optionally set SETUP_TEST_BROWSER=msedge to use installed Edge instead of Playwright Chromium, and SETUP_TEST_SCREENSHOT to save the validated form preview.

The administration integration test also verifies recovery previews, checksum rejection before downtime, live restore, retained originals, startup failure and startup retry. Run node tests/admin-recovery-test.cjs with Playwright and Chromium installed to exercise confirmation and recovery controls in a browser. Set PLAYWRIGHT_CHANNEL=msedge to use an installed Edge browser instead. Run node tests/admin-players-test.cjs for player filtering, moderation and announcement confirmations, unavailable-state controls and narrow-screen layout. Player parser and targeting tests are included in test_admin*.py; real empty roster queries and announcement delivery are exercised by the admin integration test. Connected-player kick/ban outcomes require a real game client. Run node tests/admin-worlds-test.cjs to verify world drafts, cancellation, confirmation and read-only controls. The administration integration test creates a world through the Worlds API, switches to the original world, then back again.

For world creation, also run python3 -m unittest discover -s tests -p 'test_world_creation.py' -v and the configuration tests. Validate real generation with disposable data for both TMOD_WORLDEVIL=corruption and crimson; check the generation log and saved .wld/.twld files. Reuse the world name to check that startup loads it without regeneration, then apply an unused name in web mode to check creation during the save/stop/start workflow.

The image includes Python 3.12 for container-native backups. Run python3 -m unittest discover -s tests -p 'test_backup*.py' -v on Linux. Also run sudo python3 tests/backup-integration-test.py tmodloader:dev after building the image. This creates disposable data and checks an actual server backup/restore cycle with ownership and health verification.

Maintenance controls are covered by test_admin_operations.py and test_admin_restart.py. Run node tests/admin-maintenance-test.cjs with Playwright and Python available for the action buttons, countdown controls, backup schedule form, and log retention settings. Run python tests/maintenance-integration-test.py tmodloader:dev against local Docker for real save/restart, countdown cancellation, and calendar backup validation in disposable containers and volumes.

Run the checks relevant to your change. Runtime changes should pass the full set:

bash -n ./*.sh tests/*.sh
shellcheck --severity=warning autosave.sh container-init.sh entrypoint.sh healthcheck.sh inject.sh \
  log-filter.sh manage-mods.sh prepare-config.sh run-server.sh tests/*.sh
docker compose config --quiet
docker build --tag tmodloader:dev .

Run the script tests against the built image:

docker run --rm --user tml:tml --entrypoint bash \
  --mount type=bind,source="$PWD",target=/repo,readonly \
  tmodloader:dev \
  /repo/tests/manage-mods-test.sh /terraria-server/manage-mods.sh

docker run --rm --user tml:tml --entrypoint bash \
  --mount type=bind,source="$PWD",target=/repo,readonly \
  tmodloader:dev \
  /repo/tests/locale-test.sh /usr/bin/steamcmd

docker run --rm --user tml:tml --entrypoint bash \
  --mount type=bind,source="$PWD",target=/repo,readonly \
  tmodloader:dev \
  /repo/tests/config-test.sh /terraria-server/prepare-config.sh

docker run --rm --user tml:tml --entrypoint bash \
  --mount type=bind,source="$PWD",target=/repo,readonly \
  tmodloader:dev \
  /repo/tests/log-filter-test.sh /terraria-server/log-filter.sh /terraria-server/run-server.sh

docker run --rm --user tml:tml --entrypoint bash \
  --mount type=bind,source="$PWD",target=/repo,readonly \
  tmodloader:dev \
  /repo/tests/runtime-control-test.sh /usr/local/bin/inject

bash tests/server-smoke-test.sh tmodloader:dev

The smoke test creates temporary Docker resources, starts a real tModLoader server, verifies health and command injection, stops it, checks the exit status, verifies root initialization, repaired persistent-volume ownership, the low-privilege server identity and hardened runtime, and persistent logs. It can take several minutes on an uncached host.

When invoking bind mounts from PowerShell, replace $PWD with an absolute Windows path. GitHub Actions runs the same build and runtime checks on pull requests.

Runtime updater validation

test_admin_updates.py covers release filtering, failed compatibility checks, interrupted promotion, paired-data rollback, first-world failure handling and recovery authorization. tests/admin-updates-test.cjs covers the dashboard notice, diagnostics and recovery confirmation with deterministic API responses.

For a real upstream upgrade and rollback, build an image with an older supported stable release, then run the opt-in integration test (it creates and removes only disposable Docker resources):

docker build --build-arg TMOD_VERSION=v2026.06.3.6 -t tmodloader:updates-old-test .
python tests/runtime-update-integration-test.py tmodloader:updates-old-test

Repeat with --platform linux/arm64 and a separate image tag when changing runtime installation. This test contacts GitHub and expects a newer supported release. It verifies a cached fallback survives container recreation and restores a paired world checkpoint. Existing server lifecycle tests set TMOD_AUTO_UPDATE=0 so upstream release timing cannot silently change their subject under test.

Change guidelines

  • Use set -Eeuo pipefail in Bash scripts unless a documented compatibility reason prevents it.
  • Quote expansions and keep ShellCheck clean at warning severity.
  • Validate user-controlled values before writing config files or commands.
  • Never print passwords, tokens, or other secrets.
  • Add regression coverage for fixed bugs and failure paths.
  • Keep network-dependent tests out of the script test suite; use deterministic mocks there and reserve network/server behavior for the Docker smoke test.
  • Update README.md, .env.example, and CHANGELOG.md when behavior or configuration changes.

Versioning and changelog

VERSION contains the container's MAJOR.MINOR.PATCH SemVer core:

  • Increment MAJOR for incompatible configuration, data-layout, or operational changes.
  • Increment MINOR for backward-compatible container features.
  • Increment PATCH for backward-compatible fixes and security updates.

Upstream tModLoader releases are installed by the runtime updater and do not require a container version bump. If deliberately publishing a new image with a different bundled runtime, use a new container version to preserve immutable tags. Before publishing, increment VERSION, add a matching ## [X.Y.Z] - YYYY-MM-DD section to CHANGELOG.md, and return ## [Unreleased] to an empty state. Follow Keep a Changelog: newest releases first, ISO dates, and human-readable entries under applicable Added, Changed, Deprecated, Removed, Fixed, or Security headings. Omit empty categories and update version comparison links. Generated GitHub release notes lead with these changes and keep image/source/validation details in an expandable section. Stable releases and images use X.Y.Z; previews use X.Y.Z-preview. The bundled tModLoader version is recorded in release notes and OCI labels. Numbered tags are immutable. The publisher runs when VERSION changes on master, or through manual dispatch. It selects initial stable/preview runtimes for that container release; it does not poll upstream on a schedule.

Pull requests and publishing

For Docker Hub credentials, initial publication, and upload retries, see Docker Hub publishing. Validate mirror changes with python3 -m unittest discover -s tests -p 'test_dockerhub.py' -v.

Use an imperative commit subject and explain the user-visible result, risks, compatibility impact, and validation in the pull request. Do not manually move public image tags as part of a contribution. After changes reach master, the publisher builds and tests an untagged candidate digest before updating GHCR tags. It then creates a GitHub Release from the matching versioned changelog section. The automation refuses to reuse numbered tags; only latest and preview aliases move.

Dashboard browser regression tests also include tests/admin-profiles-test.cjs, tests/admin-playthroughs-test.cjs, tests/admin-overview-test.cjs, tests/admin-attention-test.cjs and tests/admin-unsaved-test.cjs.

Validate dashboard runtime recovery with python tests/dashboard-runtime-recovery-test.py IMAGE. This uses disposable data, confirms checkpoint restoration and game health, and verifies the authenticated dashboard remains responsive without changing container uptime.