Phing All The Things!
Omni Adams

Lazy development

sleeping cat

Stay DRY

http://ardalis.com/DRY---Don%E2%80%99t-Repeat-Yourself---Motivator
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="phing-the-things" default="test">
     <target name="test">
         <exec executable="phpunit" passthru="true"
                 checkreturn="true" />
     </target>
 </project>
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="phing-the-things" default="test">
     <target name="test">
         <exec executable="phpunit" passthru="true"
                 checkreturn="true" />
     </target>
 </project>
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="phing-the-things" default="test">
     <target name="test">
         <exec executable="phpunit" passthru="true"
                 checkreturn="true" />
     </target>
 </project>
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="phing-the-things" default="test">
     <target name="test">
         <exec executable="phpunit" passthru="true"
                 checkreturn="true" />
     </target>
 </project>
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="phing-the-things" default="test">
     <target name="test">
         <exec executable="phpunit" passthru="true"
                 checkreturn="true" />
     </target>
 </project>
phing-the-things$ phing test
Buildfile: /Users/Omni/phing-example/build.xml
 [property] Loading /Users/Omni/phing-example/build.properties

phing-example > test:

PHPUnit 3.7.13 by Sebastian Bergmann.

Configuration read from /Users/Omni/phing-example/phpunit.xml

..............................
Time: 0 seconds, Memory: 7.25Mb

OK (30 tests, 52 assertions)

BUILD FINISHED
Total time: 0.3155 seconds
F.............................
Time: 0 seconds, Memory: 7.25Mb

There was 1 failure:

1) GitTest::testGetCommitInfo
LOL cats have clogged the tubes!
/Users/Omni/phing-example/tests/GitTest.php:51

FAILURES!
Tests: 30, Assertions: 51, Failures: 1.
Execution of target "test" failed for the following reason: /Users/Omni/phing-example/build.xml:102:46: Task exited with code 1

BUILD FAILED
/Users/Omni/phing-example/build.xml:102:46: Task exited with code 1
Total time: 0.5653 seconds
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="phing-the-things" default="test">
     <target name="test">
         <exec executable="phpunit" passthru="true"
                 checkreturn="true" />
     </target>
 </project>
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="phing-the-things" default="test">
     <target name="test">
         <exec executable="phpunit" passthru="true"
                 checkreturn="true" />
     </target>
 </project>
F.............................

Time: 0 seconds, Memory: 7.25Mb

There was 1 failure:

1) GitTest::testGetCommitInfo
LOL cats have clogged the tubes!

/Users/Omni/phing-example/tests/GitTest.php:51

FAILURES!
Tests: 30, Assertions: 51, Failures: 1.

BUILD FINISHED

Total time: 0.5619 seconds
LOLWUT?
 <target name="test">
     <exec executable="phpunit" passthru="true"
             checkreturn="true">
         <arg value="--exclude-group=integration" />
     </exec>
 </target>
 <target name="test">
     <exec executable="phpunit" passthru="true"
             checkreturn="true">
         <arg value="${phpunitFlag}" />
     </exec>
 </target>
Find X
 <property name="phpunitFlag"
     value="--group=smoke" />
 <property name=""outputDir" value="./docs" />
phing-the-things$ phing test -DphpunitFlag=--group=smoke
Buildfile: /Users/Omni/phing-example/build.xml
 [property] Loading /Users/Omni/phing-example/build.properties

phing-example > test:

PHPUnit 3.7.13 by Sebastian Bergmann.

Configuration read from /Users/Omni/phing-example/phpunit.xml

........
Time: 0 seconds, Memory: 7.25Mb

OK (8 tests, 12 assertions)

BUILD FINISHED
Total time: 0.1058 seconds
 composer=/opt/composer.phar
 server1.user=oadams
 server1.url=www.example.lan
 <property file="build.properties" />
 <target name="properties-example">
     <exec executable="${composer}" />
     <exec executable="ssh" passthru="true">
         <arg value="-t" />
         <arg value="${server1.user}@${server1.url}" />
         <arg value="sudo /sbin/service httpd restart" />
     </exec>
 </target>
first
things
first
 # build.properties
 author=Omni
 title=Phing All The Things
 <property name="author" value="Other Guy" />
 <property file="build.properties" />
 <property name="title" value="Phing-a-ling" />
Smelly feet
 <patternset id="files">
     <include name="**/*.php" />
     <exclude name="third-party/**" />
     <exclude name="vendor/**" />
 </patternset>

 <target name="phpcs">
     <phpcodesniffer standard="./coding_rules.xml" format="full"
             showWarnings="true">
         <fileset dir=".">
             <patternset refid="files" />
         </fileset>
     </phpcodesniffer>
 </target>
