PHPBenelux - Using Phing




          10-5-2011
          ~30 mins

       Marco de Krijger
About me

Marco de Krijger

    http://www.linkedin.com/in/marcodekrijger

    mdekrijger@e-sites.nl
Contents

   What is Phing
   Why using Phing
   Features
   Example Phing build file
   Phing and CI
   Extending Phing
   Questions
What is Phing
   Phing homepage: http://phing.info
    “PHing Is Not GNU make; it's a PHP project
    build system or build tool based on Apache Ant”
   Phing is like a jigsaw
    puzzle. It has a lots
    of easy to use building
    blocks to cover everything
    between a code base and
    a live production
    environment
Why using Phing

   Phing homepage:
    “If you find yourself writing custom scripts to
    handle the packaging, deploying, or testing of
    your applications”
   A shared platform that is maintained →
    less programming && less communication with
    (new) developers                       I'm not needed,
                                               so I can be empty

    “An excellent developer
    makes himself needless”
Features
In a nutshell
Example deployment

   “Phing look and feel” Info target
   e-sites library (ESL)
       Deploy ESL
       Revert version
<?xml version="1.0" encoding="UTF-8"?>
                                       Deployment code
<project name="ESL" default="info">

<target name="deployMinor">
<version releasetype="Minor" file="VERSION" property="version"/>
<svncommit workingcopy="." message="Updated VERSION file to ${version}" username="user" password="password"/>
<svncopy repositoryurl="http://svn.dev/library/esl/Branches/v1" todir="http://svn.dev/library/esl/Tags/release-${version}" username="user"
password="password"/>
<svnupdate todir="." username="user" password="password"/>
<phingcall target="deploy"/>
</target>


<target name="deploy" description="Deploy ESL" depends="tarball">
<fail unless="version" message="Please specify version to export e.g. -Dversion=1.0.0" />
<phingcall target="deployserver">
<property name="host" value="dev"/>
</phingcall>
<!-- clean up mess →
<delete dir="/tmp/eslpackage" quiet="true"/>
</target>

<target name="tarball">
<fail unless="version" message="Please specify version to export e.g. -Dversion=1.0.0" />
<!-- this is to check if SVN tag exists →
<svnlastrevision repositoryurl="http://svn.dev/library/esl/Tags/release-${version}" propertyname="tag" username="user" password="password"/>
<property name="build.dir" value="/tmp/eslpackage" />
<delete dir="${build.dir}" quiet="true"/>
<svnexport username="user" password="password" repositoryurl="http://svn.dev/library/esl/Tags/release-${version}" todir="${build.dir}"/>
<delete file="${build.dir}/build.xml"/>
<tar destfile="/tmp/eslpackage/esl.tar" compression="gzip">
<fileset dir="${build.dir}">
<include name="**/**" />
</fileset>
</tar>
</target>

<target name="deployserver" if="host,version">
<scp username="esites" host="${host}" todir="/tmp" file="/tmp/eslpackage/esl.tar" pubkeyfile="/var/www/.ssh/id_rsa.pub"
privkeyfile="/var/www/.ssh/id_rsa"/>
<!-- untar and symlink →
<ssh username="esites" host="${host}" command="mkdir /var/www/includes/ESL-${version}; cd /var/www/includes/ESL-${version}; tar -zvxf /tmp/esl.tar; ln
-s ./ESL-${version} /var/www/includes/ESLv1_tmp; mv -Tf /var/www/includes/ESLv1_tmp /var/www/includes/ESLv1;rm -f /tmp/esl.tar"
pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/>
</target>
Phing and CI

   Example with Jenkins (Hudson) “building ESL”
       Execute unit tests
       Codesniffer for standards
       PHPMD for mess detection
       Code coverage report for unit test
       PHPDepend stats



                                    +
<?xml version="1.0" encoding="UTF-8"?>
<project name="ESL">
<target name="build" description="Build ESL">
                                                Jenkins build file
