Skip to content

[phpunit-bridge] bin/phpunit will not play well with a custom vendor directory location #30467

@brooksvb

Description

@brooksvb

Symfony version(s) affected: All

Description
I get the following error when running bin/phpunit:

[LogicException]                                   
No lockfile found. Unable to read locked packages 

The full output of the command is as follows:

vagrant@<REDACTED>:~/project$ bin/phpunit
#!/usr/bin/env php
Installing phpunit/phpunit (7.0.3)
Plugins have been disabled.
  - Installing phpunit/phpunit (7.0.3): Loading from cache
Created project in phpunit-7.0
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies
Package operations: 23 installs, 0 updates, 95 removals
  - Removing zendframework/zend-code (3.3.1)

                                                     
  [LogicException]                                   
  No lockfile found. Unable to read locked packages  
                                                     

install [--prefer-source] [--prefer-dist] [--dry-run] [--dev] [--no-dev] [--no-custom-installers] [--no-autoloader] [--no-scripts] [--no-progress] [--no-suggest] [-v|vv|vvv|--verbose
] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--ignore-platform-reqs] [--] [<packages>]...

I have a custom solution for allowing a dynamic vendor directory location so that I can keep my vendor directory outside of the NFS folder of the project inside my Vagrant virtual machine for performance reasons. The solution involves setting the COMPOSER_VENDOR_DIR environment variable to the desired vendor location, which is supported by composer itself for the installation location. I manually added in support for checking this environment variable into my Symfony project. However, the simple-phpunit script in the phpunit-bridge package does not allow me any way to support this without modifying the dependency itself.

I disabled my custom vendor location to use the normal path, and this resolved the problem and I can run bin/phpunit without errors. I'm not sure exactly where the problem is in the simple-phpunit that causes this to happen, because I would think my COMPOSER_VENDOR_DIR envvar gets passed through to the internal composer runs.

I also externally set the SYMFONY_PHPUNIT_DIR to a custom location of my liking outside the NFS directory, which worked in installing the phpunit dependency where I wanted, but it did not prevent the above error.

How to reproduce
I have 3 relevant environment variables:

export COMPOSER_VENDOR_DIR=/var/symfony/vendor
export SYMFONY_VAR_DIR=/var/symfony
export SYMFONY_PHPUNIT_DIR=/var/symfony/.phpunit

Custom Symfony code relevant to my case:

// bin/console

...
// For requiring autoload whose location may be dynamic
$vendorDirectory = getenv('COMPOSER_VENDOR_DIR');
if ($vendorDirectory === false) {
    $vendorDirectory = dirname(__DIR__).'/vendor';
}
require $vendorDirectory.'/autoload.php';
unset($vendorDirectory);
...
// config/bootstrap.php

...
// For requiring autoload whose location may be dynamic
$vendorDirectory = getenv('COMPOSER_VENDOR_DIR');
if ($vendorDirectory === false) {
    $vendorDirectory = dirname(__DIR__).'/vendor';
}
require $vendorDirectory.'/autoload.php';
unset($vendorDirectory);
...
// src/Kernel.php

... // Following are changes for setting custom var directory location

    /**
     * @var string
     *
     * Custom added. At construct time, checks for SYMFONY_VAR_DIR environment variable. If defined, that directory
     * is used. Otherwise the default location is used.
     *
     * Environment variable is expected to have no trailing slash and be an absolute path to a directory.
     */
    private $varDirectory;

    public function __construct(string $environment, bool $debug)
    {
        parent::__construct($environment, $debug);

        $this->varDirectory = getenv('SYMFONY_VAR_DIR');
        if ($this->varDirectory === false) {
            $this->varDirectory = $this->getProjectDir().'/var';
        }
    }

    public function getCacheDir()
    {
        // Custom modified to use varDirectory
        return $this->varDirectory.'/cache/'.$this->environment;
    }

    public function getLogDir()
    {
        // Custom modified to use varDirectory
        return $this->varDirectory.'/logs';
    }
...

My attempted changes to bin/phpunit to fix the problem

// bin/phpunit

#!/usr/bin/env php
<?php

$vendorDirectory = getenv('COMPOSER_VENDOR_DIR');
if ($vendorDirectory === false) {
    $vendorDirectory = dirname(__DIR__).'/vendor';
}

if (!file_exists($vendorDirectory.'/symfony/phpunit-bridge/bin/simple-phpunit')) {
    echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
    exit(1);
}

if (false === getenv('SYMFONY_PHPUNIT_VERSION')) {
    putenv('SYMFONY_PHPUNIT_VERSION=7.0');
}
if (false === getenv('SYMFONY_PHPUNIT_REMOVE')) {
    putenv('SYMFONY_PHPUNIT_REMOVE=');
}
if (false === getenv('SYMFONY_PHPUNIT_DIR')) {
    putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit');
}

// Use custom vendor path
require $vendorDirectory.'/symfony/phpunit-bridge/bin/simple-phpunit';

Possible Solution
I'm not sure exactly what needs to be changed because I don't understand the entirety of the simple-phpunit script, but my COMPOSER_VENDOR_DIR needs to be respected for the location of the vendor directory, and passed into any internal composer runs where that is important.

If I can at least prevent the errors that keep me from using phpunit-bridge I would be satisfied, but I feel like it should be a supported feature to have a non-standard vendor directory location and customize it somehow.

If anyone can suggest a temporary solution I would greatly appreciate it.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions