Download - Building and Deploying PHP apps with Phing

Transcript
Page 1: Building and Deploying PHP apps with Phing

Building and deploying PHP apps with

>< ><

Michiel Rook

PHP Johannesburg April 2014

Page 2: Building and Deploying PHP apps with Phing
Page 3: Building and Deploying PHP apps with Phing
Page 4: Building and Deploying PHP apps with Phing

About me

• Freelance PHP & Java contractor / consultant

• PHP since '99

• Phing project lead

• Dutch Web Alliance

• http://www.linkedin.com/in/michieltcs

• @michieltcs

Page 5: Building and Deploying PHP apps with Phing

This talk

• Why a build tool

• What is Phing

• Usage

• Various examples

• Deployments

• Extending Phing

Page 6: Building and Deploying PHP apps with Phing

Why a build tool?

Page 7: Building and Deploying PHP apps with Phing

This is PHP!?

Page 8: Building and Deploying PHP apps with Phing

Repetitive tasks

• Version control

• Database changes

• Testing

• Minifying

• Packaging

• Uploading

• Deploying

• Configuring

Page 9: Building and Deploying PHP apps with Phing

Good programmers are lazy

Page 10: Building and Deploying PHP apps with Phing

Good programmers automate repeatablethings

Page 11: Building and Deploying PHP apps with Phing

Automate!

• Easier handover

• Improves quality

• Reduces errors

• Saves time

• Consolidate scripts, reduce technical debt

Page 12: Building and Deploying PHP apps with Phing
Page 13: Building and Deploying PHP apps with Phing

What is Phing?

Page 14: Building and Deploying PHP apps with Phing

Phing is AWESOME

Page 15: Building and Deploying PHP apps with Phing

What is Phing?

• “PHing Is Not GNU make; it's a PHP project build systemor build tool based on Apache Ant.”

• XML build files

• Mostly cross-platform

• Integrates various popular (PHP) tools

• Lots. Of. Tasks.

Page 16: Building and Deploying PHP apps with Phing
Page 17: Building and Deploying PHP apps with Phing

"Phing is good glue"

Page 18: Building and Deploying PHP apps with Phing

The basics

Page 19: Building and Deploying PHP apps with Phing

Installing Phing

• PEAR installation

$ pear channel-discover pear.phing.info$ pear install [--alldeps] phing/phing

• Optionally, install the documentation package

$ pear install phing/phingdocs• Composer

• Phar package

Page 20: Building and Deploying PHP apps with Phing

Build file

• XML• Contains standard elements

• Task: performs a specific function (copy, git commit, etc.)• Target: collection of tasks, can optionally depend on othertargets

• Project: root node, contains multiple targets

Page 21: Building and Deploying PHP apps with Phing

Example build file

<project name="Example" default="world"><echo>Hi!</echo>

<target name="hello"><echo>Hello</echo>

</target>

<target name="world" depends="hello"><echo>World!</echo>

</target></project>

Page 22: Building and Deploying PHP apps with Phing

Example build file

$ phing [-f build.xml]Buildfile: /home/michiel/phing/build.xml

[echo] Hi!

Example > hello:

[echo] Hello

Example > world:

[echo] World!

BUILD FINISHED

Page 23: Building and Deploying PHP apps with Phing

Properties

• Simple key-value pairs

• ${attribute}

• Replaced by actual value

Page 24: Building and Deploying PHP apps with Phing

Properties

<project name="Example" default="default"><target name="default">

<property file="build.properties" /><property name="foo" value="bar" />

<echo>${foo}</echo></target>

</project>

Page 25: Building and Deploying PHP apps with Phing

Properties

$ phingBuildfile: /home/michiel/phing/build.xml

Example > default:

[echo] bar

BUILD FINISHED

Page 26: Building and Deploying PHP apps with Phing

Fileset

• Denotes a group of files

• Include or exclude files based on patterns

• References: define once, use many

Page 27: Building and Deploying PHP apps with Phing

Fileset

<copy todir="build"><fileset dir="./application">

<include name="**/*.php" /><exclude name="**/*Test.php" />

</fileset></copy>

<fileset dir="./application" includes="**"/>

<fileset dir="./application" includes="**" id="files"/>

<fileset refid="files"/>

Page 28: Building and Deploying PHP apps with Phing

Fileset

• Selectors allow fine-grained matching on certain attributes

• contains, date, file name & size, ...

<fileset dir="${dist}"><and>

<filename name="**"/><date datetime="01/01/2011" when="before"/>

</and></fileset>

Page 29: Building and Deploying PHP apps with Phing

Conditions

