ファイル変更を監視して、コマンドを実行してくれる最近のフロントエンドビルドツール。Gruntとgulpが有名どころっぽいんですが、PHPの開発にも併用して使うと楽しいです。
やりたいこととしては、以下の工程を自動化したいわけです。ローカル環境でもっと高頻度にCIを回したいという感じ。
- ブラウザとエディタとターミナルを準備。
- ブラウザには http://localhost:9000/ などでカバレッジレポートを表示。
- ターミナルでは常時PHPUnitの結果が表示される
- エディタはもちろんソースコードとユニットテストコードを書く(何を使ってもよい)
- ソースコード・テストコードをエディタで書いて、保存する
- ファイル変更を検知して、自動でphpunitコマンドを実行
- PHPUnitのカバレッジレポート(HTML版)をlivereloadし、テストの足りなさそうなところを通知
昔はエディタを選んだり、環境を選んだりして結構苦労して実現していたらしいですが、今はツールをインストールしてちょちょっと設定するだけです。いい時代になったもんだ。
以下、PHPUnitやapigenなどの設定ファイルは省略しているので、こちらも見てください。
https://github.com/spindle/spindle-lib-template
Grunt
まずはGruntで実現したい場合。Gruntはこの手のツールのパイオニア的存在らしいですが、設定ファイルが煩雑になりがちで、後発のgulpの人気に押され始めているとか。
上記を実現する程度であれば、Gruntでもgulpでもさして手間は変わりません。
PHP 開発でも Grunt を使う - ngの日記
こちらをだいたいパクりました。
Gruntのインストール
他にも解説している記事が一杯あるので、適当なところで。node.jsとnpmはインストール済みであるとします。
$ npm install -g grunt-cli
$ cd path/to/php-lib-repository
$ echo '{}' > package.json
$ npm install --save-dev grunt
$ npm install --save-dev grunt-shell
$ npm install --save-dev load-grunt-tasks
$ npm install --save-dev grunt-contrib-watch
$ npm install --save-dev grunt-contrib-connect
これでpath/to/php-lib-repositoryの中ではgruntコマンドが使えるようになります。 gruntの設定ファイルを書きます。
Gruntfile.coffee
#
# Gruntfile.coffee for php-library development
#
# 1. install node.js & npm
# 2. $ npm install -g grunt-cli
# 2. $ npm install
# 3. $ grunt
# 4. open http://localhost:9000/ (livereload enabled)
# 5. coding on src/* and tests/*
#
# enjoy!
# @license https://creativecommons.org/publicdomain/zero/1.0/ CC0-1.0 (No Rights Reserved.)
module.exports = (grunt) ->
grunt.initConfig
shell:
phpunit:
command: 'vendor/bin/phpunit'
options: {stdout: true, stderr: true}
apigen:
command: 'vendor/bin/apigen.php'
options: {stdout: true, stderr: true}
pdepend:
command: [
'vendor/bin/pdepend'
'--jdepend-chart=builds/pdepend.svg'
'--overview-pyramid=builds/pyramid.svg'
'--summary-xml=builds/summary.xml'
'src/'
].join ' '
options: {stdout: true, stderr: true}
connect:
server:
options:
port: 9000
base: 'builds'
livereload: true
watch:
php:
tasks: 'shell:phpunit'
files: [
'src/**/*.php'
'tests/**/*.php'
]
options:
livereload: true
require('load-grunt-tasks')(grunt)
grunt.registerTask 'default', ['connect', 'watch']
grunt.registerTask 'test', ['shell:phpunit']
grunt.registerTask 'all', ['shell']
あとはgrunt
と打ち込むと、ファイルの監視とlivereloadが有効になったWebサーバーが立ち上がります。
http://localhost:9000/ をブラウザで開いておき、ソースを書いていきます。PHPUnitの最近のカバレッジレポートはかなり綺麗なので、テンション上げながら作業ができます。
gulp
ぶっちゃけPHP関連のコマンドを実行する程度であれば、Gruntからgulpに乗り換えるメリットはあまりないかもしれません。設定ファイルの行数もあまり変わりませんし。
gulpのインストール
こちらもnode.jsとnpmはインストール済みであるとします。
$ npm install -g gulp
$ cd path/to/php-lib-repository
$ echo '{}' > package.json
$ npm install --save-dev gulp
$ npm install --save-dev gulp-connect
gulpfile.js
gulp test
でPHPUnit実行、gulp inspect
でapigenとPHP_Depend実行、gulp server
でファイル監視とサーバー立ち上げを開始です。
/**
* gulpfile.js for php-library developement
*
* 1. install node.js & npm
* 2. $ npm install
* 3. $ gulp server
* 4. open http://localhost:9000/ (livereload enabled)
* 5. coding on src/*.php and tests/*.php
*
* enjoy!
*
* @license https://creativecommons.org/publicdomain/zero/1.0/ CC0-1.0 (No Rights Reserved.)
*/
var gulp = require('gulp');
var exec = require('child_process').exec;
var connect = require('gulp-connect');
gulp.task('default', ['test', 'inspect']);
gulp.task('help', function(){
console.log('gulp test\t... kick vendor/bin/phpunit command');
console.log('gulp inspect\t... kick vendor/bin/apigen and vendor/bin/pdepend');
console.log('gulp server\t... start static web server on http://localhost:9000/');
console.log('\tcoverage report... http://localhost:9000/coverage/');
console.log('\tApiGen document... http://localhost:9000/api/');
});
gulp.task('test', function(done){
exec('vendor/bin/phpunit', function(err, stdout, stderr){
console.log(stdout);
console.error(stderr);
done();
});
});
gulp.task('inspect', function(done){
var i = 0, count = function(){ if (++i > 1) done() };
exec([
'vendor/bin/pdepend',
'--jdepend-chart=builds/pdepend.svg',
'--overview-pyramid=builds/pyramid.svg',
'--summary-xml=builds/summary.xml',
'src/'].join(' '), count);
exec('vendor/bin/apigen.php', count);
});
gulp.task('connect', ['default'], function(){
connect.server({
root: [__dirname + '/builds/'],
port: 9000,
livereload: true
});
});
gulp.task('reload', ['test'], function(){
return gulp.src('builds/coverage/**')
.pipe(connect.reload());
});
gulp.task('server', ['connect'], function(){
gulp.watch(['src/**', 'tests/**'], ['reload']);
});
カバレッジレポートの出力先であったり、watch対象のディレクトリは適宜実情に合わせて調整してください。