Documentation
 <target name="document" depends="require-doc">
     <mkdir dir="${doc}/api" />
     <exec executable="phpdoc" passthru="true">
         <arg value="--directory=." />
         <arg value="--ignore=vendor/*" />
         <arg value="--ignore=src/*" />
         <arg value="--progressbar" />
         <arg value="--target=${doc}/api" />
         <arg value="--title=API documentation" />
     </exec>
 </target>
 <target name="document" depends="require-doc">
     <mkdir dir="${doc}/api" />
     <exec executable="phpdoc" passthru="true">
         <arg value="--directory=." />
         <arg value="--ignore=vendor/*" />
         <arg value="--ignore=src/*" />
         <arg value="--progressbar" />
         <arg value="--target=${doc}/api" />
         <arg value="--title=API documentation" />
     </exec>
 </target>
 <target name="document" depends="require-doc">
     <mkdir dir="${doc}/api" />
     <exec executable="phpdoc" passthru="true">
         <arg value="--directory=." />
         <arg value="--ignore=vendor/*" />
         <arg value="--ignore=src/*" />
         <arg value="--progressbar" />
         <arg value="--target=${doc}/api" />
         <arg value="--title=API documentation" />
     </exec>
 </target>
 <target name="document" depends="require-doc">
     <mkdir dir="${doc}/api" />
     <exec executable="phpdoc" passthru="true">
         <arg value="--directory=." />
         <arg value="--ignore=vendor/*" />
         <arg value="--ignore=src/*" />
         <arg value="--progressbar" />
         <arg value="--target=${doc}/api" />
         <arg value="--title=API documentation" />
     </exec>
 </target>
 <exec executable="ps" outputProperty="ps-output">
     <arg value="x" />
     <arg value="|" />
     <arg value="grep" />
     <arg value="selenium" />
     <arg value="|" />
     <arg value="grep" />
     <arg value="-v" />
     <arg value="grep" />
     <arg value="|" />
     <arg value="grep" />
     <arg value="-v" />
     <arg value="phing" />
 </exec>
 <exec executable="ps" outputProperty="ps-output">
     <arg line="x |grep selen |grep -v 'grep\|phing'" />
 </exec>
Don't cross the streams
Jenga game falling over
Dependency graph
 <target name="build" depends="test" />

 <target name="coverage" depends="require-doc">
     <exec executable="phpunit" passthru="true">
         <arg value="--coverage-html=${doc}/cover" />
         <arg value="${phpunitFlag}" />
     </exec>
 </target>
 <target name="require-doc">
     <if>
         <not>
             <isset property="doc" />
         </not>
         <then>
             <fail message="doc isn't set in .properties file" />
         </then>
     </if>
 </target>
 <property name="foo" value="not-test" />

 <target name="example" depends="other-task">
     <phingcall target="other-task">
         <property name="foo" value="test" />
         <property name="bar" value="test" />
     </phingcall>
     <phingcall target="other-task" />
 </target>

 <target name="other-task">
     <echo message="${foo}" />
     <echo message="${bar}" />
 </target>
Lazy cat
 <uptodate property="css-compiled"
       targetfile="style.css">
     <srcfiles dir="styles" includes="**/*less" />
 </uptodate>
 <uptodate property="css-compiled"
       targetfile="style.css">
     <srcfiles dir="styles" includes="**/*less" />
 </uptodate>
 <uptodate property="css-compiled"
       targetfile="style.css">
     <srcfiles dir="styles" includes="**/*less" />
 </uptodate>
 <uptodate property="css-compiled"
       targetfile="style.css">
     <srcfiles dir="styles" includes="**/*less" />
 </uptodate>
 <uptodate property="css-compiled"
       targetfile="style.css">
     <srcfiles dir="styles" includes="**/*less" />
 </uptodate>
 <uptodate property="css-compiled"
       targetfile="style.css">
     <srcfiles dir="styles" includes="**/*less" />
 </uptodate>
 <target name="compile-css"
           unless="css-compiled">
     <exec executable="lessc" passthru="true"
            checkreturn="true">
         <arg value="-x" />
         <arg value="styles/*.less" />
         <arg value="style.css" />
     </exec>
 </target>
Composer logo
 <available property="exists" file="composer.phar" />
 <target name="get-composer" unless="exists">
     <exec executable="curl" output="composer.php">
        <arg value="-sS" />
        <arg value="https://getcomposer.org/installer"/>
        <arg value="|" />
        <arg value="php" />
     </exec>
     <chmod file="composer.phar" perm="664" />
 </target>
 <available property="exists" file="composer.phar" />
 <target name="get-composer" unless="exists">
     <exec executable="curl" output="composer.php">
        <arg value="-sS" />
        <arg value="https://getcomposer.org/installer"/>
        <arg value="|" />
        <arg value="php" />
     </exec>
     <chmod file="composer.phar" perm="664" />
 </target>
