I maintain about a dozen plugins in the Moodle plugins repository. I use Moodlerooms’ moodle-plugin-ci project to test all of them on Travis CI. It’s a fantastic tool and rely heavily on it.

This fall I’ve been working on a plugin which, because of various hooks into Lafayette’s internal infrastructure, I’m not releasing publicly. I’d still like to test it in the usual way, so I decided to run the tests on our internal GitLab infrastructure.

Building a container

Dagefoerde pitched a usable .gitlab-ci.yml some time ago. This could be run on our existing docker-based CI infrastructure with basically no tweaks. Adding those packages on each run took several minutes, so I crafted a custom container (based on PHP 5.6, which is what we’re running) to eliminate the overhead. The package part is pretty simple:

RUN apt-get clean
RUN apt-get update
RUN apt-get install -y \
        git \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libmcrypt-dev \
        libpng12-dev \
        libicu-dev \
        g++ \
        mysql-client \
        php5-mysql \
        npm
RUN ln -s "$(which nodejs)" /usr/bin/node
RUN docker-php-ext-install -j$(nproc) iconv mcrypt intl zip mysqli
RUN docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/
RUN docker-php-ext-install -j$(nproc) gd

A few lines add the PHPUnit and Composer support:

ADD https://phar.phpunit.de/phpunit.phar /usr/local/bin/phpunit
RUN chmod +x /usr/local/bin/phpunit

RUN curl -sS https://getcomposer.org/installer | php
RUN mv composer.phar /usr/local/bin/composer
RUN chmod +x /usr/local/bin/composer

Confident, I deployed this container instead of the stock php:7.0 and it promptly died:

  [Symfony\Component\Process\Exception\ProcessFailedException]                
  The command "phpenv config-add /builds/ci/res/template/moodle.ini" failed.  
  Exit Code: 127(Command not found)                                           
  Working directory: /builds                                                  
  Output:                                                                     
  ================                                                            
  Error Output:                                                               
  ================                                                            
  sh: 1: phpenv: not found     

Huh?

phpenv

Getting this working was tricky. There are several different phpenv projects floating around. Travis CI uses CHH/phpenv. The installation notes are a bit sparse, and didn’t spell out that you needed to install php-build as well to use the phpenv config-add and phpenv config-rm commands. I adapted most of this block from jolicode/phpenv, with some tweaks to reflect that I was running everything under root:

RUN git clone https://github.com/CHH/phpenv.git /tmp/phpenv && \
        /tmp/phpenv/bin/phpenv-install.sh && \
        /bin/bash -c "echo 'eval \"\$(phpenv init -)\"' >> /etc/profile.d/phpenv.sh" && \
        echo 'eval "$(phpenv init -)"' >> /root/.bashrc
ENV PATH /root/.phpenv/bin:$PATH
RUN git clone https://github.com/CHH/php-build /root/.phpenv/plugins/php-build && \
        cp /tmp/phpenv/extensions/rbenv-config-* /root/.phpenv/plugins/php-build/bin/
RUN mkdir -p /root/.phpenv/versions/system/etc/conf.d

Directory collisions

Our internal Moodle projects in GitLab are organized into a “Moodle” group. When GitLab clones a project during a CI run it puts it into the /builds/moodle/<project name> directory. This causes a problem, because by default moodle-plugin-ci will try cloning core Moodle into /builds/moodle. The directory isn’t empty in our case, so this clone fails.

The first way I solved this was by proposing a feature request to moodle-plugin-ci: allow a customized installation path for Moodle. A second way, I realized later, was to create such a directory myself in the .gitlab-ci.yml file, and then create the ci project and core installation one level deep. The build path for the project ($CI_PROJECT_DIR) is absolute anyway. It looks a little clunkier than the default, but it works:

– mkdir moodle-ci
– cd moodle-ci
– composer create-project -n –no-dev moodlerooms/moodle-plugin-ci ci ^1
– export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"
– chmod u+x /builds/moodle-ci/ci/bin/moodle-plugin-ci
– chmod u+x /builds/moodle-ci/ci/bin/*

In this revised setup, builds looks like this:

builds/
	moodle-ci/
		ci/
		moodle/
	your-moodle-plugin/

Multiple versions

GitLab doesn’t have the same concept of the Travis build matrix, but you can approximate it using a job template:

.job_template: &job_definition
script:
– moodle-plugin-ci phplint
– moodle-plugin-ci phpcpd
– moodle-plugin-ci phpmd
– moodle-plugin-ci codechecker
– moodle-plugin-ci csslint
– moodle-plugin-ci shifter
– moodle-plugin-ci jshint
– moodle-plugin-ci validate
– moodle-plugin-ci phpunit
– moodle-plugin-ci behat

job1:
<<: *job_definition
image: lafayette/php56-moodle:latest
variables:
MOODLE_BRANCH: "MOODLE_33_STABLE"

job2:
<<: *job_definition
image: lafayette/php70-moodle:latest
variables:
MOODLE_BRANCH: "MOODLE_33_STABLE"

This works well enough for my purposes. For an internal project, I’m only interested in testing my current environment, and the next likely environment. I don’t need to test postgresql, or myriad Moodle versions that we don’t run.

Featured image by Slambo at en.wikipedia (Transferred from en.wikipedia.) [CC BY-SA 2.0], via Wikimedia Commons