TYPO3 Core Contribution Guide

Version

main

Language

en

Author

TYPO3 contributors

License

This document is published under the Creative Commons BY-NC-SA 4.0 license.

Rendered

Wed, 16 Jul 2025 06:52:46 +0000


On these pages you will learn how to become a TYPO3 Core contributor.


Table of Contents:

ADDITIONAL INFORMATION

About This Guide

This guide provides all necessary information to enable you to contribute to the TYPO3 source code.

The main focus is submitting patches (to fix bugs or add new features) to the TYPO3 source code, but you will also find information for writing bug reports, adding documentation, running tests, reviewing and testing patches etc.

Why contribute?

Here are some ideas why contribution is great:

  • Do you earn your income through the TYPO3 ecosystem? Contribute to keep it alive and going, securing your work.
  • Do you want to become a more experience developer? Or gather UX/UI expertise in a large, broadly used system?
  • Do you work in a company that has less sophisticated code testing and review capacities, and you want to learn from the TYPO3, understand it, and use your knowledge to work more effectively?
  • Do you want to keep up to date with latest development, be a part of it to shape it suit your needs? Have a democratic impact on a large project affecting many people?
  • If you know about fresh changes, it will make it much easier to perform updates for your projects! If you spot breaking changes affecting your project, you can much better give feedback on it and shape the final implementation.
  • Get in touch with awesome, kind and dedicated like-minded people like you. Be part of a community and feel connected, and see people appreciating your help.

How this guide is structured

The guide is structured in a way to give you all necessary information in the order that you need it. This means you can read it from the beginning and use it as a hands on guide, performing the steps as you go along.

The further you go along, the more advanced the topics will become.

But, you can also use it as a reference guide and jump straight to a section you are looking for. In this case, use the search box to search for what you are looking for or browse through the menu.

For example:

  • Create a Patch walks you through making a change in the TYPO3 core (e.g. fix a bug or create a new feature).

The chapters are structured as follows:

  • The chapters in INTRODUCTION give you an introduction. They are not necessary for contribution but will give you some background information which may make some things easier.
  • The chapters in SETUP show how to setup a TYPO3 installation, Git and your accounts for contribution. This is a necessary prerequisite for most actions (e.g. creating a patch), but must be done only once. We recommend to start with this.
  • The chapters in HOWTOS walk you through one task. In most cases, it is assumed that you already setup your environment.
  • ADDITIONAL INFORMATION contains a cheat sheet git cheat sheet, Troubleshooting and the Appendix which is a reference of some topics in more depth than what was described in the main section. These pages near the end of the manual assume that you are already familiar with contributing and serve as reference pages.

Conventions used in this guide

  • When referring to elements in the gui, we use this formatting: Add new SSH key.
  • Keystrokes are referred to by CTRL + c

Other ways to contribute

Besides developing for the TYPO3 core, there are many other ways to contribute and help the TYPO3 community.

You can find general information here:

Contribute to this Guide

If you find a bug in this manual, please be so kind as to check the online version on https://docs.typo3.org/typo3cms/ContributionWorkflowGuide/. From there you can hit the Edit on GitHub button in the top right corner and submit a pull request via GitHub. Alternatively you can just report an issue on Github.

Maintaining high quality documentation requires time and effort and the TYPO3 Documentation Team always appreciates support. If you want to support us, please join the slack channel #typo3-documentation.

Have a look at Contribute to the TYPO3 documentation for more information about how to contribute to the TYPO3 documentation.

And finally, as a last resort, you can get in touch with the Documentation Team by mail.

Help & Community

This guide attempts to provide all information necessary to contribute to the TYPO3 codebase. However, you might run into problems. If this is the case, there are several possibilities to get help. Do not hesitate to ask others, if you can't find the information you need.

Slack

The main communication platform for TYPO3 is the Slack chat system. In order to register for Slack, you first need a typo3.org account and then request a Slack account. This is explained here: Slack.

You can ask specific questions about contributing in the #typo3-cms-coredev channel, general TYPO3 questions should be asked in the #typo3-cms channel.

For more information on Slack, see Slack in the Appendix.

Events

Coding is great, but coding with others may be even better. There is a wide variety of TYPO3 events where you can meet people, gain knowledge and have fun doing it. Some of these events are especially suited for core contributors, though you will probably benefit from any TYPO3 event in some way or another.

Look for events like "Review Friday", "Code Sprints" and "Developer Days" or one of the many "BarCamps".

Next, we will describe some events that are relevant for Core contribution. They are not specifically targeted at providing support, but the event may be open to new Core contributors and may give you the opportunity to ask questions and get help. In any case, read the event description and if in doubt, contact the person listed in the event description.

Code Sprints

For joining code sprints, it is recommended that you have at least a little experience with TYPO3 Core contribution and are familiar with the workflow.

Look for the next Code Sprints on the Events page on typo3.org.

In the event description you should also find information about reimbursement and other information. You will usually need to signup for the event.

TYPO3 Developer Days

The Developer Days usually take place once a year. It is a great way to connect with other TYPO3 developers. If the "Coding Nights" take place during the Developer Days, it is a very good opportunity to code for TYPO3 with others.

You will also find the next Developer Days on the Events page on typo3.org.

TYPO3 Contribution Explained

Ok, so you want an overview first, that's fine. Actually, it's a brilliant idea to understand the concept first to help you understand why we do things the way we do them. So let us walk you through that.

Common Workflow

So this it what your usual coding workflow may look like.

  1. You clone or pull from a central Git repository and change some lines of code
  2. You push right back to that central repository

This workflow has some drawbacks though, because there is only a very low level of peer control over the code you are pushing. Chances are relatively high that your change might break something elsewhere, does not comply to TYPO3s coding guidelines, doesn't work on the respective PHP versions for the TYPO3 version you are working on.... in short: it's dangerous.

TYPO3 Contribution Workflow

As you can see, our workflow is a bit different, simply because we do not allow to push right back to our Git repository. We use a 6-eye principle to ensure proper quality assurance and Gerrit helps us here - but let's go over the workflow step by step.

  1. You clone or pull as usual and do changes to the codebase.
  2. When trying to push back to the Git repository, you will not be allowed to do so. In fact, the only entity that may push back to our Git repository is Gerrit itself, so the same rules apply for everybody.
  3. Instead, you push your changes to Gerrit and they will show up as a pending code review.
  4. From here, any contributor can review the change.
  5. Reviewing consists of two parts, the Code Review where a contributor checks if the code style is according to our coding guidelines or in general makes sense by reading and the Verification which means if the code does what it is supposed to do (like fixing an issue) and checks whether the unit, functional and acceptance tests run through.
  6. If a review has enough positive votes (at least two people voting verified+reviewed), an active contributor (aka member of the Core team, called "Merger") is able to merge that review into the existing codebase. The reason we need a member of the Core team to finally merge the change is that we run a "You break it, you fix it" policy. So, the Core team member that merged a change immediately becomes responsible for that change in case the original author decides to no longer work on it. And he / she will be responsible for backporting it to selected older TYPO3 versions.

Introduction to Forger

The majority of the work in the TYPO3 project is managed via a tool called Forger_, which acts as a read-only view on issues and reviews.

Forger performs several tasks, including:

#. Provides an extensive search over issues on Forge_, available via the search box found on the start page and in the top right corner.

  1. Visualize the current development with a lot of useful graphs. You can learn more about the graphs here.
  2. Show and filter reviews incl. filters to easily find things to review. Check out the Reviews menu.
  3. Offer a variety of Kanban-style boards both for issues and reviews. Take a look at the Sprints menu, for example Sprints: Reviews: Bugfixes. Note: this is a great way to follow the current development. Just put up any board on a huge screen and use an auto-reload plugin in your browser.
  4. Supply an Issue Management view to show issues aggregated by year, month and status, based on the last time they were updated.
  5. A rst file generator which is useful when you add documentation snippets to a review.

Setting up Your Accounts

These are the TYPO3 online tools you will be using. For these you need a typo3.org account.

  • Forge: our Issue Tracker based on Redmine
  • Gerrit: our Code Review System
  • Slack: which is used for general communication (not required, but strongly recommended)

Follow the instructions to setup your accounts:

Signup for a TYPO3.org Account

Head over to the signup page on my.typo3.org and fill out the form.

Username
Pick a username you like. The form will directly tell you whether it's available or not. To save yourself from annoying problems later on down the road, to not use special characters like @ or ! in your username. Just use alphanumeric characters.
E-mail
Your email address should be the one you want to be using for notification emails from Forge and Gerrit. Also think twice whether your company email is appropriate here.
Full Name
Please use your real name here. It isn't really fun discussing with l33troXXor92.
Password
Choose a strong password here. Ideally, use a password manager to create a really strong password.
Repeat
Enter your (really strong) password here.

Setting up Gerrit (ssh)

  1. Click the Sign In button in the top right corner of the page review.typo3.org.

    You will be prompted with a regular Basic Authentication window, simply enter your TYPO3.org username and password you had set up earlier.

  2. Create your SSH key

    If you don't know how to create your SSH Public/Private Key, we have compiled a list of links for you:

  3. Add your public SSH key to Gerrit

    • Click on your profile in the top right corner and click Settings.
    • On the left hand side, click SSH Keys.
    • Copy-paste the contents of your public SSH key file (e.g. ~/.ssh/id_rsa.pub) into the text field next to New SSH key and then click on Add new SSH key.

If you work with different computers, for example with a notebook at work and another computer at home you can either copy your private key or create a separate key for the other computer. Luckily Gerrit can handle multiple keys.

Slack

If you wish to contribute, joining the #typo3-cms-coredev channel in the TYPO3 slack workspace is recommended as it is the projects chosen platform for communication.

It is mandatory to create a typo3.org account, before you can join the TYPO3 Slack workspace.

Register for Slack account

  1. Signup for typo3.org account (if not done already)

    In order to join the slack workspace, you must already have your typo3.org account.

  2. Go to Slack for TYPO3 on my.typo3.org.

    On that page, you will also find information about recommended channels.

  3. Login with your typo3.org account, then go to the "My Profile" tab and select "Use TYPO3 Slack".

  4. Follow the next steps

    including clicking on the link in the welcome email with subject "Stefan Busemann has invited you to join a Slack workspace" from slack.

Join #typo3-cms-coredev channel

  1. Open Channels Browser

    Once logged in https://typo3.slack.com, go to Channels Browser by clicking on Channels:

  2. Search for coredev-channel and select it:

  3. Click "Join Channel"

More information

See Appendix: Slack for more information on Slack.

Prerequisites and Useful Tools

Required:

  • Git
  • Once you have setup the Git repository, it is advised to look at the listed dependencies (basically: Docker) for runTests.sh (see Using runTests.sh).

Recommended:

  • IDE with TYPO3 plugins, such as PhpStorm or Visual Studio Code. While you can also use a simple editor, a properly setup IDE will help with code-completion, marking errors and applying coding guidelines.
  • DDEV for setting up the PHP/Database web environment as a base for the TYPO3 installation. Alternative methods are possible (XAMPP, LAMP, MAMP, WAMP, custom docker-compose) or even using a custom locally installed web server and database. DDEV provides custom configurations for TYPO3 which can be used for core development as well, and is an easy-to-use layer on top of docker-compose.

Information on using these tools is covered in detail later on this chapter.

Git Setup

These steps will walk you through your basic Git setup when working with TYPO3.

git clone

Create a directory for your TYPO3 core installation and change into it, e.g.:

shell command
mkdir /var/www/t3coredev
cd /var/www/t3coredev
Copied!

Clone the TYPO3 CMS core repository:

Use the SSH clone method if you've added your SSH key to your GitHub account:

shell command
git clone git@github.com:typo3/typo3 .
Copied!

As an alternative, you can always use the HTTPS clone method:

shell command
git clone https://github.com/typo3/typo3.git .
Copied!

Of course you can also use your custom user-specific workspace like /home/kaspar/TYPO3-Contribution/ to store the files, as you do not necessarily need to run a webserver to later setup your installation.

Set Username and Email

-- required (unless this is already setup globally, see git config --global -l)

You need to instruct git to work with your name and email address. Make sure the email address and user name are the same as those you used when setting up your TYPO3 account:

shell command
git config user.name "Your Name"
git config user.email "your-email@example.org"
Copied!

Set autosetuprebase

-- required

In order to avoid weird merges in your local repository when pulling in new commits from typo3.org, we encourage everybody to set the autosetuprebase Git option, such that your local commits are always rebased on top of the official code:

shell command
git config branch.autosetuprebase remote
Copied!

Install Your Commit Hooks

There are two git hooks available for TYPO3 development:

To set them up, you can use the existing Composer command or copy the hooks manually.

Install commit-msg and pre-commit hook to .git/hooks

shell command
composer gerrit:setup
Copied!

More information: Custom TYPO3 Composer Commands.

shell command
# ensure folder exists
mkdir -p .git/hooks

# copy commit-msg hook
cp Build/git-hooks/commit-msg .git/hooks/commit-msg
# optional: copy pre-commit hook
cp Build/git-hooks/unix+mac/pre-commit .git/hooks/

# make executable
chmod +x .git/hooks/commit-msg
chmod +x .git/hooks/pre-commit
Copied!

Setting up Your Remote

-- required

You must instruct Git to push to Gerrit instead of the original repository. It acts as a kind of facade in front of Git:

shell command
git config remote.origin.pushurl ssh://<YOUR_TYPO3_USERNAME>@review.typo3.org:29418/Packages/TYPO3.CMS.git
Copied!

This will instruct Git to push using the refs/for namespace when you do git push:

shell command
git config remote.origin.push +refs/heads/main:refs/for/main
Copied!

Reminder: The TYPO3 source repository is hosted on GitLab. That Git repository is only mirrored to the TYPO3 GitHub repository. Gerrit is coupled to GitLab.

Setting up a Commit Message Template

-- optional

If you follow these instructions, whenever you create a new commit, Git will use the template to create the commit message, which you can then modify in your editor. So use this to make it easier for you to fill out the required information.

First, create a file, for example ~/.gitmessage.txt.

 /.gitmessage.txt
[BUGFIX|TASK|FEATURE]

Resolves: #
Releases: main, 13.4
Copied!

Make Git use this file as a template for the commit message:

shell command
git config commit.template ~/.gitmessage.txt
Copied!

For additional information about how to write a proper commit message see Commit Message rules for TYPO3 CMS.

Show Configuration

-- optional

Show current configuration:

shell command
git config -l
Copied!

The result should look like this:

result
...
remote.origin.url=git@github.com:typo3/typo3
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.main.remote=origin
branch.main.merge=refs/heads/main
branch.autosetuprebase=remote
remote.origin.pushurl=ssh://<YOUR_TYPO3_USERNAME>@review.typo3.org:29418/Packages/TYPO3.CMS.git
commit.template=/path/to/.gitmessage.txt
...
Copied!

Or, compare the .git/config file inside the repository:

.git/config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote "origin"]
    url = git@github.com:typo3/typo3
    fetch = +refs/heads/*:refs/remotes/origin/*
    pushurl = ssh://<TYPO3_USER_NAME>@review.typo3.org:29418/Packages/TYPO3.CMS.git
[branch "main"]
    remote = origin
    merge = refs/heads/main
[branch]
    autosetuprebase = remote
[commit]
    template = /path/to/.gitmessage.txt
Copied!

Other resources

... highlight:: bash

Setup the TYPO3 installation

You will now need to setup a working installation of TYPO3. There are different ways how you can do this. We provide a few examples in the Appendix:

In any case, use the cloned Git repository as basis (see git clone).

composer install

Run composer install in the same directory you cloned the TYPO3 CMS core repository.

It is recommended to use runTests.sh for this (see Core testing in depth). The "direct command" is an alternative, but it requires your local system to have proper PHP and Composer versions ready to use. You only need to run one of these!

Build/Scripts/runTests.sh -s composerInstall
Copied!
composer install
Copied!

Use EXT:styleguide

It is recommended to use the styleguide extension to auto generate several example pages which can be used for testing the frontend and backend of TYPO3.

The EXT:styleguide (GitHub) extension is part of the TYPO3 Core repository. It is mostly used to showcase TCA / FormEngine features, but it has since evolved to provide additional features.

The styleguide extension can create pages within the TYPO3 site, specifically:

  • The "Styleguide TCA demo" will create several pages showcasing TCA features, including examples for common column types.
  • The "Styleguide Frontend" uses a custom TypoScript template provided by the styleguide extension and creates pages which can be viewed in the frontend.

Also, the styleguide presents you with examples of several backend UI elements like notifications, tabs, accordions and more.

The extension is very helpful for Core contributors and reviewers, because it allows to test many TCA related configurations easily, without the need to create custom extensions to reproduce problems.

EXT:styleguide has been integrated to the TYPO3 Core monorepository with version 13. On former TYPO3 versions you need to install this package either in the Extension Manager or by Composer.

Go explore!

Setup

  1. Activate the styleguide extension in the Extension Manager

    shell command
    # create pages
    bin/typo3 styleguide:generate -c
    # or (with DDEV)
    ddev typo3 styleguide:generate -c
    
    # show help
    bin/typo3 styleguide:generate -h
    Copied!
  2. In the Modules bar click on System > Styleguide
  3. Click on the Styleguide menu item (former TYPO3 versions present a custom module menu item)

    The Styleguide overview appears.

  4. Click on TCA / Records / Frontend
  5. Create pages

    Click the buttons:

    • Create styleguide page tree with data
    • Create styleguide frontend

The pages will now be created. Wait a moment until a flash message appears.

Setup your IDE

In the Appendix, you can find some hints that might be useful for PhpStorm: Setup.

Coding Guidelines

There is an .editorconfig file in the TYPO3 core repository. See https://editorconfig.org/ for more information.

Please note that the rules in .editorconfig are very minimal. So, additionally, setup your editor / IDE to use the recommendation as described in the Coding Guidelines of TYPO3.

See PhpStorm setup CGL for information about setting up PhpStorm to comply with the Coding Guidelines.

Quick Start: Get ready to contribute to TYPO3 in under 30 minutes!

This Tutorial / How To will show you the easiest and quickest way to become a contributor to TYPO3.

It is aimed at developers who have a good general knowledge, but need to know the specifics and rules of TYPO3 contributions.

We will use very brief wording and only few "read further" hints to streamline the process with conventions. Please check out the structure of this whole guide for more information.

These are the sections:

  • OS: Windows WSL2, macOS, Linux
  • Docker environment (Podman, OrbStack, Colima works too)
  • DDEV
  • Terminal (Bash)
  • Git client
  • SSH client plus SSH key(s) and an email account
  • A PHP IDE of your choice (PhpStorm, Visual Studio Code, vi(m), ...)
  • my.TYPO3.org, using SSO for:
  • Gerrit (Review System)
  • Forge (Redmine Issue Tracker)
  • (recommended) Slack (Chat)
  • Clone repository
  • Set up SSH key, Git hooks and push URL
  • Configure DDEV
  • Start Docker containers
  • Install TYPO3
  • Enable EXT:styleguide
  • Launch TYPO3 Backend
  • Develop
  • Set up Forge issue
  • Commit and push to Gerrit
  • Work in Gerrit
  • Announce your contribution
  • Implement Feedback
  • Merge/abandon a patch
  • Coordinate with the team
  • Cherry-picks and resetting
  • Reviewing other patches

Quick Start: Prerequisites

We will not explain you how to set up the following prerequisites. There are several tutorials for this on the web, and if you follow the Quick Start guide, you should know how to do this.

  1. Operating System

    A computer running Windows with WSL2, macOS or Linux - connected to the Internet.

  2. Docker

    Either the "original" Docker Desktop or an alternative like OrbStack, Podman, Colima or others. Linux users do not need to install any Desktop variants, but can use their base Docker or Podman setup.

  3. DDEV

    DDEV is a layer on top of Docker. How to utilize it is covered in this guide.

  4. Terminal (Bash)

    Your operating system needs to provide a Bash terminal, many steps of this guide will be executed on the shell.

    You are free to use another local shell for your work, but the scripts provided by the TYPO3 Core (most importantly runTests.sh) require Bash to be available.

  5. Git client

    This guide expects you can execute git terminal commands.

    This guide uses the https method to connect to GitHub, so you do not need to have a GitHub account.

  6. SSH client plus SSH key(s) and an email account

    This guide expects you can execute ssh terminal commands and connect to foreign hosts. You will need a private SSH key pair and know how to authenticate with it. You need an email account to setup accounts.

  7. PHP IDE / Editor

    It is recommended to use a good PHP IDE. As part of the target audience of this guide you should already use something like PhpStorm, Visual Studio Code, vi(m)...

  1. Assumed path structure and name usage

    We will use:

    • $HOME/work/TYPO3-Contribute/ as your working directory (created in the guide).
    • John Doe to be your name.
    • john.doe@example.com to be your email address that you used for all accounts.
    • john-doe to be your TYPO3.org username.
    • A TYPO3 legacy mode installation (Non-Composer) with MariaDB 10.11 and PHP 8.2.

    Adjust any occurences of this to match your environment.

Quick Start: Accounts needed

  1. My TYPO3 (https://my.typo3.org)

    Vital account! Acts as a Single Sign On (SSO) provider for several other services. See Signup for a TYPO3.org Account.

  2. Gerrit (https://review.typo3.org)

    The code review system that is used for your code contributions. There, all patches are commented and voted/approved/rejected.

    First login via the My TYPO3 SSO account. Afterwards you need to upload your SSH public key here. See Setting up Gerrit (ssh).

  3. Forge (https://forge.typo3.org/)

    The issue tracking platform (Redmine) where bugs and feature requests are reported. Every patch in Gerrit needs to have a corresponding issue.

    You login here via the My TYPO3 SSO account.

  4. Slack (https://typo3.slack.com/)

    The chat platform where developers get in touch with each other. The channel #typo3-cms-coredev is important.

    You need to register an account for Slack, see https://typo3.org/community/meet/chat-slack/ and Slack.

Quick Start: Set up Git repository

  1. Init directory and clone Repository

    Create contribution folder and clone TYPO3 into a it
    mkdir -p $HOME/work/TYPO3-Contribute && \
        cd $HOME/work/TYPO3-Contribute && \
        git clone https://github.com/typo3/typo3.git .
    Copied!
  2. Set up Git specifics

    Set up git user meta data and repository
    git config user.name "John Doe" && \
        git config user.email "john.doe@example.com" && \
        git config remote.origin.pushurl \
            ssh://john-doe@review.typo3.org:29418/Packages/TYPO3.CMS.git && \
        git config remote.origin.push +refs/heads/main:refs/for/main
    Copied!
    Configure recommended git options only for the repository
    git config branch.autosetuprebase remote
    Copied!
    Install hooks and git commit template
    mkdir -p .git/hooks && \
      cp Build/git-hooks/commit-msg .git/hooks/commit-msg && \
      cp Build/git-hooks/unix+mac/pre-commit .git/hooks/ && \
      chmod +x .git/hooks/commit-msg && \
      chmod +x .git/hooks/pre-commit && \
      {
        echo '[BUGFIX|TASK|FEATURE|DOCS]'
        echo ''
        echo 'Resolves: #'
        echo 'Releases: main'
      } > $HOME/.gitmessage-typo3.txt && \
      git config commit.template $HOME/.gitmessage-typo3.txt
    Copied!

Quick Start: Set up DDEV

  1. Set up DDEV with default convention

    Create a suitable ddev configuration
    ddev config \
        --project-name='t3c-main' \
        --project-type='typo3' \
        --docroot='.' \
        --database='mariadb:10.11' \
        --php-version='8.2' \
        --composer-version='stable' \
        --nodejs-version='22' \
        \
        --project-tld='ddev.site' \
        --router-http-port='80' \
        --router-https-port='443' \
        --webserver-type='apache-fpm' \
        --additional-hostnames='t3c-dev.ddev.site,t3c-prod.ddev.site' \
        \
        --timezone='Europe/Berlin' \
        --web-environment='TYPO3_CONTEXT=Development' \
        --webimage-extra-packages='build-essential,locales-all'
    Copied!

    Adapt parameters as wanted.

    The output should be similar to this:
    Creating a new DDEV project config in the current directory (/.../TYPO3-Contribute)
    Once completed, your configuration will be written to /.../TYPO3-Contribute/.ddev/config.yaml.
    
    Configuring a 'typo3' named 't3c-main' project with docroot '.' at /.../TYPO3-Contribute
    TYPO3 does not seem to have been set up yet, missing LocalConfiguration.php (/.../TYPO3-Contribute/typo3conf/LocalConfiguration.php)
    Generating AdditionalConfiguration.php file for database connection.
    Configuration complete. You may now run 'ddev start'.
    Copied!
  2. Start DDEV instance

    Start configured ddev project
    ddev start
    Copied!
    The output should be similar to this:
    Starting t3c-main...
    Building project images...
    .................Project images built in 17s.
    Network ddev-t3cmain_default  Created
    Container ddev-t3c-main-db  Created
    Container ddev-t3c-main-web  Created
    Container ddev-t3c-main-db  Started
    Container ddev-t3c-main-web  Started
    Waiting for containers to become ready: [web db]
    Starting ddev-router if necessary...
    Container ddev-router  Running
    Waiting for additional project containers to become ready...
    All project containers are now ready.
    Successfully started t3c-main
    Project can be reached at https://t3c-main.ddev.site https://t3c-dev.ddev.site.ddev.site https://t3c-prod.ddev.site.ddev.site https://127.0.0.1:32802
    Copied!

Quick Start: Set up TYPO3

  1. Perform composer install

    Note that we encourage to use the TYPO3 Core runTests.sh runner, and thus do not use a local or DDEV composer command directly:

    Install composer dependencies using default php version
    ./Build/Scripts/runTests.sh -s composerInstall
    Copied!

    Bear in mind: Even though we use composer to install dependencies, the resulting TYPO3 installation will be in Legacy mode, not Composer-Mode. This is still how TYPO3 performs most of its core testing and development.

  2. Set up TYPO3 database

    Note that we perform the setup using the automatable TYPO3 Console, not the Web GUI. All command options use the DDEV configuration conventions, (db:db@db), you do not need to adapt this.

    Setup the instance using the TYPO3 setup command
    ddev exec touch FIRST_INSTALL && \
        ddev typo3 setup \
            --driver=mysqli \
            --host=db \
            --port=3306 \
            --dbname=db \
            --username=db \
            --password=db \
            --admin-username=john-doe \
            --admin-user-password='John-Doe-1701D.' \
            --admin-email="john.doe@example.com" \
            --project-name='TYPO3 Contribution' \
            --no-interaction \
            --server-type=apache \
            --force
    Copied!
    This should result in a message:
    âś“ Congratulations - TYPO3 Setup is done.
    Copied!
  3. Activate EXT:styleguide

    Ensure extension setup and activate required extensions (EXT:styleguide, EXT:indexed_search)
    ddev typo3 extension:setup && \
        ddev typo3 extension:activate indexed_search && \
        ddev typo3 extension:activate styleguide
    Copied!
    Setup all default backend user groups
    ddev typo3 setup:begroups:default --groups=Both
    Copied!
    Create styleguide TCA and FRONTEND page tree
    ddev typo3 styleguide:generate --create -- tca && \
        ddev typo3 styleguide:generate --create -- frontend-systemplate
    Copied!
    Which should give this output:
    [OK] Extension(s) "core, filelist, frontend, impexp, lowlevel, form, extbase, fluid, fluid_styled_content, install,
        reports, redirects, setup, rte_ckeditor, adminpanel, backend, belog, beuser, dashboard, extensionmanager, felogin,
        info, seo, sys_note, tstemplate, viewpage" successfully set up.
    [OK] Activated extension styleguide successfully.
    [OK] Backend user group(s) created: Editor, Advanced Editor
    TCA page tree created!
    Frontend page tree created!
    Copied!

    Note there remain some extensions disabled (filemetadata, indexed_search, linkvalidator, opendocs, reactions, recycler, scheduler, webhooks, workspaces). If you plan to work on these, activate them similarly, or use the Extension Manager in the TYPO3 Backend.

  4. Log in to TYPO3

    You should now be able to log in to the TYPO3 backend with the username and password as specified above (john-doe : John-Doe-1701D.) by calling:

    Open up the TYPO3 Backend for the ddev instance
    ddev launch typo3
    Copied!

Quick Start: Create a patch

Please read Quick Start: Create a patch - Intention for a longer text about an example which kind of patch you could contribute.

Now with this example in mind, we have two modified files that we want to commit:

  • typo3/sysext/backend/Classes/Form/Element/JsonElement.php
  • typo3/sysext/backend/Tests/Unit/Form/Element/JsonElementTest.php
  1. Create a matching Forge Ticket

    Every patch needs to have a reason to be introduced. For this, you need to create an issue on Forge, see Introduction to Forge. With our example you could create an issue like:

    Tracker: Task

    Subject: The TCA Json FormEngine input needs a HTML5 attribute "input-type='json'"

    Description: (Describe why the attribute would be needed. Conclude with "I will create a patch for this" to let other know you'll be working on it)

    Now note down the number of your issue which you can see next to the title after creation, or in the URL (for example: 12345).

  2. Ensure proper Git state

    Make sure you are in the right directory and following the previous steps, you should not have any other modified files:

    Check git status of the repository
    git status
    Copied!

    The output should be:

    On branch main
    Your branch is up to date with 'origin/main'.
    
    Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git restore <file>..." to discard changes in working directory)
        modified:   typo3/sysext/backend/Classes/Form/Element/JsonElement.php
        modified:   typo3/sysext/backend/Tests/Unit/Form/Element/JsonElementTest.php
    
    no changes added to commit (use "git add" and/or "git commit -a")
    Copied!
  3. Add changed files to git stage:

    Add single files to git stage to be pre-selected for a commit
    git add typo3/sysext/backend/Classes/Form/Element/JsonElement.php && \
        git add typo3/sysext/backend/Tests/Unit/Form/Element/JsonElementTest.php
    Copied!

    If your change is a breaking, a feature or deprecation, add a Changelog entry.

  4. Commit the files

    Create a git commit for files in the git stash
    git commit
    Copied!

    Now your default terminal editor should open (usually vi or nano) and show this:

    The commit message template is loaded to help with commit message structure
    [BUGFIX|TASK|FEATURE|DOCS]
    
    Resolves: #
    Releases: main
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    #
    # On branch main
    # Your branch is up to date with 'origin/main'.
    #
    # Changes to be committed:
    #       modified:   typo3/sysext/backend/Classes/Form/Element/JsonElement.php
    #       modified:   typo3/sysext/backend/Tests/Unit/Form/Element/JsonElementTest.php
    #
    Copied!
    Replace that to read:
    [TASK] Add HTML5 spec "input-type='json'" to TCA type=json
    
    Resolves: #12345
    Releases: main
    Copied!

    Close your editor with saving the commit message. For proper formatting and wording of a commit message, please read the details in Commit Message rules for TYPO3 CMS.

  5. Push to Git repository

    Push the commit to configured remote push url (Gerrit)
    git push
    Copied!
    Output:
    Enumerating objects: 11859, done.
    Counting objects: 100% (11859/11859), done.
    Delta compression using up to 10 threads
    Compressing objects: 100% (3900/3900), done.
    Writing objects: 100% (9919/9919), 3.06 MiB | 9.53 MiB/s, done.
    Total 9919 (delta 6847), reused 8104 (delta 5373), pack-reused 0 (from 0)
    remote: Resolving deltas: 100% (6847/6847)
    remote: Processing changes: refs: 1, new: 1, done
    remote:
    remote: SUCCESS
    remote:
    remote:   https://review.typo3.org/c/Packages/TYPO3.CMS/+/85025 [TASK] Add HTML5 spec "input-type='json'" to TCA type=json [NEW]
    remote:
    To ssh://review.typo3.org:29418/Packages/TYPO3.CMS.git
    * [new reference]         main -> refs/for/main
    Copied!
  6. Open review URL

    Open the given URL https://review.typo3.org/c/Packages/TYPO3.CMS/+/85025 in your browser. You should now see your contributed patch!

    Also, automatically the Pipeline will now run server-side tests on your patch. Coding Guidelines will be addressed. This may lead to further patch modification.

  7. Announce your patch, gather feedback, improve

    Sometimes, feedback will come naturally to your patch, by people seeing it in the Gerrit patch pipeline.

    You are welcome to join the Slack channel #typo3-cms-coredev and advertise your contribution for feedback.

    You might want to check Common code review checks / checklist for things that people will review in your patch, hopefully leading to be merged.

    Depending on the feedback you may need to further refine your patch.

    You can do this by locally editing your files. Then it is vital that you do not perform a new git commit, but always only amend your commit:

    # ... edit files
    # ... commit all changed files
    git commit -a --amend
    git push
    Copied!

    See Upload a new Patch Set for details.

  8. Cleaning up

    It's important to cleanup your local checkout after working on a change or reviewing it, to avoid stacking multiple changes into a not intentional relation chain. See resetting for information on this.

  9. Special notes

    In some cases you may need to alter assets of the TYPO3 Core, like TypeScript or SCSS. See Building for how to build and then commit these files to your patch.

  10. Thank you!

    The TYPO3 community is thankful for you following this guide, and we hope once you have set up your development environment for it you can enjoy being an active contributor!

Quick Start: Reviewing and contributing more

Now that you followed this guide, you have a setup to continuously work with. It has hopefully not taken up much of your time.

With your environment, you can:

  1. Keep up to date with development

    By executing this in your working environment, you can always catch up to the latest main TYPO3 version:

    Stash away things you may be working on
    git stash
    Copied!
    Reset to current upstream state
    Build/Scripts/runTests.sh -s clean && \
        git fetch --all && \
        git reset --hard origin/main && \
        git pull --rebase && \
        ./Build/Scripts/runTests.sh -u && \
        ./Build/Scripts/runTests.sh -s composerInstall && \
        ddev typo3 cache:flush && \
        ddev typo3 cache:warmup && \
        ddev typo3 extension:setup
    Copied!

    This resets your local state to the the current upstream state, including recently merged changes. This may involve changes in Composer dependencies, database changes or changes in the Dependency Injection container configuration. The steps above are a fail-safe way to ensure a working environment:

    Check status of the repository
    git status
    Copied!
    ... which should output something similar to following:
    On branch main
    Your branch is up-to-date with 'origin/main'.
    
    nothing to commit, working tree clean
    Copied!

    After that, you should also log into the TYPO3 backend and ensure via the Database Analyzer that your database is up to date.

  2. Coordinate with the team

    You can review and vote on other people's patches, gather knowledge and enjoy improving TYPO3 as a whole.

    You can check out any Patch on gerrit on your updated instance:

    Check out the patch and changeset by using the corresponding download link in Gerrit
    git fetch https://review.typo3.org/Packages/TYPO3.CMS refs/changes/25/85025/1 \
        && git cherry-pick FETCH_HEAD
    Copied!
    Ensure working state for checkout change
    ./Build/Scripts/runTests.sh -s composerInstall && \
        ddev typo3 cache:flush && \
        ddev typo3 cache:warmup && \
        ddev typo3 extension:setup
    Copied!

    Also maybe execute 'Database Analyzer' and clear browser cache

    After that you can git commit --amend && git push and publish new patch sets.

    You can even commit and contribute on other people's patches - always make sure to ask first, before you do that.

  3. Read on

    Further information on reviewing and contributing:

Report an Issue

Introduction to Forge

The issue tracker Forge is currently based on Redmine. It is used to report and handle open issues (including bugs and feature requests).

Note that Forge is not only used for the Community to report bugs and features, but also the Core development team creates issues for each and every change to TYPO3.

First, get yourself an account, see Setting up Your Accounts.

When you want to report a bug or suggest a new feature, go to the "Issues" section for the TYPO3 Core.

Searching for Existing Issues

Before you go ahead and report a bug, it is recommended that you check Forger to see if the same issue or something similar has already been reported.

Forger's search functionality makes it easy to find existing issues. Filters are located on the the left hand side of the navigation menu. You can use this feature to help refine searches.

Of course you are also able to use the search functionality of Forge itself, which offers some more specific filter options.

You help the people maintaining the issue tracker a lot by first making sure your problem is not covered already. The less duplicate issues our team needs to triage, the more time we have for actually addressing bugs and features.

Identify the Issue

Before you report a bug or suggest a new feature, make sure that the issue you report will be helpful by following these guidelines:

Remove side effects
Work on a TYPO3 instance which is as clean as possible so you can rule out extensions messing with the TYPO3 Core. If you need to set up an extension to illustrate the problem, make sure it is as free of side effects as possible. Ideally, try to reproduce your problem or feature by using existing Core extensions (like Use EXT:styleguide).
Narrow down the problem
Try different browsers, this will help the team (and you) a lot to provide a proper description of the problem.
Be up to date

First of all you should make sure that the bug does exist on the latest TYPO3 version; we always recommend you to upgrade your TYPO3 environment to the latest release of the LTS version, see https://get.typo3.org/.

Or even better: use the latest version from git (main).

Be explicit
It can take a lot of time to reproduce or understand issues. Please try to be as brief as possible, but as detailed as needed. Supplying code examples to reproduce an issue, or showing screenshots helps a lot!
Remain involved
If we have questions about your issue, and need feedback from you, please ensure you get notified to replies to your issue and try to respond. Often, further details are needed.
Talk to the core team
If you are a developer yourself and are able to address an issue (no matter if bug or feature) yourself, but need some guidance on how to approach it, don't hesitate to talk to us on Slack in the #typo3-cms-coredev channel. (Remember to register first.) This channel is not a support channel for end-users. Those needs are covered by https://typo3.org/help.

Create an issue

Get your typo3.org account, head over to Forge and log in (if you aren't already). You can find the TYPO3 core issue tracker here: https://forge.typo3.org/projects/typo3cms-core/issues.

If you click "New issue" you will see a form with a couple of fields that are important. Let's go over these really quick.

Tracker

The tracker is just Redmine's term for the type of an issue. The trackers you will be using the most are Feature and Bug.

The others are mostly for internal organization (like Stories and Epics) and things which aren't really a feature or a bug... they are just Tasks somebody needs to take care of, because the Core development team also uses this system for their daily work.

Subject

Pick a meaningful subject. Something like "Error in list module" is very generic and doesn't help describing the problem. Just imagine how you would like to get a report for yourself :)

Bad example:
Bug
Good example:
JS error in Internet Explorer when inserting record in list module.

Description

For bugs, provide steps how to reproduce the problem. See Best practices for writing a good bug report for some extra hints on what should go in the description.

Be sure to add images, code snippets and or stacktraces if they help to refine the problem description. See (optional) Files for hints on adding files.

Always keep in mind these points when writing your issue report:

Be detailed in describing your problem
The more detail you add, the higher are the chances that we understand your problem.
Be concise and clear
No one will judge you for your literary skills. We need to understand quickly where the problem lies.
Format your issue
Formatting your report helps readability. For longer text, use headers (h1, h2) to structure it. Use highlighted code (<>) for code snippets. Don't use very long sentences, instead use bullet points. See the section Hints for formatting in Redmine for more information on formatting your text.
Be polite.
Always.

Category

Choose a category that fits your issue.

Core developers tend to identify with certain areas of TYPO3, which are mirrored in the category system (usually by "Core extension" or area).

The better you can classify your problem, the more likely it is that a Core developer will spot your issue in "his area".

TYPO3 version

(for bugs only)

Choose the TYPO3 version, where the error occurs. Ideally try to report an issue for the latest TYPO3 version where your issue applies to.

Older TYPO3 versions outside of the latest LTS support range are less likely to receive attention due to being in "priority bugfix-mode". Only the latest LTS release receives full support, and anything in ELTS support mode is not covered by the issue tracker.

Check https://get.typo3.org/ for supported releases and their state.

PHP Version

(for bugs only)

Choose the PHP version, where the error occurs. If in doubt, leave this blank. Usually, it is enough to supply the TYPO3 version.

(optional) Files

You can additionally uploads files if they help to understand and reproduce the problem.

Some hints for files:

  • Do not copy-paste huge stack dumps into the description. Cut out the relevant parts for the description and add the complete stack dump as extra file.
  • Images can be a huge help in understanding the problem. Do not insert complete screen dumps but clip the image to the relevant parts. If it helps, add boxes or arrows to highlight important things in the image. Use Redmine formatting for inline images
  • If a video is even better in understanding a bug, try to create a short (!) video that clarifies your issue. For example, use an animated gif screen capture tool to create an animated gif.

Best practices for writing a good bug report

It is not necessary to add all available information to your bug report. It is important to provide the specific information that is necessary to be able to understand, reproduce and fix the bug.

Use your common sense and your experience to guide you: What would you need if you wanted to find the bug in the code and fix it yourself? What do you need if you want to reproduce it to debug it or test if the patch solves the problem?

A good bug report should contain all or any of these elements:

  1. Prerequisites:

    Here you can add:

    • A brief description of your environment. Depending on the nature of the bug it might include your operating system (Windows, Linux, macOS, ...), the full version of TYPO3 and PHP, the webserver used, the database used (MySQL, MariaDB, ...) and its version. In any case, the full version of TYPO3 (e.g. 12.4.22) is very helpful. If your bug is reproducible on several versions (e.g. 13.4.0 and 12.4.22), that is helpful as well.
    • A description of the TYPO3 setup that you are using or that is necessary to trigger the bug. Your issue came out using TYPO3 with multiple languages? Or when you have more than two frontend groups? You have to tell us, otherwise we could not be capable of reproducing your issue.

    We don't need a full description of your environment, or the full TypoScript configuration, but just the parts that are relevant to trigger the bug.

  2. Steps to reproduce the problem

    This is a short easy-to-follow guide that allows us to understand how to trigger the bug following it. Using a numerated list of steps is just fine here; you can also add screenshots. If possible, use TYPO3 Core extensions like Use EXT:styleguide to make an issue reproducible. The easier our support helpers are able to follow your instructions, the more likely it is we can also find the problematic area in the TYPO3 code.

  3. Actual results

    This is the heart of your problem: what happened after you followed the steps? Please add also here if your problem is repeatable or comes out randomly.

  4. Expected results

    What you expected to happen instead.

  5. Additional notes

    Additional information like special conditions or other details not reported on the previous points.

Please consider that these guidelines are very generic. Not always all these parts are necessary, but having the necessary information could help a lot to reproduce and fix the bug.

This not only applies to bugs, but also feature requests. For feature requests, state why a change is needed/helpful, what problems it solves. TYPO3 is a very modular and highly configurable system - not every feature needs to be solved in the TYPO3 core, but can be an extension (maybe yours!) instead.

Hints for formatting in Redmine

Redmine offers quite a few text formatting options: use them to make your report readable. Remember, good formatting makes reading the bug report easier and increases the probability that people will be able to reproduce the problem and help with fixing, testing and merging patches. During the life cycle of a bug report and patch, several people will be reading your report. High readability and clarity makes things easier for everyone and saves time.

Images

If you attach images (which makes sense, because a screenshot says more than 1000 words), consider displaying it inline in your description using exclamation marks to wrap your filename in - this saves everybody a click and makes it easier to understand which image goes where. Do not use fullscreen screenshots, provide a screenshot of the relevant parts of the problem.

Example:

Redmine inline formatting
!filename.png!
Copied!

See:

Code formatting

Do not add screenshots of code, use the <pre><code> tags in Redmine so we can search for the lines of code via Forger.

Continued workflow

So, you've filed an issue following the steps above, and submitted it.

What now? Read further in Issue Workflow (Forge).

Additional Resources

... highlight:: shell

Create a Patch

Quick links:

So you want to fix a bug or add a new feature to TYPO3? Great!

Step by Step Walkthrough

You should have a cloned Git repository with a working TYPO3 installation as described in setup (or via the Quick start guide). Especially the Git setup is required.

  1. Create an Issue on Forge

    More information: Report an Issue

    Every patch must have a matching issue on Forge, so create an issue now or submit a patch for an existing issue.

  2. Make your changes to the code, add documentation, tests

    This part is pretty straightforward. But be warned, there are still a few dark places deep inside the TYPO3 core dating back to the medieval times of PHP4. Yes, TYPO3 has been around for quite some time now. And there is ancient code we didn't have to touch yet because it just works.

    Make sure to look at How to deprecate classes, methods, arguments and hooks in the TYPO3 core in the Appendix for information about how to deprecate things if you need to make changes to the public API.

    For new features, breaking changes and deprecations, it is necessary to add information to the changelog.

    If you change SCSS, JavaScript or TypeScript files, you can build locally.

    Add Unit Tests or Functional Tests for new functionality, refine existing tests if necessary. Tests are important because they ensure that TYPO3 will behave consistently now and in the future.

    See Testing the core in TYPO3 Explained for more information about writing and running tests.

    Once you have finalized your patch, check out the Common code review checks / checklist for a list of what kind of review checks people may perform on your contribution. Stay ahead of the game and address those yourself first.

  3. Commit your changes

    Please make sure that you read the Commit Message rules for TYPO3 CMS in the Appendix. Your code will not be merged if it does not follow the commit message rules.

    For a bugfix, your commit message may look something like this:

    commit message
    [BUGFIX] Subject line of max 52 chars
    
    Some descriptions with line length of max. 72 characters
    
    Resolves: #12346
    Releases: main, 13.4
    Copied!

    Only create one commit. Do not create a branch. Work on main.

    shell command
    git commit -a
    Copied!

    The commit-msg hook will do some sanity checks and add a line starting with Change-Id:.

    If you have activated the pre-commit hook it will loudly complain if something does not conform to the coding guidelines.

    In that case, use the runTests.sh script to to fix CGL issues.

    After you have created your commit, you can still make changes by amending to your commit:

    shell command
    git commit -a --amend
    Copied!
  4. Push to Gerrit

    To submit the patch to Gerrit, issue the following command:

    shell command
    git push origin HEAD:refs/for/main
    Copied!

    If you have setup the default as described in Setting up Your Remote it is sufficient to use:

    shell command
    git push
    Copied!

    In case you want to push a "Work in progress", check out: Workflow - work in progress.

    If Gerrit accepts your push, it responds with the following messages:

    result
    remote: SUCCESS
    remote:
    remote:   https://review.typo3.org/c/Packages/TYPO3.CMS/+/<gerrit-id> [...] ... [NEW]
    remote:
    To ssh://review.typo3.org:29418/Packages/TYPO3.CMS.git
    * [new reference]         main -> refs/for/main
    Copied!

    If you see an error, check out the Git Troubleshooting section.

    You can visit the link to https://review.typo3.org to see your patch in Gerrit.

    The Continuous Integration service, running on GitLab Pipelines, will automatically be executed in the background and perform checks and tests on your patch. Failing tests will be linked to that instance, where jobs can also be retried (given sufficient permissions when being logged in to GitLab).

    Advanced users / core team only: See cheat sheet: other branches for pushing to other branches.

  5. Optional: Advertise review on Slack channel
Once your push to Gerrit goes through, you will receive a URL for your new

change. If you are on Slack you can now advertise your new change in the #typo3-cms-coredev channel. You can get a preformatted line of your change to post in the channel by clicking the copy button next to the title in Gerrit_:

This is not something, you will do for every review. As a first contributor it is recommended to mention that you are new to the process.

Now, it's time to sit back and await feedback on your changes. The review team process dozens of requests each day, so expect a succinct response that is short and to the point. You will get notified by email, if there is activity on your patch in Gerrit (e.g. votes, comments, new patchsets, merge etc.).

Check out the section Review a patch for more about this process, in which you can also be involved!

It is not unusual for a patch to get comments requesting changes. If that happens, please respond in a timely fashion and improve your review. If things are unclear, ask in the #typo3-cms-coredev channel on https://typo3.slack.com.

Next Steps

You will find some more information about the review process in the chapter Handle and Improve a Patch (Gerrit). The following pages are especially relevant for new contributors:

  • Tips for new contributors
  • Introduction to Gerrit describes the review tool Gerrit.
  • Find a review on Gerrit is helpful if you don't know how to find your patch on Gerrit.
  • Gerrit works with up- and downvoting patches. A patch must get a specific number of upvotes before it can be merged. Code Review gives an introduction to how this works.
  • When you make additional changes to your patch, make sure you do not add another commit. Append to your original commit instead as described in Upload a new Patch Set.
  • Before starting to work on a new, unrelated patch you need to run the Cleanup tasks.

Building assets

This page explains building assets like JavaScript and CSS files.

For the most part, the TypeScript, JavaScript and SCSS sources are contained in Build/Sources. These are compiled to target files, usually located in:

  • CSS: typo3/sysext/*/Resources/Public/Css
  • JavaScript: typo3/sysext/*/Resources/Public/JavaScript

If you make changes to the source files, you can build locally using runTests.sh:

Build/Scripts/runTests.sh -s build
Copied!

Note you can also use npm + nvm locally, if you are proficient with setting this up locally.

It is also possible to lint the files locally:

Build/Scripts/runTests.sh -s lintScss
Build/Scripts/runTests.sh -s lintTypescript
Copied!

Remember to commit the compiled files alongside any patches, they are part of the monorepo.

Add Documentation

Quick links:

The documentation TYPO3 Core Changelog and documentation for System Extensions is maintained in the Core.

Quickstart to contribute documentation

To work on the Core documentation of TYPO3, you need to work with the main TYPO3 mono-repository. You can not contribute Documentation patches on single read-only repositories like https://github.com/typo3-cms/felogin through the GitHub interface!

You can, however, use the GitHub interface and contribute to https://github.com/TYPO3/typo3/tree/main/typo3/sysext/felogin. Submitting a GitHub PR will result in a GitHub Action workflow that closes your PR, transfers it to forge, transfers it to gerrit, and link them to each other. That workflow can be prone to errors though, especially if a branch other than main is involved.

So, if possible you could better follow the Quickstart guide to set up a Core contribution installation. A lot can be left out, as you do not necessarily even need a TYPO3 instance running when you only want to contribute documentation.

The minimal steps to contribute documentation "the right way" (and to allow you to properly participate in our review workflow) is this:

  1. Prerequisites

    From the Quickstart Prerequisites you need:

    1. Operating System
    2. GIT client
    3. SSH client + keys
    4. Optional Bonus: Docker (to render documentation), a suitable Text-Editor
  2. Set-up accounts

    You need all of the Quickstart Accounts (My TYPO3, GitHub, Gerrit, Forge)

  3. Set-up GIT

    Set up and clone the TYPO3 mono-repository as described in Quickstart GIT.

    Note: the steps Quick Start: Set up DDEV and Quick Start: Set up TYPO3 are not needed for Documentation-only use.

  4. Start documenting

    Now you can start editing files in, for example, typo3/sysext/felogin/Documentation/Index.rst and when you are done, you can render the documentation (see Render any system documentation locally) to verify the look of your changes.

  5. Create issue

    Once you feel comfortable and happy with your patch, you go to create an issue on Forge. Choose the category Documentation and enter an appropriate description like:

    Tracker: Task

    Subject: Add example for EXT:felogin RedirectLoginHandler

    Description: (Describe what kind of documentation changes you made. Mention to which TYPO3 version it applies)

  6. Submit patch

    Now follow the steps outlined in Quick Start: Create a patch, and refer to the Documentation files you edited, instead of the PHP files given as examples there. This will then submit your patch to our Gerrit review instance.

Changelog

Some patches require a .rst (reStructuredText) Changelog file describing the change. Not all patches need an entry in the Changelog. Check the list below. Also see the current TYPO3 Core Changelog for some examples.

Every file may optionally contain tags, but it must contain at least a NotScanned, PartiallyScanned or FullyScanned tag for the extension scanner. See Extension scanner in TYPO3 Explained for more information.

Render the Changelog locally

If you have Docker or Podman installed you can try out the rendering of the changelog locally:

cd typo3/sysext/core
docker run --rm --pull always -v $(pwd):/project -it ghcr.io/typo3-documentation/render-guides:latest --config=Documentation
xdg-open "Documentation-GENERATED-temp/Index.html"
Copied!
cd typo3/sysext/core
docker run --rm --pull always -v $(pwd):/project -it ghcr.io/typo3-documentation/render-guides:latest --config=Documentation
xdg-open "Documentation-GENERATED-temp/Index.html"
Copied!

Render any system documentation locally

As above, you can render any extension locally, too. You need to change the directory to the extension directory you want to render. For EXT:felogin that would be:

cd typo3/sysext/felogin
docker run --rm --pull always -v $(pwd):/project -it ghcr.io/typo3-documentation/render-guides:latest --config=Documentation
xdg-open "Documentation-GENERATED-temp/Index.html"
Copied!
cd typo3/sysext/felogin
docker run --rm --pull always -v $(pwd):/project -it ghcr.io/typo3-documentation/render-guides:latest --config=Documentation
xdg-open "Documentation-GENERATED-temp/Index.html"
Copied!

Forger reST Helper

Use the Forger reST Helper to generate changelogs.

This is strongly recommended because the tool will generate correctly formatted files. You can always add more to the .rst file directly later.

Select the type of rst snippet you want to create, enter your issue number and click the search button. Select appropriate tags.

When you are done, copy the generated text and create a file with the same name as suggested in the generator in typo3/sysext/core/Documentation/Changelog/....

Types of Changes

There are four different types of changes which have to follow a certain format and always need to go into typo3/sysext/core/Documentation/Changelog/<release>/.

Choose one which fits your patch:

Breaking Changes

A patch moved or removed a specific part of core functionality that may break extensions if they use this part.

Mandatory sections:

  1. Description - why things had to break backwards compatibility.
  2. Impact - how will the change affect your installation.
  3. Affected Installations - describe scenarios under which circumstances a TYPO3 install will be affected by this change.
  4. Migration - provide instructions what needs to be done to get things working again. Explicitly mention if no migration is possible.

Deprecations

A patch deprecates a certain core functionality for a planned removal. See more information: Deprecations

Mandatory sections:

  1. Description - why things had to be deprecated.
  2. Impact - how will the change affect your installation.
  3. Affected Installations - describe scenarios under which circumstances a TYPO3 install will be affected by this change.
  4. Migration - provide instructions what needs to be done to get things working again. Explicitly mention if no migration is possible.

Features

A patch adds new functionality.

Mandatory sections:

  1. Description - what can the new feature do.
  2. Impact - how users are affected by this new feature.

Important Information

Anything that does not fit the other categories but is important enough to require a Changelog entry.

  1. Description - describe what is so important it needed an rst snippet

Check Your rst File

When your change is finished, you can run the following script to check that your rst file is ok. The script will check all files in typo3/sysext/core/Documentation/Changelog:

shell command
Build/Scripts/validateRstFiles.php
Copied!

This script will check if the .rst files contain all mandatory tags that are required for the Changelog. It will not do a reST syntax check.

In order to make sure that your file contains no syntax errors and will be rendered correctly, do one or more of the following:

Policy for Changing the Main Documentation

Once a new TYPO3 release comes out, the main documentation (e.g. TYPO3 Explained, TCA Reference etc.) must be updated.

The procedure is documented in Apply changelog entries to the docs.

Document System Extensions

Documentation for system extensions is maintained within a Documentation directory in the respective system extension directory, e.g. typo3/sysext/form/Documentation.

Not all system extensions have their own documentation. Some documentation (e.g. for the system extension core) is maintained within the TYPO3 Explained.

If in doubt, ask in the #typo3-cms-coredev channel on Slack.

For starting a system extension from scratch, please see Use the init command to create the Documentation folder.

For an overview of the rendered documentation for system extensions, see System Extensions.

When you have made changes to the documentation, you can render locally with docker to test your changes as described in Render the Changelog locally.

More Information

Using runTests.sh

What is runTests.sh?

This is a shell script which is included in the TYPO3 Core git repository. It used to supply commands for running tests, but has since evolved to include other commands as well for checking, fixing, building etc. It will be used for a number of tasks and will be a vital part during your Core contribution workflow.

The script uses Docker (also supporting podman) and several Docker images to run the tasks - using the correct versions (of PHP, Node/NPM etc.) for the current branch of your TYPO3 repository.

Show help

It is recommended to use the -h option (help) to show the help output and especially look at the beginning of the output for a description and the listing of dependencies. The listing in section -s shows available commands, and the bottom lists several examples you can copy+paste to try.

Show help:

shell command
Build/Scripts/runTests.sh -h
Copied!

Prerequisites

See the listed options/commands in the help output.

Options

-h
show help
-s
choose the command to run (if omitted, unit tests are run)
-p
PHP version (if omitted, the default version is used)
-b
choose podman (default) or docker for image execution
-d
Database type (sqlite, mariadb, mysql, postgres)
-i
Database version in conjunction with -d, for example -d mariadb -i 11.4 for MariaDB 11.4
-x
Enable xdebug usage
-u
Update docker image versions

For more options, see the help (-h).

We will quickly go over each type of command next.

Output example:

Options:

-s <...>
    Specifies which test suite to run
        - acceptance: main application acceptance tests
        - acceptanceInstall: installation acceptance tests, only with -d mariadb|postgres|sqlite
        - build: execute frontend build (TypeScript, Sass, Contrib, Assets)
        - cgl: test and fix all core php files
...
Copied!

Commands

We categorize the commands and show some examples here. It is recommended to use -h as described previously to view the help output and examples. The trailing * is used as wildcard to indicate that there are further commands which start with the same string.

Commands for building:

  • -s composerInstall: install composer dependencies from composer.lock
  • -s build: build CSS+JS assets
  • ...

Checks and fixes, run static analyzer, lint etc:

  • -s cglGit : check (and fix!) the CGL issues in the files which are in the most recent git commit
  • -s cgl (cgl*)
  • -s lintPhp
  • -s lintScss (lint*)
  • -s phpstan (phpstan*)
  • -s checkComposer (check*)
  • ...

Commands for running tests:

  • -s unit (unit*)
  • -s functional (functional*)
  • -s acceptance (acceptance*)
  • ...

Cleanup, clear cache:

  • -s clean (clean*)
  • ...

Dispatchers:

  • -s npm -- [npm command]
  • -s composer -- [composer command]

Additional setup

Be sure to exclude the typo3temp and .cache directory from indexing in your IDE (e.g. PhpStorm) before starting the acceptance tests.

Also, if you are using DDEV for example with Mutagen performing filesystem synchronization, it is vital that you configure the typo3temp and .cache directory to be excluded in your file .ddev/mutagen/mutagen.yml like this:

sync:
  defaults:
    mode: "two-way-resolved"
    stageMode: "neighboring"
    ignore:
      paths:
        # ...
        - "typo3temp/"
        - "public/typo3temp"
        - ".cache"
        # ...
Copied!

Due to the testing framework and involved components like PHPstan, PHPUnit and Composer writing many, many small files this can make your tests several HUNDREDS percent slower, especially on macOS.

Examples

All examples expect to be executed from a git cloned working directory of TYPO3 CMS main branch (as described in TYPO3 Core Contribution Guide).

composer install

Run composer install:

shell command
Build/Scripts/runTests.sh -s composerInstall
Copied!

CGL check and fix

Perform checks on Coding Guidelines and fix them.

This applies the command only to the files in the latest commit:

shell command
Build/Scripts/runTests.sh -s cglGit
Copied!

If you only want to see possible fixes being applied, you can execute the command in "dry-run" mode:

shell command
Build/Scripts/runTests.sh -s cglGit -n
Copied!

Run all unit tests

shell command
Build/Scripts/runTests.sh
Copied!

Run unit tests with xdebug (uses default port 9000)

shell command
./Build/Scripts/runTests.sh -x
Copied!

Run specific unit tests with xdebug

shell command
Build/Scripts/runTests.sh -x <directory or file>
Copied!

Example:

Build/Scripts/runTests.sh -x typo3/sysext/core/Tests/Unit/LinkHandling/
Copied!

Run functional tests

shell command
./Build/Scripts/runTests.sh -s functional
Copied!

Run functional tests with PostgreSQL

shell command
./Build/Scripts/runTests.sh -s functional -d postgres
Copied!

Run acceptance tests

shell command
./Build/Scripts/runTests.sh -s acceptance
Copied!

Depending on the power of your local machine you can expect about 30 minutes or more for the acceptance tests.

Troubleshooting

Before diagnosing problems in the script, make sure to check if Docker is running smoothly on your system.

A quick test is to run the docker hello-world image:

shell command
docker run hello-world
Copied!

You should see something like this message:

result
Hello from Docker!
This message shows that your installation appears to be working correctly.
Copied!

See Get Started, Part 1: Orientation and setup

Also, see docker troubleshooting pages for more in-depth information, such as Docker for Mac: Logs and troubleshooting

There is no built-in debugging to the runTests.sh script. It can happen that (docker or other) command execution needs to be debugged.

For this you need to get your hands dirty and inspect the file. Most commands are performed like this:

runTests.sh (excerpt)
lintScss)
    COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt stylelint"
    ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-css-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}"
    SUITE_EXIT_CODE=$?
    ;;
Copied!

to debug this, you can add an "echo" statement to reveal $COMMAND and also put an echo before the ${CONTAINER_BIN} statement, like this:

runTests.sh (excerpt)
lintScss)
    COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt stylelint"
    CONTAINER_COMMAND="${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-css-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c ${COMMAND}"
    echo "EXECUTE:"
    echo $COMMAND
    echo $CONTAINER_COMMAND
    SUITE_EXIT_CODE=$?
    ;;
Copied!

Then when you execute the script, instead of the command being executed, you can see what is used. Copy+paste that execution to your local shell and see if you can spot specific errors. You may want to add options like -v to the $COMMAND to see, why that command may fail.

Results

All results will be displayed on the screen. The script should exit with standard exit codes:

  • 0 means all is ok
  • != 0 means error

Reports of the acceptance tests will be stored in typo3temp/var/tests/AcceptanceReports with screenshots from the remotely controlled browser.

Direct commands without Docker

If you have problems with docker, you can run some of the lowlevel scripts and commands directly. However it does depend on your system, whether they run successfully (due to PHP, composer and other dependencies). The docker / runTests.sh method gives us the possibility to have a controlled environment where the tests run in. That also means, the databases that the functional tests require are already created automatically. That is not the case, if you run the tests locally on your current system.

That being said, running the tests directly is not being officially supported, but you can try this out yourself.

You can look in the source of Build/Scripts/runTests.sh to see which commands the runTests.sh script calls and run these directly (also see the "Troubleshooting" section above). Not everything will work, because there may be dependencies, that are only available in the docker container.

Also, you can run some of the scripts in Build/Scripts directly, which are otherwise just dispatched from within a docker container.

Examples:

Run all unit tests

shell command
bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml
Copied!

Run specific unit tests

shell command
bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml <directory or file>
Copied!

Example:

bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml typo3/sysext/core/Tests/Unit/LinkHandling/

Copied!

Run all functional tests

shell command
bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml
Copied!

Check for Coding Guidelines

The cgl checking commands / scripts not only check, they repair as well! They can also be utilized from GIT hooks.

Mac / Linux:

shell command
Build/Scripts/cglFixMyCommit.sh
Copied!

Windows:

shell command
Build/Scripts/cglFixMyCommit.bat
Copied!

More information

  • More details about the test system, test strategies, execution and set up can be found in TYPO3 explained.

Core testing in depth

Introduction

This chapter is about executing TYPO3 Core tests locally and is intended to give you a better understanding of testing within TYPO3's Core. A full Core git checkout comes with everything needed to run tests in TYPO3.

Core development is most likely bound to the Core main branch - backporting patches to older branches is usually handled by Core maintainers ("Mergers") and often doesn't affect other Core contributors.

The main entry point to perform testing and build-related actions is the helper Build/Scripts/runTests.sh. It works best when executed on a Linux based host but can be run under macOS and Windows with some filesystem performance drawbacks on macOS. It utilizes Docker containers, and more details can be found in Using runTests.sh.

Additionally, it is possible to execute tests on a local system without using Docker. Depending on which test suite is executed, developers may need to configure their environments to run the desired test. We however learned not too many people actually do that as it can become tricky. This chapter does not talk about test execution outside of Build/Scripts/runTests.sh.

System dependencies

Many developers are familiar with Docker. As outlined in the history chapter, test execution needs a well defined, isolated, stable and reliable environment to run tests and also remove the need to manage niche dependencies on your local environment for tests such as "execute functional test 'X' using PostgreSQL with xdebug".

Git and docker (or podman) are required. For standalone test execution, a local installation of PHP is not required. You can even composer install a Core by calling Build/Scripts/runTests.sh -s composerInstall in a container.

If you're using a Mac, install or update Docker to the most recent version using the packaging system of your choice.

If you are using Ubuntu Linux 18.04 or higher, everything should be ok after calling sudo apt-get install git docker once. For other Linux distributions including older releases of Ubuntu, users should have a look at the Docker homepage to see how to update to a recent version. It usually involves adding some other package repository and updating / installing using it. Make sure your local user is a member of the docker group, else the script will fail with something like /var/run/docker.sock: connect: permission denied.

Windows can rely on WSL to have a decent docker version, too.

Quick start

From now on, it is assumed that git and docker (or podman) are available with the most up-to-date release running on the host system. Executing the basic Core unit test suite boils down to:

# Initial core clone
git clone git@github.com:typo3/typo3.git && cd typo3
# Install Composer dependencies
Build/Scripts/runTests.sh -s composerInstall
# Run unit tests
Build/Scripts/runTests.sh
Copied!

That's it. You just executed the entire unit test suite. Now that we have examined the initial Core clone and a Composer install process, we will look at the different ways we can utilize the runTests.sh for other scenarios.

Overview

So what just happened? We cloned a Core, Composer installed dependencies and executed Core unit tests. Let's have a look at some more details: runTests.sh is a shell script that figures out which test suite with which options a user wants to execute, does some error handling for broken combinations and then uses local docker commands to run specific containers with specific options. Using these containers, the actions are performed, and the containers are stopped after execution.

A Core developer doing this for the first time may notice that several container images will be pulled before continuing. These are the dependent images needed to execute certain jobs. For instance, a container providing the specific PHP-version may be fetched. The same containers are used for the TYPO3 CI GitLab Pipeline, even utilizing the same runTests.sh script. What's impressive is that you can locally run the same tests like a fully-fledged CI server..

The GitLab CI Pipeline is maintained through the Ansible infrastructure found on https://git.typo3.org/typo3/CI/testing-infrastructure/-/tree/main/ansible?ref_type=heads, and the Pipeline itself is set up through https://github.com/TYPO3/typo3/tree/main/Build/gitlab-ci/.

Compared to your local execution it's just that the combinations of tests and splitting to different jobs which is slightly different, for instance GitLab CI paralelly performs multiple tests with more complex version matrixes (PHP and Databases).

If a patch is pushed to GitLab and it complains about something being broken, it is possible to replay and fix the failing suite locally, then push an updated patch and hopefully enable the tests to pass.

A runTests.sh run

Let's pick a runTests.sh example and have a closer look:

lolli@apoc /var/www/local/cms/Web $ Build/Scripts/runTests.sh -s functional typo3/sysext/core/Tests/Functional/Authentication/
PHPUnit 11.2.5 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.2.19
Configuration: /Users/garvin/TYPO3/typo3-core-bugreproduce-base/typo3-core/Build/phpunit/FunctionalTests.xml

................................................................. 65 / 67 ( 97%)
..                                                                67 / 67 (100%)

Time: 00:12.077, Memory: 103.00 MB

OK (67 tests, 176 assertions)

###########################################################################
Result of functional
Container runtime: docker
PHP: 8.2
DBMS: sqlite
SUCCESS
###########################################################################

lolli@apoc /var/www/local/cms/Web $ echo $?
0
lolli@apoc /var/www/local/cms/Web $
Copied!

The command asks runTests.sh to execute the "functional" test suite -s functional and to not execute all available tests but only those within typo3/sysext/core/Tests/Functional/Authentication/. The script first starts the containers it needs: Redis, memcached (previously also MariaDB by default, which is now using SQLite instead, due to less dependencies). All in one network. It then starts a PHP 8.2 container and calls phpunit from there to execute the tests. phpunit executes only one test in this case, that one is green. The containers and networks are then removed again. Note the exit code of runTests.sh (echo $?) is identical to the exit code of the phpunit call: If phpunit reports green, runTests.sh returns 0, and if phpunit is red, the exit code would be non zero.

Examples

First and foremost, the most important call is -h - the help output. The output below is cut, but the script returns a useful overview of options. The help output is also returned if given options are not valid:

lolli@apoc /var/www/local/cms/Web $ Build/Scripts/runTests.sh -h
TYPO3 Core test runner. Execute acceptance, unit, functional and other test suites in
a container based test environment. Handles execution of single test files, sending
xdebug information to a local IDE and more.
...
Copied!

Some further examples: The most important tests suites are unit tests, functional tests and acceptance tests, but there is more:

# Execute the unit test suite with PHP 8.3
Build/Scripts/runTests.sh -s unit -p 8.3

# Execute some backend acceptance tests
Build/Scripts/runTests.sh -s acceptance typo3/sysext/core/Tests/Acceptance/Backend/Topbar/

# Execute some functional tests with PHP 8.2 and postgres DBMS
Build/Scripts/runTests.sh -s functional -p 8.2 -d postgres typo3/sysext/core/Tests/Functional/Package/

# Execute the cgl fixer
Build/Scripts/runTests.sh -s cglGit

# Verbose runTests.sh output. Shows main steps and Composer commands for debugging
Build/Scripts/runTests.sh -v
Copied!

As shown there are various combinations available. Just go ahead, read the help output and play around. There are tons of further test suites to try.

Also note that you can use the -b option to switch between docker and podman container execution, with podman being the default (when available).

One interesting detail should be mentioned: runTests.sh uses several containers from https://github.com/orgs/TYPO3/packages for PHP and JavaScript environments. Use the command Build/Scripts/runTests.sh -u to fetch the latest versions of these containers.

Debugging

To speed up test execution, the PHP extension xdebug is not usually loaded. However, to allow debugging tests and system under tests, it is possible to activate xdebug and send debug output to a local IDE. We'll use PhpStorm for this example.

Let's verify our PhpStorm debug settings first. Go to File > Settings > Languages & Frameworks > PHP > Debug. Make sure "Can accept external connections" is enabled, remember the port if it is not the default port (9000) and also raise "Max. simultaneous connections" to two or three. Note remote debugging may impose a security risk since everyone on the network can send debug streams to your host.

Phpstorm debug settings window

Accept changes and enable "Start listening for PHP connections". If you changed settings, turn them off and on once to read new settings.

Phpstorm with enabled debug listening

Now set a break point in an assignment. Note break points do not work "everywhere", for instance not on empty lines and not on array assignments. The best way is to use a straight command. We'll use a simple test file for now, add a breakpoint and then execute this test. If all goes well, PhpStorm stops at this line and opens the debug window.

Phpstorm with active debug session
Build/Scripts/runTests.sh -x -s functional -p 8.1 -d postgres typo3/sysext/core/Tests/Functional/Package/RuntimeActivatedPackagesTest.php
Copied!

The important flag here is -x! This is available for unit and functional testing. It enables xdebug in the PHP container and sends all debug information to port 9000 of the host system. If a local PhpStorm is listening on a non-default port, a different port can be specified with -y.

If PhpStorm does not break as expected, some adjustments in this area may be required. First, make sure "local" debugging works. Set a breakpoint in a local project and see if it works. If it works locally, the container based debugging should also work. Next, make sure a proper break point has been set. Additionally, it may be useful to activate "Break at first line in PHP scripts" in your PhpStorm settings. runTests.sh mounts the local path to the same location within the container, so path mapping is not needed. PhpStorm also comes with a guide how to set up debugging.

Building

Luckily, runTests.sh also helps us to build JavaScript and CSS assets:

Build/Scripts/runTests.sh -s build
Copied!

Again, this utilizes all the needed containers for the proper NodeJS environment, so you have zero local dependencies on properly building.

You can also run a watch task thanks to the full integration of npm command execution:

Build/Scripts/runTests.sh -s npm -- run watch:build
Copied!

History

Introduction

The TYPO3 Core development has quite an impressive history on automatic testing. This chapter outlines some of the important steps the system went through over the years. It may be just an interesting read but may also explain why things are as they are now.

Next to this chapter, typo3.com blog picks up the testing topic once in a while. If a developer reads this who still needs to convince management persons that testing saves time and money on a project, the series starting with Serious Software Testing may give some ideas.

2009

The first Core unit test has been committed in early 2009. The Core was still using SVN as version control system at this point. More than ten years ago. The tests have later been released with TYPO3 version 4.3 in fall 2009. The system back then relied on the TYPO3 extension phpunit. This TER extension bundled the native phpunit package and added a TYPO3 backend module on top. It found all extensions that delivered unit tests, allowed to execute them and showed the result in the module. This was the first time "green bar feeling" came up: All tests green.

2012

This was after TYPO3 v4.5 times - a version that carried us for a long time. Several TYPO3 Core contributors meanwhile added some hundreds of unit tests in various Core extensions. There was an issue, though: Not too many persons developing the TYPO3 Core cared about unit tests and executed them before providing or merging patches. As a result, tests were frequently failing and only a small group of persons took care and fixed them once in a while. Unit tests and system under test are symbiotic: If one is changed, the other one needs changes, too. If that does not happen, unit tests fail.

However, the young project Travis CI came online and allowed free test environments for open source projects. The TYPO3 Core quickly started using that, a first .travis.yml has been added early 2012 and all merged patches executed the test suite. Persons merging patches got feedback on failed builds and were able to act upon: Either fix the build or revert the patch. The Core Team established an "always green" rule for Core development.

The Travis CI setup at this point basically created a working instance around the checked out the Core to run tests: It additionally cloned a helper repository, cloned the phpunit extension, did set up a database and other stuff, then executed the Core unit tests to result with "good" or "bad".

Until 2018, this first .travis.yml file went through more than 100 changes.

2013

With frequent test execution via Travis CI more and more developers working on the Core were forced to run tests locally to debug tests or add new ones. We slowly got an idea in which situations unit tests are helpful and when they are not.

One flaw in our unit test system became more pressing, though: The phpunit extension that we relied on has been designed to run tests in the backend context of TYPO3 as a module. The unit tests were executed with all the state the backend created to run modules. This was troublesome since lots of unit tests now directly or indirectly relied on this state, too. And worse, this state changed depending on the developers local test system - other extensions that hooked into the system could lead to failing unit tests. With this system, tests tend to execute fine locally but then broke on Travis CI or on some other persons development system. Test execution has at this point already been done via CLI by most developers, and the unit test bootstrap basically created a full TYPO3 backend context similar to the GUI based phpunit extension.

Moreover, we had many tests that somehow changed global state and then influenced other tests. This part lead to the situation that a test worked if executed as single test but failed if executed together with all others - or vice versa.

We ultimately learned at this time that managing system state is an essential part of the Core framework. And so we started refactoring: The Core bootstrap has been hacked into manageable pieces that could be called by the unit test bootstrap in small steps. The tests started to become "real" unit tests that test only one small piece of code at a time.

With improving the unit tests and their bootstrap it also became clear that we needed a second type of tests that do the opposite of unit testing: We wanted to test not only a single isolated fraction of code, we also wanted to test the collaboration of bigger framework parts that includes many classes and database operations. In short: functional testing.

With our learning's from unit tests however it was clear that functional test execution needed to be executed in a well defined and isolated environment to be reliable: We could not just execute them in the context of the local developers system. Moreover, we had to isolate tests from each other: PHP is designed to work on a per-request basis. A CLI or web request comes in, the system bootstraps, does the job, then dies. The next request does a new bootstrap from scratch. This simplifies things a lot for developers since they don't need to take care of request overlapping state and don't need to take care too much about consumed memory. And if a single request dies in the middle of the execution, the next one still may happily work and successfully do its job. This characteristic of a scripting language can be a huge advantage over other server-side languages. And TYPO3 uses this a lot: If a request is finished in TYPO3 context, the system is "tainted" and can't be used for a second request again.

To handle this situation we came up with a functional bootstrap that creates standalone TYPO3 instances per test file. The system sets up a new TYPO3 instance for each test file in an own folder in typo3temp, links over source code from the main system, creates configuration files in this instance, creates a dedicated database and initializes it with all tables needed by extensions loaded in this instance. To then handle the isolation of single requests, each functional test runs as a new forked process that does not carry any information from another test run. Doing all this was expensive, but at least the functional test were so stable that we had very little trouble with tests that execute fine on one system but fail on another one. Additionally, running functional tests could never destroy the main instance.

2014

Next to tons of detail changes, two main steps happened in 2014.

First, the unit test isolation has been finished. The initiative "standalone unit test" changed the unit test bootstrap to execute only a very basic part of the system. Instance specific configuration files like config/system/settings.php were no longer read, no database connection established, the global backend user and language objects were no longer set up and so on. In the end, not much more than the class auto loading is initialized. To reach this, many tests had to improve their mocking of dependencies and had to specify the exact state they needed. With this being done, side effects between tests reduced a lot and a dedicated unit test runner executing tests in random order was added to find situations where test isolation was still not perfect. Nowadays unit testing is pretty stable on all machines that execute them due to these works. With nearly ten thousand tests in place it is rather seldom that a test fails on one machine and is successful on another. And if that happens, the root cause is often a detail down below in PHP itself that has not been perfectly aligned during test bootstrap - for instance a missing locale or some detail php.ini setting.

Second, the test execution was changed to use a Composer based setup instead of cloning things on its own. This was at TYPO3 v6.2 times when Composer was first introduced in TYPO3 world - testing was one of the first usages. In this process we were able to ditch the TYPO3 specific extension based flavor of phpunit and switched to the native version instead. This turned out to be a wise decision since TYPO3 Core testing now no longer relied on development of a third party TER extension but could use the native testing stack directly and for instance pick up new versions quickly.

2015

Functional testing gained a lot of traction: The DataHandler and various related classes in the TYPO3 Core are the most crucial and at the same time complex part of the framework. All the language, multi-site, workspace and inline handling is nifty and it's hard to change code in this area without breaking something. This is still an issue and improving this situation is a mid- to long-term goal. So we decided to use functional tests to specify what the DataHandler does in which situations. There are hundreds of tests that play through complex scenarios, example: "Add some fixture pages and content, call DataHandler to create a localized version in a workspace, call DataHandler to merge that workspace content into live, verify database content is as expected, set up a basic frontend, call frontend as see if expected content is rendered." Nowadays, if changing DataHandler code, functional tests can tell precisely if a change in this area is ok or not. As a result, we don't see many regressions in this area anymore.

Adding so many functional tests has a drawback, though: The needed isolation and expensive functional test setup is rather slow. Executing the functional test suite means creating tens of thousands of database tables. While unit testing is quick (a decent machine handles our ten thousand unit tests in thirty seconds), executing a thousand functional tests can take an hour or more. This can be improved by setting up a database in a memory driven ram disk and some other tricks, but still, functional test execution is clearly not a super charged turbo.

Additionally, we had to increase the test isolation even more: There are test scenarios that execute both backend and frontend functionality. This is hard in TYPO3: A backend request is a backend request and it can't be used as a frontend request at the same time. Extension developers may know this: In TYPO3 it's hard to do frontend requests from within the backend or from CLI - extensions like solr or direct_mail struggle at this point, too and need to find some solution working around this. In functional testing, a test scenario that does a frontend request thus forks processes twice: First, the backend part is executed as standalone process as explained above, which then forks another process to execute the frontend request. As a result, only hard-boiled Core developers tend to work on such functional tests: They are slow, hard to debug and complex to set up.

2016

In early 2016, Core developers added another type of testing: Acceptance tests. Those tests use a browser to actually click around in the backend to verify various parts of the system. For instance, TYPO3 Core had a history of breaking the installation procedure once in a while: Most Core developers set up a local development system once and then never or only seldom see the installation procedure again. If code is changed that breaks the installer, this may go through not noticed. Acceptance testing put an end to this: There are tests to install a fresh TYPO3, log in to the backend, install the introduction extension and then verify the frontend works. The installer never hard broke again since that. Other acceptance tests nowadays use the styleguide extension to click through some complex backend scenarios, verify the backend throws no javascript errors and so on.

We however quickly learned that acceptance testing is fragile: Unit and functional testing has been stabilized very well meanwhile - they do not break at arbitrary places. Acceptance testing however is more complex: A web server is needed, some system to pilot the browser is needed, single clicks may run into timeouts if the system is loaded, pages are sometimes not fully loaded before the next click is performed. Additionally the TYPO3 backend still relies on iframes for all main modules, which again does not simplify things. It took the Core development two further years to stabilize this well enough so acceptance tests could be executed often without throwing false positives at various places. In the end acceptance testing is another great leap forward to ensure major parts of the TYPO3 Core do work as expected.

Another thing became more and more pressing in 2016: The automatic testing via Travis CI started to show drawbacks. We continued adding lots of tests and test suites over the years and executing everything after each code merge took an increasing amount of time. Even with all sorts of tricks, Travis CI was busy for more than half an hour to go through the suite, merging more than two patches per hour thus added to a queue. There were Core code sprints were Travis reported green or red on a just merged patch only half a day later. We tried to pay the service for more processing power, but payed plans do not work with Travis CI for open source repositories (maybe they changed that restriction meanwhile). We also knew that the amount of tests will increase and thus lead to even longer run times. Additionally, Travis CI was configured to only test patches that were actually merged into the git main branches. So we always only knew after a merge if the test suite stays green. But we wanted to know if the test suite is green before merging a patch. Enabling Travis CI to test each and every patch set that is pushed to the review system was out of question due to the long run times, though.

So we looked for alternatives. Luckily, the TYPO3 GmbH was founded in 2016 and got an open source license by atlassian for their main products. Atlassian has an own continuous integration solution called bamboo. This CI allows adding "remote agents" that pick up single jobs to run them. It's possible to scale by just adding more agents. We thus split the time consuming test tasks into single parts and execute them in parallel on many agents at the same time. This also allowed us to execute the test suite before merging patches: If pushing a patch set to the review system, the bamboo based testing immediately picks up the new patch version and runs the entire suite, a result is reported a couple of minutes later. So, this is all about throwing enough hardware at the testing issue: The TYPO3 GmbH has a deal with the Leibniz Rechenzentrum who grant us hardware on one of their clusters to perform the tests.

2017

To the end of TYPO3 Core v8 development the bootstrap, helper and set up code to execute Core tests has been extracted from the Core to an own repository, the typo3/testing-framework. This allowed re-using this package within extensions to execute own tests. It however took that repository another major Core version to mature well enough to easily do that. Writing and executing tests for TYPO3 extensions is possible for a long time already, but extension authors were mostly on their own in finding a suitable solution to do that. This chapter may put an end to this confusion.

2018

Since 2016, the TYPO3 Core test setup went through further changes and improvements: Various test details were added that checked the integrity of the system. TYPO3 v8 switched to doctrine so we started executing the functional tests on meanwhile four different database systems, a nightly test setup has been established that checks even more system permutations and software dependencies and much more.

As another important step, the Core developers worked on the functional test isolation again in TYPO3 v9: As explained above, the functional tests forked processes twice if frontend testing was involved. With TYPO3 v9 however, the TYPO3 Core bootstrap has been heavily improved, with having a special eye on system state encapsulation: Next to the incredible PSR-15 works in this area, two further API's have been established: Context and Environment. Remember each functional tests case runs in an own instance within typo3temp? TYPO3 Core always had the PHP constant PATH_site that contained the path to the document root. With having test cases in different locations, this constant would have to change. But it can't, it is a constant and PHP luckily does not allow redefining constants. The environment API of TYPO3 Core v9 however is an object that is initialized during Core bootstrap. Next to some other details, it also contains the path to the document root. Adding this class allowed us to ditch the usage of PATH_site in the entire Core. This removed the main blocker to execute many functional test suites in one PHP process. After solving another series of hidden state of the framework, the functional test setup could finally be changed to not fork new processes for each and every test anymore. So now, we can proof that one TYPO3 backend instance can handle many backend requests in one process - we are sure our framework state is encapsulated well enough to allow such things. This change in the TYPO3 Core and dropping the process isolation for functional backend tests significantly simplified working with functional tests now and debugging is much easier and improved Core code at the same time. This pattern repeated often over the years: The test suites show quite well which parts of the Core need attention. Working in these areas in turn improves the Core for everyone and allows usages that have not been possible before.

In late 2018 another thing has been established: The runTests.sh script allows Core developers to easily execute tests within a container based environment that takes care of all the nasty system dependency problems. The test setup for some test suites is far from trivial: Acceptance tests need a web server, chrome and selenium, functional tests need different database systems that at best run in RAM, and so forth. Not too many Core developers went through all that to actually run and develop tests locally. The script now hides away all that complexity and creates a well defined and simple to use environment to run the tests, the only dependencies are recent docker and docker-compose versions.

2019

The above milestones show that efforts in the Core testing area have positive effects on Core and extension code and allow system usages that have not been possible before.

There are some further hard nuts we have to crack, though: For example, while the process isolation for functional backend tests has been dropped in 2018, the tests still fork processes to execute frontend scenarios. This is still ugly. It shows that calling a TYPO3 frontend from within the backend context or from CLI is still not easily possible. As a goal, a developer in such a situation would usually want to do this: Preserve the current framework state, create a PSR-7 request for the frontend, fire it, get a PSR-7 response object back, reset the framework state and then further work with the response object. Lots of details to allow this are in place since TYPO3 v9 already, with only some missing details: For instance, there is that nasty constant TYPO3_MODE that is set to "FE" in a frontend call and "BE" in a backend call. So yeah, this constant is not constant. It is one of the main blockers that prevents us from dropping the backend/frontend functional test isolation. So, this constant must fall, and this will be one of the things that will be hopefully resolved with TYPO3 v10. As soon as this last process isolation is dropped from the functional test setup, extension authors will know that executing a frontend request from within the backend must be easily possible. We're looking forward to that - it will be one of the last steps to finally manage framework state in a good way and maybe we can rewrite this documentation section soon.

2020

The pending milestone of 2019 has been achieved in late 2020: The core functional tests no longer spawn PHP processes to execute frontend requests. A PSR-7 sub request is initiated with core v11 instead.

This is quite an achievement: It is the proof that core framework state is encapsulated well enough to finally execute a frontend request from within a backend request or CLI. As one major pre-condition, the broken constant TYPO3_MODE is finally gone (deprecated and unused in core). Further core versions can drop that constant and extensions will have to drop their usage, too. So with v12, TYPO3_MODE will be gone, and TYPO3 can create cool features from this. So again, the core testing paved the way for new opportunities and TYPO3 usages.

2024

TYPO3 currently uses 4 dedicated "bare bone" Servers to perform CI tasks. This hardware performs 11.513 unit tests in  15 seconds. A typical pre-merge pipeline runtime is at  5 minutes with 2 permutations of acceptance tests, 3 permutations of  7500 functional tests, 3 permutations of unit tests plus statical code analysis, linting, build checks.

The 4 servers are provisioned using Ansible: https://git.typo3.org/typo3/CI/testing-infrastructure/-/tree/main/ansible?ref_type=heads and Pipelines configured in https://github.com/TYPO3/typo3/tree/main/Build/gitlab-ci/.

Debug TYPO3

Debugging With PhpStorm and Xdebug

In order to configure PhpStorm with Xdebug you need to do three things:

  1. Install xdebug
  2. Configure xdebug settings in your php.ini
  3. Use the appropriate plugin in your browser
  4. Configure PhpStorm

php.ini

Example setup:

php.ini
xdebug.remote_enable = 1
xdebug.remote_host = localhost
xdebug.max_nesting_level = 1000
Copied!

You should also configure the port (xdebug.remote_port) if that should differ from the default (9000).

Remember to restart your Webserver / php-fpm / Docker after you made your changes.

Install Plugin

Install plugin "Xdebug Helper" for your browser. To start debugging, click on the bug icon and select "Debug".

PhpStorm

  • Check Run: Webserver Debug Validation
  • Start Run: Start listing for PHP Debug Connections
  • Create some breakpoints

More Information

Handle and Improve a Patch (Gerrit)

This chapter focuses on handling an existing patch, by reviewing it, modifying it, reverting it etc. If you want to create a new patch, look at Create a Patch.

The code contribution workflow is based on patches and patchsets. A patch can be updated multiple times, adding a new patchset on top. Every patch contains a single commit. If changes are made to a patch, the already existing commit is changed (git commit --amend). How to do this is explained in Upload a new Patch Set

To make sure, every patch applied to the TYPO3 codebase meets the highest standards, every patch must be reviewed. Only after at least 2 people have tested the patch and at least 2 people have verified it (one of them must be a member of the core team), can the patch be merged (for more details on voting, see Vote).

Additionally, a suite of tests (unit, functional and acceptance) will automatically run on every patch (set), the results being shown as a +1 or -1 by "Core CI".

Tips for contributors & reviewers

This page contains some general tips beyond the description of the workflow.

Tips for new contributors

You are a new contributor. You found an issue in the Core you wanted to see fixed, you found a solution, you are satisfied with it, you setup your environment, you figured out how to create a patch and push to Gerrit, you managed to create a forge issue and you finally pushed your patch.

Congratulations! That is great!

Now your patch is hanging around in the review queue on Gerrit and either nothing happens, it is voted down, people tell you your patch is not good enough or suggestions are made to improve it and you don't know how.

Don't despair young padawan! The community around TYPO3 tries to act friendly and helpful, we're not hurting anyone on purpose. We're open to anyone and especially like to see new contributors and try to help getting them onboarded and up to speed. Please consider the following things before becoming frustrated or giving up:

  • Most of the time spent on TYPO3 CMS core development is done for free. This gives contributors and reviewers freedom on what they work on. Unfortunately, this also means that sometimes a patch is not given the dedication it should receive.
  • The review queue is often longer than the review power available. (See the dashboard on Forger for the number of open reviews.) Sometimes patches are overlooked just because there is other hot stuff being worked on.
  • Parts of the team usually work on something bigger. It may happen that some patches in the hot areas are merged very quickly while others do not get any attention. This is somehow natural and cannot be avoided since at any given time some reviewers usually focus on certain areas to get them right.
  • Sometimes the whole team focuses on different stuff. For example, usually around "big" releases, the team focuses on bug fixing, so feature patches may get stuck for some time.
  • Sometimes large parts of the active contributors are inactive at the same time. There are for example main holiday sessions with low overall activity.
  • Sometimes getting little or no feedback on patches also has other reasons. Maybe the issue description is insufficient or not understood, maybe there is no documented way on how to reproduce a certain issue, or the bug or feature is bogus, or the issue is so complex and hard to solve that no one really wants to get their hands dirty on it.

What you can do to get feedback

Here are some things you can do to raise awareness and get more feedback on your patch and to help getting it reviewed (and eventually merged):

  • Raise awareness: You are allowed to "ping" a patch once in a while. For example, you could add a comment "Hey, what is the status here, how to proceed with this patch?". This will raise the issue to the top in the queue and increases your chance of feedback. In general: Ask what is wrong, raise awareness, ask what is missing.
  • Ask for help: Sometimes, issues can be solved in a better way if they are coordinated in direct chat. The TYPO3 CMS team uses Slack as instant communication platform. You are always welcome to join the #typo3-cms-coredev channel and ask for help on your pending patches. Please see for more information on how to join slack. Joining the #typo3-cms-coredev Slack channel usually helps sorting out things and gives a much better feeling on how the team works and what is going on.

How to improve your patch

It happens quite often that the first version of a patch is not merged directly and needs a couple of patch sets before it is finalized. In fact, merging "Patch Set 1" is the exception, and having something merged in less than an hour is rather seldom. We're trying to do things right, sometimes patches go through a whole lot of patch sets and evolve in Gerrit until everyone is satisfied. This can take some time.

This is what you can do:

  • Familiarize yourself with Gerrit.
  • If reviewers make specific suggestions to improve your patch follow these suggestions and upload another patchset.
  • If you do not know what the suggestions mean or are unsure what to do, ask for help on Slack in the #typo3-cms-coredev channel.
  • Act helpful and friendly: Chances are higher that your patch will be merged if the way you are communicating is fair. This is even more important for reviewers and active contributors, we do not allow ranters and haters in our team and we try to stick to our Code of conduct Please keep that in mind when working with us. You will be rewarded with the pleasure of working with a group of pretty smart people if you act accordingly.
  • Don't get frustrated by -1 votes: Voting a patch down is a natural process in the review system and is not a sign that we hate you, your patch or your kitten. Our goal is to only merge things that are verified to be ready to go. A -1 basically blocks a patch from merging for a reason, and reviewers always add information on what is wrong or missing. Everyone wants to improve the system, so a -1 is just one method to achieve this.

Tips for reviewers and active contributors

First, everyone is allowed to vote positive and negative on pending patches in the Gerrit review queue for the TYPO3 CMS core product. We appreciate good reviews on both code review and testing and this entry point was used by quite some people already who were later nominated to be component or framework mergers.

Frequently giving good reviews and improving patches is noticed and rewarded and the team recognizes new helping hands. Another good entry point is joining code sprints, look out for some if you have ambitions to be involved in core development.

Acting as a reviewer and especially as an active contributor gives some additional responsibility in dealing with the project and working with other people in the review system. While technical discussions are sometimes mastered with different opinions clashing each other, it is always important to be respectful and fair to each other. There is no reason to act rude just because some other reviewer has a different view to a specific point.

That being said, now some common guidelines and practical hints on reviewing habits.

Be helpful

Act especially helpful to newcomers!

TYPO3 CMS is a living product and people join and leave the project. It is important to welcome fresh blood and help them to get up to speed. Not every effort in this area will be successful, but we must not scare away people just because someone did something wrong with their first patches. Help them to improve their patches: Fix commit messages, push new patch sets, add forge tickets and give friendly hints of advice about problems with the current state of patches and how to solve these problems.

Be honest

Do not +1 a patch for review unless you have reviewed it or a +1 for tests unless you have tested and verified that it resolves the issue.

See also the policies on voting.

Do not merge hastily

Do not merge hastily after pushing a new version!

Reviews of the final merged patch version are mentioned in the Git commit message, reviewers of patches get karma by having their name in the core commit log. This can be a nice motivator, so it is good habit to wait for re-vote or to hint to people that they might like to re-vote if a last version of a patch was pushed and the patch is close to being merged. Some pages count successful votes on patches and have metrics for persons being active in the project based on final reviews mentioned in the git log. Give them a chance to get their review points, it is great to see those numbers.

Push new patchsets

Don't be scared of pushing new patch sets!

There are two different pieces of information on a merged patch set: The author of a patch and the committer. Usually, the author of a patch is the person who pushed the first patch set to gerrit, while the committer is the person who finally pressed the merge button. When pushing new patch sets, the author information is usually not overwritten, so you do not "steal" the authors name by pushing new patch sets. However it is possible to explicitly overwrite the author name with another name, but this is used rarely and only if a patch changed so heavily that the person who pushes a new patch set says "This is now my patch since it has nothing to do with the initial version anymore". Usually, it is a good idea to keep the original author name when updating a patch. This will happen correctly automatically if a pending patch set from gerrit is cherry-picked, amended and pushed in to keep the original author information.

Decide about general issues before fixing nitpicks

First, think about the solution itself and if that is ok, fix nitpicks!

Core patches must follow our general Coding guidelines to get maintainable, readable and quickly understandable source code. In general, patches are not merged before the CGL are followed.

However, if looking at patches, it is important to first answer these questions:

  • Is the issue itself relevant?
  • Does the solution embed well in current development strategies?
  • Is the architectural solution ok or is the patch just fixing some symptom instead of a different, maybe bigger problem?
  • Does the solution contradict other patches we have in the same area?

So, first it should be decided if the architectural solution is fine. If that is the case, the patch can then be optimized towards CGL needs. It happened sometimes that a first patch was pushed, and some reviewers immediately started doing nitpicks on CGL stuff, leading to tons of new patch sets until the patch itself was codewise clean. After that, someone else showed up, looked at the real issue and came to the statement that the solution itself is bogus. Such things can easily kill motivation: Having a patch in the review queue, updating it because of CGL stuff and later being voted down because of systematic concerns about the solution after lots of energy was already put into the patch. It should be the other way round: First align if a solution itself is accepted, and if that is clear, do details like coding guidelines and minor improvements.

Fix CGL issues

Fix CGL issues yourself instead of voting -1 for CGL issues!

As said, we only want code merged that follows CGL. However, voting -1 because of simple CGL violations can easily scare away people and kill motivation. Therefore it is a very appreciated habit to not vote -1 because of CGL issues, but to cherry-pick those patches, fix those issues and to push again, instead.

This has several positive side effects: A trained reviewer is used to quickly cherry-pick, amend and push new patch sets anyway, so reading and fixing at the same time usually takes less time than voting -1 and forcing someone else to read through comments, apply and push again. And it will kill less motivation for the patch committer who will not be forced to push again, wait for reviews, push again, and so on, "just" because of CGL issues.

A friendly reviewer just fixes those issues on its own an pushes a new set, then does the real review: "Hey, nice patch set. I like it and it works. Just pushed a new version fixing minor CGL stuff. Would be cool if you read through my changes compared to your version and if you try to follow those in the first place next time. But your fix itself is great, I verified it and it works. +1 for that, thank you!". Gives better karma, right?

As usual there are exceptions to those rules. Sometimes a reviewer has no time to do those CGL fixes and decides to vote -1 instead, or maybe a patch is codewise so ugly that is does not make much sense to put energy into that. This is ok, just keep in mind that in general we appreciate minor issues to be fixed by the reviewer directly.

Voting

Consider the policies and tips for voting patches.

Common code review checks / checklist

For reviewing and giving feedback, here's a couple of things that are often addressed. You can use this list both for checking other people's patches, as well as your own.

General checks

  • Is the code-flow readable? Does it need more (or less) comments? Any code complexities ("cognitive complexity") that could be easier to read when using different conditions/loops/sub-methods?
  • Do breaking changes occur that need to be noticed? This can also apply to:

    • Type hinting / type declarations
    • using PHP features beyond the supported PHP version
    • Loss of existing functionality
    • Typos
  • Are new class, method, function, variable names understandable
  • Are possibilities for early code returns and reduced nesting levels addressed?
  • If SCSS/TypeScript changes are involved, are the resulting build files included in the patch, and were built with the right environment?

Testing

  • Is there a need to add unit/functional testing for specific changes
  • Are regression tests for a bugfix needed?

Formalities

  • Is the "Releases: " scope of a patch spanning the proper TYPO3 versions (depending on the state of current LTS and priority-bugfix-only releases)
  • Does the licensing of any foreign code introduced match the Core licensing?
  • Is the commit message complete, clear and properly mentions all part of a patch?
  • If a new Exception is added, is the timestamp-identifier unique and recent?
  • When new PHP files are added, do they contain the TYPO3 License and a declare strict_types header?

PHP specifics

  • Are the "final" and "private/protected" and "readonly" scopes of classes, methods and variables used properly?
  • Is Dependency Injection used where applicable?

Documentation

  • If a change is Breaking or comes with a larger impact: Is a "Breaking.rst" or "Important.rst" document part of the patch?
  • If a patch is a new feature: Is a "Feature"-rst part of the patch? Check out the rst file generator for help on creating files like this.
  • Is the provided commit message, reST files and the code itself aligned? Sometimes in the process of reworking a patch multiple times, these three place of documentation can become out of sync.
  • Does your patch deprecate anything? If so, have you followed How to deprecate classes, methods, arguments and hooks in the TYPO3 core?

Xliff / language files

When changes are made to Xliff files (translations):

  • Is the correct spelling in American (US) English used?
  • Does the file use proper indentation levels and characters (tab)?
  • If an existing language key is changed on a LTS branch, it must NOT introduce new argument placeholders or remove existing ones, or change the meaning of an existing label. Instead, a new language key has to be introduced (and the old one can be removed or at least deprecated/documented as outdated). Otherwise, localization changes will be pushed to earlier TYPO3 versions and could cause PHP exceptions when argument placeholders mismatch. When labels are removed, translations will fall back to their english counterpart in prior patchlevel versions.
  • Removed language keys will only be removed in the TYPO3 major version scope where the change is committed to.
  • A language label must only be removed in "main" versions, never backported to other branches. This would remove the label from translations of existing, non-updated TYPO3-setups of that version from the translation server downloads. Labels can only be removed if they have never been used in the any of the patchlevel releases that came before. Example: A language key that has been used in 13.4.1 and then Fluid templates were changed in 13.4.10 (to not need the key anymore). Because of this, the key can not be removed, because existing 13.4.1 releases would then no longer contain the translation.
  • Any existing label change committed to main will automatically update labels in ALL other TYPO3 versions, even if the TYPO3 Core repository does not backport the patch to earlier versions. Non-existing labels will not be included/updated of course. This is under the assumption, that existing label contents are only altered in terms of spelling/grammar, but never change in meaning or arguments.

More?

If you feel this section is missing good things to watch out for, please contribute to the documentation. This list does not claim to be complete, but should act as a kind of "Cheat-Sheet" or checklist for reviewing.

Introduction to Gerrit

Gerrit is a web based code review and project management tool for Git based projects.

TYPO3's Gerrit interface is located at https://review.typo3.org.

Gerrit handles the review process and is a gatekeeper in front of the official TYPO3 Git repository on github.com/typo3/typo3 (mirrored from a TYPO3 GitLab instance). Directly pushing to the GitHub (or GitLab) repository is not allowed. Instead every change has to pass a review process in Gerrit, which later pushes the change to the GitLab->GitHub repositories.

Overview of the UI

This chapter will explain the most important parts of the Gerrit UI to you. For most developers, this interface should be mostly self-explanatory. Gerrit also comes with its own help system.

This is a screenshot of an open review on Gerrit. We will go through the parts of the UI next:

Screenshot of a code review on Gerrit
  1. The search box lets you write complex search queries with little coding knowledge. For detailed information on how to use the search, refer to the official documentation on https://review.typo3.org/Documentation/user-search.html. Most people use Forger, because it provides more sophisticated ways to find a review. Look at Find a review on Gerrit for more information.
  2. The commit message formatted like we explained in "The commit message".
  3. The Reply Button which you will use to vote on code quality and testing as well as to send comments. We will be covering this button in more detail later.
  4. The Download Button. You will be using this control to cherry pick a change.
  5. Other changes related to this change. This can be either due to a similar topic or because the commit summary is related to the change we are currently reviewing.
  6. The current review status. Here you can see who has voted (and how they voted) on a change. The votes only apply to one given patchset. If a new patchset is uploaded, it must be revoted. Note the +1 by TYPO3com, which means that the automatic testsuite ran successfully.
  7. All changed files in this current change. You can click every file to take a look at what exactly has changed. There is a select box on top of the file list that allows you to do a diff between patch sets to quickly see what has changed.
  8. The history of this change. Here you can see comments, new patch sets, votes on a change etc.

Find a review on Gerrit

For finding an existing review (patch), there are several possibilities. Use whatever is most convenient for you or what fits your needs.

Forger

In any case, you can use Forger to search for the review.

Examples:

  • Sprints TYPO3-Core to see a board of all open core issues by type (Next patchlevel, Regressions)

Email notification

If you are in any way involved in the review (e.g. you are author, reviewer or you made changes), you will get a notification about it to your email address. The notification contains a link.

Gerrit: Your Changes

For your own patches, go to Gerrit and select Your: Changes.

Gerrit: Open Changes

Select Changes : Open to get the latest changes or changes with recent modifications.

Forge

Once a patch has been pushed for an issue, the corresponding issue on Forge will contain comments with the topic "Updated by Gerrit Code Review ..." and a link to the review on Gerrit.

... highlight:: bash

Cherry-pick a patch

In order to test a patch or make additional changes on it, you will need to cherry-pick it from the review system into your local git repository.

  1. Find the review on Gerrit

    see Find a review on Gerrit

  2. Select the latest patchset and click download

    If the recent patchset is not shown, select it first:

    Then click on Download:

  3. Click on copy next to the line for "Cherry pick"

    This copies the command to the clipboard.

  4. Clean up your local repository

    Save your local changes beforehand, if you have any. Otherwise the git reset performed after that would delete local changes, which may happen if you work on different patches simultaneously with the same repository directory.

    git stash save 'comment-your-changes'
    Copied!
    git fetch --all
    git reset --hard origin/main
    git pull --rebase
    Copied!
  5. Execute the command (git cherry-pick)

    In your shell, paste the copied command and execute it. Example:

    git fetch https://review.typo3.org/Packages/TYPO3.CMS refs/changes/47/56947/11 && git cherry-pick FETCH_HEAD
    
    Copied!

    Re-apply your local changes, if you had any.

    git stash pop 'comment-your-changes'
    Copied!
  6. Cleanup your TYPO3 installation

    Depending on the changes made by the patch, you may have to apply some changes to your TYPO3 installation as well. Also, if the last time you pulled from the GitHub repository is some time ago, you may need to pull the most recent dependencies. And you may need to rebuild the CSS/JS assets. See Cleanup TYPO3 installation.

Cleanup tasks

Cleanup git repository

Before Cherry-picking a patch or starting a new patch:

Reset local repository
Build/Scripts/runTests.sh -s clean && \
    git fetch --all && \
    git reset --hard origin/main && \
    git pull --rebase
Copied!

Cleanup TYPO3 installation

After downloading a new patch or making changes to an existing patch, you may need to cleanup your TYPO3 installation.

It depends on the files that have changed, what you need to execute. In any case or if in doubt, you can safely perform all steps.

Flush the cache:
ddev typo3 cache:flush && \
    ddev typo3 cache:warmup
Copied!
Changes in composer.json:
Build/Scripts/runTests.sh -s composerInstall
Copied!

Changes in .css / .js files:

Delete browser cache or hard refresh (e.g. CTRL + F5)

Also you may need to create the JS/CSS assets:

./Build/Scripts/runTests.sh -s build
Copied!

Changes in DB schema (ext_tables.sql):

Create missing tables and fields
ddev typo3 extension:setup
Copied!

Maintenance: Analyze Database Structure, Apply selected changes.

Update core-testing docker images

Pull latest core-testing images versions
./Build/Scripts/runTests.sh -u
Copied!

One-liner command

If you want to reset your local installation in one go, you could use the following one-liner command, combining the mentioned parts from above:

Reset local repository to upstream state
./Build/Scripts/runTests.sh -u && \
    Build/Scripts/runTests.sh -s clean && \
    git fetch --all && \
    git reset --hard origin/main && \
    git pull --rebase && \
    ./Build/Scripts/runTests.sh -s composerInstall && \
    ddev typo3 cache:flush && \
    ddev typo3 cache:warmup && \
    ddev typo3 extension:setup
Copied!

... highlight:: bash

Upload a new Patch Set

This chapter handles improving an existing patch. For creating a new patch, see Create a Patch.

  1. Get the latest patchset of the patch

    The latest version of the patch is still in your local git repository. If not, you must cherry-pick the latest patch set from Gerrit as described in Cherry-pick a patch.

  2. Edit files to improve the patch
  3. Add tests (recommended)

    If you add functionality, it is a good idea to add tests.

    See Unit testing with the TYPO3 testing framework in TYPO3 Explained for more information about writing Unit Tests.

  4. Test your changes (optional)

    Run the TYPO3 testsuite locally, as described under Using runTests.sh. Otherwise, don't worry, the automatic CI will do that for every committed patch set on the TYPO3 infrastructure.

  5. Add files and amend to commit

    Update the change by amending the previous commit. This will overwrite the commit you fetched from Gerrit with your changes:

    shell command
    git commit --amend -a
    Copied!

    You can amend as often as you want.

    Bear in mind that this kind of Git commit amending is a bit different than when you do it with GitHub (and using force-push). For Gerrit, every push will be a patch set. Previous patch sets can never be overwritten by amending, so do not worry.

  1. Push your change to Gerrit

    Once you are satisfied, push your improved Patch Set to Gerrit:

    shell command
    git push origin HEAD:refs/for/main
    Copied!

    Each pushed set will iterate a new patch set, and all previous patch sets can always be compared and even checked out later on.

    If you want, you can even provide an individual commit message to your push, so that in gerrit your code change shows up with what usually a "commit message subject" could do:

    shell command
    git push origin HEAD:refs/for/main%m="Some_String_Without_Whitespace"
    Copied!

    The underscore characters will be replaced by whitespace. You can also use the following bash script or shell alias to interactively do that:

    push-with-message.sh
    #!/bin/bash
    
    read -p "Please enter pseudo-commit message: " answer
    answer=$(echo "$answer" | tr -c '[:alnum:]' '_')
    git push origin HEAD:refs/for/main%m=$answer
    Copied!

Review a patch

Reviewing a patch consists of two steps:

  1. Code-review
  2. Testing the change

You have the option to contribute to both stages or just a single stage in the review process.

Both steps are free for everyone in the OpenSource community, you are not required to be a Core merger or Team member.

If you're able to improve the patch yourself, your contribution would be very much appreciated. Visit Upload a new Patch Set to find out more about how you can help improve patches.

Code Review

A basic code review is possible by using the Gerrit web interface.

For some tips on what to review, check our Common code review checks / checklist.

  1. Select the latest patchset

    This should already be selected by default, but if you changed the patchset, you should select Go to the latest patch set (above the list of changed files).

  2. To leave a comment, click on one of the files

    Commenting in the files directly is optional, but strongly recommended. If you just want to leave a general comment which needs no context, you can skip to step 8 (Reply).

  3. Optionally change the view

    You will see a diff of this file against the current codebase.

    You can change the view in the top right (Diff view) e.g. side-by-side or unified (or change this in your settings).

  4. Leave one or more comments

    Click on the line number in the file and a comment box will open.

  5. Click Save.

  6. Go back

  7. (Optional) Add comments to more files.
  8. Now press Reply.

    Using the Reply button, you can post your comments (and optionally add an additional note).

    Vote by clicking the Reply button

    Of course you should also vote for the change (Be graceful with -1 votes though).

Test a patch

For testing the patch you need to import the change into your local repository.

Look at Cherry-pick a patch for information on how to do this.

Test the patch in your local TYPO3 installation and verify the reported bug is fixed and no other bugs are introduced with the change.

Depending on the outcome of your tests, place your positive/negative vote in Gerrit, using the Reply button.

If you want to help the author and provide an improved patch, continue with the section Upload a new Patch Set.

Otherwise throw the changes away, to bring your repository back to a clean state:

git reset --hard origin/main
Copied!

Vote

In order to comment or vote on a change you can click on the Reply and enter your comment. Here, you can also apply your votes.

Remember, everyone with just a TYPO3 user account is able to vote, you do not need to be a team member or Core merger.

Chose your vote, say something nice and click SEND

  • +1 : you approve of the patch
  • -1 : you do not approve, in this case give your reason as a comment

Click on Send and your comments will be saved. At the same time all other contributors who either watched this change or have already voted on this change will get notified.

Policy for votes

Code Review: Needs +1 of two reviewers, one of them being a Core Merger.

Verified: Needs +1 of two reviewers, one of them being a Core Merger.

Votes from the CI GitLab Pipeline Server (user "Core CI") do not count. This means that a patch which is fully reviewed usually has at least 3 Verified +1 votes, two from humans and one from "Core CI" ("Core CI is happy" for Verified+1, "Core CI is not happy" for Verified-1). Each comment by Core CI is linked to the log of the performed job, so that you can inspect the output.

Authors should not vote for their own patches, unless the patch has been changed substantially by other developers.

As soon as the patch has reached the approved status by getting a +2 on Code Review and Verified, a Core Merger can decide to push the Submit button, finally pushing it to the main repository.

Hints on voting -1

See also Review a patch about the policies on voting and how to vote.

In general, -1 on reading and/or testing of a patch is a mechanism used to improve a patch. Still, -1 still takes a risk to kill someone elses patch and it usually actively prevents a merge. There are ways to override a -1, but those are not pushed through in real live Gerrit habits. In general, if voting -1, you take some responsibility for this patch by saying "This one shouldn't be solved until this or that is fixed". Some hints on using -1 in reviews:

  • Think about your vote and always give a logical explanation. "-1 looks ugly" is not enough.
  • If a patch is broken, does not fix the issue, is bogus, architecturally wrong or collides with other goals, a -1 is clearly ok.
  • -1 can also be used if you are actively working on a patch and want to prevent a quick merge: "-1, working on it now, will push soonish".
  • -1 may be ok if you have general doubts but you can not pinpoint it and need a second opinion: "Hey, this solution looks somehow weird and I doubt this is what we should do here. I think we should ask person x or person y, who has a deeper knowledge of this subsystem, to take a look at it. I do not want this patch to be merged until this is sorted out and will vote -1 for now for this reason."
  • If you are on the "receiving end" of a "-1" or even a "-2" vote, please do not be afraid or feel bad. This is done as part of the process to make TYPO3 evolve as best as it can. Try to work out problems or negative feedback, be kind to each other and remember you are contributing to OpenSource because the experience of improving things together, and learning from each other is what drives us.

Vote resets ("Revote")

Whenever a new patch is submitted, all votes are reset. So if previously a patch was voted to be merged, but then a last-minute issue is getting addressed, after the commit every vote will be back to zero.

Contributors to a patch review will receive notifications about this and are encouraged to review the patch and re-apply their vote if they still feel confident.

It is ok if the patch owner pings previous votes to please consider adding a revote, so that a patch can be pushed forwards.

How to handle [WIP] patches

It is possible to push patches as "WIP" (work in progress) patches. This is a way to show people a quick-shot version of something that is not finished yet, but goes into the right direction. Usually, WIP patches are not actively reviewed by others and the original author should take responsibility to finish this patch later.

As a contributor, you usually can not expect someone else to pick up your WIP patch and finish it, except you stated that goal clearly: "Hey, I've done a quick shot with this patch to show a possible solution for this issue, but the patch is not finished yet. Foo and bar is missing and we still need a concept for foobar. I'll probably not work actively work on it anytime soon, but maybe the current state is helpful already".

Better: "Hey, I worked in this area and came up with this WIP patch for now. I wanted to show into which direction this patch is leading, but we currently have some open questions. However, it would be great if you can give me feedback to the general approach at this early state already to decide if it is worth following this solution to its end."

Having too many WIP patches in the review queue is not really helpful. Consider to fork the project in GitHub or somewhere else and push to gerrit again if your patches evolved.

Stale reviews / Cleaning up

Since TYPO3 iterates on many, many patches and issues each day, the list of Gerrit reviews (as well as Forge issues) may feel intimidating.

Due to this it is vital to "clean up" patches from time to time:

  • If you are no longer planning to work on a patch, maybe better abandon it, or ask other involved people to carry on.
  • If your patch is not getting feedback for a long time, ask in the #typo3-cms-coredev channel of the TYPO3 slack workspace if people may want to review or give feedback on. Or try to find people working in a similar area of your patch and see if you can join forces.
  • From time to time, check on patches you have voted on, to see if you can push things forward to either get merged or abandoned.
  • Sometimes just check all your own open patches and see if you might catch interest in picking it up again.
  • Please either update older patches in "Merge conflict" mode or state your intent to abandon the patch.

Rebase

What is rebase?

Simply speaking, git reapplies commits on top of another base tip (as explained in the Pro Git book).

When you start your patch, it will be based on a specific commit. Meanwhile, other commits are merged and the TYPO3 codebase changes. Your patch will still be based on an older version of the source.

remote | local | commits
------------------------

 +                 x : latest commit
 |
 |
 +                 d
 |
 +                 c
 |       +         b : your commit
 |       |
 +--------         a : parent of your commit
 |
 +
Copied!

When you rebase, your change, will be reapplied to a different commit (typically the latest one) and your patch will be based on the latest version.

There are other applications for rebase (e.g. squash commits), but only this is the one relevant for the TYPO3 Contribution Workflow, so this is what we mean when we talk about rebase.

Do not let information on the Web confuse you: Usually it is assumed that someone is working on a different branch (feature branch). In our commit model, we always work on one branch (main) and we only create one commit for a change.

When should you rebase?

When you are working on a patch, you can regularly rebase in order to get the latest changes.

You can also do it before you run tests and push your change.

In fact, it is good practice to do this!

How do you rebase?

The following assumes, there are not yet any merge conflicts. If there are merge conflicts, you must resolve them as you rebase / merge / cherry-pick. See the section Resolve Merge conflicts.

Method 1: Use Rebase button on Gerrit

Prerequisites:

If you have already pushed your change to Gerrit, you can use the Rebase button.

This is only possible, if there are not yet any merge conflicts.

Do it:

Load your patch in the browser, click on "Rebase" and then "Rebase on top of the main branch".

Method 2: git pull --rebase

This is a command-line method. You can do this regularly while working on your patch.

Prerequisites:

This command assumes, you are currently working on your patch in your local git repository and you have a clean working directory, meaning you committed your changes.

shell command
git pull --rebase origin main
Copied!

(which is the pull command you already know, with the additional option --rebase.)

or

shell command
git fetch
git rebase origin/main
Copied!

What does it do:

From the manpage: "... rebase the current branch on top of the upstream branch after fetching." (upstream is origin/main)

Remember, git pull (internally) does a git fetch and then git merge. With this command, git does a git fetch and then a git rebase using the upstream branch (latest main branch).

More information:

  • `StackOverflow: Difference between git pull and git pull --rebase

<https://stackoverflow.com/questions/18930527/difference-between-git-pull-and-git-pull-rebase>`__

Resolve Merge conflicts

What are merge conflicts?

Usually, git does a good job of merging several changes in one file.

However, there are occasions where git does not know what to do, because one change conflicts with another, meaning there are more than one possible way to merge.

This is actually a good thing.

In case of a merge conflict you will usually have these possibilities:

  1. Use change 1
  2. Use change 2
  3. Use a combination which you manually combine.

Example

Original file:

111
222
Copied!

Change 1

111
aaa
222
Copied!

Change 2

111
bbb
222
Copied!

Git cannot resolve this automatically, because it is ambiguous. What should the result be?

Result 1

111
aaa
bbb
222
Copied!

Result 2

111
bbb
aaa
222
Copied!

The merge conflict markers (in the file) will show:

111
<<<<<<< HEAD
bbb
=======
aaa
>>>>>>> aaa
222
Copied!

How to see merge conflicts in Gerrit or Forger

If your patch has merge conflicts. Gerrit as well as Forger will show you:

Gerrit: Load your patch page in the browser.

Forger: Open one of the ReviewSprint views on Forger.

In that case, you will need to resolve the conflicts in some way.

See next section How to resolve conflicts? for more information about resolving merge conflicts.

How to resolve conflicts?

Some git commands will show you that there are conflicts e.g. git cherry-pick, git rebase, git pull --rebase etc. It will have inserted markers in the files and ask you to resolve them and then continue.

You must resolve the conflict for all these files. There are several ways to do this.

Most editors or IDEs assist you in doing this. Check the information for your IDE.

Resolving the conflict, involves a 3-step process:

  1. Identify files with conflicts: the git commands usually show which files have conflicts, also your Editor or IDE should show you (PhpStorm does).
  2. Resolve the conflicts
  3. Resume: Depending on the command that was executed (e.g. rebase, merge, cherry-pick), you will usually need to add the files and call something like rebase --continue or cherry-pick --continue

Identify files with conflicts

The command (e.g. git rebase) usually tells you which files have conflicts, e.g. git rebase gives us the following output:

CONFLICT (content): Merge conflict in typo3/sysext/install/Classes/Updates/ExtensionManagerTables.php
Copied!

Identify files with conflicts (cherry-pick)

Unfortunately git cherry-pick is a little stubborn and does not show you which files are concerned:

$ git cherry-pick d48c3626d828de880342
$ > error: could not apply d48c362... bbb
$ > hint: after resolving the conflicts, mark the corrected paths
$ > hint: with 'git add <paths>' or 'git rm <paths>'
$ > hint: and commit the result with 'git commit'
Copied!

However, git status will show you:

$ git status
$ > On branch main
$ > You are currently cherry-picking commit 805a207.
$ > (fix conflicts and run "git cherry-pick --continue")
$ > (use "git cherry-pick --abort" to cancel the cherry-pick operation)
$ >
$ > Unmerged paths:
$ >  (use "git add <file>..." to mark resolution)
$ >
$ >  both modified:   file_with_conflicts.txt
$ >
$ > no changes added to commit (use "git add" and/or "git commit -a")
Copied!

All files shown with "both modified" will need to be attended to.

Resolve the conflicts manually

If you want to do it manually (instead of using an IDE to do it visually), look for all occurrences of <<<<<<<.

These are markers. They are used as follows (as in example above):

The merge conflict will show:

111
<<<<<<< HEAD
bbb
=======
aaa
>>>>>>> aaa
222
Copied!
  1. Beginning of conflict: <<<<<<<, after that name of branch for version 1 (here: HEAD)
  2. Separation: ======= Marks end of version1 and beginning of version2
  3. End of conflict: >>>>>> and then name of branch version 2.

There may be more than one conflict in a file!

Special case: JavaScript/CSS merge conflicts

JavaScript and CSS assets are build from sources in the monorepo, with the commands:

# optionally, reset state
Build/Scripts/runTests.sh -s clean

Build/Scripts/runTests.sh -s build
Copied!

This "compiles" files with ".scss" and ".ts" extensions to their bundled ".css" and ".js" variants. TYPO3 also versions these files inside the monorepo.

Commiters need to be aware they need to maintain these asset versions, if they change any of the build source files, and commit them alongside their patch.

Since the compiled files are merged on one single line, a merge conflict in these files will occur, if your patch works on anything CSS/JS related and other changes have been introduced meanwhile.

The solution to resolve merge conflicts in these files is actually vers easy. Just re-perform the commands from above (... build), which will re-create the assets from your cherry-picked patchset. You may need to resolve conflicts in the .ts/.scss files beforehand, if there are any due to rebasing.

Afterwards, you can include the generated .css/.js file your git amend commit like any other resolved conflict (see below).

Resume command

When you are done, add the file and then continue:

git add <path1>
git add <path2>
Copied!

In most cases, git will have told you what to do when it showed the conflict.

Resume git rebase

git rebase --continue
Copied!

Resume git cherry-pick

git cherry-pick --continue
Copied!

Commit changes after rebase/cherry-pick

Once your git repository is in sync with HEAD and your cherry-picking was successsful, you can edit/add files, commit and push as usual:

git commit --amend
git push
Copied!

Issue Workflow (Forge)

So, you've filed an issue following the steps above, and submitted it.

What now?

First and foremost: Thank you for doing this. You are now a part of the OpenSource ecosystem. It lives and thrives with its users, and is constantly evolving.

The TYPO3 community is proud to be active and diverse, and boast a long-standing track record of fostering this system that we all love with continuous development effort.

Most of the TYPO3 Contributors perform their work in their spare time, and we all spend our time differently. Some people work on big tasks and have an agenda of years ahead, and maybe are even paid to work on TYPO3 (through either Partners, Agencies, TYPO3 GmbH or other means). Other people work on this system instead of watching a movie in the evening.

So the bottom line is: In OpenSource development, you do not really know who and when somebody will take care of your issue. It can catch someones instant attention, but it may also lay unchecked for days, or weeks... or longer. Impactful bugs are easily addressed because the more people report an issue, the more likely it is to get awareness and interest.

A few volunteers in the TYPO3 community try to regularly catch up with issues, so no report is likely to be lost like tears in the rain. Your input is valuable, and valued by our team - but please bear with us.

If your issue does not get addressed immediately, try to get involved in the Community. Check out https://typo3.org/help for platforms to discuss about the issue you found.

Or, maybe you can find time and capacity to work on an issue yourself, with the help of this Contributor's Guide!

Once an issue has been triaged by our support volunteers, this will usually happen:

Status

  1. New

    This is the initial state of an issue. It may get reverted to this status, when possible feedback loops are done, but the issue itself could not yet be "Accepted" due to missing strategic or capacity decisions.

  2. No status change, but "things happen"

    Your issue may remain in status "New" or "Accepted", but further feedback might be added, or relations to other issues could be added, or other metadata (like tags) get adjusted. If you see this happening, some of our support staff has "seen" your issue. If your issue is older, and you see this happening, this might be a good time to get involved again and see if your issue still applies.

  3. Needs Feedback:

    Your issue has been set from Status "New" to "Needs Feedback".

    This means, we have further questions to process or discuss your issue. Once you provide the feedback, the person involved with it will usually get back to you again.

  4. Accepted

    Your issue has been "accepted" to be reproducible and understandable, and will hopefully find a volunteer to fix it.

    Please bear in mind that this status does not mean someone immediately begins to work on it. It is just a status that developers can use to search for accepted issues to work on. And it is a good pool of issues to address for example in remote or on-site Code sprints (see https://typo3.org/community/meet/regular-open-sprints).

  5. In Progress

    Someone has actively taken on your issue to work on.

  6. Under Review

    This is the status you are looking for.

    This means a Patch has been made that should address your problem. The link to such a Patch in our review system will be attached to the comment.

    Now it is very important for that patch to:

    • actually fix your issue
    • be accepted by Core mergers to be part of the TYPO3 code

    Anyone can create/contribute a patch to any issue, one does not need to be assigned to it. One is also free to contribute to existing Patches of an issue.

    And most importantly: You are VERY welcome to review the patch yourself. If you can comment on the patch tracking system that a patch solves your problem, and even vote for it, this will highly increase the chances of your patch getting merged.

    Sometimes discussion about solving an issue is then carried on to the Gerrit review system, which is linked in the issue comment. You may want to regularly check on that patch state and maybe give feedback there.

    Please note that the patch system is meant for highly technical feedback. If your feedback is more general, please provide that only in the issue tracker.

    An issue that is "Under Review" may get merged very quickly, but it may also even take very long to get merged, or even rejected/abandoned.

  7. Resolved

    Making a note here: Huge success! Your issue report lead to an actual code improvement of TYPO3, and the patch resulting from your issue has been merged. Thank you!

    Sometimes it might not be what you expected at first, because requirements and needs may change, and need to be adapted for the broad community.

    It can also occur that the issue you reported for a specific TYPO3 version is only fixed for a more recent version, and not the one you reported with. Sadly we cannot backport every single bugfix, and need to make internal decissions about which changes get put into older versions. Patches never get merged to versions below the LTS (Long-term support) threshold.

    The upside: The patch that has been made may apply to your own instance. You can always download patches and apply them locally, see Applying Core patches for details.

  8. Closed

    This may be a frustrating status for your issue to be put in. We need to close issues that:

    • are no longer reproducible
    • are outdated
    • are not fixable/adressable within reasonable resource limits
    • do not align with the TYPO3 project goal
    • receive no feedback for a longer time
    • relate to abandoned patches

    If your issue has been closed but you believe this is a mistake, our support staff are just humans after all, please bear with us. You can still give feedback to closed issues, you can reach out through other community means, or you can also create follow-up issues.

  9. Outside help / Volunteering opportunity

    The more watchers an issue has, the more likely it is regarded as being of importance.

    It can help if you regularly search the issue tracker yourself for similar problems than yours, and maybe set relations to new issues, or comment in issues that you haven't submitted yourself, but where you can contribute.

    The task of maintaining the issue tracker is a large one; several dozen issues are worked on each day. If you can help to add relations to related tickets, or provide feedback or additional information in "foreign" tickets, this can help us out.

    The ideal help of course is if you are able to solve issues by providing solutions or patches to issues.

Target Versions

Target versions are set by the Core team only. Until we can enforce this technically, feel free to remove target versions set by issue reporters.

Candidate for patchlevel:

All issues that qualify for patchlevel versions should go into this pool. Naturally, this can only be bug fixes or tasks.

A board does not make sense for this, since the issue status can only be New or Needs Feedback on these issues. Find the pool here.

Dedicated Patchlevel Versions:

This is the “real” next patchlevel release that is planned.

Whenever a contributor takes up a task he/she will have to make sure the ticket is set from “Candidate for patchlevel” to this dedicated version.

Taking up such an issue comes with the commitment to get this issue done by the time of release. Other members of the core team should support this cause by reviewing as usual.

Candidate for Major Version

Features and tasks will go into this pool. These can be worked on as usual.

Review a patch as a Core Merger

Please see Review a patch for general information on how to review a patch, also the cheat-sheet on common review issues.

As a Core Merger you have a huge responsibility because your vote (or misvote) has an impact on dedicated work of contributors or colleagues. This swings both ways: You can also greatly impact confidence and participation by being involved in a public voting and commenting process.

Remember that you represent the TYPO3 project as a public-facing "Person with Power". Please try to always vote by explaining your reasoning, and feel free to correspond with your fellow Co-Mergers for impactful decisions.

Vote by clicking the Reply button

Voting +1

Practical considerations

The Core Merger who gave an early +1 should try and go back to transform the +1 into a +2 after a second review came in, if applicable.

Each newly pushed patch requires a complete new round of voting before it can be submitted. So everyone that reviewed once is invited to re-vote as soon as a new patch is pushed. Using Gerrit's Patch History feature allows to quickly see what has changed from the already reviewed patch to the new one.

Consider these rules when comparing patches:

  • If the patch was re-pushed due to the comments, check the diff between the versions of the patch.
  • If the patch needed to be rebased onto current main, the change set might contain the changes due to rebasing. So better check the diff between base and most recent version in this case.

Voting +2

Ready to merge

A Core Merger can give a +2 vote on Code Review and Verified if there is already a positive vote by another Core Merger.

Patches of low complexity

A Core Merger can give a +2 and submit right away in case of patches that are of very low complexity (like spelling corrections, indentation, or obvious bugs), and are highly unlikely to negatively impact anything.

A Core Merger can give a +2 and wait a bit before submitting (used to be called "FYI24", "FYI48", ...).

Voting -2

A -2 vote by a Core Merger blocks a patch from merging. In contrast to -1, a -2 is a veto. Use with care. With a -2, you are taking responsibility of the patch and basically stating that it will not be done until you actively remove your negative vote.

To date, we have had no real problem with someone giving -2 and then not acting responsibly. It would be great if it stays this way.

Merge patches

The merging process

  1. Prerequisites

    A patch can only be merged if it has received a + 2 vote from a Core Merger. A +2 can be given by the second Core Merger to review the patch positively.

    Merging gets blocked by a single -2 vote.

  2. Submit the patch

    You can merge by clicking the Submit button. The Core Merger to merge the patch also has to do the Backporting if the submit-message requests for a backport.

    The Submit button on a patch in status Ready to submit.

  3. The patch is successfully merged

    When the merging is successful, the Change looks like this:

    The patch in status Merged.

  4. Backport if necessary

    If required in the commit message, do the backport next.

  5. How to revert a submitted change

    There is a Revert button available now. Please stick to the revert workflow if reverting a change should become necessary.

Backport a Change

Before you start, wait until the review process has been successfully completed for the most recent affected branch.

Use Gerrit for the cherry-pick

First try to use the Gerrit cherry-pick feature for automatic backporting.

  1. Cherry pick into a branch

    Cherry picking via Gerrit

  2. Choose branch and adjust commit message

    In the following modal, you can select the branch to backport. Existing branches are shown by autocomplete.

    Remove from the commit message everything below the Change-ID because the information about former reviewers is not needed for the cherry pick. Make sure that you don't alter the Change-ID but remove every line (also empty ones) below it. After doing so hit the Cherry Pick button.

    Adjust the commit message and click Cherry Pick

  3. Review backport patch

    This creates a new Change on Gerrit that needs to be reviewed and merged once more.

    A new change based on another branch is created. It has the status "Active" once more.

  4. Merge the backport

    If the backport is straight-forward and not complex, you can vote +2 and continue to merge the backport. Otherwise it should be reviewed by at least one other Core Merger.

    Merging the backport

Manual backport

If the automatic backport fails, you need to manually cherry-pick the patch to the target branch. (e.g. cherry-pick the main patch onto your local (up to date) 13.4 branch) You will most likely need to adjust the code for the older branch.

Edit the commit message to comply to the guidelines again. (e.g. remove the Reviewed- and Tested- lines added by Gerrit)

Push the review back to Gerrit.

On Gerrit the original patch will show the cherry-pick as a related patch.

In which TYPO3 release was a patch merged into?

See Information: Where was a patch included? for information on how to use the Included in menu button to see, in which TYPO3 releases a patch was merged into.

Revert patches

It is important to have traceable code. This means that any person inspecting the bug tracker, Gerrit changes or the commit log shall be able to trace if a patch has been reverted. Therefore we must add this information to all affected places.

If there's the need to revert a patch, please stick to the following rules:

  1. Create a ticket on Forge for the revert, if there's not yet a bug report. (Maybe re-use the original ticket, if you re-push the patch again with the original ticket number.)
  2. Visit the original ticket in Forge and

    1. link it to the revert ticket
    2. add a comment to the ticket with information that it is reverted
    3. set the Status from Resolved to Accepted
  3. Use the Revert button in Gerrit
  4. Modify the commit message of the newly created patch to contain

    1. the commit hash as generated by Gerrit
    2. a description why the revert is needed
    3. a Releases-line that contains all releases where the original patch was merged (check if the backports where really merged)
    4. a Resolves-line for the revert ticket as created above (you can skip this if you re-used the original ticket)
    5. a Reverts-line for the ticket of the original patch

... highlight:: bash

Git Cheat Sheet

This is a short list of commands. If you are not familiar with the workflow yet, make sure you follow the link at the beginning of each section and read the detailed description.

The following commands assume you are in the working directory of the TYPO3 core repository.

git clone

Clone TYPO3 CMS Git repository into current directory:

shell command
git clone git@github.com:typo3/typo3 .
Copied!

Setup

For detailed setup instructions, please see: Git Setup

Migrations

Migrate master => main

If you are using an older installation with the master branch you can switch like this from master to main:

shell command
# Make sure that git pull loads from the "main" branch
git branch --set-upstream-to origin/main

# Rename your current "master" branch locally to "main" to match TYPO3's naming scheme
git branch -m master main
Copied!

Please also adapt your commit message template (if configured) to use "main" instead of "master".

Migrate to GitHub

If you are working with an older t3coredev installation and are not using the GitHub URL yet, you can switch like this:

shell command
# set remote url for "origin"
git remote set-url origin https://github.com/typo3/typo3.git
# set push URL to gerrit (this has not changed)
git config remote.origin.pushurl "ssh://<your-username>@review.typo3.org:29418/Packages/TYPO3.CMS.git"
Copied!

Workflow - common commands

For details see Create a Patch

Reset repo to last remote commit in (remote) main branch:

shell command
git reset --hard origin/main && git pull origin main
Copied!

Stage and commit all changes:

shell command
git commit -a
Copied!

Is the same as:

shell command
git add .
git commit
Copied!

Stage and commit all changes to already existing commit:

shell command
git commit -a --amend
Copied!

Push changes to remote main branch on gerrit (default method):

shell command
git push
Copied!

This assumes, you have correctly configured your remote as described in Setting up Your Remote. If not, you must explicitly push using the refs/for namespace:

shell command
git push origin HEAD:refs/for/main
Copied!

Workflow - work in progress

In case you want to push a "Work in progress", use the following instead:

shell command
git push origin HEAD:refs/for/main%wip
Copied!

You can also configure Gerrit to always mark your pushes as WIP. In order to do this head over to https://review.typo3.org/settings/ and configure "Set new changes" to "work in progress" by default".

See: https://gerrit-review.googlesource.com/Documentation/user-upload.html#wip

Workflow -other branches

Show all branches:

shell command
git branch -a
Copied!

Checkout 13.4 branch:

shell command
git checkout 13.4
Copied!

Checkout 12.4 branch:

shell command
git checkout 12.4
Copied!

Long story short: In most cases, push to main. The rest is being taken care of by core team members!

Push 13.4 branch:

shell command
git push origin HEAD:refs/for/13.4
Copied!

Push 12.4 branch:

shell command
git push origin HEAD:refs/for/12.4
Copied!

Workflow - commit msg

Details: Commit Message rules for TYPO3 CMS

Example commit message for a bugfix:

commit message
[BUGFIX] Subject line

Description

Resolves: #12345
Releases: main, 10.4
Copied!

Other keywords:

[BUGFIX]
[FEATURE]
[DOCS]
[TASK]
[!!!][FEATURE]
[WIP][TASK]
Copied!
  • subject < 52 chars (if possible, otherwise <= 72)
  • other lines <= 72 chars
  • hyperlinks with > 72 chars are allowed when required (Inserting links / long lines)

Workflow - push with Gerrit message

Due to the nature of the commit workflow with gerrit, and a commit always getting amended, you have no individual commit messages for one Gerrit patch set.

To workaround that, you can add small comments to individual patch sets pushed to Gerrit like this:

git push origin HEAD:refs/for/main%m=Fixed_issue_in_JavaScript
Copied!

Since that notation is a bit bland (no spaces, no linebreaks, no special characters, it can be helpful to utilize a small Bash script:

push_with_message.sh
#!/bin/bash
read -p "Please enter pseudo-commit message: " answer

answer=$(echo "$answer" | tr -c '[:alnum:]' '_')
git push origin HEAD:refs/for/main%m=$answer
Copied!

Replace "main" with possibly other branches (13.4, 12.4, ...) that you may want to push to.

Workflow - Undoing / fixing things

Throw away all changes since last commit:

shell command
git reset HEAD --hard
Copied!

Unstage a file (remove file from index, but keep in working dir):

shell command
git reset <path>
Copied!

Change author for last commit:

shell command
git commit --amend --author "Some Name <some@email>"
Copied!

Squash last 2 commits:

shell command
git rebase -i HEAD~2
Copied!

In the editor, replace 'pick' with 'squash' in the line describing the latest commit

This is very handy, in case you accidentally created a new commit instead of adding to an existing commit (with git commit --amend). This way, you can merge the last 2 commits and the commit messages.

Information: Where was a patch included?

Sometimes you see an old gerrit issue that was committed and pushed against main, but wonder in which TYPO3 version it was included. Often, you can already deduce from a Releases: main, 12.4 line that it was committed when 13.4 was main. But if you only see Releases: main you might begin to look up the date of a patch and relate it to release dates, or begin to inspect the git repository manually.

But: Hold on! Just check out the Gerrit interface and on the top right you see the menu, from where you also cherry-pick a patch or download a patch. There's a menu entry Included in which will reveal all TYPO3 releases (via GIT tags), a patch was included in.

References

See also these not TYPO3 specific cheat sheets for git if you are not very familiar with git:

To learn more about the internal working of Git, check out these resources:

Troubleshooting

Git Troubleshooting

Before you're able to push your commits you have to set up your account. Make sure, you setup Git correctly.

Also, you may want to check your configuration

Permission Denied

shell command
git push origin HEAD:refs/for/main
Copied!
result
Permission denied (publickey).
fatal: The remote end hung up unexpectedly
Copied!

If this error happens, double check if you are:

  • Using the correct SSH user name (which is your user name on typo3.org)
  • If your username contains special characters (like @ or !), you must escape them using a backslash (or even better: use a username without special characters)
  • You must use an SSH key known to Gerrit
  • You must use the correct URL

The following push command (with -v) shows you the push URL (which must contain review.typo3.org):

shell command
git push origin HEAD:refs/for/main -v
Copied!
result
Pushing to ssh://<username>@review.typo3.org:29418/REPOSITORY_NAME.git
Permission denied (publickey).
fatal: The remote end hung up unexpectedly
Copied!

Debugging the SSH Connection

Try connecting to the server with using an SSH client (OpenSSH, Putty, etc.):

shell command
ssh -p 29418 <username>@review.typo3.org
Copied!

If the output looks like this, everything is fine:

result
****    Welcome to Gerrit Code Review    ****

Hi <Name>, you have successfully connected over SSH.

Unfortunately, interactive shells are disabled.
To clone a hosted Git repository, use:

git clone ssh://<username>@review.typo3.org:29418/REPOSITORY_NAME.git

Connection to review.typo3.org closed.
Copied!

Otherwise, your SSH client does not automatically choose the right private key file. By default, SSH searches for the key in ~/.ssh/id_rsa and ~/.ssh/id_dsa.

You can manually specify the location using the -i parameter:

shell command
ssh -p 29418 -i <path-to-private-key> <username>@review.typo3.org
Copied!

If this works, modify ~/.ssh/config to define the file name for connections to review.typo3.org:

 /.ssh/config
Host review.typo3.org
  User <username>
  IdentityFile ~/.ssh/<keyfile>
  Port 29418
Copied!

Now the connection should work without having to specify any parameters as described above.

If this does not work another issue might be that your SSH version is too new and does not accept the signature algorithm. You can test this by executing:

shell command
ssh -v -p 29418 -i <path-to-private-key> <username>@review.typo3.org 2>&1 | grep "no mutual signature algorithm"
Copied!

If you see the following:

result
debug1: send_pubkey_test: no mutual signature algorithm
Copied!

you need to allow the rsa Algorithm in your SSH config:

 /.ssh/config
Host review.typo3.org
  ...
  PubkeyAcceptedKeyTypes +ssh-rsa
Copied!

Push: invalid committer

shell command
git push -v origin HEAD:refs/for/main
Copied!
result
Pushing to ssh://<username>@review.typo3.org:29418/REPOSITORY_NAME.git
remote: ERROR:  https://review.typo3.org/#/settings/contact
remote:
To ssh://<username>@review.typo3.org:29418/REPOSITORY_NAME.git
! [remote rejected] HEAD -> refs/for/main (invalid committer)
error: failed to push some refs to 'ssh://<username>@review.typo3.org:29418/REPOSITORY_NAME.git'
Copied!

This message simply means that your email address is not registered as a Web-Identity. If this error happens, just go to the website that the error message suggests: https://review.typo3.org/#/settings/contact. Register the email address you use to push (button Register New Email) - even if it is already in the dropdown list. Click on the link you receive via email. Be sure your are already logged in on review.typo3.org. Otherwise the link does register the email address. Check if your new identity is registered (https://review.typo3.org/#/settings/web-identities). Pushing should work now.

You are not a committer

If you are trying to push changes and get this error message, then your email address is probably not known to the system. Open Settings > Identities in Gerrit and check the email address, which is connected to your account (you can add more of them if needed). Additionally, check your settings in Git with the following command:

shell command
git config user.email
Copied!

If needed, change it with the following command:

shell command
git config --global user.email your-email@example.org
Copied!

You may change the user/author of your last commit with:

shell command
git commit --amend
Copied!

Missing Change-Id in commit message

result
! [remote rejected] HEAD -> refs/for/X/X (missing Change-Id in commit message)
Copied!

If pushing a commit fails with this error message, you probably did not copy the commit-hook. Make sure that the file .git/hooks/commit-msg exists and is executable.

Afterwards, you have to amend your commit to make it include the Change-Id:

shell command
git commit --amend
Copied!

Push: prohibited by gerrit

If Gerrit rejects your push with:

result
[remote rejected] main -> main (prohibited by gerrit)
Copied!

you are likely trying to do a simple git push. However, as Gerrit prohibits directly pushing to the target branches, you have to use this lengthy command:

shell command
git push origin HEAD:refs/for/<release-branch>
Copied!

For example:

shell command
git push origin HEAD:refs/for/main
Copied!

Push: Invalid Key Format

You get an error about an invalid key format. This might happen if you didn't save your key in the OpenSSH format but in a proprietary format like i.e. offered by PuTTY.

Review the sections about creating a valid public/private key pair on your operating system: Setting up Gerrit (ssh)

A valid private key in OpenSSH format starts with the following lines:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,0314A92F87D7FEDF
Copied!

followed by about 25 lines of seemingly random signs.

Pushing old Patch Set again (updating/rebasing)

If you want to update an older patch set/version, so that it appears to be the current one, you always need to get an updated commit hash. So you cannot just checkout Patch Set 1 (or any other one) and perform a Git push. This would be refused with a "no new changes" error message.

So you need to amend the commit using:

git commit --amend
Copied!

and then, even without modifying the Commit Message, it gets a new SHA. This commit can then be pushed again.

Resolving Merge Conflicts in generated asset files

If you cherry pick a patch for review, you might encounter a merge conflict with a generated asset file (JavaScript or CSS build files):

result
Mergeconflict in typo3/sysext/backend/Resources/Public/Css/backend.css
Copied!

To resolve the conflict, do not try to resolve conflicts in a huge 1-line file, but instead re-create the assets using the following workflow:

shell command
# Perform re-build using the helper "runTests.sh"

# Make sure dependencies are up to date
./Build/Scripts/runTests.sh -s composerInstall

# Clean possibly previously build files
./Build/Scripts/runTests.sh -s clean

# Execute the build
./Build/Scripts/runTests.sh -s build

# Now add all conflicting files as resolved:
git add typo3/sysext/backend/Resources/Public/Css/backend.css

# Continue the cherry-pick process
git cherry-pick --continue
Copied!

You will see the Commit Message again and you can now save it. When you push this change, it will create a new Patchset - this is expected behavior.

In which TYPO3 release was a patch merged into?

See Information: Where was a patch included? for information on how to use the Included in menu button to see, in which TYPO3 releases a patch was merged into.

Appendix

The appendix contains some additional information that covers topics in more depth than what is already described in the main section.

Working with Git Tower

Git Tower is a Git GUI for OSX.

Tower provides extended support for Gerrit_, which comes in handy because we work with Gerrit in the TYPO3 project.

Although it is a paid product, we think the cost is absolutely worth it.

You can learn more about Git Tower on their website https://www.git-tower.com/.

Enabling Extended Gerrit Support in Tower

In Tower's preferences window, activate the Gerrit Code Review option. This will enable the following adaptions in Tower's UI.

Restart Tower after you enabled the setting.

Pushing to Gerrit

With the Gerrit option enabled in Tower's preferences, performing "Push" operations to Gerrit becomes easier:

Custom Menu Options
When right-clicking a local branch in the sidebar, a new Push <branch> to Gerrit… menu option is available. If you hold down the ⌥ key, the item becomes a "quick" action that will be performed without a confirmation dialog.
Custom Toolbar Button

You can add a custom Gerrit Push button to the toolbar. To do this, choose Customize Toolbar from the "View" main menu and drag the corresponding button onto the toolbar.

You'll find that the following dialog is optimized for pushing to Gerrit. It will automatically format the Push Refspec according to Gerrit's requirements - so you can simply enter the name of the code review branch you want to push to.

GRUNT install on OSX

First off, make sure you installed npm like described here.

In your Terminal app navigate to the folder that you cloned the TYPO3 source into. Switch into the Build folder and run

npm install
Copied!

This will install Grunt as well a s couple of Task plugins we use in the TYPO3 core. To make sure grunt is running, run

grunt css
Copied!

This will run all registered tasks defined in the TYPO3 core.

Npm install on OSX

Head over to https://docs.npmjs.com/cli/ and follow the install instructions.

Once you have installed it, you can open up the Terminal app which is located under Applications/Utilities on your mac. Once in the terminal, type npm -v to get the version number of npm that is currently running on your machine.

... highlight:: bash

Creating a SSH Public Key on OSX

You generate an SSH key through Mac OS X by using the Terminal application. Once you upload a valid public SSH key, Gerrit can authenticate you based on this key.

An SSH key consists of a pair of files. One is the private key, which you should never give to anyone. No one will ever ask you for it and if so, simply ignore them - they are trying to steal it. The other is the public key. When you generate your keys, you will use ssh-keygen to store the keys in a safe location so you can authenticate with Gerrit.

To generate SSH keys in Mac OS X, follow these steps:

  1. Enter the following command in the Terminal window:

    ssh-keygen -t ed25519
    
    Copied!

    This starts the key generation process. When you execute this command, the ssh-keygen utility prompts you to indicate where to store the key.

  2. Press the ENTER key to accept the default location. The ssh-keygen utility prompts you for a passphrase.
  3. Type in a passphrase. You can also hit the ENTER key to accept the default (no passphrase). However, this is not recommended.

After you confirm the passphrase, the system generates the key pair and you will see output like this:

Your identification has been saved in /Users/yourmacusername/.ssh/id_ed25519.
Your public key has been saved in /Users/yourmacusername/.ssh/id_ed25519.pub.
The key fingerprint is:
ae:89:72:0b:85:da:5a:f4:7c:1f:c2:43:fd:c6:44:38 yourmacusername@yourmac.local
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|         .       |
|        E .      |
|   .   . o       |
|  o . . S .      |
| + + o . +       |
|. + o = o +      |
| o...o * o       |
|.  oo.o .        |
+-----------------+
Copied!

Your private key is saved to the id_rsa file in the .ssh subdirectory of your home directory and is used to verify the public key you use belongs to your Gerrit account.

Your public key is saved to a file called id_rsa.pub in the .ssh subdirectory of your home directory. You can copy it to your clipboard using the following command:

pbcopy < ~/.ssh/id_ed25519.pub
Copied!

Now you can head over to Gerrit_, go to settings and paste your public key as described here.

Gerrit is using the special port 29418 instead of the default SSH port 22 which has to be configured accordingly. This can be done in your local ~/.ssh/config file which would contain the following sections then:

 /.ssh/config
Host review.typo3.org
Port 29418
Copied!

Testing your connection:

shell command
ssh -T <YOUR_TYPO3_USERNAME>@review.typo3.org
Copied!

SSH and Git tools on Windows

On Windows you have two different ways to use Git:

  • WSL2 - The Windows Subsystem for Linux (2nd edition) is a native Linux environment that runs alongside Windows
  • Git for Windows - The native Git version for Linux

As Git requires SSH tools in order to talk to repositories via SSH you have two options:

  • WSL2 - SSH is available within the WSL distributions by default
  • Git for Windows - You may either use the Windows native tools (see below) or use those shipped with Git for Windows.

Installing native SSH tools

Using the native tools has the benefit of having an ssh-agent as a Windows service.

OpenSSH Client tools is an optional Windows feature and can be installed via the Windows settings. Search for "Manage Optional Features". Check for "OpenSSH Client" and install via "Add a feature" button if not already present.

Installing Git For Windows

Download Git For Windows from https://git-scm.com/download/win.

Run the installer Git-x.y.z-nn-bit.exe.

The following steps outline some of the dialogs shown in the process to help you making the right decisions.

Accept the GPL2 license.

Windows Explorer integration is very handy, especially the "Git Bash here" option.

Choose your editor.

Adjust the default Git branch naming to your likings.

Follow the recommendation. This is especially necessary for some IDEs.

Decide whether you want to go with the bundled OpenSSH binaries or use "external" ones, for instance those shipped with Windows. For users of PuTTY the second option might be feasible too, but this usually involves more setup with IDEs and other tools than going with OpenSSH binaries.

Select what best fits your needs.

Select the option "Checkout as-is, commit commit as-is". This ensures Git does not mangle your files magically. Better make sure your editor is set to use LF while contributing to TYPO3. (While the other options seem convenient, keep in mind that maybe you have to use CRLF for some reason at some point. This will need extra work to achieve.)

Select the terminal of your choice. MinTTY is a good choice, because it's mostly what you would expect from a terminal.

Choosing "Rebase" is a safe default setting to start with. It makes sure that your commits are placed on top of whatever you pull in from the remote. If conflicts occur you have to solve them in your commit, contrary to a merge commit. This is a good option for TYPO3 development, but you may want to adjust this for other projects. It can be configured per repository, this is just the global default.

Check if GCM is helpful for you. With TYPO3 repositories you always use SSH to push things, so this won't matter.

Try those features. The caching is indeed neat.

Pseudo console support eases use of docker exec commands from within Git Bash. The "file system monitor" is up to you.

Done! You are good to go.

Continue with the general Git setup instructions.

Creating an SSH Public Key on Windows

Microsoft has decent documentation on this:

https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement#user-key-generation

Cloning with SourceTree on Windows

SourceTree General Setup

Prerequisites

In order to use SourceTree in Windows PuTTY should be installed and your SSH key loaded into pageant (see Create SSH key on Microsoft Windows).

Installation

  1. Download SourceTree at https://www.atlassian.com/software/sourcetree
  2. Execute the installer

Basic Settings

First of all set the basic settings for your Git configuration by clicking on the settings button in SourceTree and add your name, email and SSH Key. Make sure the option "SSH Client" is set to PuTTY/Plink.

Clone

To clone a new repository click on "Clone/New".

Enter the URL to your repository and the path to your local folder. For easier access to your repositories leave the bookmark check box checked.

Click on Clone. Checking out the full TYPO3 Core repository might take some time, please be patient.

Reviewing and testing patches

Update the repository

Before applying a patch you should update the repository to its latest state. Press the pull button from the main button bar:

Then click OK:

Cherry-picking

First visit the page of the patch in Gerrit. From the Download menu, choose the copy button after the 'Cherry Pick' line.

The next step has to be done via the command line. Open git bash by pressing "Terminal" and paste the copied line with the 'Ins' button:

The patch is now applied and you can start testing.

Creating patches

Commit hook

In each folder that contains a repository you need to execute the following command to install a Git hook which adds a unique Change-Id to the commit message (and performs a few checks). Choose the repository from your bookmarks and click "Terminal" to open a git bash for that repository. Copy the following command to the bash and execute it:

curl -o .git/hooks/commit-msg "https://typo3.org/fileadmin/resources/git/commit-msg.txt" && chmod +x .git/hooks/commit-msg
Copied!

Setup for pushing to Gerrit

In the Git Bash window (click Terminal), enter the following commands to set that you push to Gerrit instead of the TYPO3 repository directly.

git config url."ssh://<username>@review.typo3.org:29418/Packages/TYPO3.CMS.git"
git config remote.origin.push refs/heads/*:refs/for/*
git config branch.autosetuprebase remote
Copied!

Create a branch

It's easier to undo all the changes in a patch if you create a branch for it. Click on the branch button and enter a name for your new branch, then click "Create Branch".

Now start coding and commit your changes (By pressing the "Commit" button). Make sure your commit message is writtenmaccording to the >>>rules for the commit message<<< and click OK.

Your changes are now stored locally in a separate branch.

Send the patch to Gerrit

Click the "Push" button to open the push dialog.

Check the checkbox in front of your feature branch. As remote branch add "refs/for/main" - which will create a new patchset for main. If you want to create patches for older branches use 'refs/for/<branchName>', for example 'refs/for/TYPO3_6-2'. Be aware that you have to fix a bug in the main branch first before it can go to older branches.

Now click ok. You should get a Gerrit link to your new change in the resulting output.

Cleaning up

To get back to the main branch just click on it at the "Branches" section. If you want to delete your feature branch, right click on it and choose "Delete".

Troubleshooting for Windows

SSH

Permission denied (publickey)

If you try to push to gerrit and you keep getting the following error message

Permission denied (publickey).
fatal: Could not read from remote repository.
Copied!

Checklist for SSH problems

  1. Make sure the public SSH key is stored in your Gerrit account.

    See Setting up Gerrit (ssh)

  2. Check if your private SSH key is in the correct OpenSSH format.

    You can export your SSH key to the correct OpenSSH format with the Putty Key Generator with Conversions -> Export OpenSSH Key -> save with a filename, but without a file ending!

  3. Check if the ssh-agent is running or turn it on

    ssh-agent -s
    Copied!
  4. Add your SSH key to the ssh-agent

    ssh-add ~/.ssh/my_key
    Copied!

    The SSH key should have NO file ending (like .ppk). In windows explorer you should find the SSH key in the file:

    C:\Users\<username>\.ssh\
    Copied!

Setting up TYPO3 manually under Linux

Prerequisites

You will need a Webserver, PHP and database on your system. Look at the page System requirements and check out the specific system requirements for the current main branch on the Download TYPO3 page.

Just as a minimal example, this is a list of packages you might want to install on a Debian flavored Linux system (e.g. Ubuntu).

Setup

Apache Webserver

shell command
sudo apt-get install apache2
sudo a2enmod deflate rewrite headers mime expires
Copied!

PHP

Install the latest PHP version for the core development branch (see composer.json in TYPO3 repository on GitHub), including the required PHP extensions listed in System requirements.

shell command
sudo apt-get install libapache2-mod-<version> php<version>-cli ...
Copied!

Make some changes to php.ini and reload. Also refer to the System requirements for the recommended values, but you may want to increase the values for your development environment.

Make some changes to php.ini (or appropriate file in conf.d) and reload:

php.ini (or other PHP config filename)
memory_limit = 512M
max_execution_time = 240
max_input_vars = 1500
Copied!

Restart Webserver:

shell command
sudo service apache2 restart
Copied!

MySQL Server

shell command
sudo apt-get install mysql-server
Copied!

ImageMagick

shell command
sudo apt-get install imagemagick
Copied!

Create a basic site for your installation

Edit a sitefile, make sure it will point to the correct htdocs directory:

/etc/apache2/sites-available/t3coredev.conf
<VirtualHost *:80>
  ServerAdmin youremail@yourdomain
  ServerName t3coredev
  DocumentRoot /var/www/t3coredev
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Copied!

Enable it:

shell command
sudo a2ensite t3coredev
sudo service apache2 reload
Copied!

Create a domain in your /etc/hosts

/etc/hosts
127.0.0.1 localhost t3coredev
Copied!

You will now be able to access your TYPO3 installation via http://t3coredev/typo3/ and it will greet you with an error message, because it is not configured yet

Next step

Proceed with Setting up TYPO3 manually.

Creating a SSH Public Key on Unix/Linux

Please refer to OSX section about generation of SSH keys, it is the same way.

Coding Guidelines

More information is found in the Coding Guidelines section of the "TYPO3 Explained" manual (formerly known as "Core API").

This is just a very brief overview.

PHP

Make sure you are using the correct PHP code style. It is based on the TYPO3 Coding Standards, (which follows PER-CS1.0 / PSR-12 and transition into PER-CS2.0 at the time of this writing), and covered in the TYPO3 Coding Guidelines.

See PhpStorm setup: CGL for information on how to configure the correct coding style.

The Appendix contains information on scripts to check / fix coding guideline issues: CGL check and fix

JavaScript

The following rules should be applied for JavaScript: Airbnb JavaScript Style Guide

TypeScript

The following rules should be applied for TypeScript: Excel Micro TypeScript Style Guide.

Xliff files

Language files are usually stored in a Folder Resources/Private/Language in files with the ending .xlf. While no tabs are allowed to indent in PHP files, you should edit Xliff files using tabs. Please also check Xliff / language files for Xliff-specific things to pay attention to.

Commit Hooks

commit-msg Hook

  • File: .git/hooks/commit-msg
  • Source file: Build/git-hooks/commit-msg

This hook is mandatory. It must be used for core contribution!

First of all, this hook will be executed whenever you do a commit on your local machine.

The most important task of the hook is to generate a unique Change-Id for your commit. This Change-Id is mandatory for Gerrit to identify your change. There is no way around this and it is not up for discussion :) This Change-Id will only be generated if it is not yet present in your commit message - please do not try to come up with a Change-Id on your own, the result will be chaos.

Apart from that the hook will check your commit message for logical errors like missing keywords, Resolves lines etc. For detailed information on the format of a commit message, click here. This also describes cases in which you might exceed the line length of 72 characters (hyperlinks).

If the commit-msg hook finds errors in your commit-msg, you can try again, by amending to the commit:

git commit --amend

Copied!

pre-commit Hook

  • File: .git/hooks/pre-commit
  • Source file: Build/git-hooks/unix+mac/pre-commit
  • This hook is optional. This hook is not available for Windows., however it can be executed on Windows machines by using a tool like the Git BASH.

The pre-commit hook checks all added PHP files staged for the commit for Coding Guideline issues and will report any problems it finds.

To fix the issues, see CGL check and fix.

After fixing the files you must amend your commit:

git commit -a --amend
Copied!

Post-checkout hook for composer install

If you want to run composer install for each checkout (e.g. when switching branches, tags, etc), then you can use the post-checkout commit hook.

Create a file named .git/hooks/post-checkout with the following contents:

#!/usr/bin/env python3
#-*- coding: utf-8 -*-

"""A post-checkout git hook to execute `composer install`

:Author: Philipp Gampe
"""

import subprocess
import string
import os
import sys

PATH_TO_COMPOSER = '/home/phil/bin/composer.phar'
HOOK_DIR = os.path.dirname(os.path.realpath(__file__))
GIT_ROOT_DIR = os.path.dirname(os.path.dirname(HOOK_DIR))

def main():
    if sys.argv[3] == '1':
        os.chdir(GIT_ROOT_DIR)
        return subprocess.run([PATH_TO_COMPOSER, 'install'], timeout=30)

if __name__ == '__main__':
    result = main()
    if result:
        exit(result.returncode)
    else:
        exit(0)
Copied!

Commit Message rules for TYPO3 CMS

Since we strive to automate a lot of things the commit message plays an important role in order to be able to automate.

Git and related tools work best when following a certain guideline for commit messages. A deeper introduction on git revision log conventions is helpful to understand the scope.

Here is an example of a final commit message. The Change-Id will be generated by the commit-hook. Do not set the Change-Id on your first commit!

[BUGFIX] Introduce some serious fixing

Most importantly, describe what is changed with the commit
and not what is has not been working
(that is part of the bug report already).

More detailed explanatory text, if necessary. Wrap it to 72 characters.
The first line is treated as the subject of the commit message and
the rest of the text as the body.  The blank line separating the
subject from the body is critical (unless you omit the body entirely);
tools like git rebase can get confused if you run the two together.

Write your commit message in the '''imperative present tense'''
("Fix bug", not "Fixed bug"). This convention matches up with generated
commit messages by commands like git merge and git revert.

Help others to understand what you did (Motivation for the change?
Whats the difference to the previous version?), but keep it simple.

Problem description as well as testing and/or reproduction instructions
shall be part of the Forge ticket referenced below.
The commit message solely describes '''what is changed'''.

* Bullet points are okay, too
* An asterisk (`*`) is used for the bullet, it can be followed by a
  single space. This format is rendered correctly by Forge (redmine)
* Use a hanging indent

Resolves: #12346
Related: #12340
Releases: main, 13.4
Change-Id: I<some string generated by the git commit-msg hook>
Copied!

You can see that a commit message consists of several parts, let's go over them step by step:

Summary line (first line)

A summary line starts with a keyword and a brief summary of what the change does. Make sure to describe how the behavior is now, not how it used to be - in the end, telling someone what was broken doesn't help anyone, you want to tell what is working now :)

  • Prefix the line with a keyword: [BUGFIX], [FEATURE], [TASK] or [DOCS].

Possible keywords are:

[BUGFIX]
A fix for a bug.
[FEATURE]
A new feature (also small additions). Most likely it will be an added feature, but it could also be removed. Features may exclusively be targeted for the "main" branch of TYPO3 CMS, because no new features are allowed in older branches. Exceptions to this have to be discussed on a case-to-case basis with the designated release managers. Features have to be documented in the changelog.
[DOCS]
This tag is used for changes regarding the documentation.
[TASK]
Anything not covered by the above categories. E.g. Refactoring of a component

Additionally other flags should be added under certain circumstances:

[!!!]
Breaking change. After this patch, something works different than before and the user / admin / extension developer will have to change something. Has to be documented accordingly and should only be targeted for the main branch. See Editing the changelog.
[SECURITY]
Visualizes that a change fixes a security issue. This tag is used by the Security Team.
  • Keep the whole line below 52 characters if possible, but below 72 in any case
  • It is very important that the message is written in imperative mood; that means that it must be written as if you are giving a command or an instruction, since a commit is a set of instructions for how to go from a previous state to the new state and the commit message should describe this process. This convention matches up with generated commit messages by commands like git merge and git revert. If in doubt, the golden rule to follow is very simple: Review your subject lines, and apply the following words in front of it:

if applied, this commit will **"your subject line here"**

For example (you will find some more examples later):

If applied, this commit will **Invalid session token on creating content element in admin panel** Does not make any sense.

If applied, this commit will **"Fix backend edit URL in admin panel"** Reads nicely and explains what happened

  • After the keyword, make sure to start the summary with a capital letter.
  • Avoid using EXT:somesystemextension in the commit subject: looks ugly and is redundant when you look at what code changed.
  • In case of reverting a previous commit, basically you should just prepend [TASK] to the message automatically generated by a git revert. For example, in case of reverting a feature you would use: [TASK] Revert "[FEATURE] Transform Lead to Gold"

Deprecations

Some examples of topic descriptions

[BUGFIX] Throw HttpStatusExceptions in BackendController

[FEATURE] Add option to hide BE search box in list mod

[!!!][FEATURE] Implement new BE login form service

[!!!][TASK] Replace Foo API with new approach

[SECURITY] Escape record title in RecordsOverview

Note: The [!!!] prefix is added at the very beginning of the line, so it doesn't get overlooked.

Description (Message body)

Here you can go into detail about the how and why of the change. It should be brief, but yet descriptive so people reviewing your change get an idea what they need to look out for

  • Describe the fix/change introduced by the Change Request. (The problem is already described in the Forge ticket.)
  • Keep it simple and don't repeat information that is already part of the issue tracker. Especially avoid "How to reproduce" part. At most, try to explain the change itself, if it is not already clear by reading the diff. Do not repeat the code change itself in the body text.
  • Wrap the lines after 72 characters manually

Relationships

  1. Resolves: You need to reference an issue on Forge here simply by adding #[ISSUE_NUMBER]. For features and tasks, it closes the issue on merge.:

    commit message
    Resolves: #12345
    Copied!

    Historical : Some issues from the time since the introduction of GIT (March 1st 2011) and the migration of the bug tracker to Forge (March 29th 2011), still refer to Mantis bug tracker numbers, with a prefix the number with an M , i.e.:

    commit message
    Resolves: #M12345
    Copied!
  2. Related: Other issues related to this change which are not resolved (for all types, it simply adds a relation, no closing). You need to reference an issue on Forge by just adding the issue number like in:

    commit message
    Related: #12345
    Copied!
  3. Releases: This is a comma separated list of the target versions you intend to apply this fix on. In general, we always fix things on main first and then backport a change if it goes along with our support rules for older versions. Example:

    commit message
    Releases: main, 13.4, 12.4
    Copied!

    Always make sure the target version does indeed exist, when in doubt, as in the coredev channel on Slack.

  4. Depends: For TYPO3 documentation patches. Refer to the corresponding TYPO3 Core patch:

    commit message
    Depends: ChangeIdOfCorePatch
    Copied!
  5. Change-Id: Do not write or change this line yourself. But keep the line once it exists.

    The change id is a randomly generated unique ID that identifies this change in Gerrit. The Change-Id line is automatically added by our pre-commit hook. The commit hook is executed when you have finished editing and save the commit message.

    Attention: Be sure to keep the existing Change-Id when adding a new patchset to an existing review. Use git commit --amend to do so.

Reverting patches

If there's the need to revert a patch, please add this information to the commit message:

  1. Add a Resolves-line for the ticket that is giving the reason for the revert.
  2. Add a Reverts-line for the ticket that belongs to the original patch.

You will find more information about the life cycle of a patch here Revert patches.

Commit Template

You can use a custom template for automatically generating a commit message with the basics.

This is covered in the Git setup instructions, see Setting up a Commit Message Template.

Bad summary lines examples vs. good examples

Please note that the following examples are taken from real commits.

Example 1

[FOLLOWUP][BUGFIX] Remove uglify of jquery-ui/sortable.js
Copied!

should have been:

[BUGFIX] Remove uglify of jquery-ui/sortable.js
Copied!

Example 2

[BUGFIX] EXT:filelist Cancelling the file exists already modal works now
Copied!

should have been:

[BUGFIX] Allow cancelling modal that appears when file exists
Copied!

Example 3

Revert "[FEATURE] EXT:form - introduce YAML "imports""
Copied!

should have been:

[TASK] Revert "[FEATURE] introduce YAML "imports""
Copied!

Example 4

[TASK] Revert "Add support for PSR-15 HTTP middlewares"
Copied!

should have been:

[TASK] Revert "[FEATURE] Add support for PSR-15 HTTP middlewares"
Copied!

Example 5

[TASK] use horizontal ellipsis instead of 3 dots
Copied!

should have been:

[TASK] Use horizontal ellipsis instead of 3 dots
Copied!

Example 6

[BUGFIX] Element Browser should only render default language pages
Copied!

should have been:

[BUGFIX] Limit element browser to only render default language pages
Copied!

Example 7

[BUGFIX] D3.js uses basic authentication credentials cached in browser
Copied!

should have been:

[BUGFIX] Use only basic authentication credentials cached in browser in D3.js
Copied!

Example 8

[DOCS] 1/1 9.1 Documentation
Copied!

should have been:

[DOCS] Add documentation for version 9.1 (1/1)
Copied!

Example 9

[FEATURE] Option to globally enable redirect hit count
Copied!

should have been:

[FEATURE] Add option to globally enable redirect hit count
Copied!

Example 10

[TASK] Improved extension configuration API
Copied!

should have been:

[TASK] Improve extension configuration API
Copied!

Example 11

[BUGFIX] NewContentElementWizardController to NewContentElementController
Copied!

should have been:

[BUGFIX] Remove recently introduced NewContentElementWizardController
Copied!

Example 12

[BUGFIX] Invalidate session token on creating content element in admin panel
Copied!

Should have been:

[BUGFIX] Fix backend edit URL in admin panel
Copied!

... highlight:: bash

Composer

About Composer

Composer is a dependency manager for PHP.

So what it basically does is find packages you have defined to be part of your application (in our case TYPO3). But what if these packages rely on other packages as well? This is where Composer jumps in and takes care of keeping all these packages in sync.

Since we use quite some packages (because why would we invent things ourselves that are already there?) Composer is an extremely useful tool for us.

Install Composer

Follow the installation instructions from https://getcomposer.org. Afterwards, you should have a working executable composer available.

Verify composer is working:

$ composer --version

Copied!

Composer Commands

Once you have installed Composer, this is the command you should run after you clone the Git source and after every git pull request or switching branches:

composer install
Copied!

But, just follow the setup instructions, it will walk you through the commands in the correct order!

Custom TYPO3 Composer Commands

Some additional Composer commands have been added for Core development.

Just run:

composer
Copied!

to list them. You will see something like:

gerrit:setup                           Enable all the git hooks needed to make contribution easy
gerrit:setup:commitMessageHook:enable  Enable the commit message hook needed for gerrit
gerrit:setup:preCommitHook:disable     Disable pre commit hook to run some checks locally
gerrit:setup:preCommitHook:enable      Enable pre commit hook to run some checks locally
Copied!

Extension scanner

Whenever functionality is deprecated or removed by a breaking change it should be added to the Extension Scanner as either a weak or strong match.

When changing Core API, Core developers should monitor the extension scanner and add matcher configurations where possible. This is typically the case if PHP API was changed and the patch comes with a deprecation or breaking ReST file to document the change.

Connection to the changelog reStructuredText files

All changelog type reStructuredText (reST) files since Core version 9 have to be tagged with one of the three tags FullyScanned, PartiallyScanned or NotScanned. In particular, the FullyScanned tag is used by the extension scanner to mark instances as "not affected by this change", as such they should be added with care and only if the scanner configuration matches all changes mentioned in the reST file.

If only parts of the reST file are covered, PartiallyScanned has to be added and the reST file should mention which parts are and are not covered. If the scanner does not cover a reST file at all then NotScanned can be added.

Last line of a fully scanned reST file in the changelog
..  index:: Frontend, FullyScanned, ext:frontend
Copied!

If a reST file is renamed the file may be covered in a matcher configuration which then needs to be adapted as well. The reST files are not bound to specific directories in the matcher configuration so moving a reST file to a different location within the Changelog directory has no effect.

Extension scanner PHP configuration

The match configurations can be found below the following path: EXT:install/Configuration/ExtensionScanner. Choose the file that is related to your change and add the removed functionality to the extension scanner match configuration. As a key we use the fully qualified name.

Example: Deprecate a class

EXT:install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
'TYPO3\CMS\Frontend\Http\UrlProcessorInterface' => [
    'restFiles' => [
        'Deprecation-96641-UnusedHookRelatedUrlProcessorInterface.rst',
    ],
],
Copied!

Example: Drop an argument from a method

EXT:install/Configuration/ExtensionScanner/Php/MethodArgumentDroppedMatcher.php
'TYPO3\CMS\Core\Authentication\BackendUserAuthentication->checkAuthMode' => [
    'maximumNumberOfArguments' => 3,
    'restFiles' => [
        'Breaking-97265-SimplifiedAccessModeSystem.rst',
    ],
],
Copied!

About the PHP part of the extension scanner

The PHP part of the extension scanner is based on the library nikic/php-parser. This library creates an abstract syntax tree from any given compilable PHP file. It comes with a traverser for recursive iteration over the tree that implements a visitor pattern, own visitors can be added. A single "matcher" is a visitor added to the traverser. A default visitor resolves all shortened namespaced class usages to their fully qualified name, which is a great help for our matchers.

This basically means: The whole AST is traversed exactly once for each PHP file and all matchers are called for each node. Matches can then decide if they match a configured deprecation or breaking scenario.

All matchers are covered by unit tests and a fixture that shows what exactly is matched. Studying the fixture can be a good way to understand the matcher.

Matchers are systematically named: for method calls there is a usually one variant for dynamic and one for static calls. If for example a static method changed its argument signature by removing an argument then the according matcher class is \TYPO3\CMS\Install\ExtensionScanner\Php\MethodArgumentDroppedStaticMatcher.

Single matcher configurations are pretty obvious, new ones should be added at the end. When adding matcher configurations it should be verified the match it is not already covered by some other matcher (possibly in another reST file).

How to deprecate classes, methods, arguments and hooks in the TYPO3 core

TYPO3 Core development policy states that public API will not be changed without a grace period where extension authors can adapt to the changes. In that grace period a deprecation warning will be thrown. If you want to remove or change functionality in the TYPO3 Core, it has to be deprecated first.

Here is how:

Deprecate a class

  • Add a @deprecated annotation to the class doc comment
  • Deprecate the constructor - see next section about deprecating a method

Deprecate method

  • Add a @deprecated annotation to the method doc comment
  • Add a trigger_error call to the method, describing the migration path and triggering an error of type E_USER_DEPRECATED
trigger_error(
  'Content with <link> syntax was found, update your content to use the t3:// syntax, and migrate your content via the upgrade wizard in the install tool',
  E_USER_DEPRECATED
);
Copied!

Deprecate method arguments

If you want to deprecate method arguments, check for argument existence and trigger an error the same way you would for a method. If you want to deprecate and remove an unused argument, use func_get_args() or func_num_args() (see example below):

public function TS_AtagToAbs($value)
{
    if (func_num_args() > 1) {
        trigger_error('Second argument of TS_AtagToAbs() is not in use and is removed, however the argument in the callers code can be removed without side-effects.', E_USER_DEPRECATED);
    }
    // ...
}
Copied!

Make class properties protected

To reach full encapsulation of classes, the public access to properties should be removed. The property access should be done by public methods only.

Public properties that should be protected can be migrated to protected or private and wrapped with getters/setters as needed.

During a phase of deprecation, entries into the deprecation log are triggered, if an extension accesses a previously public property. The code still keeps working until the next major release, when the deprecation and public access fallback are removed from the code.

To deprecate usage of a (still) public property that should be changed to protected in the future:

  1. Add the \TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait trait to the class.
  2. Add the property $deprecatedPublicProperties to the class and list all properties that should no longer be accessed from outside of the class.
  3. Make the property private/protected.
+use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
+
class RecordHistory
{
+       use PublicPropertyDeprecationTrait;
+
+       /**
+         * @var string[]
+         */
+        private $deprecatedPublicProperties = [
+            'changeLog' => 'Using changeLog is deprecated and will not be possible anymore in TYPO3 v11.0. Use getChangeLog() instead.',
+       ];
+
        /**
         * @var array
         */