• Nested elements that evaluate to booleans

• Used in "condition", "if" and "waitfor" tasks

Page 30: Building and Deploying PHP apps with Phing

Conditions

<if><equals arg1="${foo}" arg2="bar" /><then>

<echo message="The value of property foo is bar" /></then><else>

<echo message="The value of property foo is not bar" /></else>

</if>

Page 31: Building and Deploying PHP apps with Phing

Conditions

<if><available file="composer.json" /><then>

<exec checkreturn="true" command="composer install"passthru="true" logoutput="true" dir="build" />

</then></if>

Page 32: Building and Deploying PHP apps with Phing

Examples

Page 33: Building and Deploying PHP apps with Phing

Examples

• Version control

• Unit testing

• Packaging

• Deployment

• Database migration

• Continuous integration

Page 34: Building and Deploying PHP apps with Phing

Version control

• Git

• SVN

• CVS

Page 35: Building and Deploying PHP apps with Phing

Version control

<svnexportrepositoryurl="svn://localhost/project/trunk/"todir="/home/michiel/dev"/>

<svnlastrevisionrepositoryurl="svn://localhost/project/trunk/"propertyname="lastrev"/>

<echo>Last revision: ${lastrev}</echo>

Page 36: Building and Deploying PHP apps with Phing

Version control

<gitcommitrepository="/home/michiel/dev/phing"message="Update documentation" allFiles="true"/>

<gitpushrepository="/home/michiel/dev/phing"refspec="master" tags="true" />

Page 37: Building and Deploying PHP apps with Phing

PHPUnit

• Built-in support for most configuration options

• Gathers code coverage information

• Various output formats / reports

• PHPUnit 4.x support soon!

Page 38: Building and Deploying PHP apps with Phing

PHPUnit

• Stop the build when a test fails

<phpunit haltonfailure="true" haltonerror="true"bootstrap="my_bootstrap.php" printsummary="true"><batchtest>

<fileset dir="src"><include name="**/*Test.php"/>

</fileset></batchtest>

</phpunit>

Buildfile: /home/michiel/phpunit/build.xml

Demo > test:

[phpunit] Total tests run: 1, Failures: 1, Errors: 0,Incomplete: 0, Skipped: 0, Time elapsed: 0.00591 s

Execution of target "test" failed for the following reason:/home/michiel/phpunit/build.xml:3:44: Test FAILURE (testSayHello inclass HelloWorldTest): Failed asserting that two strings are equal.

Page 39: Building and Deploying PHP apps with Phing

PHPUnit example

• Determine which files to include in the coverage report

<coverage-setup database="reports/coverage.db"><fileset dir="src">

<include name="**/*.php"/><exclude name="**/*Test.php"/>

</fileset></coverage-setup>

• Gather code coverage and other data during the test run<phpunit codecoverage="true">

<formatter type="xml" todir="reports"/><batchtest>

<fileset dir="src"><include name="**/*Test.php"/>

</fileset></batchtest>

</phpunit>

Page 40: Building and Deploying PHP apps with Phing

PHPUnit example

• Generate some reports

<phpunitreport infile="reports/testsuites.xml"format="frames" todir="reports/tests"/>

<coverage-report outfile="reports/coverage.xml"><report todir="reports/coverage" title="Demo"/>

</coverage-report>

Page 41: Building and Deploying PHP apps with Phing

Documentation

• Phing currently integrates with popular documentationtools

• phpDocumentor (2)• ApiGen

• Also supports r(e)ST (reStructuredText)

<phpdoc2 title="Phing API Documentation" output="docs"><fileset dir="../../classes">

<include name="**/*.php"/></fileset>

</phpdoc2>

Page 42: Building and Deploying PHP apps with Phing

phpDocumentor

Page 43: Building and Deploying PHP apps with Phing

Packaging

• Create bundles or packages• tar• zip• phar• PEAR

Page 44: Building and Deploying PHP apps with Phing

Tar / zip

<tar compression="gzip" destFile="package.tgz"basedir="build"/>

<zip destfile="htmlfiles.zip"><fileset dir=".">

<include name="**/*.html"/></fileset>

</zip>

Page 45: Building and Deploying PHP apps with Phing

Phar packages

<pharpackagecompression="gzip"destfile="test.phar"stub="stub.php"basedir="."><fileset dir="hello">

<include name="**/**" /></fileset><metadata>

<element name="version" value="1.0" /><element name="authors">

<element name="John Doe"><element name="e-mail"

value="[email protected]" /></element>

</element></metadata>

</pharpackage>

Page 46: Building and Deploying PHP apps with Phing

SSH

<ssh username="john" password="smith"host="webserver" command="ls" />

<scp username="john" password="smith"host="webserver" todir="/www/htdocs/project/"><fileset dir="test">

<include name="*.html"/></fileset>

</scp>

Page 47: Building and Deploying PHP apps with Phing

Jenkins

Page 48: Building and Deploying PHP apps with Phing

Jenkins

Page 49: Building and Deploying PHP apps with Phing

Jenkins

Page 50: Building and Deploying PHP apps with Phing

Putting it all together

Page 51: Building and Deploying PHP apps with Phing
Page 52: Building and Deploying PHP apps with Phing

Build & deploy script

Objectives:

• Perform syntax check

• Run tests

• Create package

• Deploy via SSH

• To selectable target / environment

• Update database

• Roll back

Page 53: Building and Deploying PHP apps with Phing

Syntax checks & tests

<phplint haltonfailure="true"><fileset dir=".">

<include name="src/**" /></fileset>

</phplint>

<phpunit haltonfailure="true"><batchtest>

<fileset dir="."><include name="src/**/*Test.php" />

</fileset></batchtest>

</phpunit>

Page 54: Building and Deploying PHP apps with Phing

Packaging

<tstamp><format property="build.timestamp" pattern="%Y%m%d%H%M%S"/>

</tstamp>

<property name="build.release" value="${project.name}-${build.timestamp}" /><property name="package.name" value="${build.release}.tar.gz" />

<tar destfile="artifacts/${package.name}" basedir="${build.dir.project}" />

Page 55: Building and Deploying PHP apps with Phing

Multiple targets

• Several deployment targets: testing, staging, production, ...

• One property file per target

• Select based on input

ssh.host=127.0.0.1ssh.username=phingssh.key.private=development-sshssh.key.public=development-ssh.pubdeploy.location=/home/phing/apps

Page 56: Building and Deploying PHP apps with Phing

Multiple targets

<input propertyname="deploy.target"validArgs="testing,staging,production">

Enter target name</input>

<property file="${deploy.target}.properties"/>

Page 57: Building and Deploying PHP apps with Phing

Uploading

<ssh host="${ssh.host}"username="${ssh.username}"privkeyfile="${ssh.key.private}"pubkeyfile="${ssh.key.public}"command="mkdir -p ${deploy.location.project}/${build.release}"failonerror="true" />

<echo>Copying package</echo><scp host="${ssh.host}"

port="${ssh.port}"username="${ssh.username}"privkeyfile="${ssh.key.private}"pubkeyfile="${ssh.key.public}"todir="${deploy.location.project}/${build.release}"file="${package.name.full}" />

Page 58: Building and Deploying PHP apps with Phing

Uploading

<echo>Extracting package</echo><ssh ...

command="cd ${deploy.location.project}/${build.release};tar xzf ${package.name}"

failonerror="true" />

Page 59: Building and Deploying PHP apps with Phing

Symbolic links

• All releases stored in separate directories

• Symlink "current" to latest release

• Allows for easy (code) rollbacks

<echo>Creating symbolic link</echo><ssh ...

command="cd ${deploy.location.project};if [ -h &quot;current&quot; ]; thenrm -f previous; mv current previous; fi;ln -s ${build.release} current" />

Page 60: Building and Deploying PHP apps with Phing

Database migration

• Set of delta SQL files (1-create-post.sql)

• Tracks current version of your db in changelog table

• Generates do and undo SQL files

CREATE TABLE changelog (change_number BIGINT NOT NULL,delta_set VARCHAR(10) NOT NULL,start_dt TIMESTAMP NOT NULL,complete_dt TIMESTAMP NULL,applied_by VARCHAR(100) NOT NULL,description VARCHAR(500) NOT NULL

)

Page 61: Building and Deploying PHP apps with Phing

Database migration

• Delta scripts with do (up) & undo (down) parts

--//

CREATE TABLE `post` (`title` VARCHAR(255),`time_created` DATETIME,`content` MEDIUMTEXT

);

--//@UNDO

DROP TABLE `post`;

--//

Page 62: Building and Deploying PHP apps with Phing

Database migration

<dbdeployurl="sqlite:test.db"dir="deltas"outputfile="deploy.sql"undooutputfile="undo.sql"/>

<pdosqlexecsrc="deploy.sql"url="sqlite:test.db"/>

[dbdeploy] Getting applied changed numbers from DB:mysql:host=localhost;dbname=demo

[dbdeploy] Current db revision: 0[dbdeploy] Checkall:[pdosqlexec] Executing file: /home/michiel/dbdeploy/deploy.sql[pdosqlexec] 3 of 3 SQL statements executed successfully

