Travis-CI: how to cache composer executable between builds? - php

On every travis build, composer self-update is run. And it gets updated on every build. Is it possible to cache composer executables like we do it with vendor dir via
cache:
directories:
- vendor
- $HOME/.composer/cache
I thought about caching the whole /home/travis/.phpenv/versions/5.5/bin/composer but I feel this is not right because the contents of this folder may change without notifying caching system about a change (when travis updates php version for example).
Any suggestions (except for custom composer, of course)?

I'd recommend not updating composer itself, but let travis handle it. (its automatically updated every 30/60 days)
Also i can recommend using the new containerized infrastructure to speed up the runs and allow caching...
language: php
sudo: false
cache:
directories:
- $HOME/.composer/cache
php:
- 5.5
- 5.6
- 7
- hhvm
install:
- composer install
script: vendor/bin/phpunit
The sudo: false statement indicates the use of containers. The cache: statement makes sure composer caches correctly.
If you really want to cache the composer binary:
language: php
php:
- 5.5
- 5.6
- 7
- hhvm
cache:
directories:
- $HOME/.composer/cache
install:
- travis_retry composer self-update && composer --version
- export PATH="$HOME/.composer/vendor/bin:$PATH"
- travis_retry composer install --prefer-dist --no-interaction
script: vendor/bin/phpunit
Also just as a heads up, if testing for HHVM and you need to set the datetime, have a look at https://github.com/travis-ci/travis-ci/issues/2523. My way of solving this is adding a .ini-file in my test-directory with the datetime and setting this in the correct folder for all test-runners. This is prepended in the install:-step:
- mkdir -p /home/travis/.phpenv/versions/$(phpenv version-name)/etc/conf.d
- phpenv config-add test/phpconfig.ini
Anyway, a bit more information than you requested, but i hope this helps someone looking for composer/travis/stuff :)

Related

How to automatically switch php versions when cd'ing into another directory bash

