Easy Deployer Bundle fails on symlinking parameters.yml - php

I am trying to use easy-deploy-bundle to deploy a symfony project cannot deploy any symfony project, even to my local machine. The symlinking for the parameters.yml file from the shared directory always fails with the error below.
I have cloned the symfony-demo project, this is a symfony 3.3.10, the parameters.yml file is empty but present in the shared/app/config dir.
Error:
[Symfony\Component\Process\Exception\ProcessFailedException]
The command "(export SYMFONY_ENV=prod; cd /home/patrick/code/testedb-deploy/releases/20171015162057 && ln -nfs /home/patrick/code/testedb-deploy/shared/app/config/parameters.yml /home/patrick/code/testedb-deploy/releases/20171015162057/app/config/parameters.yml)" f
ailed.
Exit Code: 1(General error)
Working directory: /home/patrick/code/testedb
Output:
================
Error Output:
================
ln: failed to create symbolic link '/home/patrick/code/testedb-deploy/releases/20171015162057/app/config/parameters.yml': No such file or directory
This is my deploy file:
<?php
use EasyCorp\Bundle\EasyDeployBundle\Deployer\DefaultDeployer;
return new class extends DefaultDeployer
{
public function configure()
{
return $this->getConfigBuilder()
->server('localhost')
->deployDir('/home/patrick/code/testedb-deploy')
->repositoryUrl('git#github.com:superpatty/symfony-demo.git')
->symfonyEnvironment('prod')
->resetOpCacheFor('https://demo.symfony.com')
;
}
public function beforeStartingDeploy()
{
$this->log('Checking that the repository is in a clean state.');
$this->log('Running tests, linters and checkers.');
$this->runLocal('./bin/console security:check --env=dev');
$this->runLocal('./bin/console lint:twig app/Resources/ --no-debug');
$this->runLocal('./bin/console lint:yaml app/ --no-debug');
$this->runLocal('./bin/console lint:xliff app/Resources/ --no-debug');
$this->runLocal('./vendor/bin/simple-phpunit');
}
public function beforeFinishingDeploy()
{
}
};
Has anyone else come across this issue and how to get around it?

Related

APP_SERVER env var not found when deploying with EasyDeploy

