Category Archives: Allgemein

Email notification for SSH logins

On servers I maintain I usually have a script running that sends an email whenever someone logs in via SSH. It allows me to keep track on whether something fishy is going on in a very easy way.

It’s not bulletproof but at least provides me with a certain level of safety that everything is all right.

The other day I had to reinstall a server after some time and of course I had to – again – search for how to set that email script up.

Continue reading Email notification for SSH logins

Xdebug in Docker

Yesterday Dmitri Goosens wrote about how to integrate Xdebug into almost any Docker Setup in PHPStorm. An article that I definitely need to digest a bit more as the PHPStorm integration is something that I often neglect. I am happy when it works on the CLI šŸ˜

One thing though that Dmitri skips though (an dfor good reasons) is how to get Xdebug into your Docker environment.

As I have done that quite a number of times by now I thought I’d share the way I do it currently.

This is my Dockerfile

FROM php:8.3-rc-fpm
RUN PHPIZE_DEPS="autoconf \
      cmake \
      file \
      g++ \
      gcc \
      libc-dev \
      libpcre2-dev \
      make \
      git \
      pkgconf \
      re2c" \
    && XDEBUG_VERSION="" \
    && if [ "$(php -v | head -n 1 | grep 8.3)" != "" ]; then XDEBUG_VERSION="-3.3.0alpha3"; fi \
    && apt-get update \
    && apt-get install -y $PHPIZE_DEPS \
    && pecl install xdebug${XDEBUG_VERSION} \
    && docker-php-ext-enable xdebug \
    && echo "xdebug.mode=debug\nxdebug.discover_client_host=on\nxdebug.start_with_request=yes\nxdebug.log_level=0" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
    && apt-get remove -y $PHPIZE_DEPS

That should install a running version of Xdebug on whatever version of PHP you are using and even allows to use the soon to be relesased PHP8.3.

The main lines here are

    pecl install xdebug${XDEBUG_VERSION} \
    docker-php-ext-enable xdebug \

everything else is decoration resp. necessary that those two lines can do their magic.

Feel free to adapt the FROM line to whatever PHP-version you want to use from dockers official PHP-image (remember that that is not maintained by the PHP folks! It’s maintained by Docker!)

After a docker build -t phpxdebugtest . you should now be able to call docker run phpxdebugtest php -v and see this

PHP 8.3.0RC5 (cli) (built: Nov 1 2023 05:26:54) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.0RC5, Copyright (c) Zend Technologies
with Xdebug v3.3.0alpha3, Copyright (c) 2002-2023, by Derick Rethans

And now have fun integrating that Xdebug enabled PHP-Container into your PHPStorm.

Git is awesome

I just recently fat-fingered a branch-deletion of a remote branch. But luckily git has you covered should you do that. Let me tell you the story…

I don’t know why on a lot of keyboards the letters D and F are right next to each other (well, I know but that’s a different story). So far that never was an issue.

But! If you start sloppy typing and while hitting the F key you also hit the D that usually just means you will have to use the backspace and delete a character you didn’t want.

Unless you are on the CLI and hit ENTER immedately after …

What happened:

I was working on a branch and commited some stuff to it. As I already had a PR open for it on github I pushed the change.

Of course the CI found a minor thing in the code. I was casting something that was unnecessary. So I removed that cast in the code and commited that as well to my local branch. As it was a really minor change that I should have done with the previous commit already I decided to do a git commit --amend --no-edit . Just add that to the previous commit and be done.

That now replaced the last commit with a new one and I had to force-push that to the remote branch.

And now I fat fingered.

Instead of git push origin branchname -f I typed git push origin branchname -df

And the -d means: Delete that branch on the remote server.

I mean it’s not that much of a loss. I could have just used git push origin branchname again and be done.

But with deleting the remote branch I also closed the PR. And just pushing the branch again would require me to create a new branch instead of being able to reopen the old one. Why? because the old PR was associated with the old commit-hash. But I now had a new commit-hash.

So how could I fix that?

git reflog to the rescue! While still on the local branch I issued this:

git reflog
4fcb8ff4d (HEAD -> branchName, origin/branchName) HEAD@{0}: commit (amend): Commit Message
0cc696b53 HEAD@{1}: commit: Commit Message
458011b1b HEAD@{2}: rebase (continue) (finish): returning to refs/heads/branchName

