deployer icon indicating copy to clipboard operation
deployer copied to clipboard

PHPStan and PHPUnit tests fail because of autoloader issues in deployer

Open rutgerrademaker opened this issue 2 years ago • 8 comments

  • Deployer version: v7.0.0-rc.8
  • Deployment OS: Ubuntu

In our recipe we are using PHPStan and PHPUnit (amongst others) to test our recipe. When we started migrating to Deployer 7 our tests could not be executed anymore because of "Autoloader issues" It looks they are related to the fact Deployer only ships the Phar file itself in its releases (and not the files in src/ anymore)

PHPStan e.g throws:

 ------ --------------------------------------------------------------------- 
  Line   tests/UrlMapperTest.php                                              
 ------ --------------------------------------------------------------------- 
  91     Class Deployer\Exception\Exception not found.                        
         💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
 ------ --------------------------------------------------------------------- 
 
  ------ --------------------------------------------------------------------- 
  Line   src/samples/magento2/deploy.php                                      
 ------ --------------------------------------------------------------------- 
  18     Function set not found.                                              
         💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
  21     Function set not found.                                              
         💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
  24     Function set not found.                                              
         💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
  33     Function set not found.                                              
         💡 Learn more at https://phpstan.org/user-guide/discovering-symbols  
 ------ --------------------------------------------------------------------- 

Where PHPUnit will throw

PHPUnit\Framework\Exception: Class "Deployer\Exception\Exception" does not exist

including vendor/autoload.php, like suggested in #3070 e.g

require_once __DIR__ . '/../vendor/autoload.php';

does not do the trick

I already tried stuff like adding the phar file to composer's autoloader section but that did not work out (also not sure if that is even possible)

What did work though was adding a hard reference in composer.jsons autoload section to a deployer/deployer package outside of my project I am working on. e.g

    "autoload": {
        "files": [
            "/home/rutger/packages/deployer/vendor/autoload.php"
        ]
    }

But this of course will not work in CI/CD

I get the feeling this is a bug in Deployer 7, or some documentation on how to use autoloading this is missing. I hope something can be done about this.

For the record, PHPstorm has no issues finding the references inside the phar file, also the code just executes just fine It's the lack of ability to running PHPStan and PHPunit tests that is the issues here.

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar

rutgerrademaker avatar Jul 08 '22 12:07 rutgerrademaker

Well, Deployer comes as a single phar archive. Not sure how to enable phpstan with it.

Maybe exclude deploy.php?

antonmedv avatar Jul 08 '22 13:07 antonmedv

@antonmedv Thanks for the quick reply It's not just deploy.php, its our entire recipe which also holds a bunch of "normal classes" e.g

<?php
declare(strict_types=1);

namespace Some\Namespace;

use Deployer\Exception\Exception;

use function Deployer\get;
use function Deployer\run;
use function Deployer\writeln;

Class SomeClass
{
}

So excluding is not really an option here

For now, we a requiring deployer/deployer "from source" to work around the issue, but we'd really like to just require a stable tag/version and make sure the autoloader can find the classes inside the phar

I'm not sure if that is even possible though, so maybe this issue should be a "question" after all on how to get this resolved Maybe there is a trick to add an extra autloload.php file to the official release that points to the files in the phar?

I found https://github.com/composer/composer/issues/5036#issuecomment-467761062, and although such an approach works for our PHPUnit classes it does not for PHPStan

Via that threat I discovered "phive" (https://github.com/phar-io/phive) which might be of help (but need to test it myself)

rutgerrademaker avatar Jul 11 '22 07:07 rutgerrademaker

@antonmedv

Could you please (re)consider to re-add the source to the releases?

N.B. I think it would make sense to distribute the phar without any (Composer) dependencies. Wasn't this also what https://github.com/deployphp/distribution was for?

Distributing it (only) as a phar via this composer package still has the downside of the dependencies in the composer.json/composer.lock file

If I look at e.g https://github.com/netz98/n98-magerun2#installation I see that they do NOT promote installing the phar via composer, but instead as a direct download. It is still an option to require it as composer (dev) dependency though

rutgerrademaker avatar Jul 11 '22 08:07 rutgerrademaker

Yes, I think it is ok to add source back. With bundled bin.

antonmedv avatar Jul 11 '22 09:07 antonmedv

I ran into a similar problem just now. I built a wrapper around Deployer and my CI started shouting at me because of missing Classes.

I see that you remove the require and autoload blocks from the composer.json on release. That means other packages can never depend on this package.

I assume this is done for performance reasons when running just the phar?

I could work around this by adding the dependencies and autoloading back on the consumer end when the sources are back in the release but that seems like a bad idea ...

Any ideas how to work around this?

bastianschwarz avatar Jul 29 '22 17:07 bastianschwarz

I played around with this a bit more today and came up with the following ... well, I guess it's still a workaround:

Create a bootstrap file for PHPUnit (can be used for Psalm, PHPStan, ...):

require_once __DIR__ . '/../vendor/autoload.php';

\Phar::loadPhar(__DIR__ . '/../deployer.phar');
require_once 'phar://deployer.phar/vendor/autoload.php';

I also created a symlink to the acutal Phar wit a .phar extension in my package root. Mostly to make PHPStorm play nice since it only indexes Phars if they actually have the .phar extension. Added benefit is that I can easily update the path to the actual phar.

This might cause collisions with other packages in case I ever add a package as dependency that already exists in the phar but ... guess the risk is ok for now.

Not ideal, I'd be really happy if there was a "proper" dev package with all the sources and autoloading intact and a distro package that only contains the phar.

But as long as it works ...

bastianschwarz avatar Jul 30 '22 19:07 bastianschwarz

Not ideal, I'd be really happy if there was a "proper" dev package with all the sources and autoloading intact and a distro package that only contains the phar.

I think we can create something like this.

antonmedv avatar Jul 30 '22 20:07 antonmedv

Since I saw the source was added back again I gave this a second try At first glance it did not seem to work out, most likely as no autoload section was specified in Deployer's composer.json

For now I managed to move on again by adding this to our own recipe (which requires deployer/deployer:^7)

    "autoload": {
        "psr-4": {
            "Deployer\\": "vendor/deployer/deployer/src",
        }
    },

It feels kind of hacky but at least we can move on now :)

-- edit --

Seems like the explicit auto-loading of "vendor/deployer/deployer/src/functions.php" made phpstan work, but it broke the recipe as it auto-loaded it twice. So, I removed that line from composer.json (also from the examle here) and replaced with a bootstrap file in my phpstan.neon instead

parameters:
  bootstrapFiles:
    - vendor/deployer/deployer/src/functions.php

rutgerrademaker avatar Aug 19 '22 10:08 rutgerrademaker