Chicken or egg?
Deployment
assumptions
Paranoia
Tags
 <target name="tag" depends="require-version">
     <gittag annotate="true" name="${version}"
             repository="."
             message="Tagged version ${version}" />
     <gitpush repository="." tags="true"
             quiet="true" />
 </target>
phing-the-things$ phing tag
Buildfile: /Users/Omni/Sites/phing/build.xml
 [property] Loading /Users/Omni/Sites/phing/build.properties

phing-the-things > require-version:

       [if] Error in IfTask
Execution of target "require-version" failed for the following reason: /Users/Omni/Sites/phing/build.xml:146:12: /Users/Omni/Sites/phing/build.xml:150:18: You must pass in a version: -Dversion=1.2.3
BUILD FAILED
/Users/Omni/Sites/phing/build.xml:146:12: /Users/Omni/Sites/phing/build.xml:150:18: You must pass in a version: -Dversion=1.2.3
Total time: 1.5921 second
phing-the-things$ phing tag-no-version
Buildfile: /Users/Omni/Sites/phing/build.xml
 [property] Loading /Users/Omni/Sites/phing/build.properties

phing-the-things > tag-no-version:

   [gittag] git-tag command: /usr/bin/git tag -a -m'Tagged version ${version}' '${version}'
   [gittag] git-tag: tags for "." repository
   [gittag] git-tag output:

BUILD FINISHED

Total time: 0.2039 seconds

phing-the-things $ git tag
${version}
 <target name="tag-version">
     <version releasetype="${release}" file="version.txt"
         property="version" />
     <exec executable="git" passthru="true">
         <arg line="add version.txt" />
     </exec>
     <exec executable="git" passthru="true">
         <arg line="commit -m 'Updated version ${version}'" />
     </exec>
     <gittag annotate="true" name="${version}" repository="."
             message="Tagged version ${version}" />
 </target>
 <target name="tag-version">
     <version releasetype="${release}" file="version.txt"
         property="version" />
     <exec executable="git" passthru="true">
         <arg line="add version.txt" />
     </exec>
     <exec executable="git" passthru="true">
         <arg line="commit -m 'Updated version ${version}'" />
     </exec>
     <gittag annotate="true" name="${version}" repository="."
             message="Tagged version ${version}" />
 </target>
 <target name="tag-version">
     <version releasetype="${release}" file="version.txt"
         property="version" />
     <exec executable="git" passthru="true">
         <arg line="add version.txt" />
     </exec>
     <exec executable="git" passthru="true">
         <arg line="commit -m 'Updated version ${version}'" />
     </exec>
     <gittag annotate="true" name="${version}" repository="."
             message="Tagged version ${version}" />
 </target>
 <target name="tag-version">
     <version releasetype="${release}" file="version.txt"
         property="version" />
     <exec executable="git" passthru="true">
         <arg line="add version.txt" />
     </exec>
     <exec executable="git" passthru="true">
         <arg line="commit -m 'Updated version ${version}'" />
     </exec>
     <gittag annotate="true" name="${version}" repository="."
             message="Tagged version ${version}" />
 </target>
 <target name="tag-version">
     <version releasetype="${release}" file="version.txt"
         property="version" />
     <exec executable="git" passthru="true">
         <arg line="add version.txt" />
     </exec>
     <exec executable="git" passthru="true">
         <arg line="commit -m 'Updated version ${version}'" />
     </exec>
     <gittag annotate="true" name="${version}" repository="."
             message="Tagged version ${version}" />
 </target>
phing-the-things$ phing tag-version -Drelease=minor
Buildfile: /Users/Omni/Sites/phing/build.xml
 [property] Loading /Users/Omni/Sites/phing/build.properties
phing-the-things > tag-version:

[master 4b48e9f] Updated version file to 0.1.0
 1 file changed, 1 insertion(+), 1 deletion(-)
   [gittag] git-tag command: /usr/bin/git tag -a -m'Tagged version 0.1.0' '0.1.0'
   [gittag] git-tag: tags for "." repository
   [gittag] git-tag output:

BUILD FINISHED
Total time: 0.3507 seconds

