Closed lukasleitsch closed 2 years ago
Thanks! That looks good to me. Did you manage to test this image on a project? I just want to make this is not going to suddenly break everybody's pipeline. 😅
For what it's worth, I applied this patch to our fork of this repo (which adds the ldap
extension) and our pipelines are running fine :)
That's good enough for me. Thank you so much for giving it a test! 🍺
@lorisleiva This breaks our pipelines because the docker image is now missing git
. We use Gitlab CI/CD and we host some private composer and npm packages and use git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/".insteadOf "git@gitlab.com:"
to allow for easy authentication. Since git is no longer installed, this is not possible.
@jesperbjerke @lorisleiva Same issue here...
Phpunit not working, and it was yesterday.
I've also run into a strange issue, as nunomaduro/larastan
requires composer/composer
; when I reach the deployment stage and re-run Composer minus development dependencies, it ends up cannibalizing itself:
+ which composer
./vendor/bin/composer
+ composer --version
Composer 2.1.14 2021-11-30 10:51:43
+ composer install --no-dev --optimize-autoloader --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts
Installing dependencies from lock file
Verifying lock file contents can be installed on current platform.
Package operations: 0 installs, 0 updates, 63 removals
- Removing theseer/tokenizer (1.2.1)
- Removing symfony/yaml (v5.4.0)
- Removing symfony/stopwatch (v5.4.0)
- Removing symfony/options-resolver (v5.4.0)
- Removing symfony/filesystem (v5.4.0)
- Removing squizlabs/php_codesniffer (3.6.1)
- Removing seld/phar-utils (1.1.2)
- Removing seld/jsonlint (1.8.3)
- Removing sebastian/version (3.0.2)
- Removing sebastian/type (2.3.4)
- Removing sebastian/resource-operations (3.0.3)
- Removing sebastian/recursion-context (4.0.4)
- Removing sebastian/object-reflector (2.0.4)
- Removing sebastian/object-enumerator (4.0.4)
- Removing sebastian/lines-of-code (1.0.3)
- Removing sebastian/global-state (5.0.3)
- Removing sebastian/exporter (4.0.4)
- Removing sebastian/environment (5.1.3)
- Removing sebastian/diff (4.0.4)
- Removing sebastian/complexity (2.0.2)
- Removing sebastian/comparator (4.0.6)
- Removing sebastian/code-unit-reverse-lookup (2.0.3)
- Removing sebastian/code-unit (1.0.8)
- Removing sebastian/cli-parser (1.0.1)
- Removing react/promise (v2.8.0)
- Removing psr/cache (3.0.0)
- Removing phpunit/phpunit (9.5.10)
- Removing phpunit/php-timer (5.0.3)
- Removing phpunit/php-text-template (2.0.4)
- Removing phpunit/php-invoker (3.1.1)
- Removing phpunit/php-file-iterator (3.0.6)
- Removing phpunit/php-code-coverage (9.2.10)
- Removing phpstan/phpstan (1.2.0)
- Removing phpspec/prophecy (v1.15.0)
- Removing phpdocumentor/type-resolver (1.5.1)
- Removing phpdocumentor/reflection-docblock (5.3.0)
- Removing phpdocumentor/reflection-common (2.2.0)
- Removing php-cs-fixer/diff (v2.0.2)
- Removing phar-io/version (3.1.0)
- Removing phar-io/manifest (2.0.3)
- Removing nunomaduro/larastan (1.0.2)
- Removing nunomaduro/collision (v5.10.0)
- Removing myclabs/deep-copy (1.10.2)
- Removing mockery/mockery (1.4.4)
- Removing laravel/sail (v1.12.10)
- Removing laravel/homestead (v13.0.0)
- Removing justinrainbow/json-schema (5.2.11)
- Removing hamcrest/hamcrest-php (v2.0.1)
- Removing friendsofphp/php-cs-fixer (v3.3.2)
- Removing filp/whoops (2.14.4)
- Removing fakerphp/faker (v1.17.0)
- Removing facade/ignition-contracts (1.0.2)
- Removing facade/ignition (2.17.2)
- Removing facade/flare-client-php (1.9.1)
- Removing doctrine/instantiator (1.4.0)
- Removing doctrine/annotations (1.13.2)
- Removing composer/xdebug-handler (2.0.3)
- Removing composer/spdx-licenses (1.5.6)
- Removing composer/semver (3.2.6)
- Removing composer/pcre (1.0.0)
- Removing composer/metadata-minifier (1.0.0)
- Removing composer/composer (2.1.14)
- Removing composer/ca-bundle (1.3.1)
Fatal error: Uncaught Error: Class "React\Promise\RejectedPromise" not found in /builds/my-org/my-app/vendor/react/promise/src/FulfilledPromise.php:30
Stack trace:
#0 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(134): React\Promise\FulfilledPromise->then(Object(Closure), Object(Closure))
#1 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(168): React\Promise\Promise::React\Promise\{closure}(Object(React\Promise\FulfilledPromise))
#2 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(231): React\Promise\Promise->settle(Object(React\Promise\FulfilledPromise))
#3 /builds/my-org/my-app/vendor/react/promise/src/FulfilledPromise.php(42): React\Promise\Promise::React\Promise\{closure}(NULL)
#4 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(135): React\Promise\FulfilledPromise->done(Object(Closure), Object(Closure), Object(Closure))
#5 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(168): React\Promise\Promise::React\Promise\{closure}(Object(React\Promise\FulfilledPromise))
#6 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(231): React\Promise\Promise->settle(Object(React\Promise\FulfilledPromise))
#7 /builds/my-org/my-app/vendor/react/promise/src/FulfilledPromise.php(42): React\Promise\Promise::React\Promise\{closure}(NULL)
#8 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(135): React\Promise\FulfilledPromise->done(Object(Closure), Object(Closure), Object(Closure))
#9 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(168): React\Promise\Promise::React\Promise\{closure}(Object(React\Promise\FulfilledPromise))
#10 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(231): React\Promise\Promise->settle(Object(React\Promise\FulfilledPromise))
#11 /builds/my-org/my-app/vendor/react/promise/src/FulfilledPromise.php(42): React\Promise\Promise::React\Promise\{closure}(NULL)
#12 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(135): React\Promise\FulfilledPromise->done(Object(Closure), Object(Closure), Object(Closure))
#13 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(168): React\Promise\Promise::React\Promise\{closure}(Object(React\Promise\FulfilledPromise))
#14 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(231): React\Promise\Promise->settle(Object(React\Promise\FulfilledPromise))
#15 /builds/my-org/my-app/vendor/react/promise/src/FulfilledPromise.php(42): React\Promise\Promise::React\Promise\{closure}(true)
#16 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(135): React\Promise\FulfilledPromise->done(Object(Closure), Object(Closure), Object(Closure))
#17 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(168): React\Promise\Promise::React\Promise\{closure}(Object(React\Promise\FulfilledPromise))
#18 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(231): React\Promise\Promise->settle(Object(React\Promise\FulfilledPromise))
#19 /builds/my-org/my-app/vendor/react/promise/src/FulfilledPromise.php(42): React\Promise\Promise::React\Promise\{closure}(Object(Symfony\Component\Process\Process))
#20 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(135): React\Promise\FulfilledPromise->done(Object(Closure), Object(Closure), Object(Closure))
#21 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(168): React\Promise\Promise::React\Promise\{closure}(Object(React\Promise\FulfilledPromise))
#22 /builds/my-org/my-app/vendor/react/promise/src/Promise.php(231): React\Promise\Promise->settle(Object(React\Promise\FulfilledPromise))
#23 [internal function]: React\Promise\Promise::React\Promise\{closure}(Object(Symfony\Component\Process\Process))
#24 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Util/ProcessExecutor.php(342): call_user_func(Object(Closure), Object(Symfony\Component\Process\Process))
#25 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Util/Loop.php(98): Composer\Util\ProcessExecutor->countActiveJobs()
#26 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Installer/InstallationManager.php(497): Composer\Util\Loop->wait(Array, NULL)
#27 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Installer/InstallationManager.php(470): Composer\Installer\InstallationManager->waitOnPromises(Array)
#28 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Installer/InstallationManager.php(390): Composer\Installer\InstallationManager->executeBatch(Object(Composer\Repository\InstalledFilesystemRepository), Array, Array, false, true, Array)
#29 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Installer/InstallationManager.php(282): Composer\Installer\InstallationManager->downloadAndExecuteBatch(Object(Composer\Repository\InstalledFilesystemRepository), Array, Array, false, true, Array)
#30 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Installer.php(742): Composer\Installer\InstallationManager->execute(Object(Composer\Repository\InstalledFilesystemRepository), Array, false, true)
#31 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Installer.php(273): Composer\Installer->doInstall(Object(Composer\Repository\InstalledFilesystemRepository))
#32 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Command/InstallCommand.php(140): Composer\Installer->run()
#33 /builds/my-org/my-app/vendor/symfony/console/Command/Command.php(298): Composer\Command\InstallCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#34 /builds/my-org/my-app/vendor/symfony/console/Application.php(1005): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#35 /builds/my-org/my-app/vendor/symfony/console/Application.php(299): Symfony\Component\Console\Application->doRunCommand(Object(Composer\Command\InstallCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#36 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Console/Application.php(327): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#37 /builds/my-org/my-app/vendor/symfony/console/Application.php(171): Composer\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#38 /builds/my-org/my-app/vendor/composer/composer/src/Composer/Console/Application.php(128): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#39 /builds/my-org/my-app/vendor/composer/composer/bin/composer(74): Composer\Console\Application->run()
#40 {main}
thrown in /builds/my-org/my-app/vendor/react/promise/src/FulfilledPromise.php on line 30
Cleaning up project directory and file based variables
ERROR: Job failed: exit code 1
To get around this, I've had to update my deployment script to explicitly reference /usr/local/bin/composer
.
Strange, I've added /usr/local/bin
to the PATH of the image recently.
I think it's more a matter of the composer
binary being found in ./vendor/bin
, which comes first in the $PATH
.
From the snippet above:
+ which composer
./vendor/bin/composer
I think the trick here is to remove ./vendor/bin/
from the beginning of $PATH
, as Composer will automatically prepend it when running a Composer script:
Note: Before executing scripts, Composer's
bin-dir
is temporarily pushed on top of thePATH
environment variable so that binaries of dependencies are directly accessible. In this example no matter if thephpunit
binary is actually invendor/bin/phpunit
orbin/phpunit
it will be found and executed.
Without it, running which composer
would produce a result of /usr/local/bin/composer
and subsequent calls to Composer that affect the vendor/
directory would not impact the running instance.
This also has the benefit of using the Composer configuration to prepend the vendor and bin paths, as Composer permits users to configure these values.
Would that be the case in the terminal as well though? It seems to me that composer only pushes the local vendor bin when running a script defined in the composer.json
.
You're correct: Composer only pushes its bin directory to the front of the path when running Composer scripts (or composer exec
).
Imagine we have the following paths:
/usr/local/bin/composer
/var/www/vendor/bin/composer
/root/.composer/vendor/bin/phpcs
/var/www/vendor/bin/phpcs
Under the current $PATH
settings, these commands would map like this:
$ which composer
/var/www/vendor/bin/composer
$ which phpcs
/var/www/vendor/bin/phpcs
This feels reversed; I think it's reasonable to expect that running composer --version
would reference the globally-installed instance.
If we drop ./vendor/bin
from $PATH
:
$ which composer
/usr/local/bin/composer
$ which phpcs
/root/.composer/vendor/bin/phpcs
This would require pipelines that have been built around this unconventional $PATH
to be updated, however; if a site was previously just calling phpcs
(expecting to reference ./vendor/bin/phpcs
), it would start using the global installation instead.
Perhaps more-impactful would be PHPUnit: since it's not installed globally (nor should it be, IMO), pipelines that were simply running phpunit
to implicitly refer to ./vendor/bin/phpunit
may encounter "command not found: phpunit" errors.
Fortunately, there are a couple easy ways to fix that within a pipeline:
./vendor/bin/phpunit
)composer exec
to let Composer prepend the vendor-bin directory to $PATH
(e.g. composer exec phpunit
)Define a Composer script (e.g. composer test
) and call that from the pipeline:
// composer.json
{
// ...
"scripts": {
"test": "phpunit --some-opts"
}
}
I think it's reasonable to expect that running
composer --version
would reference the globally-installed instance.
I am afraid I disagree with that premise. If you want to access composer
globally, you can use composer --global
. I've never worked on a project that expect global binaries to be prioritised over local binaries.
This PR installs all required dependencies with the
docker-php-extension-installer
.The
docker-php-extension-installer
shown that some extensions already installed. Therefore, I cleaned up the already installed extensions.Closes #94