I have this error when the deploy script tries to install the assets:
(Setup PHP 7.2, Symfony 4.4)
[Symfony\Component\Process\Exception\ProcessFailedException]
The command "ssh -A root#vps.net -p 21 '(export APP_ENV=prod; cd /var/www-deploy/site.com/releases/20191129224025
&& php /var/www-deploy/site.com/releases/20191129224025/bin/console assets:install /var/www-deploy/site.com/releases/20191129224025/public --symlink --no-debug --env=prod)'" failed.
Exit Code: 1(General error)
Working directory: /Users/coil/Sites/site.com
Output:
================
Error Output:
================
In EnvVarProcessor.php line 162:
Environment variable not found: "APP_SERVER".
I have put the .env file in the shared files, so it's copied when the release directory is created, this file is in the directory.
public function configure(): DefaultConfiguration
{
return $this->getConfigBuilder()
// ...
->sharedFilesAndDirs(['.env'])
// ...
}
I also tried to put the env vars in the .bashrc file of the user who deploys:
printenv | grep -i app
APP_DEBUG=0
APP_SECRET=whatever
APP_ENV=prod
APP_SERVER=prod
So, I don't understand, why the environment variables are still not found. And why they are not taken from the .env file.
If I interrupt the deployment and if I manually run the same command on the server it works well. Thanks.
[Edit 2019-11-30] I think I understand know, when running the command, there is an export of the APP_ENV that is done. And, if the application detects this env variable it will just skip the .env file. So, I need to avoid setting this env var, or I must set all instead of this one only.
[Edit 2021-02-13] I have fixed the bin/console file and removed the "hack". Instead of testing the APP_ENV var I test the APP_SECRET one which is not set by EasyDebug:
if (!isset($_SERVER['APP_SECRET'])) {
(new Dotenv())->load(__DIR__.'/../.env');
}
Old solution:
It now works with the following modififications, in src/Configuration/DefaultConfiguration.php:
} elseif (4 === $symfonyMajorVersion || (3 === $symfonyMajorVersion && 4 >= $symfonyMinorVersion)) {
$this->_symfonyEnvironmentEnvVarName = 'APP_ENV';
I have passed an unkown env var to Symfony:
$this->_symfonyEnvironmentEnvVarName = 'APP_FAKE_ENV';
So the .env file is not ignored any-more. I think there is a missing option to set or not this environment var based on the setup of the application. I'll try to do a PR to the bundle.
So, as the bundle is not modified yet, I have modified the private property, in order to make the command use my .env files instead of environment variables:
/**
* #see https://stackoverflow.com/q/1762135/633864
*/
private function forceEnvironmentEnvVarName(DefaultConfiguration $configuration): DefaultConfiguration
{
$myClassReflection = new ReflectionClass(get_class($configuration));
$symfonyEnvironmentEnvVarName = $myClassReflection->getProperty('_symfonyEnvironmentEnvVarName');
$symfonyEnvironmentEnvVarName->setAccessible(true);
$symfonyEnvironmentEnvVarName->setValue($configuration, 'FAKE_APP_ENV');
$symfonyEnvironmentEnvVarName->setAccessible(false);
return $configuration;
}

Why my class is not found on Heroku while it does on local environment?

I have a tiny project that is working correctly in my local environment. But when I push it to Heroku, an exception is thrown saying:
Uncaught Error: Class 'App/Controllers/Home/HomeController' not found in /app/App/Controllers/Controller.php:158
Here's the method where the exception is thrown:
/**
* #return mixed
*/
public static function executeFromRoute()
{
// This method checks the URI and finds the correct class to use.
// Because I am trying to access the root URL, it should returns:
// "App/Controllers/Home/HomeController"
$controllerClass = self::getControllerClass();
$controllerAction = self::getControllerAction();
$controller = new $controllerClass; // LINE 158
if (!method_exists($controller, $controllerAction)) {
throw new \Exception('Action not found.', 500);
}
return $controller->$controllerAction();
}
The file HomeController has been correctly uploaded to the git repository of Heroku:
> heroku run "ls App/Controllers/Home"
Running ls App/Controllers/Home on ⬢ MY_SUB_DOMAIN... up, run.6604 (Free)
HomeController.php
I already executed heroku run "composer install" and heroku run "composer dump-autoload".
I didn't alter the content of the Procfile file:
web: heroku-php-apache2
I specified my App directory within my composer.json file:
{
(...),
"autoload": {
"psr-4": {
"App\\": "App"
}
}
}
I don't get why my class is not found on Heroku while it does on local environment?
Did I miss something?
The issue was present on Heroku and not on my local environment because Heroku is on Linux while I am on Windows. I read many posts about warnings on how important letter cases and separators (/ and \) are on Linux, but I didn't find a solution with my first tries.
But I finally found out.
My Controller::getControllerClass() method returned App/Controllers/Home/HomeController, but it should return \App\Controllers\Home\HomeController instead in order to create an instance of it.
So I replaced:
$controller = new $controllerClass;
By:
$controllerClass = '\\' . str_replace(DIRECTORY_SEPARATOR, '\\', $controllerClass);
$controller = new $controllerClass();

BitBucket pipeline fails on test cases

I'm having hard time to configure a BitBucket pipeline to deploy a CakePHP application to a hosting server.
Reading some tutorials I've ended up with this pipeline:
image: edbizarro/bitbucket-pipelines-php7
pipelines:
branches:
master:
- step:
caches:
- composer
script:
- composer install --no-interaction --no-progress --prefer-dist
- composer test
- composer deploy-to-production
but it always fails:
Build setup -> OK
composer install -> OK
composer test -> FAIL
+composer test
phpunit --colors=always
Deprecated Error: Plugin::load() is deprecated. Use Application::addPlugin() instead. This method will be removed in 4.0.0. - /opt/atlassian/pipelines/agent/build/config/bootstrap.php, line: 179
You can disable deprecation warnings by setting Error.errorLevel to E_ALL & ~E_USER_DEPRECATED in your config/app.php. in [/opt/atlassian/pipelines/agent/build/vendor/cakephp/cakephp/src/Core/functions.php, line 311]
PHPUnit 6.5.14 by Sebastian Bergmann and contributors.
Exception: Unable to insert fixtures for "App\Test\TestCase\Controller\CustomersControllerTest" test case. SQLSTATE[HY000] [2002] No such file or directory in [/opt/atlassian/pipelines/agent/build/vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureManager.php, line 380]
Script phpunit --colors=always handling the test event returned with error code 244
I cannot ls the virtual remote folders but I can mine... so I inspected App\Test\TestCase\Controller\CustomersControllerTest:
<?php
namespace App\Test\TestCase\Controller;
use App\Controller\CustomersController;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
class CustomersControllerTest extends TestCase
{
use IntegrationTestTrait;
public $fixtures = [
'app.Customers',
'app.Orders'
];
public function testIndex()
{
$this->markTestIncomplete('Not implemented yet.');
}
public function testView()
{
$this->markTestIncomplete('Not implemented yet.');
}
public function testAdd()
{
$this->markTestIncomplete('Not implemented yet.');
}
public function testEdit()
{
$this->markTestIncomplete('Not implemented yet.');
}
public function testDelete()
{
$this->markTestIncomplete('Not implemented yet.');
}
}
Because I'm not using tests, can I (safely) avoid the composer test step?
By the way, on the hosting server the PHP version is 5.6 while in the pipeline's image is specified version 7. Might this lead to a problem?

Composer Error in Jenkins

I have been trying to setup a build system for PHP and has the following Jenkins pipeline.
pipeline {
agent { docker { image 'my-custom-image' } }
stages {
stage('Build') {
steps {
sh 'composer config --global --auth http-basic.repo.packagist.com token mytokencode'
}
}
}
}
Here it is pulling the docker image, but when the composer command is executed, it it throwing following error :
Cannot create cache directory /.composer/cache/repo/https---repo.packagist.com-domain/, or directory is not writable. Proceeding without cache
Cannot create cache directory /.composer/cache/files/, or directory is not writable. Proceeding without cache
[ErrorException]
touch(): Unable to create file /.composer/config.json because No such file or directory
and the build is failing. How can I fix this ?
You could set the COMPOSER_HOME environment variable to the actual directory, them Composer will save all the cache data there. Something like:
pipeline {
agent { docker { image 'my-custom-image' } }
stages {
stage('Build') {
steps {
sh 'COMPOSER_HOME=$(pwd) composer config --global --auth http-basic.repo.packagist.com token mytokencode'
}
}
}
}
I was able to use composer cache by creating a volume between my Jenkins machine and the Docker image. You can try to reproduce:
At your pipeline script, create the volume using an argument:
agent {
docker {
image 'my-custom-image'
args '-v $HOME/.composer/cache:/usr/local/share/composer/cache'
}
}
Check where your $HOME directory is pointing to, it can be different depending on how you installed Jenkins. I'm using it as an apt package on Ubuntu 16. For me, it's pointing to /var/lib/jenkins
Inside your $HOME directory, a folder named ".composer" is needed with right permissions so the docker can use it. I set it up with chmod -R 775.

Symfony4 Error loading classes custom folder "Expected to find class... but it was not found"

Problem
I'm trying to setup a custom directory structure
for some shared classes in my Symfony project. I
want to create a custom folder in the root of my
project and I want to use the Symfony auto-load
feature to automatically register services from
that folder.
So I added a custom services namespace to the
services.yaml file:
# src ./config/services.yaml
services:
...
TestNamespace\:
resource: '../TestNamespace/*'
...
And I added an empty class in the custom folder:
# src ./TestNamespace/TestClass.php
namespace TestNamespace;
class TestClass
{
}
When I run the app I get the following error:
(1/2) InvalidArgumentException
Expected to find class "TestNamespace\TestClass" in file
"/path/to/ClassLoadErrorDemo/demo/TestNamespace/TestClass.php"
while importing services from resource
"../TestNamespace/*", but it was not found! Check the
namespace prefix used with the resource.
(2/2) FileLoaderLoadException
Expected to find class "TestNamespace\TestClass" in file
"/path/to/ClassLoadErrorDemo/demo/TestNamespace/TestClass.php" while
importing services from resource "../TestNamespace/*", but it was not
found! Check the namespace prefix used with the resource in
/path/to/ClassLoadErrorDemo/demo/config/services.yaml (which is loaded
in resource "/path/to/ClassLoadErrorDemo/demo/config/services.yaml").
I double checked the paths, namespace and the class
name multiple times and everything seems fine and I
don't understand why I still get the error.
Controllers in the ./src folder seem to load fine.
What am I doing wrong here?
Steps to reproduce
I created a demo repo to isolate the problem.
git clone https://github.com/smoelker/SymfonyClassLoadErrorDemo.git
cd SymfonyClassLoadErrorDemo/demo
composer install
mv TestNamespace/TestClass.php_ TestNamespace/TestClass.php
php bin/console server:start
Update your composer.json autoload setup
{
[...]
"autoload": {
"psr-4": {
"TestNamespace\\": "TestNamespace/",
"": "src/"
}
},
[...]
}
After run: composer dump-autoload and try again.
composer dump-autoload --classmap-authoritative will only work if your src directory is present at the time you run the command.
This can be an issue with multi-stage Docker builds in particular, when you are normally only copying the composer.json/composer.lock into the build image.

Categories