I have multiple projects that I work on.
Some are on php 7.3, most of 7.4 and a single one on 8.1
Having to switch php everytime when I switch projects is a solution I have now, but sometimes I need to do a quick check on another project, and that breaks code running in another project because the global php are updated.
All my projects are composer based, but composer doesn't "spit out" what the most desired php version is.
How can I based on composer.json/lock detect the correct php version to use?
This script is made with php installed via ppa:ondrej/php. If your php versions are self compiled, and not linked in for example /usr/bin/php7.4 you'll need to modify the paths to the correct paths. This code however does assume the binaries are named php7.x or php8.x
This also requires that there is a composer installed on your system.
Add the following code to your .bashrc file.(nano ~/.bashrc)
Explanations of what does what are in the comments in the code.
function do_php() {
# Path where to find the php binaries
PHPPATH='/usr/bin'
# PHP versions in order of most used
declare -a phpversions=("7.4" "7.3" "8.1" "8.0" "7.2" "7.1" "7.0");
# Get a direct path to composer
composer_path="$(whereis composer | cut -d ' ' -f 2)"
# Loop through all php versions
for phpversion in "${phpversions[#]}"
do
PHP=$PHPPATH/php$phpversion
# If the given php version is installed
if [ -f $PHP ]; then
# Check if it matches the requirements
SUCCESS=$($PHP $composer_path check-platform-reqs 2>/dev/null | grep php | tr -s ' ' | cut -d ' ' -f 3)
# If we're matching
if [ "$SUCCESS" == "success" ]; then
# Run command with given binary
$PHP "$#"
# exit function
return
fi
fi
done
#Nothing matched, just run with default php and let the programmer deal with the issue
\php "$#"
}
# Set the alias for php to do_php
alias php='do_php'
All my projects are composer based, but composer doesn't "spit out" what the most desired php version is.
How can I based on composer.json/lock detect the correct php version to use?
Well composer itself can not magically tell you what your intend (per project) is, however you can configure this easily on a per-project basis with platform packages. For the PHP version it is the php package:
{
"config": {
"platform": {
"php": "7.0.3"
}
}
}
(Compare: Composer config platform, Run composer using different version of PHP without changing the environment variables)
You can also add extensions and libraries. Now you have configured the information in your project and composer will use that version when installing and updating dependencies (e.g. for 7.0.3 above, package versions that require >= 7.0.4 won't install).
7.0.3 is a bad example (just copied the version from Composer docs), let's say you're in a PHP 7.4 project:
$ composer config platform.php '7.4.30'
It is also now easy to map on the Sury packages binary names, just keep the head:
$ composer config platform.php | head -c3
7.4
For Composer invocations itself it won't be necessary any longer, however you may want to do other things, so here some hints, that already work within Composer:
The #php script shortcut (Composer, see Executing PHP scripts)
The PHP_BINARY environment variable (Composer, see same)
Those are all based on the php binary composer is running with. So if you need to inject it, call composer with the adequate php version:
$ composer config platform.php '8.1.11'
$ php$(composer config platform.php | head -c3) $(which composer) diagnose
Checking composer.json: OK
...
PHP version: 8.1.11 - Package overridden via config.platform, same as actual
PHP binary path: /usr/bin/php8.1
...
(Example: Composer invocation with Ondřej Surý php8.1 package on Ubuntu)
So eventual composer scripts/hooks should be covered.
For invocation in general I'd suggest to use a build manager to define targets, their dependencies and the rules how they are made. You should have the make utility already on your box and then it is just make and done for most of the time. You can add the php executable name to configuration there, control the platform version in composer.json and have this even re-useable across projects. no need to add it to the environment when you can have it in the project IMHO (Compare Automation and Make).
When it comes the day you start to migrate your project to another php version, you have only one environment. With a build manager you can easily run the same setup with different php versions to check the upgrade path (and even can do this in parallel). Just for the outlook. Keep it simple and stupid, then you have the best options in the long run (and also portability across projects).

docker and php: getting dependencies (composer) into the container

A little context: I am new to docker and dont know of any best-practices yet. My task is to create a webservice based on php and i decided to use docker-compose for provisioning.
Because we are all fancy devs, we know - there is no way to build a php application without using composer these days.
My question:
Should i install dependencies in the build? So by adding this to my Dockerfile:
RUN cd /app && composer install --no-interaction --prefer-source --optimize-autoloader
Or should i install dependencies during development and build the container image with included dependencies?
I only know of one way NOT to do it: install dependencies locally on the dev machine and build the container afterwards. But how would the "best practice" look like?
And - because i am a newbee in this field - how would i run a "composer require some/package" for my app service container?
By the way
I also noticed a message "Do not run Composer as root/super user!" when building the container. I added COMPOSER_ALLOW_SUPERUSER=1 to my Env file (as seen here), but this message still appears.
Is it possible to NOT execute composer install as root in a docker container? Can i ignore that message?
Thanks in advance,
Philipp
For the moment i am working towards the following solutuion:
Development environment:
Add the whole src as volume:
volumes:
- .:/app
initial composer install command
docker-compose exec app composer install
install new composer package:
docker-compose exec app composer require some/package
The package will be installed via the container in your composer package directory (/vendor by default of course), the source code can be inspected in your ide, etc.
Production environment:
Only app state defined as volume, for example:
volumes:
- public/uploads:/app/public/uploads
add /vendor to .dockerignore
and run composer install during build
RUN cd /app && composer install --no-dev --no-interaction --optimize-autoloader
So you will have a pre-built image to deploy, but still be able to develop in a more agile way.
There are still two downsides in this solution, maybe someone has input for me:
1) build becomes kind of slow - it seems composer caching does not work properly
A solution (i dont know if this is possible in composer) could be a volume for the composer cache directory.
2) all packages created by docker are owned by root, so you can only work on those files/folders with sudo/root session.
I have no idea how to fix this properly. Maybe i could create a user with the name of the dev user for the development container and have this user run commands and php-fpm, etc... For production root would be okay i guess.
I am still very new to docker and open for better solutions, so i wont accept this answer.
UPDATED
To add new user in docker user in Dockerfile. as follows
RUN useradd -ms /bin/bash newuser
USER newuser
if you want to create home user too
WORKDIR /home/newuser
or
mkdir /home/newuser
if you want to back to root user, you can do like
USER root
two-sides-of-a-coin -
It is a good practice to do on building images period which I also do the same as you.
we will get latest update from public repositories but another side of coin is that we cannot ensure they are the same version as we develop.
you need to handle this by specifying exact version in composer.json (do not use ^, *).

Travis configuration for composer packages