-       public $changeLog = [];
+       protected $changeLog = [];
Copied!

Make class methods protected

This works in a similar way as Make class properties protected: The trait \TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait allows to make public methods protected or private without breaking extensions.

This can be used in case the public methods may still be called by extensions. This will then trigger a deprecation.

In order to make a method private or protected:

  1. Add the \TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait trait to the class.
  2. Add the property $deprecatedPublicMethods to the class and list all methods that should no longer be accessed from outside of the class.
  3. Make the method private/protected.
+use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
+
class PageRepository
{
+       use PublicMethodDeprecationTrait;
+
+       /**
+         * @var string[]
+         */
+        private $deprecatedPublicMethods = [
+            'init' => 'init() is now called implicitly on object creation, and is not necessary anymore to be called explicitly. Calling init() will throw an error in TYPO3 v10.0.',
+       ];
+

-       public function init($show_hidden)
+       protected function init($show_hidden)
Copied!

Deprecate a hook

As hooks provide extension points throughout the core, deprecating and removing them should be carefully considered, but sometimes the placement of a hook doesn't make sense anymore as the functionality around it changed or other hooks / mechanisms replaced it's purpose. If you have to deprecate a hook, call trigger_error before the hook call:

if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksDb_PostProc'])
    && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksDb_PostProc'])
) {
    trigger_error(
        'The hook "t3lib/class.t3lib_parsehtml_proc.php->modifyParams_LinksDb_PostProc" will be removed in TYPO3 v10, use LinkService syntax to modify links to be stored in the database.',
        E_USER_DEPRECATED
    );
    $parameters = [
        'currentBlock' => $v,
        'linkInformation' => $linkInformation,
        'url' => $linkInformation['href'],
        'attributes' => $tagAttributes
    ];
    foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_parsehtml_proc.php']['modifyParams_LinksDb_PostProc'] as $className) {
        $processor = GeneralUtility::makeInstance($className);
        $blockSplit[$k] = $processor->modifyParamsLinksDb($parameters, $this);
    }
}
Copied!

