Composer for
Corporate Use

Stephan Hochdörfer // October 19 2016

About me


  • Stephan Hochdörfer
  • Head of Technology, bitExpert AG
    (Mannheim, Germany)
  • S.Hochdoerfer@bitExpert.de
  • @shochdoerfer

  • #PHP, #DevOps, #Automation
  • #phpugffm, #phpugmrn, #unKonf



Our story: Diversity

Back in the days: Subversion

No fixed dependencies

Big waste of time

No way out?

How can Composer help?


Clear dependencies

Transitive dependencies?





Transitive dependencies?

Transitive dependencies?

Security issues?




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
[]
                    
                

Roave Security Advisories

Be aware of licensing issues

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

Perspective change

Small problem domains

Choose the "perfect" toolset

Local dependencies FTW!

Local dependencies FTW!

# https://github.com/dflydev/just-run-phpunit
PHPUNIT_PATH=vendor/bin:bin

function phpunit {
    TEST_PATHS=($PHPUNIT_PATH)
    for TEST_PATH in "${TEST_PATHS[@]}"
    do
        if [ -x "${TEST_PATH}/phpunit" ]
        then
            "${TEST_PATH}/phpunit" "$@"; return $?
        fi
    done

    PHPUNIT_ON_PATH="$(type -P phpunit )"
    if [ -n "${PHPUNIT_ON_PATH}" ]; then
        "${PHPUNIT_ON_PATH}" "$@"; return $?
    else
        echo "phpunit not found!"; return 127
    fi
}

Build your own packages

Package design challenges


Composer Use-Cases

1. Simplify your project setup

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

Customizing customers apps

2. Standardize pkg layouts

3. Split app, maintain core lib

Example: Manage assets

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"
        ]
    }
}

Developing in parallel?

It`s a marathon, not a sprint!

4. Private packages?

Hosting your packages



Satis is a ultra-lightweight, static
file-based version of packagist.



Toran acts as a proxy for
Packagist and GitHub.

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
    }
}

Mirror packages

{
    "name": "My own repo",
    "homepage": "http://satis.mydomain.loc",
    "require-dependencies": true,
    "require-dev-dependencies": true,
    "repositories": [
        { "type": "composer", "url": "http://packagist.org" }
    ],
    "require": {
        "silex/silex": "v1.2.2"
    },
    "archive": {
        "directory": "dist",
        "format": "zip",
        "skip-dev": false
    }
}

Your Satis Repository

Using Satis

{
    "repositories": [{
            "type": "composer",
            "url": "http://satis.mydomain.loc/"
        }
    ]
}
$ composer.phar require zendframework/zend-mail
$ composer.phar require mycompany/mypackage

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

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]

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"
        }
    }
}

(Side note)

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





Jenkins Node Config

Jenkins Node Environment

Jenkins Job Config

Push Config files to node

Validate composer.json

Installing dependencies

Running the build

Run satis build for package

Jenkins Satis Job Config

Define Job Parameters

Executing Satis

Notify users after build

Running the build

Result








Thank you! Questions?







Do not forget to rate the talk:
https://joind.in/talk/f49ed