Skip to content

Getting started ​

What furnace is ​

Furnace answers one question: does this extension actually work on every Magento, Mage-OS and PHP combination it claims to support? It does so with three pieces.

  • Cells are long-lived, real installations, each pinned to one platform version and one PHP version, with sample data and two store views (Luma and Hyvä). Furnace never builds Magento during a run; it resets a cell and uses it.
  • Goldens are snapshots of a healthy cell: the database plus the four files that carry its identity. Every run restores the golden before it starts and after it finishes, so a cell is pristine for the next extension.
  • Gates are the checks, run in a fixed order. Static gates run once on the host. Cell gates repeat for every matching cell: install, cron, integration, seed, production, browser. Each gate runs only if the one before held.

The extension side is deliberately small. A repository ships its test content (unit and integration tests inside each module, Playwright specs under dev/tests/specs, an optional seeder) and one file, furnace.json, that declares what it is and what it needs. Furnace owns every invocation, bootstrap and generated config, so no suite can drift to a hand-edited target URL or a retry count.

Two verdicts come out of a run, and they are different claims. Passed means nothing failed. Certified means nothing failed, every gate actually ran, and the fleet covers every platform and PHP tuple the policy requires.

Install furnace ​

Furnace is a PHP 8.1+ Symfony Console application. It needs the pdo_mysql, curl and simplexml extensions, Composer, rsync, git, unzip and a MySQL or MariaDB client. Install development dependencies so the Rector gate is available.

bash
git clone <your furnace remote> ~/.furnace-src
cd ~/.furnace-src && composer install
ln -sf ~/.furnace-src/bin/furnace ~/.local/bin/furnace

# optional: zsh completion
mkdir -p ~/.oh-my-zsh/completions
furnace completion zsh > ~/.oh-my-zsh/completions/_furnace

The installed furnace is a symlink into the checkout, so there is no build step to forget. furnace --version prints 1.0.0-alpha, the commit it runs from and whether the tree has uncommitted changes. If the default php on your PATH lacks pdo_mysql, bin/furnace re-executes itself under a versioned interpreter (php8.3 and php83 style names both work).

Tool paths are never hardcoded. Composer is looked up in /usr/local/bin, /usr/bin, ~/.local/bin and PATH, or set with FURNACE_COMPOSER. The MySQL client flavour decides the TLS flag it is passed.

Verify the checkout before trusting it:

bash
php tests/run.php            # plain PHP test harness, no PHPUnit needed
vendor/bin/phpstan analyse   # must report no errors

Before your first run ​

Furnace tests against cells living in ~/qoliber-furnace (override with FURNACE_CELLS). They are long-lived: a run resets a cell to a known state rather than building one. Cells and goldens explains how one is provisioned.

Confirm the fleet is ready:

bash
furnace init --deep

init repairs what it can and then proves each cell can actually execute an integration test. Expect roughly a minute per cell for the --deep part. Without it you learn only that the files look right, which is a weaker claim than it sounds: most cell faults present identically as "PHPUnit executed 0 tests".

If cells are failing after a reboot, see when something breaks.

The ten-minute loop ​

bash
# 1. Is the fleet fit to judge anything?
furnace doctor

# 2. Give the extension a manifest, then check it against the protocol
cd ~/qoliber-extensions/my-extension
furnace conform --init
furnace conform --explain

# 3. Fast checks only: rector, syntax floor on every PHP, phpstan/phpcs, unit tests
furnace run

# 4. The full ladder on one cell, without the slow browser stage
furnace run --gate=all --cell=m248 --skip-e2e

# 5. The whole matrix, three cells at a time, with reports
furnace run --gate=all --parallel=3 --json=/tmp/run.json --html=/tmp/run.html

Two further modes, each a page of its own:

bash
# the packages customers download, straight from the registry
furnace run --gate=all --release=1.2.0

# the other install path: setup:install from an empty database
furnace run --gate=all --fresh-install --cell=m248

Roughly how long ​

RunTakes about
furnace run (static)30 seconds
one cell, --skip-e2e5 to 10 minutes (integration dominates)
one cell, --fresh-install2 to 3 minutes (setup:install on 2.4.8 took 85 s)
one cell with browser testsup to 45 minutes
nine cells, --parallel=3, no e2e15 to 25 minutes

Keep --skip-e2e on while iterating. Exit codes are 0 for passing checks that all ran, 1 for a failure or an incomplete run, and 2 for invalid options.

Watching a run ​

--parallel=N shows a table that rewrites itself, naming what each cell is doing:

  ⠹ mageos1   Mageos 2.3.0 / PHP 8.3   integration   1m12s   test 65/93
  ⠸ m248      Magento 2.4.8 / PHP 8.4  e2e[hyva]     4m03s   e2e renders the hub page
  ✓ m249      Magento 2.4.9 / PHP 8.4  certified     6m21s

Every command a gate runs is also streamed to ~/.furnace/runs/<run>/<cell>/ with its command line, exit code and duration, so a second terminal can follow:

bash
tail -f ~/.furnace/runs/*/mageos1/integration.log
tail -f ~/.furnace/runs/*/m248/install-composer-require.log

Cells are locked for the whole run. A second furnace process reports the cell as in use and skips it; it never interleaves. Check with pgrep -af "furnace run" before starting a matrix.

Furnace 1.0.0-alpha · internal tooling · qoliber.com