Creating the required build files

A part of the configuration of the build will be stored in Jenkins, but it's mostly for publishing the reports and the documentation (if you need it). We saw the actual configuration on how to run the various scripts in Chapter 8, Analyzing Testing Information. This is in the build.xml file. This default name can be picked up by Jenkins automatically. This can be configured, but it's pointless to do so unless you already have a file with that name.

The build file should sit at the root of the project repository, and it should have a valid XML.

The language we are going to use to write the build file is Apache Ant. There are either more complex solutions, such as Maven, or more ad-hoc solutions such as Phing for this, but I still prefer Ant. This is because it's simple and flexible (it's verbose, but once you've written it, there isn't much to be said). It also allows you to run anything that is not specific for a particular language.

We're going to create the build file by copying the basic structure from the jenkins-php project (available at http://jenkins-php.org/automation.html), and then by amending it with the corrections that I'll explain in the next few paragraphs. I'll be splitting the functionality of Composer, Yii, and Codeception in separate files, while the main functionality (from jenkins-php) will remain as it is.

Understanding the basic Ant structure

Ant is quite simple because it's a collection of directives. The root of the XML is a <project> tag, which contains a series of <target> tags that can be called from the Jenkins job, and you can choose the <property> option for defining the properties, and then choose the <include> statements for including separate files.

There is no default name for the targets, but the main target is usually called build. It comes with a series of dependencies, which trigger the other targets sequentially.

Each directive has a series of additional attributes and tags, and these can be nested in them. The user contributed directives can also be downloaded separately for these (and most of the Linux distributions provide the common ones in a separate package). This can help you in avoiding the effort that is put in when you have to create these by hand. For instance, you can use this for archiving and packaging a collection of files, which are normally wrappers for the actual command-line tools.

Note

Remember that Ant is not an imperative programming language, so check its documentation if you want to extend and modify the language.

The documentation for the core Ant directives is available online at http://ant.apache.org/manual/, and it's probably a good starting point for understanding it.

Adjusting the build.xml file

Compared to the file you have copied from jenkins-php, we are going to keep most of the targets, albeit the phpunit target, which can be safely deleted. This is because we're going to switch to a custom target specifically for Codeception. The rest of the changes will be made in separate files, and they will be discussed after this.

The most important changes that need to be made are relative to the folders you want these programs to work on. Every single command accepts different arguments, so include all the directories you want. Let's start amending the first target, which will do a syntax check of all the files that we specify:

<target name="lint" description="Perform syntax check of sourcecode files">
    <apply executable="php" failonerror="true">
        <arg value="-l" />

        <fileset dir="${basedir}/models">
            <include name="**/*.php" />
            <modified />
        </fileset>
        <fileset dir="${basedir}/modules">
            <include name="**/*.php" />
            <modified />
        </fileset>
        <fileset dir="${basedir}/controllers">
            <include name="**/*.php" />
            <modified />
        </fileset>
        <fileset dir="${basedir}/tests">
            <include name="**/*.php" />
            <modified />
        </fileset>
    </apply>
</target>

Next, we can add our code directories to be picked up by phploc, which will give us an idea of the complexity of our project:

<target name="phploc-ci"
        depends="prepare"
        description="Measure project size using PHPLOC and log result in CSV and XML format. Intended for usage within a continuous integration environment.">
    <exec executable="${toolsdir}phploc">
        <arg value="--count-tests" />
        <arg value="--log-csv" />
        <arg path="${basedir}/build/logs/phploc.csv" />
        <arg value="--log-xml" />
        <arg path="${basedir}/build/logs/phploc.xml" />
        <arg path="${basedir}/models" />
        <arg path="${basedir}/controllers" />
        <arg path="${basedir}/modules" />
        <arg path="${basedir}/tests" />
    </exec>
</target>

pdepend uses a different syntax in defining new directories; as you can see, if you need to make changes, you will need to invoke the commands' help manually:

<target name="pdepend"
        depends="prepare"
        description="Calculate software metrics using PHP_Depend and log result in XML format. Intended for usage within a continuous integration environment.">
    <exec executable="${toolsdir}pdepend">
        <arg value="--jdepend-xml=${basedir}/build/logs/jdepend.xml" />
        <arg value="--jdepend-chart=${basedir}/build/pdepend/dependencies.svg" />
        <arg value="--overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg" />
        <arg path="${basedir}/models,${basedir}/controllers,${basedir}/modules,${basedir}/tests" />
    </exec>
</target>

Next in line is PHP Mess Detection (PHPMD), which will help us keep the code clean and tidy. Once again, the syntax is slightly different than the previous ones:

<target name="phpmd-ci"
        depends="prepare"
        description="Perform project mess detection using PHPMD and log result in XML format. Intended for usage within a continuous integration environment.">
    <exec executable="${toolsdir}phpmd">
        <arg path="${basedir}/models,${basedir}/controllers,${basedir}/modules" />
        <arg value="xml" />
        <arg path="${basedir}/build/phpmd.xml" />
        <arg value="--reportfile" />
        <arg path="${basedir}/build/logs/pmd.xml" />
    </exec>
</target>

PHP Code Sniffer (PHPCS) can be also taken as an additional and more important step for linting your code. As explained, we also need to specify the specific Yii coding standard:

<target name="phpcs-ci"
        depends="prepare"
        description="Find coding standard violations using PHP_CodeSniffer and log result in XML format. Intended for usage within a continuous integration environment.">
    <exec executable="${toolsdir}phpcs" output="/dev/null">
        <arg value="--report=checkstyle" />
        <arg value="--report-file=${basedir}/build/logs/checkstyle.xml" />
        <arg value="--standard=${basedir}/vendor/yiisoft/yii2-coding-standards/Yii2/ruleset.xml" />
        <arg value="--extensions=php" />
        <arg value="--ignore=autoload.php" />
        <arg path="${basedir}/models" />
        <arg path="${basedir}/controllers" />
        <arg path="${basedir}/modules" />
        <arg path="${basedir}/tests" />
    </exec>
</target>

The last one is PHP Copy-Paste Detector (PHPCPD), which does exactly what it says on the label:

<target name="phpcpd-ci"
        depends="prepare"
        description="Find duplicate code using PHPCPD and log result in XML format. Intended for usage within a continuous integration environment.">
    <exec executable="${toolsdir}phpcpd">
        <arg value="--log-pmd" />
        <arg path="${basedir}/build/logs/pmd-cpd.xml" />
        <arg path="${basedir}/models" />
        <arg path="${basedir}/controllers" />
        <arg path="${basedir}/modules" />
    </exec>
</target>

As you have probably noticed, some of the targets that I've pasted here are the -ci targets. These targets are required by Jenkins in order to generate all the necessary reports. We will pick these up and publish them in our build later. Remember to mirror the changes on the other targets as well; I have excluded them here to avoid redundancy.

In addition to these changes, it's worth noticing that I've selected the Yii 2 CheckStyle rule set for validating the syntax. This step is quite useful for maintaining the overall code style and for keeping it in sync with the one used by the developers of the framework, and cross-team.

Now that we've made the basic changes, let's go to the Composer, Yii, and the Codeception files.

Preparing the environment for the build

The build command, which is the default invoked target, has a chain of dependencies that will sequentially trigger the prepare target, run some other targets for the build, run the tests, and then generate the required documentation with phpDox.

The prepare target depends on the clean target. These two steps will clean up the environment, generate the required folder structure to accommodate the results that will be produced by the following steps, and set some properties to avoid invoking the target twice.

For instance, the prepare target has the following property set at the end:

<property name="prepare.done" value="true"/>

While the target definition is:

<target name="prepare"
        unless="prepare.done"
        depends="clean, composer.composer, yii.migrate-all"
        description="Prepare for build">

It has now become clear that unless the property is set, we can execute the content of the target. The same thing happens with the clean target.

In these two targets, we need to update the list of directories that are cleaned and recreated every time the job is run. You should, at least, have the following directories, and you can also include any other directories that are relevant to your project for clean.

<target name="clean"
        unless="clean.done"
        description="Cleanup build artifacts">
    <delete dir="${basedir}/runtime/*"/>
    <delete dir="${basedir}/web/assets/*"/>
    <delete dir="${basedir}/vendor"/>
    <delete dir="${basedir}/build/api"/>
    <delete dir="${basedir}/build/logs"/>
    <delete dir="${basedir}/build/pdepend"/>
    <delete dir="${basedir}/build/phpdox"/>
    <delete dir="${basedir}/tests/codeception/_output"/>
    <property name="clean.done" value="true"/>
</target>

And for prepare, the following directories will be recreated:

<target name="prepare"
        unless="prepare.done"
        depends="clean, composer.composer, yii.migrate-all"
        description="Prepare for build">
    <mkdir dir="${basedir}/build/api"/>
    <mkdir dir="${basedir}/build/logs"/>
    <mkdir dir="${basedir}/build/pdepend"/>
    <mkdir dir="${basedir}/build/phpdox"/>
    <mkdir dir="${basedir}/tests/codeception/_output"/>
    <property name="prepare.done" value="true"/>
</target>

Adding the required configuration settings

Before we start adding our custom files, we need to add some of the configuration files, which some of the executables, namely phpmd and PHPDox, will expect to be in the /build directory.

The jenkins-php project will provide most of these configuration files, and these can be copied from http://jenkins-php.org/configuration.html.