Page 63: Building and Deploying PHP apps with Phing

Database migration

-- Fragment begins: 1 --INSERT INTO changelog

(change_number, delta_set, start_dt, applied_by, description)VALUES (1, 'Main', NOW(), 'dbdeploy','1-create_initial_schema.sql');

--//

CREATE TABLE `post` (`title` VARCHAR(255),`time_created` DATETIME,`content` MEDIUMTEXT

);

UPDATE changelogSET complete_dt = NOW()WHERE change_number = 1AND delta_set = 'Main';

-- Fragment ends: 1 --

Page 64: Building and Deploying PHP apps with Phing

Database migration

-- Fragment begins: 1 --

DROP TABLE `post`;

--//

DELETE FROM changelogWHERE change_number = 1AND delta_set = 'Main';

-- Fragment ends: 1 --

Page 65: Building and Deploying PHP apps with Phing

Restart services

<ssh ...command="sudo service apache2 reload"failonerror="true" />

Page 66: Building and Deploying PHP apps with Phing

Rolling back

<trycatch><try>

<ssh ...command="cd ${deploy.location.project};

rm -f current;mv -f previous current"

failonerror="true" /><echo>Rollback complete</echo>

</try><catch>

<echo>No previous version deployed!</echo></catch>

</trycatch>

Page 67: Building and Deploying PHP apps with Phing

Extending Phing

Page 68: Building and Deploying PHP apps with Phing

Writing your own task

• Extend from Task

• Contains main() method and optionally init()

• Setter method for each attribute in the build file

Page 69: Building and Deploying PHP apps with Phing

Our new task should

• Accept filesets

• Count number of lines in each file

• Fail the build if a file with zero lines is found

Page 70: Building and Deploying PHP apps with Phing

Our new task

<?php

require_once 'phing/Task.php';

class CountLinesTask extends Task{

public function main(){

$foundEmpty = false;

if ($foundEmpty) {throw new BuildException("One or more files have zero lines");

}}

}

Page 71: Building and Deploying PHP apps with Phing

Injecting file sets

private $_filesets = array();

/*** Creator for _filesets** @return FileSet*/public function createFileset(){

$num = array_push($this->_filesets, new FileSet());return $this->_filesets[$num-1];

}

Page 72: Building and Deploying PHP apps with Phing

Injecting file sets

foreach ($this->_filesets as $fileset) {$files = $fileset->getDirectoryScanner($this->project)

->getIncludedFiles();$dir = $fileset->getDir($this->project)->getAbsolutePath();

foreach ($files as $file) {$path = realpath($dir . DIRECTORY_SEPARATOR . $file);$lines = count(file($path));

$this->log($path . ": " . $lines . " line(s)");

if ($lines == 0) {$foundEmpty = true;

}}

}

Page 73: Building and Deploying PHP apps with Phing

Using the task

<project name="Count Lines" default="count"><target name="count">

<taskdef name="countlines"classpath="/home/michiel/tasks"classname="CountLinesTask" />

<countlines><fileset dir=".">

<include name="**/*.txt" /></fileset>

</countlines></target>

</project>

Page 74: Building and Deploying PHP apps with Phing

Using the task

Buildfile: /home/michiel/examples/count.xml

Count Lines > count:

[countlines] /home/michiel/examples/empty.txt: 0 line(s)[countlines] /home/michiel/examples/lines.txt: 3 line(s)Execution of target "count" failed for the following reason:/home/michiel/examples/count.xml:7:20: One or more files have zero lines

BUILD FAILED/home/michiel/examples/count.xml:7:20: One or more files have zero linesTotal time: 0.0454 seconds

Page 75: Building and Deploying PHP apps with Phing

Alternative: Ad Hoc

<target name="main"><adhoc-task name="foo"><![CDATA[class FooTask extends Task {

private $bar;

public function setBar($bar) {$this->bar = $bar;

}

public function main() {$this->log("In main(): " . $this->bar);

}}]]></adhoc-task><foo bar="TEST"/>

</target>

Page 76: Building and Deploying PHP apps with Phing
Page 77: Building and Deploying PHP apps with Phing

Where to go from here

• Tool versions

• Performance

• Documentation

• PHP 5.3/5.4/5.5

• IDE support

• CI integration

Page 78: Building and Deploying PHP apps with Phing

Questions?

Example code at https://github.com/mrook/phing-examplesPlease leave feedback at https://joind.in/10411

Contact us on:

http://www.phing.info#phing (freenode)@phingofficial

Thank you!