Composer for Corporate Use
Stephan Hochdörfer // 04.10.2014
About me
Stephan Hochdörfer
Head of Technology , bitExpert AG (Mannheim, Germany)
S.Hochdoerfer@bitExpert.de
@shochdoerfer
#PHP, #DevOps, #Automation
Who of you has heard of Composer? Who uses it?
This is no intro to Composer...
Our story: Diversity
A lot of different project with a lot of technology stacks.
Back in the days: Subversion
Long time Subversion user, moved to Git about 3 years ago. Back in the SVN days we made heavy use of svn:externals to "manage" our dependencies.
No fixed dependencies
To be honest: We did not really deal with dependencies, we linked in some folders. That`s sth. completly different. I knew we had to change our strategy concerning dependency management. Composer was the only real option.
How can Composer help?
What are the everyday challenges we are dealing with?
Clear dependencies
just look into composer.json or composer.lock and you know what`s going on.
Transitive dependencies?
Transitive dependencies?
Security issues?
upload your composer.lock file
Jenkins Job as nightly build to check for problems
Check composer.lock file
$ php security-checker.phar security: check ./ composer.lock
Security Check Report
~~~~~~~~~~~~~~~~~~~~~
Checked file : composer.lock
[ OK]
0 packages have known vulnerabilities
Check composer.lock file
$ curl - H "Accept: application/json" https:// security.sensiolabs.org/ check_lock - F lock= @./ composer.lock
[]
Be aware of licensing issues
Make your developers aware of the licensing problem. It is so easy to pick any package from packagist but does it ahere to your company policy or the policy of your customer?
Tracking package licenses
$ composer.phar licenses
Name: customer/ project
Version: 1.0.0
Licenses: proprietary
Dependencies:
phpoffice/ phpexcel 1.8.0 LGPL
pimple/ pimple v1.1.1 MIT
psr/ log 1.0.0 MIT
silex/ silex v1.2.1 MIT
symfony/ debug v2.5.4 MIT
symfony/ event- dispatcher v2.5.4 MIT
symfony/ http- foundation v2.5.4 MIT
symfony/ http- kernel v2.5.4 MIT
symfony/ routing v2.5.4 MIT
Run the licenses command
Jenkins Job as nightly build to check for issues
Perspective change
Composer changed the way I think about projects and their dependencies
I always try to ask the question if there`s functionality which we can reuse in multiple projects? If so, create a small, reusable package
Small problem domains
Choose the "perfect" toolset
Pick the libs that make the most sense for the project. Maybe a full-stack framework, maybe a microframework. Throw in Zend\Mail...
Install tools like PHPUnit, Phing locally within your project. These are dependencies just like Symfony or ZF
Build your own packages
Libs that take advantage of our infrastructure or the infrastructure of our customers
Pro-tip: Do not fork a project, remove the comments, change coding style and push it to packagist.org again.
Package design challenges
Mathias Noback: Principles of PHP Package Design
1. Simplify your project setup
Back in the subversion days it took quite a while to setup a project and configure svn:externals. With Composer this whole process is much smoother and can be done by any dev.
Set-up a new project
$ composer.phar create- project symfony/ framework- standard- edition
myproject
$ composer.phar create- project -- repository- url= https:// satis.loc
my/ installer myproject
Custom project installer
{
"name" : "my/project-installer" ,
"type" : "project" ,
"license" : "MIT"
}
$ composer.phar create- project -- repository- url= https:// satis.loc
my/ project- installer myproject
Speeds up your project setup
One can not only create an installer for a framework but also to set-up a default project structure for your companies` projects incl. default dependencies and Vagrant/Puppet setup for a new project. Just a matter of running vagrant up and the virtual machine is up and running and the developers start to get their work done.
Customizing customers apps
We often build applications for our customers who sell these application to their customers, usually with customizations. To make things easier for the dev teams we create custom installers on a per project basis
Standardize package layout
Guide the devlopers to make it super easy to bootstrap a new library. Create a sample filesystem layout incl. the required dependencies, e.g. setup Sphinx for documentation, configure PHPUnit and PHPDocumentor...
2. Split app, maintain core lib
This is what drives a German really crazy ;)
Build one monolithic app, split it into several apps and share common functionality via a "core" package
3. Custom package events
(pre|post)-install-cmd
(pre|post)-update-cmd
(pre|post)-status-cmd
(pre|post)-package-install
(pre|post)-package-update
(pre|post)-package-uninstall
(pre|post)-autoload-dump
...
Create custom scripts
{
"scripts" : {
"post-update-cmd" : "My \\ Composer \\ PostUpdate::execute" ,
"post-install-cmd" : [
"My \\ Composer \\ PostInstall::warmCache" ,
"phpunit"
]
}
}
Manage assets
Example: Copy assets to htdocs folder (e.g. dependent package contains php and javascript)
Vagrant Cachier Plugin
$ vagrant plugin install vagrant- cachier
VAGRANTFILE_API_VERSION = "2"
Vagrant. require_version ">= 1.6.0"
Vagrant. configure ( VAGRANTFILE_API_VERSION) do | config|
if Vagrant. has_plugin?( "vagrant-cachier" )
config. cache. scope = :box
config. cache. enable :composer
end
config. vm. define "wheezy" do | wheezy|
wheezy. vm. box = 'debian-wheezy-64'
end
end
Private packages?
Hosting your packages
Satis is a ultra-lightweight, static file-based version of packagist.
Installing Satis
$ composer.phar create- project composer/ satis -- stability= dev
Running Satis
{
"name" : "My own repo" ,
"homepage" : "http://satis.mydomain.loc" ,
"repositories" : [
{ "type" : "vcs" , "url" : "http://git.mydomain.loc/repo1.git" },
{ "type" : "vcs" , "url" : "http://git.mydomain.loc/repo2.git" }
],
"require-all" : true ,
"archive" : {
"directory" : "dist" ,
"format" : "zip" ,
"skip-dev" : false
}
}
$ php bin/ satis build config.json web/
$ php bin/ satis build config.json web/ mycompany/ mypackage
Mirror packages
{
"name" : "My own repo" ,
"homepage" : "http://satis.mydomain.loc" ,
"require-dependencies" : true ,
"require-dev-dependencies" : true ,
"repositories" : [
{ "type" : "vcs" , "url" : "https://github.com/silexphp/Silex.git" }
],
"archive" : {
"directory" : "dist" ,
"format" : "zip" ,
"skip-dev" : false
}
}
Your Satis Repository
Using Satis
{
"require" : {
"php" : ">=5.5.0" ,
"zendframework/zend-mail" : "2.2.*@stable" ,
"mycompany/mypackage" : "2.4.*@stable"
},
"repositories" : [{
"type" : "composer" ,
"url" : "http://satis.mydomain.loc/"
}
]
}
$ composer.phar install
Access Control?
Credential handling
$ composer.phar install
Loading composer repositories with package information
Authentication required (satis.mydomain.loc):
Username: myuser
Password:
Do you want to store credentials for satis.mydomain.loc in
~/.composer/auth.json ? [Yn]
Does not only work for the satis repository but also for git/svn repositories
Credential handling
{
"http-basic" : {
"satis.mydomain.loc" : {
"username" : "myuser" ,
"password" : "mypassword"
},
"git.mydomain.loc" : {
"username" : "mygituser" ,
"password" : "mypassword"
},
"svn.mydomain.loc" : {
"username" : "mysvnuser" ,
"password" : "mypassword"
}
}
}
Toran Proxy
Toran Proxy Setup
$ wget https:// toranproxy.com/ releases/ toran- proxy- v1.1.4.tgz
$ tar xvfz toran- proxy- v1.1.4.tgz
$ cp app/ config/ parameters.yml.dist app/ config/ parameters.yml
$ php app/ console server: run -- env= prod
Your Toran Proxy
Jenkins Node Config
Jenkins Node Environment
Jenkins Job Config
Push Config files to node
Jenkins Plugin: Config File Provider Plugin
Validate composer.json
Installing dependencies
$COMPOSER_USER and $COMPOSER_PASS are populated from the node environment settings we defined before.
Jenkins Plugin: Mask Passwords Plugin
Running the build
Will run PHP_CodeSniffer, PHPUnit, PDepend, ...
Run satis build for package
Jenkins Satis Job Config
Define Job Parameters
Jenkins Plugin: Parameterized Trigger Plugin
Executing Satis
Notify users after build
Jenkins Plugin: Email-ext plugin
Running the build
Result