---
title: "Contribution"
manual: "Environment State Manager"
version: "main"
permalink: "https://docs.typo3.org/permalink/fgtclb/environment-state-manager:contribution@main"
source: "Contribution/Index.rst"
rendered: "2026-10-17T14:50:33+00:00"
---

# Contribution {#contribution}

Contributions are welcome. This chapter describes how to set up a development
environment, how to run the tests and quality checks, and the commit message
rules used in this repository.

The source code and issue tracker are hosted on GitHub:
[fgtclb/environment-state-manager](https://github.com/fgtclb/environment-state-manager).

## Development environment {#contribution-environment}

All tests and quality tools run in containers through the
`Build/Scripts/runTests.sh` wrapper. The only requirement on the host is
a container runtime – **podman** (preferred) or **docker**. The wrapper pulls
the required TYPO3 testing images on first use; nothing else is installed on the
host.

Dependencies are installed into the git-ignored `.Build/` directory. The
wrapper installs them for a specific TYPO3 core and PHP version:

```bash
# Install dependencies for TYPO3 v13 on PHP 8.2 (default matrix).
Build/Scripts/runTests.sh -t 13 -p 8.2 -s composerUpdate

# Switch the working copy to the TYPO3 v14 dependency set.
Build/Scripts/runTests.sh -t 14 -p 8.2 -s composerUpdate
```

> [!NOTE]
> Only `composerUpdate` installs the dependencies for the core version
> given with `-t`, `composerInstall` does not. To run a test suite against
> a specific TYPO3 core version, run `composerUpdate -t <version>`
> **first** and pass the same `-t <version>` to the suite afterwards.
> Suites executed with a different core version installed than selected report
> false positives. `composerUpdate` removes and reinstalls `.Build/`
> and `composer.lock` (both git-ignored).

Run `Build/Scripts/runTests.sh -h` to see all options.

## Running tests {#contribution-tests}

```bash
# Unit tests.
Build/Scripts/runTests.sh -s unit

# Functional tests on SQLite (no database container required).
Build/Scripts/runTests.sh -s functional -d sqlite

# Functional tests against other database management systems.
Build/Scripts/runTests.sh -s functional -d mariadb -i 10.6
Build/Scripts/runTests.sh -s functional -d mysql -i 8.0
Build/Scripts/runTests.sh -s functional -d postgres -i 10
```

To run a single test class or method, append phpunit arguments **after a**
`--` **separator** (the wrapper parses its own options with `getopts`, so
phpunit flags must follow `--`):

```bash
Build/Scripts/runTests.sh -s functional -d sqlite -- --filter EnvironmentBuilderFactoryTest
```

The functional `Tests/Functional/Core13/` and
`Tests/Functional/Core14/` directories hold the TYPO3 core version
specific tests, gated with phpunit groups (`not-core-13` / `not-core-14`),
so the wrapper automatically runs the set matching the installed core version.

## Code quality {#contribution-quality}

```bash
# Coding guidelines: fix in place ...
Build/Scripts/runTests.sh -s cgl

# ... or check only (no changes), as run in CI.
Build/Scripts/runTests.sh -s cgl -n

# Static analysis (PHPStan).
Build/Scripts/runTests.sh -s phpstan

# Render this documentation into Documentation-GENERATED-temp.
Build/Scripts/runTests.sh -s renderDocumentation
```

The documentation suite pulls
`ghcr.io/typo3-documentation/render-guides:latest` before it renders, so a
local run uses the renderer release that CI and docs.typo3.org use, and the
summary names it in a `Renderer:` line. When the pull fails, for example
because the registry cannot be reached, the suite renders with the cached image,
says so and marks the summary line with `(cached, pull failed)`. Without a
cached image it fails. The renderer runs with `--fail-on-log --fail-on-error`,
so a warning fails the suite as well. A new renderer release can therefore turn
the suite red without a change in this repository.

Please make sure `cgl -n`, `phpstan` and the unit and functional test
suites pass before opening a pull request.

## Commit message rules {#contribution-commit-messages}

This repository follows the TYPO3 core commit message conventions.

### Format {#format}

```none
[TAG] Short imperative summary

A wrapped body (around 72 characters per line) that explains what the
change does and, more importantly, why it is needed. Describe the
behaviour change and the motivation, not the line-by-line diff.
```

Rules:

-   The subject line starts with a **tag** in square brackets, followed by a
    short summary in **imperative mood** ("Add", "Fix", "Rename"), capitalized
    and **without** a trailing period.
-   Keep the subject concise (aim for  52 characters,  72 at most).
-   Separate the subject from the body with a single blank line.
-   Wrap the body at around 72 characters and explain the *what* and *why*.
-   An issue reference is **not required**. When a change relates to a GitHub
    issue, you may reference it in the body (for example `Resolves: #123`).

### Tags {#tags}

| Tag | Use for |
| --- | --- |
| `[FEATURE]` | A new feature or capability. |
| `[TASK]` | Maintenance, refactoring, tooling, tests and other non-functional changes. |
| `[BUGFIX]` | A bug fix. |
| `[DOCS]` | Documentation-only changes. |

Breaking changes are additionally prefixed with `[!!!]` in front of the tag,
so reviewers and users can spot them immediately:

```none
[!!!][TASK] Remove deprecated state accessor

Explain what breaks and how to migrate.
```

### Examples {#examples}

```none
[FEATURE] Add backend environment builder

[TASK] Mark concrete implementations as internal

[DOCS] Document the public API and stability guarantees
```
