Composer im
Unternehmensalltag

Stephan Hochdörfer // 28.11.2015

Über mich


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

  • #PHP, #DevOps, #Automation, #unKonf



Wir: Vielfältige Projekte

In grauer Vorzeit: Subversion

Keine klaren Abhängigkeiten

Zeitverschwendung

Ausweg?

Wie hilft uns Composer?


Eindeutige Abhängigkeiten

Transitive Abhängigkeiten?





Transitive Abhängigkeiten?

Transitive Abhängigkeiten?

Alles sicher, oder was?




Security Checker CLI Tool


$ php security-checker.phar security:check ./composer.lock
Security Check Report
~~~~~~~~~~~~~~~~~~~~~

Checked file: composer.lock


  [OK]
  0 packages have known vulnerabilities

Security Checker Webservice


$ curl -H "Accept: application/json" https://security.sensiolabs.org/check_lock -F lock=@./composer.lock
[]

Roave Security Advisories

Lizierungsprobleme?

Lizensierungen offen legen

$ 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

Perspektivenwechsel

Kleine Problemdomäne

Wähle das "perfekte" Tooling

Lokale Abhängigkeiten!

Lokale Abhängigkeiten!

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

Eigene Pakete bauen

Wie mach ich es richtig?


Composer Anwendungsfälle

1. Projektsetup vereinfachen

Neues Projekt aufsetzen

$ composer.phar create-project symfony/framework-standard-edition
  myproject
$ composer.phar create-project --repository-url=https://satis.loc
  my/installer myproject

Installer Paket-Konfiguration

{
    "name": "my/project-installer",
    "type": "project",
    "license": "MIT"
}
$ composer.phar create-project --repository-url=https://satis.loc
  my/project-installer myproject

Schneller Start ins Projekt

Anpassbare Kunden-Apps

2. Pakete standardisieren

3. Mehrere Apps, ein Core

Beispiel: Assets verwalten

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
  • ...

Custom Scripts einbinden

{
    "scripts": {
        "post-update-cmd": "My\\Composer\\PostUpdate::execute",
        "post-install-cmd": [
            "My\\Composer\\PostInstall::warmCache",
            "phpunit"
        ]
    }
}

Pakete parallel entwickeln?

Marathon, kein Sprint

4. Private Composer Pakete

Composer Pakete hosten



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



Toran acts as a proxy for
Packagist and GitHub.

Satis installieren

$ composer.phar create-project composer/satis --stability=dev

Satis Konfiguration

{
    "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" }
    ],
    "archive": {
        "directory": "dist",
        "format": "zip",
        "skip-dev": false
    }
}
$ php bin/satis build config.json web/
$ php bin/satis build config.json web/ mycompany/mypackage

Öffentliche Pakete spiegeln

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

Öffentliche Pakete spiegeln

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

Das eigene Satis Repository

Satis Repository einbinden

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

Toran Proxy

Toran Proxy installieren

$ 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

Toran Proxy in Aktion

Lokale Repositories

{
    "repositories": [{
            "type": "path",
            "url": "../../packages/mycompany/mypackage"
        }
    ]
}
$ composer.phar require mycompany/mypackage

Zugriffskontrolle?

HTTP Basic Auth

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

HTTP Basic Auth (auth.json)

{
    "http-basic": {
        "satis.mydomain.loc": {
            "username": "myuser",
            "password": "mypassword"
        },
        "git.mydomain.loc": {
            "username": "mygituser",
            "password": "mypassword"
        },
        "svn.mydomain.loc": {
            "username": "mysvnuser",
            "password": "mypassword"
        }
    }
}

(Kleiner Exkurs)

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

Buildserver Integration




Jenkins Node einrichten

Jenkins Node Environment

Jenkins Job einrichten

Konfiguration kopieren

composer.json validieren

Abhängigkeiten installieren

Den Build ausführen

Satis Build antriggern

Jenkins Satis Job einrichten

Parameter definieren

Satis ausführen

User benachrichtigen

Statis Build laufen lassen

Das Ergebnis: Satis ist aktuell








Vielen Dank! Fragen?