In case of phpmd, you can adjust the level of the cyclomatic complexity threshold.

    <!-- build/phpmd.xml -->
    <rule ref="rulesets/codesize.xml/CyclomaticComplexity">
        <priority>1</priority>
        <properties>
            <property name="reportLevel" value="7" />
        </properties>
    </rule>

The default value is normally 10, but the suggested value is 5.

For PHPDox, the story is a little complex. The current configuration is not particularly flexible, so I've decided to go through the longest possible route, which is, generating the skeleton file with the help of the following command:

$ vendor/bin/phpdox --skel > build/phpdox.xml

This created a file that has all the documented options, and from there, I created my own configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<!-- build/phpdox.xml -->
<phpdox xmlns="http://xml.phpdox.net/config" silent="false">
    <project name="Yii2" source="${basedir}/.." workdir="${basedir}/phpdox">

        <collector publiconly="false">
            <include mask="${phpDox.project.source}/models/*.php" />
            <include mask="${phpDox.project.source}/modules/*.php" />
            <include mask="${phpDox.project.source}/controllers/*.php" />
            <include mask="${phpDox.project.source}/vendor/yiisoft/yii2/*.php" />
        </collector>

        <generator output="${basedir}/api">
            <build engine="html" enabled="true">
                <file extension="html" />
            </build>
        </generator>

    </project>
</phpdox>

Regardless of my efforts, the current version that I'm using (0.7) had a bug that caused it to crash when run from Jenkins. This has been fixed in the current dev-master version, but this has caused other problems for me. I'm pretty sure that you should be fine when the next version will be released. In our case, the documentation is less critical from the perspective of the non-working tests.

Adding Composer, Yii, and Codeception support in Ant

Now we need to integrate the changes that are needed to prepare our application for testing. We will be using Composer to install the required dependencies and Yii to run the needed migrations. After this we will need support for Codeception, as it's the main tool for running the tests.

As we've seen in the definition of prepare, the target is dependent on clean, composer.composer and yii.migrate-all.

The first target is taken from https://github.com/shrikeh/ant-phptools, which provides a wrapper for Composer. It's not the best, but it was the only one that showed up on a quick search. The package does what it does quite well, and it's dependent on a properties file called composer.properties, and an example of it is provided by the project author.

Tip

There are some built-in properties that are accessible in an Ant script, which can be useful for understanding, for instance, the current directory and building up the appropriate paths in a more distributable fashion. This is available at http://ant.apache.org/manual/properties.html.

Calling the composer.composer target will install Composer, if not found in the specified directory, and use it to update all the dependencies. I would prefer if it wiped the installation directory of the dependencies and then ran composer install. Unfortunately, that's the only way to install the dependencies defined in the composer.lock, instead of updating them.

Tip

If you have any doubts about the differences between composer.lock and composer.json, feel free to step back for a second, and skim through Chapter 2, Tooling up for Testing.

I've put the composer.xml and the composer.properties file in the /build directory, and I've added the following at the beginning of the project defined in build.xml.

<include file="${basedir}/build/composer.xml" as="composer"/>

Now, we can add the dependency of composer.composer to the list of the targets defined in the prepare target without any problems.

The second step is resetting the database to a state that we can use, and we will do it by re-running all of the migrations and applying all of the missing ones.

For this, I've created a simple Ant project. You can place it in your /build directory, which you can download from https://github.com/ThePeach/Yii2-Ant. The project provides a wrapper for the Yii CLI interface for running the migrations.

I won't go into the details of this project, as it's simple and it can be understood quite easily.

We can include it like we did in the Composer project earlier, as follows:

<!-- build.xml -->
<include file="${basedir}/build/yii.xml" as="yii"/>

You can invoke it either by calling the ready-made target migrate-all, as we did for the dependencies of prepare in our build.xml, or by calling the migrate MacroDef the way you want:

<migrate exec="${yii.script}" action="down"/>
<migrate exec="${yii.script}" action="up"/>
<migrate exec="${yii.tests.script}" action="down"/>
<migrate exec="${yii.tests.script}" action="up"/>

Note

Ant has to extend its basic syntax, which defines new tasks like MacroDef. You can read more about this in the official Apache Ant documentation, which can be found at https://ant.apache.org/manual/Tasks/macrodef.html.

The migrate action will always pass all as an argument to the yii script, and this is enough for what we need to achieve, but this could be improved.

Codeception is added in a similar way. You can grab a copy from the repository I've created at https://github.com/ThePeach/CodeCeption-Ant.

This Ant project provides a main target called run-tests, which you can execute without worrying too much about the parameters and such. You can also dynamically pass some parameters at run time to fine-tune the invocation of Codeception, such as codeception.suites and codeception.options.

$ ant -Dcodeception.suites=unit -Dcodeception.options=--coverage-html build

If not set, these will be assigned an empty value and --xml --coverage-xml --coverage-html respectively.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset