Our DOS programs are C++98 built with Open Watcom v2: a 16-bit DOS executable (8086, large model) and, where there is one, a 32-bit Win32 console build for Windows 95 and later. They are tested in a headless DOSBox Staging and under Wine, and the shared code is DOSLIB.
Open Watcom v2: https://github.com/open-watcom/open-watcom-v2 DOSBox Staging: https://www.dosbox-staging.org Tools repository: https://git.teletypegames.org/build/dos-tools Programs built with this toolchain: GMENU, DOSINST, BMAGIC, TTGWIKI
Like every other platform, a DOS program's repo holds a one-line marker and its metadata; the pipeline is served by the WarpEngine of teletypegames.org, and everything it runs is in the builder image.
# .woodpecker.yaml
platform: dos
// metadata.json
{
"name": "dosinst",
"version": "0.6.1",
"title": "DOSINST",
"author": "Teletype Games",
"desc": "Installs, updates and removes DOS programs from an FTP store.",
"license": "GPL-3.0",
"category": "tool",
"dos": {
"folder": "DOSINST",
"files": ["DOSINST.EXE", "DOSINST.CFG", "README.md", "LICENSE"],
"settings": ["DOSINST.CFG"],
"store_name": "DOSInst Store",
"store_description": "Installs, updates and removes DOS programs from this store.",
"win32_folder": "DOSINSTW",
"win32_files": ["DOSINSTW.EXE", "DOSINST.CFG", "README.md", "LICENSE"],
"win32_store_name": "DOSInst Store for Windows",
"win32_store_description": "DOSINST for Windows 95 and later."
}
}
The dos block says what a release holds: the folder the program is installed as, the files that go into it, the settings that are in the release zip but never in a store update (so an update keeps an installed program's configuration), and the name and text the DOSINST list shows. The win32_ keys are the same for a Win32 build, and optional.
The rest is convention: SOURCE/build.sh builds the executables into the repo root with the Open Watcom in $WATCOM, and the tests are where the commands look for them. The version is version in metadata.json, as on every platform; when SOURCE/app/version.h has a Version, it has to match (raise the two together).
After a push the pipeline runs version → test → tag; on the tag: version → test → package → upload → publish → release. The version step is the engine's shared one, and DOS releases only from a tag (release_rule "tag"), so everything after the test runs on a tag only. The tag is the pipeline's own (WarpEngine 1.9): a new version in metadata.json, pushed to master, gets its vX.Y.Z tag from the tag step, and that tag makes the release. A push that leaves the version as it is only tests; off master the build is a dev-<version>-<branch> and its dev-<branch> tag is moved, which publishes the dev build to the catalog but never to the store (the shelf takes the newest non-dev- release). Until 2026-10-27 the DOS repos had no version in metadata.json and were released by tagging by hand; a tag made by hand still works, and has to match the version.
| Step | Command | When | What it does |
|---|---|---|---|
| test | dos-check |
every event | the code style (DOSLIB's clang-format wrapper), the unit tests (SOURCE/test/unit/run.sh), the Python tests of a server side (server/test) |
| test | dos-build |
every event | SOURCE/build.sh, then every .EXE of the file lists must be there |
| test | dos-test |
every event | SOURCE/test/run.sh (DOS in headless DOSBox Staging), SOURCE/test/runw32.sh (Win32 under Wine), SOURCE/test/run.py (DOSBox screen tests) |
| tag | after a push | the engine's shared step (1.9): a new version gets its vX.Y.Z tag, whose pipeline runs the rows below; a version tagged already releases nothing; a dev build moves its branch's dev-<branch> tag |
|
| package | dos-pack |
a tag | the folder zips and each .EXE alone, listed in .release-assets |
| upload, publish | a tag | the folder zip becomes the cartridge asset, the Win32 zip win_x86; the uploaded metadata keeps the dos block |
|
| release | a version tag | the engine's shared release step: the Gitea release with RELEASE_NOTES.md, the files of .release-assets attached |
There is no store step and no deploy key: the only secrets are the global application_token and gitea_token. The FTP store, ftp://ftp.teletypegames.org/APPS, where DOSINST installs and updates from, is the WarpEngine's DOS shelf (layout: "folders"). On every publish the engine rebuilds it from the catalog: from the zip and the dos block it writes each folder without its settings files, with an INFO.INI and a FILES.LST. A program hidden or deleted in the catalog leaves the store.
git.teletypegames.org/build/dos-builder (builder.Dockerfile in the tools repository): Open Watcom v2, DOSBox Staging (in /opt/dosbox-staging, off the PATH) and Debian's DOSBox (on the PATH, for the screen tests), Wine 32-bit, g++, Python with pyftpdlib, clang-format, zip, jq and curl, with the dos-* commands. The pinned versions are in /opt/dos-ci/versions. The same image runs a program's checks locally:
docker run --rm -v "$PWD:/workspace" git.teletypegames.org/build/dos-builder:latest \
sh -c 'dos-check && dos-build && dos-test && TAG=v1.2.3 dos-pack'