While working on a laravel 5.1+ package I have this need to run automated tests through travis-ci.org. The difference with regular automated tests is the requirement to include this package into a framework and set specific configuration options to run the tests.
So the requirement would be:
install laravel
add my package as dependency
set some travis specific configurations like the travis database access
run migrations of laravel
run migrations specific for package or run an artisan command
run package specific unit tests
I searched everywhere; asked on laravel forums, asked in a travis community chat and saw this topic being closed as too localized (although an answer would have certainly been helpful now). I'm hoping my question is fit to remain open.
At this time I have the following configuration:
language: php
php:
- 5.5
- 5.6
- hhvm
addons:
hosts:
- system.hyn.me
- tenant.hyn.me
before_install:
- sudo composer self-update
install:
- composer create-project laravel/laravel
- cd ./laravel
- composer require hyn-me/multi-tenant ~0.1.0
- composer update
before_script:
- cp .env.travis .env
- export APP_ENV="testing"
- php artisan migrate -q -n --path ./vendor/hyn-me/multi-tenant/src/migrations
- cd ./vendor/hyn-me/multi-tenant
script: phpunit
Yet my knowledge of travis (thus far) is limited and before I send in an unneeded number of commits to fix my problems I'd rather have your opinion on what would be a good method to test integration into a framework.
Ps. this concerns the package hyn/multi-tenant.
Advise on how to keep this question as generic as possible would be helpful. I hope without explicitly mentioning best practice and requesting integration into framework examples helps in defining the scope of the answers.
So after weeks of pushing commits into travis, I finally made this work.
The .travis.yml:
language: php
sudo: true
php:
- 5.5
- 5.6
- 7.0
- hhvm
addons:
hosts:
- system.hyn.me
- tenant.hyn.me
install:
# fix ipv6 issue that prevented composer requests and resulted in failing builds
- sudo sh -c "echo 'precedence ::ffff:0:0/96 100' >> /etc/gai.conf"
# updates composer on travis
- travis_retry composer self-update
# clear composer cache, might speed up finding new tags
- travis_retry composer clear-cache
# set the global github token, so connections won't be cancelled
- composer config -g github-oauth.github.com $GITHUB_TOKEN
# create a new database for the hyn connection
- mysql -e 'create database hyn;' -uroot
- mysql -e "grant all privileges on *.* to 'travis'#'localhost' with grant option;" -uroot
# create a new laravel project in the subfolder laravel (default composer behaviour)
- composer create-project laravel/laravel
# set global variables
- export DB_USERNAME=travis DB_DATABASE=hyn DB_PASSWORD= QUEUE_DRIVER=sync
script:
# run the script calling unit tests and so on
- ./scripts/travis.sh
after_script:
- if [[ $TRAVIS_PHP_VERSION != '7.0' ]]; then php vendor/bin/ocular code-coverage:upload --format=php-clover ${TRAVIS_BUILD_DIR}/coverage.clover; fi
And the scripts/travis.sh
#!/bin/bash
# e causes to exit when one commands returns non-zero
# v prints every line before executing
set -ev
cd ${TRAVIS_BUILD_DIR}/laravel
BRANCH_REGEX="^(([[:digit:]]+\.)+[[:digit:]]+)$"
if [[ ${TRAVIS_BRANCH} =~ $BRANCH_REGEX ]]; then
echo "composer require ${TRAVIS_REPO_SLUG}:${TRAVIS_BRANCH}"
composer require ${TRAVIS_REPO_SLUG}:${TRAVIS_BRANCH}
else
echo "composer require ${TRAVIS_REPO_SLUG}:dev-${TRAVIS_BRANCH}"
# development package of framework could be required for the package
composer require hyn-me/framework "dev-master as 0.1.99"
composer require "${TRAVIS_REPO_SLUG}:dev-${TRAVIS_BRANCH}#${TRAVIS_COMMIT}"
fi
# moves the unit test to the root laravel directory
cp ./vendor/${TRAVIS_REPO_SLUG}/phpunit.travis.xml ./phpunit.xml
phpunit
# phpunit --coverage-text --coverage-clover=${TRAVIS_BUILD_DIR}/coverage.clover
This code might change due to new Laravel versions or changes in travis. If this is the case, you will find the latest release here.

Can't run phpunit tests from command line