<mkdir dir="./reports"/>

<fileset dir="./ESL" id="php.fileset">
<include name="**/*.php"/>
</fileset>

<!-- Set up coverage db →
<coverage-setup database="./reports/coverage.db">
<fileset refid="php.fileset"/>
</coverage-setup>

<!-- Execute unit tests →
<phpunit bootstrap="./bootstrap.php" codecoverage="true">
<formatter type="clover" todir="reports"/>
<formatter type="xml" todir="reports"/>
<batchtest>
<fileset id="unittests" dir="./tests">
<include name="**/*Test.php"/>
</fileset>
</batchtest>
</phpunit>

<!-- Do codesniffing →
<phpcodesniffer standard="Esites" format="checkstyle">
<fileset refid="php.fileset"/>
<formatter type="checkstyle" outfile="./reports/checkstyle.xml"/>
</phpcodesniffer>

<!-- Do PMD checks →
<phpmd rulesets="Esites">
<fileset refid="php.fileset"/>
<formatter type="xml" outfile="./reports/pmd.xml"/>
</phpmd>

<!-- Copy paste detection →
<phpcpd>
<fileset refid="php.fileset"/>
<formatter type="pmd" outfile="./reports/cpd.xml"/>
</phpcpd>

<!-- Get PHPDepend stats →
<phpdepend>
<fileset refid="php.fileset"/>
<logger type="jdepend-xml" outfile="./reports/jdepend.xml"/>
<logger type="jdepend-chart" outfile="./reports/dependencies.svg"/>
<logger type="overview-pyramid" outfile="./reports/overview-pyramid.svg"/>
<analyzer type="coderank-mode" value="method"/>
</phpdepend>

</target>
</project>
Jenkins graphs
            And...
           PHPCPD Copy paste
            detection
           PHPunit test results
Extending Phing

   Example
    Existing SSH task is incomplete. We want
    to capture SSH output for string matching
        Add your task/class to defaults.properties
        Create user directory in tasks
        Create your own task with setters and
         main method
<?xml version="1.0" encoding="UTF-8"?>
                                                 Custom task
<project name="ESL" default="build">

<property name="dir.source" value="/var/www/html/workingcopies/mdkrijger/personal/esltest" />
<property name="dir.destination" value="/tmp/phingdemo" />

<target name="compare" description="Compare 2 fixed directories">
<!-- Create package (tarball) →
<tar destfile="tarball.tar" compression="gzip">
 <fileset dir="${dir.source}">
 <include name="**/**" />
 </fileset>
</tar>
<!-- upload it to production environment →
<scp username="esites" host="dev" todir="/tmp" file="tarball.tar" pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/>
<!-- Extract the uploaded image, display its activity →
<ssh username="esites" host="dev" command="mkdir /tmp/phingdemo; cd /tmp/phingdemo; tar -zxvf /tmp/tarball.tar"
pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/>
<!-- This is the custom task →
<!-- get directory sizes →
<sshterm username="esites" host="devlocal" display="false" property="size1" command="du -bs ${dir.destination} | egrep -o '([0-9]*)'"
pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/>
<exec command="du -bs ${dir.source} | egrep -o '([0-9]*)'" outputproperty="size2"/>
<!-- compare them →
<if>
<not>
<equals arg1="${size1}" arg2="${size2}"/>
</not>
<then>
<fail message="Directories are not in sync! Size source: ${size2}, Size destination: ${size1}"/>
</then>
<else>
<echo message="Directories are in sync"/>
</else>
</if>
</target>

<target name="clean">
<delete dir="/tmp/phingdemo"/>
<delete file="/tmp/tarball.tar"/>
</target>

<target name="break">
<copy file="/tmp/tarball.tar" tofile="${dir.destination}/tarball.tar" overwrite="true"/>
</target>
</project>
Further reading

   Phing website
    http://phing.info
   Jenkins CI
    http://jenkins-ci.org
   Setting up Phing under Jenkins
    http://bit.ly/9EgmN
   This presentation
    http://www.slideshare.net/mdekrijger/phing-7900127