So the great thing here is that we not only have the log of our last commits (which would only show one entry for the Commit Message` commit. But we have both commit hashes. How cool is that!

That allowed me now to do git push origin 0cc696b53:branchName which pushed the commit 0cc696b53 to the server and named the resulting branch branchName . That caused GitHub to realize that the branch is still existing and allowed me to reopen the PullRequest.

So now we are almost in the same situation as before my fat fingered stupidity.

The only thing left to do now is to actually push (and not delete) the branch to the server.

And a git push origin branchName -f (no -d) later the branch is updated and the PullRequest knows about the update and CI is up and running.

Thank you git for saving my back!

composer šŸ§” phar

It bothered me for a long time that installing tools via composer cluttered my projects with unnecessary dependencies and also bind my code to the dependencies of my development toolchain and vice-versa.

The easy way to solve that was to use phar-files for the tools I am using in my development chain. So tools like phpunit, phpstan, psalm or phpcs/phpcbf. All of these can be installed via composer require --dev – but also via phive install.

The trouble though when using the phar-files was, that composer didn’t know about them and whenever I wanted to use a plugin for one of those tools, composer didn’t know that the tool was already there and so installed the tool again. Which wasn’t helpful!

I was thinking about multiple ways to handle that. Like a plugin for composer to remove installed PHAR-files from the internal resolver-tree and what other ideas I had. All of these didn’t really work out.

Until a few days it hit me: composers replace config-option!

So what did I do:

After installing my tool – in this case php-codesniffer – via phive install phpcs --copy I created a new composer.json file in the .phive-folder with the following content:

{
    "name": "myproject/phive_stuff",
    "description": "A replacement package for phars",
    "minimum-stability": "stable",
    "license": "MIT",
    "replace" : {
        "squizlabs/php_codesniffer": "*"
    }
}

Now I added this code to my projects composer.json file:

{
    "repositories": [{
        "type": "path",
        "url": ".phive/"
    }]
}

Then all that was left to do was to require the new package via

composer require --dev myproject/phive_stuff 

With all that done I can now install plugins for php-codesniffer via

composer require --dev phpcompatibility/php-compatibility

and composer will realize that php-codesniffer is already installed and not install it again.

Caveat

This has some caveats though! For example there are two tools phpcs and phpcbf that need to be installed via phive while requiring squizlabs/php-codesniffer will install both of them.

Due to the way phive works, the binaries are by default linked into the project from a main folder outside the project which can break when using docker. That’s why I usually call phive with the --copy flag as that actually adds a copy of the phar to the tools -folder.

Due to this linking phpcs suddenly created its config-file in that shared folder which had some unexpected sideeffects. When using --copy the confi is added by default to the tools folder.

So there might be some extra work necessary when using PHARs. But at least it works now šŸ˜

Further ideas

My main idea now was to automate this manual process as that is something that can automatically done by phive when installing (or updating) a tool.

Would that something that helps others as well? Feel free and leave your comment in the feature-request on github

Increase code coverage successively

I often come across legacy projects that have a very low code coverage (or none at all). Getting such a project up to a high code coverage can be very frustrating as you will have a poor code coverage for a very long time.

So instead of generating an overall code coverage report with every pull request I tend to create a so called patch coverage report that checks how much of the patch is actually covered by tests.

Having something like that in place also allows me to force contributors to include tests for their newly contributed code. Which in turn successively improves the overall code coverage up to a level where I might be able to go for that instead of the patch coverage.

But how to implement that?

That’s not as complicated as it sounds. As Sebastian Bergmann already wrote a tool for that.

Enter phpcov

Using phpcov requires us to

  • first generate a diff against the last code-revision,
  • then generate a coverage-report via phpunit --coverage-php and
  • then run phpcov against those artefacts.

So it’s as complicated as

$ git diff HEAD^1 > /tmp/patch.txt
$ ./tools/phpunit --coverage-php /tmp/coverage.cov
$ ./tools/phpcov patch-coverage --path-prefix /path/to/project /tmp/coverage.cov /tmp/patch.txt

That’s it.

It will return a non-zero value when not all lines are covered and it will tell you which lines aren’t covered.

So add that to your automation to have it executed at whatever stage you like (I recommend in the CI-pipeline of your Pull-/Merge-Request and let that fail whenever the return code is non-zero)

Github Action

If you want to see a way to implement that in GitHub Actions, check out this gist.