I am trying to run unit tests in a new laravel 5 application, using the phpunit framework. In the root path of my laravel application I ru the following command:
./vendor/bin/phpunit /tests/ExampleTest.php
And then I get the following message:
You need to set up the project dependencies using the following commands:
wget http://getcomposer.org/composer,phar
php composer.phar install
I already have composer installed in may system and I install Laravel 5 using composer. Isn't phpunit installed when I install a new laravel 5 application? If not, how can I install it in a existent laravel 5 application?
I known that I can also install phpunit globaly and resolve the problem. But maybe it will be a duplication since I have all the phpunit code already in may laravel application.
I had the same problem and it had a specific solution that may apply to other people. I store my files in Dropbox, and the vendor/bin/phpunit file should be an symlink like this
$ ls -lo vendor/bin/phpunit
lrwxr-xr-x vendor/bin/phpunit -> ../phpunit/phpunit/phpunit
However, Dropbox will occasionally replace symlinks with the original file, and this will cause the error above. The behaviour is inconsistent, and with relative symlinks seems to break when 2 machines are accessing Dropbox at the same time. Fixing the symlink worked for me or you could make a new symlink directly to the vendor/phpunit/phpunit/phpunit outside of Dropbox and run that.
Edit: Nowadays I exclude Vendor and node_modules from Dropbox - and simply run composer install when necessary. This works really well, and also deals with the hassle of syncing so many files on Dropbox. What you can do is go into the folder and delete all the files. Wait for Dropbox to sync. Then mark the folder as excluded. Finally, run composer install and you get the contents as you need. (Delete + composer install often solves other issues too).
Running composer install did nothing in my case. However, removing vendor folder and then calling composer install fixed it.
You need to have Composer installed and run composer install or composer update in your application to install the different packages listed in your composer.json.
When you install your Laravel application it doesn't install the packages right away.
You can verify the packages are installed by looking in the vendor directory of your application and check that phpunit is in there.
did you install phpunit globally? I recommend you do it.
just type in your laravel's root directory (e.g. /var/www)
cd /var/www
phpunit
if you what to test just one file, you can do something like this:
phpunit tests/ExampleTest.php
Unit Test:
D:\xampp\htdocs\Samplemed\vendor\bin>
phpunit ../../tests/Unit/Company/CompanyUnitTest
Feature Test:
D:\xampp\htdocs\Samplemed\vendor\bin>phpunit
../../tests/Feature/Company/CompanyFeatureTest
Please try this. its working fine.

PHPUnit not working with Laravel 5

I just installed a fresh Laravel 5 project, my first one on this version. PHPUnit is supposed to be out of the box with the framework and every tutorials I saw just say to type phpunit within the project folder to launch the Unit Tests.
I checked and PHPUnit is in the composer.json, I also did a composer install and composer update just in case it wouldn't be here
website(master)$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
- Removing phpunit/phpunit (4.6.1)
- Installing phpunit/phpunit (4.6.2)
Downloading: 100%
But it just doesn't work phpunit isn't recognized at all
website(master)$ phpunit
-bash: phpunit: command not found
Seems like nobody got this problem before as I Googled it. I hope I'm not doing any stupid mistake. Any idea or suggestion ? Thanks guys ;)
I didn't install PHPUnit globally and didn't define the path. So for anyone who would have same problem :
composer global require phpunit/phpunit
composer global require phpunit/dbunit
Then you add this to you ~/.bash_profile or ~/.profile
export PATH=~/.composer/vendor/bin:$PATH
This occurs when you don't have phpunit installed globally.
Run this command to use the local version (installed with composer):
vendor/bin/phpunit
in windows machine the command is different please use this command
php vendor/phpunit/phpunit/phpunit
orignal source
You can run this command in cmd before running phpunit command:
doskey phpunit="vendor/bin/phpunit"
And if you are lazy as I am, you can run this one:
doskey pu="vendor/bin/phpunit"
for people who have WINDOWS 7, use the .\vendor\bin\phpunit command instead of ./vendor/bin/phpunit
Run the command
composer config --list --global | grep -w home
You can find the find the [home] with composer path, similar to this one.
[home] /home/example_username/.config/composer
The path ~/.config/composer is where composer global packages are installed. Next run the command...
export PATH=~/.config/composer/vendor/bin:$PATH
I made a permanent link to my phpunit like this
echo 'alias phpunit=vendor/bin/phpunit' >> ~/.bash_aliases
now phpunit is working by itself and stays even after I restart the terminal
Include this line on your composer.json
"phpunit/phpunit": "4.0.*",
Run composer update.
You should be able to run the following command on your Laravel directory.
vendor/bin/phpunit

Categories