Deprecate methods still called by the TYPO3 Core

If you want to deprecate a method that still has to be used by the core itself to provide the functionality for the time being, you can achieve that by adding a new method parameter that will prevent the deprecation warning message being triggered and add that parameter to the callees in the core.

Example:

/**
 * Transformation handler: 'ts_links' / direction: "rte"
 * Converting TYPO3-specific <link> tags to <a> tags
 *
 * This functionality is only used to convert legacy <link> tags to the new linking syntax using <a> tags,  and will
 * not be converted back to <link> tags anymore.
 *
 * @param string $value Content input
 * @param bool $internallyCalledFromCore internal option for calls where the Core is still using this function, to suppress method deprecations
 * @return string Content output
 * @deprecated will be removed in TYPO3 v10, only ->TS_AtagToAbs() should be called directly, <link> syntax is deprecated
 */
public function TS_links_rte($value, $internallyCalledFromCore = null)
{
    if ($internallyCalledFromCore === null) {
        trigger_error('This method will be removed in TYPO3 v10, use TS_AtagToAbs() directly and do not use <link> syntax anymore', E_USER_DEPRECATED);
    }
    $hasLinkTags = false;
    $value = $this->TS_AtagToAbs($value);
    // ...
}
Copied!

More information

Changelogs

PhpStorm: Setup