phing-the-things $ git tag
0.0.1
0.1.0
 <target name="release-major">
     <phingcall target="tag-version">
         <property name="release" value="major" />
     </phingcall>
 </target>

 <target name="release-minor">
     <phingcall target="tag-version">
         <property name="release" value="minor" />
     </phingcall>
 </target>
 <target name="tag-svn">
     <svncopy svnpath="${svnpath}"
         password="${svnpass}" nocache="true"
         repositoryurl="svn://localhost/phing-things/trunk/"
         todir="svn://localhost/phing-things/tags/${version}"
         username="${svnuser}" />
 </target>
 <target name="tag-version-no-file">
     <exec executable="git" outputProperty="latest">
      <arg line="tag |sort -t. -k 1,1n -k 2,2n -k 3,3n |tail -1"/>
     </exec>
     <echo file="v.txt">${latest}</echo>
     <version releasetype="${release}" file="v.txt"
         property="version" />
     <delete file="v.txt" />
     <gittag annotate="true" name="${version}"
         repository="."
         message="Tagged version ${version}" />
 </target>
 <property name="build-url"
        value="https://jenkins/job/phing/lastBuild/api/json" />
 <target name="require-green-build-check">
     <exec executable="curl" outputProperty="status">
         <arg line='--silent ${build-url} |grep result |cut -d" -f4'/>
     </exec>
     <if>
         <not><equals arg1="${status}" arg2="SUCCESS" /></not>
         <then><fail message="Jenkins build is broken" /></then>
     </if>
 </target>
 <target name="deploy">
     <phingcall target="require-release" />
     <phingcall target="require-green-build-check"/>
     <phingcall target="tag-version-no-file" />
 </target>
Prepare yourself - Deployment is coming
 <target name="prepare">
     <gitclone repository="git://server/phing-things.git"
         targetPath="build" />
     <gitcheckout repository="build"
         branchname="${version}" quiet="true" />
     <delete dir="build/tests" />
     <delete file="build/build.xml" />
     <tar destfile="build-${version}.tar.bz2" basedir="build"
         includeemptydir="true" compression="bzip2" />
     <delete dir="build" />
 </target>
 <target name="deploy">
     <phingcall target="require-release" />
     <phingcall target="require-green-build-check"/>
     <phingcall target="tag-version-no-file" />
     <phingcall target="prepare" />
 </target>
 <target name="upload">
     <exec executable="scp" checkreturn="true">
       <arg value="build-${version}.tar.bz2" />
       <arg value="${server}:/var/www/" />
     </exec>
     <exec executable="ssh" checkreturn="true" passthru="true">
       <arg value="${server}" />
       <arg value="cd /var/www;tar -xjf build-${version}.tar.bz2"/>
     </exec>
 </target>
 <target name="deploy">
     <phingcall target="require-release" />
     <phingcall target="require-green-build-check"/>
     <phingcall target="tag-version-no-file" />
     <phingcall target="prepare" />
     <phingcall target="upload" />
 </target>
 <target name="go-live" depends="require-version">
     <exec executable="ssh" checkreturn="true" passthru="true">
         <arg value="${server}" />
       <arg value="cd /var/www; ln -sf build-${version} app"/>
     </exec>
 </target>
 <target name="deploy">
     <phingcall target="require-release" />
     <phingcall target="require-green-build-check"/>
     <phingcall target="tag-version-no-file" />
     <phingcall target="prepare" />
     <phingcall target="upload" />
     <phingcall target="go-live" />
 </target>
sanity
check
Computer says no
phing-the-things$ phing go-live -Dversion=1.2.3
phing-the-things$ phing go-live -Dversion=1.2.3
Cat backpedalling
!$monitored == !$exist
Worked in dev...
 <?php
 require_once 'phing/Task.php';
 class UpdateNewRelicTask extends Task {
     public function init() {
         // Runs when task is imported
     }
     public function main() {
         // Runs when task is executed
     }
 }
 <taskdef name="newrelic"
         classname="UpdateNewRelicTask" />
 <target name="update-new-relic">
     <newrelic />
 </target>
 <taskdef name="newrelic"
         classname="UpdateNewRelicTask" />
 <target name="update-new-relic">
     <newrelic />
 </target>
 class UpdateNewRelicTask extends Task {
     protected $version;

     public function setVersion($version) {
         $this->version = $version;
     }
 }
 <target name="update-new-relic">
     <newrelic version="${version}" />
 </target>
    
public function main() {
    $options = array(
        CURLOPT_POSTFIELDS => array(
            'deployment[application_id]' => $this->appId,
            'deployment[description]' => $this->version ),
        CURLOPT_HTTPHEADER => array(
            'x-api-key: ' . $this->apiKey ),
        CURLOPT_URL => $this->url,
    );
    ...
}
public function main() {
    ...
    $ch = curl_init();
    curl_setopt_array($ch, $options);
    curl_exec($ch);
    curl_close($ch);
}
New Relic example
Omni Adams Mashery

/