I find it easiest to consider the stack in three layers:
-
Host Environment or System Platform: Loosely, this is the collection of MySQL, Apache, PHP, NodeJS, and so on. These system-services and language-runtimes are provided in many distribution channels (e.g. Debian, Ubuntu, CentOS, RHEL, nix, MAMP, XAMPP, Bitnami, Docker, etc).
-
Buildkit or Toolchain: Loosely, this is the collection of
composer
,drush
,cv
,wp-cli
,bower
,civibuild
,phpunit
, and so on. These are mostly CLI tools written in PHP, NodeJS, or bash. They are usually not provided by an OS distributor (or, if they are, it can be hard to get the right versions), and they don't represent standalone network services. -
Build or Site: Loosely, this is the collection of
civicrm-core.git
along with a CMS (Drupal, WordPress, etc) and related modules/extensions/integrations. It is a web-app. When setting up a site with Civi (et al), this is the main artifact. (For example,dmaster
is the typical name for a build with Drupal 7 and themaster
version of Civi.)
Now-a-days, many teams in our industry are focused on a single design for their deployments; they will standardize the stack and define a single artifact or project which encompasses all these layers (e.g. one Dockerfile
or one docker-compose.yml
). However, Civi can be deployed in a range of environments. This has always been part of its appeal: that you can install it on top of an existing webserver running Drupal/Joomla/WordPress/etc. Each of those existing webservers has its own host-environment. Moreover, each developer who works with one of those existing webservers is likely to have a laptop with its own host-environment. As an ecosystem, we don't have the same degree of standardization that you'd find on a typical team.
The three tier analogy is not perfect, but it should help you get started by illustrating the design/scope of civicrm-buildkit.git
: you can start with just about any host-environment (Debian, MAMP, et al), setup buildkit, and then produce a
representative range of example sites (plain D7; D7+Civi master; D7+Civi 5.13; plain WP; WP+Civi master; etc).
The official CI servers include a few host environments based on bknix, e.g.
- bknix-min: This has the minimum versions of MySQL/PHP/NodeJS/etc supported by Civi.
- bknix-max: This has the maxiumum versions of MySQL/PHP/NodeJS/etc supported by Civi.
- bknix-dfl: This has middle-of-the-road versions of MySQL/PHP/NodeJS/etc.
Additionally, we have a copy of buildkit for each host-environment.
Let's do an example: we'll use the minimum host-environment to create a test site (Drupal 7 with Civi 5.13) and run all the test suites.
Connect to a test server. Login as Jenkins.
$ ssh [email protected]
myuser@test-gsoc19:~$ sudo -iu jenkins bash
jenkins@test-gsoc19:~$
At this point, the command line does not have access to PHP, MySQL, etc.
jenkins@test-gsoc19:~$ php --version
bash: php: command not found
jenkins@test-gsoc19:~$ node --version
bash: node: command not found
jenkins@test-gsoc19:~$ mysql --version
bash: mysql: command not found
We need to specify that we want to work with bknix-min:
jenkins@test-gsoc19$ eval $( use-bknix min )
[bknix-min:~]
Now, we have access all the minimum versions. Observe that the host-environment lives at
/nix/var/nix/profiles/bknix-min
.
[bknix-min:~] which php
/nix/var/nix/profiles/bknix-min/bin/php
[bknix-min:~] php --version
PHP 5.6.38 (cli) (built: Sep 11 2018 23:19:50)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
with Xdebug v2.3.1, Copyright (c) 2002-2015, by Derick Rethans
[bknix-min:~] which node
/nix/var/nix/profiles/bknix-min/bin/node
[bknix-min:~] node --version
v8.11.3
[bknix-min:~] which mysql
/nix/var/nix/profiles/bknix-min/bin/mysql
[bknix-min:~] mysql --version
mysql Ver 14.14 Distrib 5.5.58, for Linux (x86_64) using readline 5.1
Additionally, this server also has buildkit. Observe that this lives in /home/jenkins/bknix-min/civicrm-buildkit
:
[bknix-min:~] which cv
/home/jenkins/bknix-min/civicrm-buildkit/bin/cv
[bknix-min:~] cv --version
cv version v0.2.15
[bknix-min:~] which drush
/home/jenkins/bknix-min/civicrm-buildkit/bin/drush
[bknix-min:~] drush --version
Drush Version : 8.1.18
Create a site with Drupal 7 and CiviCRM 5.13. We'll use civibuild to setup the site:
[bknix-min:~] civibuild create mytest --type drupal-clean --civi-ver 5.13
[[Download mytest (type 'drupal-clean' in '/home/jenkins/bknix-min/build/mytest')]]
[[Update caches]]
...(skip a lot of text)...
[[Save CMS DB (mytestcms_umnfa) to file (/home/jenkins/bknix-min/civicrm-buildkit/app/snapshot/mytest/cms.sql.gz)]]
[[Save Civi DB (mytestcivi_ukibu) to file (/home/jenkins/bknix-min/civicrm-buildkit/app/snapshot/mytest/civi.sql.gz)]]
[[Setup MySQL for Test]]
[[Restore "/home/jenkins/bknix-min/build/mytest" DB (test) from file (/home/jenkins/bknix-min/civicrm-buildkit/app/snapshot/mytest/civi.sql.gz)]]
[[Show site summary (mytest/default)]]
- CMS_ROOT: /home/jenkins/bknix-min/build/mytest
- CMS_URL: http://mytest.35.246.100.181.nip.io:8002
- CMS_DB_DSN: mysql://mytestcms_umnfa:[email protected]:3308/mytestcms_umnfa?new_link=true
- CIVI_DB_DSN: mysql://mytestcivi_ukibu:[email protected]:3308/mytestcivi_ukibu?new_link=true
- TEST_DB_DSN: mysql://mytesttest_304ck:[email protected]:3308/mytesttest_304ck?new_link=true
- ADMIN_USER: admin
- ADMIN_PASS: wfJLUdcwvEIi
- DEMO_USER: demo
- DEMO_PASS: demo
Now, run the test suites. As a developer, it's usually better to call a specific tool (like phpunit5
); but for CI purposes,
we often use the wrapper script civi-test-run, as in:
[bknix-min:~] civi-test-run -b mytest -j /tmp/mytest-results all
The results will be recorded in JUnit XML format under /tmp/mytest-results.
https://test.civicrm.org/ is the Jenkins master. Most of the important/relevant test jobs are based on some
combination of civibuild
and civi-test-run
. For example:
CiviCRM-Core-PR
: Usescivibuild
to create a site with a proposed patch/PR, and then it callscivi-test-run
.CiviCRM-Core-Matrix
: Usescivibuild
to create a matrix of test sites (with different versions of Civi and different host-environments), and it callscivi-test-run
for each.
These jobs should be fairly thin. For example, consider this snapshot of the CiviCRM-Core-PR job:
- It doesn't call
composer
orcv
ordrush
orwget
-- it callscivibuild
. - It doesn't call
phpcs
orjshint
-- it callscivilint
- It doesn't call
phpunit5
orkarma
-- it callscivi-test-run
.
This is no accident; it's an adaptation. Jenkins is a brilliant task-runner, but the stock Jenkinx 1.x experience
encourages you to write jobs in a way which is difficult to test/reproduce/modify (i.e. all the configuration is done
by clicking around the web UI). This makes it harder to copy/share/test revisions. Instead, we move most of the
important logic+policy out Jenkins and into civicrm-buildkit.git
. This way, one can clone the repo and patch/test
the build scripts locally.
- https://docs.civicrm.org/dev/en/latest/tools/buildkit/ - Discusses how to install buildkit with some common host-environments. (Personally, I tend to use https://github.com/totten/bknix.)
- https://docs.civicrm.org/dev/en/latest/tools/civibuild/ - These docs mention (among other things) the options for tweaking each build, the options for applying PRs+patches, and ways to set policies that apply to all builds.