Here are some hints and examples, what you can do to setup PhpStorm.

Conventions on this page

If you need to select something from the menu in PhpStorm, menu items are displayed like this: File > Settings > ....

General setup

File > Settings > Languages & Frameworks > PHP

(ctrl + alt + s opens File > Settings)

  • PHP Language Level: choose appropriate version
  • CLI Interpreter: choose appropriate version
Setup PhpStorm PHP settings

Coding Guidelines

Make sure your IDE is setup properly to comply with the Coding Guidelines for TYPO3 (CGL).

EditorConfig

Please note that there is an .editorconfig file in the TYPO3 core repository. See https://editorconfig.org/ for more information. Use the EditorConfig plugin for PhpStorm.

If you use the .editorconfig file (which is included in the TYPO3 core), some standard formatting rules are already setup automatically (e.g. indent with 4 spaces for PHP files).

The rules defined in .editorconfig are very minimal and it is suggested to see the TYPO3 Coding Guidelines for more information and toolchain configuration. Please read PhpStorm documentation on using PHP CS Fixer for information on how to use the provided config.php within PhpStorm.

For a quick start, you can use the following PhpStorm code style to comply with PSR-12, which is the most recent recommendation at the time of this writing that PhpStorm provides a preset for:

PHP files

Set Predefined Style in PhpStorm: File > Settings > Editor > Code Style > PHP > Set From > Predefined Style

Choose PSR-12.

In order to test this, use Code: Reformat Code to reformat a PHP file.

More information

You can find more information on the Coding Guidelines section in the Appendix.

Plugins for PhpStorm

Here are some plugins, you might use when developing TYPO3. DynamicReturnTypePlugin and Php Inspections are not TYPO3 specific, but will show possible errors and are strongly recommended when developing for the TYPO3 core.

Install plugins in PhpStorm

  1. Open Settings: File > Settings (ctrl + alt + s)
  2. Select Plugins
  3. Start typing name of plugin and select a match
  4. Click on Install.

Optional Plugins

Setting up PhpStorm for the Testing Framework

Optional

First setup the Testing Framework. Replace <YOUR_WEBROOT> with your path to the web directory. You must use absolute paths for this.

Setup Test Frameworks in PhpStorm: File > Settings > Languages & Frameworks > PHP: Test Frameworks:

(ctrl + alt + s opens File > Settings)

  • Use composer autoloader
  • Path to script: <YOUR_WEBROOT>/vendor/autoload.php
  • Test runner: Defaut configuration file: <YOUR_WEBROOT>/Build/phpunit/UnitTests.xml
  • Test Runner: Default bootstrap file: <YOUR_WEBROOT>/Build/phpunit/UnitTestsBootstrap.php
