github annotations
… should return string but returns array|string|null.

Have you ever seen an error message like the one above before? If you’ve used tools such as PHPStan alongside GitHub Actions then it might be familiar to you.

GitHub refers to these as annotations. They are used to add an error message (on the offending line in a pull request), reported from your action’s output. This makes it easier to see why the build is failing.

I find this very useful to avoid having to click my way through the action’s log to find the mistake.

However, not every tool supports annotations — PHP-CS-Fixer being one of those that do not. So while updating some of our continuous integration/continuous delivery (CI/CD) actions, we looked deeper into this and found a pretty easy fix for this problem.

In order to display annotations, GitHub expects a specific type of output from the action. Their documentation about this is pretty hidden but the format is easy.

::error file={name},line={line},endLine={endLine},title={title}::{message}

Looking at the output of PHPStan, a tool that does support annotations, it’s not really recognizable so I suspect there is a little more magic involved on GitHub’s side.

How to add GitHub annotations to PHP-CS-Fixer

After some looking around we found that other people were also suffering from this problem. One of the things mentioned in that issue is that the symfony/console component is offering a GithubActionReporter for this, but PHP-CS-Fixer doesn’t allow you to use it.

Instead, there is an easy workaround for this problem by using the cs2pr package to convert checkstyle reports from PHP-CS-Fixer into GitHub annotations.

The easiest way to make use of this is through the shivammathur/setup-php action by including cs2pr as a tool:

- name: Setup PHP
  uses: shivammathur/setup-php@v2
    php-version: '8.1'
    tools: cs2pr

And change your step to run PHP-CS-Fixer to the following:

- name: ✅ Run PHP Linting
  run: php-cs-fixer fix -vvv --dry-run --format=checkstyle | cs2pr

This will output the PHP-CS-Fixer errors into the checkstyle format and pipe them through to the cs2pr tool, which in turn outputs the annotation syntax.

One thing to note is that PHP-CS-Fixer does not include line numbers in its output. This means that warnings will appear at the top of each file instead of inline, but it’s a compromise I’m willing to make.

I’m already a lot happier to see errors being reported alongside the code instead of having to dig through logs. I hope you find this a useful addition to your CI/CD pipeline.