Questions?

   If any

Phing

  • 1.
    PHPBenelux - UsingPhing 10-5-2011 ~30 mins Marco de Krijger
  • 2.
    About me Marco deKrijger http://www.linkedin.com/in/marcodekrijger mdekrijger@e-sites.nl
  • 3.
    Contents  What is Phing  Why using Phing  Features  Example Phing build file  Phing and CI  Extending Phing  Questions
  • 4.
    What is Phing  Phing homepage: http://phing.info “PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant”  Phing is like a jigsaw puzzle. It has a lots of easy to use building blocks to cover everything between a code base and a live production environment
  • 5.
    Why using Phing  Phing homepage: “If you find yourself writing custom scripts to handle the packaging, deploying, or testing of your applications”  A shared platform that is maintained → less programming && less communication with (new) developers I'm not needed, so I can be empty “An excellent developer makes himself needless”
  • 6.
  • 7.
    Example deployment  “Phing look and feel” Info target  e-sites library (ESL)  Deploy ESL  Revert version
  • 8.
    <?xml version="1.0" encoding="UTF-8"?> Deployment code <project name="ESL" default="info"> <target name="deployMinor"> <version releasetype="Minor" file="VERSION" property="version"/> <svncommit workingcopy="." message="Updated VERSION file to ${version}" username="user" password="password"/> <svncopy repositoryurl="http://svn.dev/library/esl/Branches/v1" todir="http://svn.dev/library/esl/Tags/release-${version}" username="user" password="password"/> <svnupdate todir="." username="user" password="password"/> <phingcall target="deploy"/> </target> <target name="deploy" description="Deploy ESL" depends="tarball"> <fail unless="version" message="Please specify version to export e.g. -Dversion=1.0.0" /> <phingcall target="deployserver"> <property name="host" value="dev"/> </phingcall> <!-- clean up mess → <delete dir="/tmp/eslpackage" quiet="true"/> </target> <target name="tarball"> <fail unless="version" message="Please specify version to export e.g. -Dversion=1.0.0" /> <!-- this is to check if SVN tag exists → <svnlastrevision repositoryurl="http://svn.dev/library/esl/Tags/release-${version}" propertyname="tag" username="user" password="password"/> <property name="build.dir" value="/tmp/eslpackage" /> <delete dir="${build.dir}" quiet="true"/> <svnexport username="user" password="password" repositoryurl="http://svn.dev/library/esl/Tags/release-${version}" todir="${build.dir}"/> <delete file="${build.dir}/build.xml"/> <tar destfile="/tmp/eslpackage/esl.tar" compression="gzip"> <fileset dir="${build.dir}"> <include name="**/**" /> </fileset> </tar> </target> <target name="deployserver" if="host,version"> <scp username="esites" host="${host}" todir="/tmp" file="/tmp/eslpackage/esl.tar" pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/> <!-- untar and symlink → <ssh username="esites" host="${host}" command="mkdir /var/www/includes/ESL-${version}; cd /var/www/includes/ESL-${version}; tar -zvxf /tmp/esl.tar; ln -s ./ESL-${version} /var/www/includes/ESLv1_tmp; mv -Tf /var/www/includes/ESLv1_tmp /var/www/includes/ESLv1;rm -f /tmp/esl.tar" pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/> </target>
  • 9.
    Phing and CI  Example with Jenkins (Hudson) “building ESL”  Execute unit tests  Codesniffer for standards  PHPMD for mess detection  Code coverage report for unit test  PHPDepend stats +
  • 10.
    <?xml version="1.0" encoding="UTF-8"?> <projectname="ESL"> <target name="build" description="Build ESL"> Jenkins build file <mkdir dir="./reports"/> <fileset dir="./ESL" id="php.fileset"> <include name="**/*.php"/> </fileset> <!-- Set up coverage db → <coverage-setup database="./reports/coverage.db"> <fileset refid="php.fileset"/> </coverage-setup> <!-- Execute unit tests → <phpunit bootstrap="./bootstrap.php" codecoverage="true"> <formatter type="clover" todir="reports"/> <formatter type="xml" todir="reports"/> <batchtest> <fileset id="unittests" dir="./tests"> <include name="**/*Test.php"/> </fileset> </batchtest> </phpunit> <!-- Do codesniffing → <phpcodesniffer standard="Esites" format="checkstyle"> <fileset refid="php.fileset"/> <formatter type="checkstyle" outfile="./reports/checkstyle.xml"/> </phpcodesniffer> <!-- Do PMD checks → <phpmd rulesets="Esites"> <fileset refid="php.fileset"/> <formatter type="xml" outfile="./reports/pmd.xml"/> </phpmd> <!-- Copy paste detection → <phpcpd> <fileset refid="php.fileset"/> <formatter type="pmd" outfile="./reports/cpd.xml"/> </phpcpd> <!-- Get PHPDepend stats → <phpdepend> <fileset refid="php.fileset"/> <logger type="jdepend-xml" outfile="./reports/jdepend.xml"/> <logger type="jdepend-chart" outfile="./reports/dependencies.svg"/> <logger type="overview-pyramid" outfile="./reports/overview-pyramid.svg"/> <analyzer type="coderank-mode" value="method"/> </phpdepend> </target> </project>
  • 11.
    Jenkins graphs And...  PHPCPD Copy paste detection  PHPunit test results
  • 12.
    Extending Phing  Example Existing SSH task is incomplete. We want to capture SSH output for string matching  Add your task/class to defaults.properties  Create user directory in tasks  Create your own task with setters and main method
  • 13.
    <?xml version="1.0" encoding="UTF-8"?> Custom task <project name="ESL" default="build"> <property name="dir.source" value="/var/www/html/workingcopies/mdkrijger/personal/esltest" /> <property name="dir.destination" value="/tmp/phingdemo" /> <target name="compare" description="Compare 2 fixed directories"> <!-- Create package (tarball) → <tar destfile="tarball.tar" compression="gzip"> <fileset dir="${dir.source}"> <include name="**/**" /> </fileset> </tar> <!-- upload it to production environment → <scp username="esites" host="dev" todir="/tmp" file="tarball.tar" pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/> <!-- Extract the uploaded image, display its activity → <ssh username="esites" host="dev" command="mkdir /tmp/phingdemo; cd /tmp/phingdemo; tar -zxvf /tmp/tarball.tar" pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/> <!-- This is the custom task → <!-- get directory sizes → <sshterm username="esites" host="devlocal" display="false" property="size1" command="du -bs ${dir.destination} | egrep -o '([0-9]*)'" pubkeyfile="/var/www/.ssh/id_rsa.pub" privkeyfile="/var/www/.ssh/id_rsa"/> <exec command="du -bs ${dir.source} | egrep -o '([0-9]*)'" outputproperty="size2"/> <!-- compare them → <if> <not> <equals arg1="${size1}" arg2="${size2}"/> </not> <then> <fail message="Directories are not in sync! Size source: ${size2}, Size destination: ${size1}"/> </then> <else> <echo message="Directories are in sync"/> </else> </if> </target> <target name="clean"> <delete dir="/tmp/phingdemo"/> <delete file="/tmp/tarball.tar"/> </target> <target name="break"> <copy file="/tmp/tarball.tar" tofile="${dir.destination}/tarball.tar" overwrite="true"/> </target> </project>
  • 14.
    Further reading  Phing website http://phing.info  Jenkins CI http://jenkins-ci.org  Setting up Phing under Jenkins http://bit.ly/9EgmN  This presentation http://www.slideshare.net/mdekrijger/phing-7900127
  • 15.