Setup Testing Framework

If this is setup correctly, it will be possible to run your unit tests from within the IDE.

Other Resources

TYPO3 Core contribution setup with DDEV

DDEV provides several pre-configured environments based on Docker.

Here is a description of how you can use DDEV to setup a working TYPO3 installation using the cloned TYPO3 CMS git repository.

You don't need to have a Webserver, a Database or PHP running on your system. Everything will be supplied by DDEV. In fact, if you do have a Webserver or Database running on your machine, make sure there are no conflicts (e.g. change the ports in the ddev config).

Prerequisites

  • Install Docker and other ddev system requirements.
  • Install DDEV as described in the Installation instructions.
  • You have cloned the TYPO3 git repository as described in git clone and have switched to the directory which contains the local git repository.

Configure DDEV

For the TYPO3 CMS core latest (main branch) DDEV v1.16.5 or later is suggested to have the correct setup included

ddev config
Copied!

DDEV should suggest the correct defaults and you just need to press ENTER:

> Project name (t3coredev):

> Docroot Location (current directory):

> Found a typo3 codebase at /var/www/t3coredev.
> Project Type [backdrop, drupal6, drupal7, drupal8, drupal9, laravel, magento, magento2, php, typo3, wordpress] (typo3):
Copied!

Change configuration

In order to make further changes to the configuration, use ddev config as shown below or edit the configuration file .ddev/config.yaml manually.

# Set correct PHP version:
ddev config --php-version='8.2'

# Change to Apache webserver because using htaccess rules works out of the TYPO3-box
# and needs no custom NGINX configuration
ddev config --webserver-type='apache-fpm'

# Add necessary packages for the npm build process,
# (only needed if you are working on assets):
ddev config --nodejs-version='22'
ddev config --webimage-extra-packages='automake,build-essential,locales-all'
Copied!

Optionally, set a new HTTP/HTTPS port to avoid conflicts with local defaults. Error message: Failed to start t3coredev: Unable to listen on required ports, port 80 is already in use,

ddev config --router-http-port='8090'
ddev config --router-https-port='8443'
Copied!

Start DDEV

ddev start
Copied!

DDEV should now show a URL under which the site can be reached:

> TYPO3 does not seem to have been set up yet, missing LocalConfiguration.php (/var/www/t3coredev/typo3conf/LocalConfiguration.php)
> Generating AdditionalConfiguration.php file for database connection.
> Successfully started t3coredev
> Project can be reached at http://t3coredev.ddev.site http://127.0.0.1:32773
Copied!

Ignore the warning about missing LocalConfiguration.php for now. We will take care of that below.

Build

It is recommended to run tasks such as composer install etc. via the runTests.sh script. We provide the direct commands in some places - in case there is good reason to run the commands directly. But, if you need the direct commands, you are encouraged to look them up using the instructions in Direct commands without Docker.

ddev composer install
Copied!
Build/Scripts/runTests.sh -s composerInstall
Copied!

The following is not necessary for the initial build, but once you change some assets (for example Typescript, SCSS files), you must build them. You might like to try this now:

cd Build
nvm use
npm install
npm run build
// or: npm run watch:build
Copied!
ddev exec "cd Build && npm install"
ddev exec "cd Build && npm run build"
Copied!
Build/Scripts/runTests.sh -s build
Copied!

The first command is required once, the second (build) command is required after every change of a resource file.

Be aware that until TYPO3 v11.5 yarn was used.

DDEV describe

Let DDEV dump information:

ddev describe
Copied!

Displays information about the project, its URLs and access to phpMyAdmin, MailHog and the MySQL database.

FIRST_INSTALL

Create a file FIRST_INSTALL:

touch FIRST_INSTALL
Copied!

Setup your TYPO3 installation

Now load the URL by running the command ddev launch.

You will now be guided through the basic installation steps by TYPO3.

Additional setup

Be sure to add the .ddev directory to your local gitignore (e.g. .git/info/exclude).

Shutdown DDEV

When you are done you can do:

ddev stop
Copied!

For a list of commands see:

ddev help
Copied!

Next step

If you are in the middle of setting up a TYPO3 installation for core development, continue with

Resources

Remember, you can use the Slack channels to ask for help! Follow the general convention for the channels: not too chatty, get straight to the point and ask, be nice. Register for the TYPO3 slack workspace if you have not done so already.

Slack channels

  • #ddev
  • #typo3-cms-coredev : Only for core development, ask general TYPO3 support questions in #typo3-cms

DDEV documentation

Setting up TYPO3 manually

Prerequisites

You will need a Webserver, PHP and database on your system. Look at the page System requirements and also check out the specific system requirements for the current main branch on the Download TYPO3 page.

You will need to set up the prerequisites for your operating system. Look at the following for guidance:

You have cloned the TYPO3 git repository as described in git clone and are in the directory which contains the local Git repository:

shell command
cd /var/www/t3coredev
Copied!

Create the database

We are assuming you are using MySQL 8.0 and the database should be called t3coredev and you will access it with username typo3 and password somepassword from localhost.

database command
mysql> CREATE DATABASE t3coredev CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
mysql> CREATE USER `typo3`@`localhost` identified by `somepassword`;
mysql> GRANT ALL ON t3coredev.* TO `typo3`@`localhost`;
Copied!

Create FIRST_INSTALL

shell command in /var/www/t3coredev
touch FIRST_INSTALL
Copied!

Installation wizard

You can now access the TYPO3 installation wizard by loading the page in the browser with the configured URL, e.g. http://t3coredev. This should redirect to http://t3coredev/typo3/install.php.

Follow the instructions of the installation wizard.

Slack

If you wish to contribute, joining the TYPO3 slack workspace is recommended as it is the projects chosen platform for communication. In order to join the slack workspace, you must already have your typo3.org account and then Register for TYPO3's Slack Platform.

On that page, you will also find information about recommended channels.

Slack channels

  • #typo3-cms-coredev is your channel of choice for core development
  • #typo3-cms is for general support issues
  • #random if you are not sure which channel to use or have a general question

You do not need to ask for permission when asking a question. Ask your question directly in the channel and wait for a response.

As always, make sure to follow the Code of conduct or the short form: be nice, be helpful!

Sitemap

Index

Quick Start: Create a patch - Intention

For this part of the guide to be effective, we establish our intent.

This could be many things:

  • Fix a bug in one of the TYPO3 Core Extensions
  • Introduce a new feature
  • Fix mistakes or add content in the Documentation of any of the Core Extensions
  • Enhance tests for certain functionality
  • Raise or add dependencies within TYPO3
  • Adjust the TYPO3 Build or Testing Pipeline
  • Make changes to the TypeScript/SCSS build of TYPO3

For the sake of clarity, let's pick a simple example:

I found a bug in the TYPO3 record editing backend (FormEngine) for the JsonElement input (TCA type json). With a new HTML5 spec, all Json presentations need a new attribute called input-format="json" to be set.

For this you have already discovered the TYPO3 Core file typo3/sysext/backend/Classes/Form/Element/JsonElement.php, which has this code at line 188:

    $editorHtml = '
        <typo3-t3editor-codemirror ' . GeneralUtility::implodeAttributes($codeMirrorConfig, true, true) . '>
            <textarea ' . GeneralUtility::implodeAttributes($attributes, true, true) . '>' . htmlspecialchars($itemValue) . '</textarea>
            <input type="hidden" name="target" value="0" />
            <input type="hidden" name="effectivePid" value="' . htmlspecialchars((string)($this->data['effectivePid'] ?? '0')) . '" />
        </typo3-t3editor-codemirror>';
} else {
    $attributes['class'] = implode(' ', array_merge(explode(' ', $attributes['class']), ['formengine-textarea', 't3js-enable-tab']));
    $resultArray['javaScriptModules'][] = JavaScriptModuleInstruction::create('@typo3/backend/form-engine/element/json-element.js');
    $editorHtml = '
        <typo3-formengine-element-json recordFieldId="' . htmlspecialchars($fieldId) . '">
            <textarea ' . GeneralUtility::implodeAttributes($attributes, true, true) . '>' . htmlspecialchars($itemValue) . '</textarea>
        </typo3-formengine-element-json>';
}
Copied!
We change this code into:
    $editorHtml = '
        <typo3-t3editor-codemirror ' . GeneralUtility::implodeAttributes($codeMirrorConfig, true, true) . '>
            <textarea input-format="json" ' . GeneralUtility::implodeAttributes($attributes, true, true) . '>' . htmlspecialchars($itemValue) . '</textarea>
            <input type="hidden" name="target" value="0" />
            <input type="hidden" name="effectivePid" value="' . htmlspecialchars((string)($this->data['effectivePid'] ?? '0')) . '" />
        </typo3-t3editor-codemirror>';
} else {
    $attributes['class'] = implode(' ', array_merge(explode(' ', $attributes['class']), ['formengine-textarea', 't3js-enable-tab']));
    $resultArray['javaScriptModules'][] = JavaScriptModuleInstruction::create('@typo3/backend/form-engine/element/json-element.js');
    $editorHtml = '
        <typo3-formengine-element-json recordFieldId="' . htmlspecialchars($fieldId) . '">
            <textarea input-format="json" ' . GeneralUtility::implodeAttributes($attributes, true, true) . '>' . htmlspecialchars($itemValue) . '</textarea>
        </typo3-formengine-element-json>';
Copied!

Note that we added input-format="json" in the marked lines.

After we patched the file, we can manually check it has the wanted effect.

To contribute this patch and to meet the TYPO3 quality criteria, this change needs to be covered by a Unit or Functional Test (see Testing and Using runTests.sh).

Since testing is vital to TYPO3, we add a test for our code change above.

By browsing through the existing TYPO3 testing directories, we often find tests that can be adapted for the change we make. In this case, there's typo3/sysext/backend/Tests/Unit/Form/Element/JsonElementTest.php which already performs a test:

self::assertStringContainsString('<typo3-formengine-element-json', $result['html']);
self::assertStringContainsString('placeholder="placeholder"', $result['html']);
self::assertStringContainsString('&quot;foo&quot;: &quot;bar&quot;', $result['html']);

// ...

self::assertStringContainsString('<typo3-t3editor-codemirror', $result['html']);
self::assertStringContainsString('placeholder="placeholder"', $result['html']);
self::assertStringContainsString('&quot;foo&quot;: &quot;bar&quot;', $result['html']);
Copied!

In most cases you need to create a distinct test method for patches you make, but in this case we can take the easy route and just append our expectation:

self::assertStringContainsString('<typo3-formengine-element-json', $result['html']);
self::assertStringContainsString('placeholder="placeholder"', $result['html']);
self::assertStringContainsString('&quot;foo&quot;: &quot;bar&quot;', $result['html']);
self::assertStringContainsString('input-format="json"', $result['html']);

// ...

self::assertStringContainsString('<typo3-t3editor-codemirror', $result['html']);
self::assertStringContainsString('placeholder="placeholder"', $result['html']);
self::assertStringContainsString('&quot;foo&quot;: &quot;bar&quot;', $result['html']);
self::assertStringContainsString('input-format="json"', $result['html']);
Copied!

After the change, we can verify our test works:

./Build/Scripts/runTests.sh -s unit typo3/sysext/backend/Tests/Unit/Form/Element/JsonElementTest.php
Copied!

with an output like:

PHPUnit 11.2.5 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.2.20
Configuration: /.../TYPO3-Contribute/Build/phpunit/UnitTests.xml

..                                                                  2 / 2 (100%)

Time: 00:00.021, Memory: 14.00 MB

OK (2 tests, 14 assertions)

###########################################################################
Result of unit
Container runtime: docker
PHP: 8.2
SUCCESS
###########################################################################
Copied!

If you take our patched file typo3/sysext/backend/Classes/Form/Element/JsonElement.php again and accidentally replace input-type="json" with input-type="jason" and re-execute the test, you will see it will properly report a failure.

This concludes stating an intent for contributing a patch and you have a modified file plus a test to contribute. Continue on Quick Start: Create a patch!