弊社は前からJenkinsを使っています。Jenkinsでもよいですが、ちょっとJava様系なのでメモリがかなり食っていますね。今回せっかくGitLabを入れたので、GitLab-CIをセットで入れたいと思っています。
基本的には本家サイトのインストールガイドに従ってやれば問題ないかと思います。弊社環境に合わせて、またちょっと工夫を書きたいと思います。
本家サイトのインストールガイド:
https://github.com/gitlabhq/gitlab-ci/blob/master/doc/install/installation.md
まず、GitLabとGitLab-CIは連携しているので、ファイル書き込みパーミッションとかうるさいのでGitLab-CIのユーザーもGitLabのインストールユーザーと同じくします。つまり、GitLab-CIもgitユーザーでインストールしていきます。
すると、config系のファイルを変更しないといけません。
例えば、
git@www1167uf:~/gitlab-ci/config$ diff unicorn.rb unicorn.rb.example 24c24 < working_directory "/home/git/gitlab-ci" # available in 0.94.0+ --- > working_directory "/home/gitlab_ci/gitlab-ci" # available in 0.94.0+ 28,29c28,29 < listen "/home/git/gitlab-ci/tmp/sockets/gitlab-ci.socket", :backlog => 64 < listen "127.0.0.1:8082", :tcp_nopush => true --- > listen "/home/gitlab_ci/gitlab-ci/tmp/sockets/gitlab-ci.socket", :backlog => 64 > listen "127.0.0.1:8080", :tcp_nopush => true 35c35 < pid "/home/git/gitlab-ci/tmp/pids/unicorn.pid" --- > pid "/home/gitlab_ci/gitlab-ci/tmp/pids/unicorn.pid" 40,41c40,41 < stderr_path "/home/git/gitlab-ci/log/unicorn.stderr.log" < stdout_path "/home/git/gitlab-ci/log/unicorn.stdout.log" --- > stderr_path "/home/gitlab_ci/gitlab-ci/log/unicorn.stderr.log" > stdout_path "/home/gitlab_ci/gitlab-ci/log/unicorn.stdout.log"
そんなにインストールが簡単かと思ったら、早速GitLab-CIを起動します。しかし、ここで問題があります。GitLabとGitLab-CIは同じgitユーザーで起動されているため、現起動スクリプトは競合しました。その結果、どれかのサービスを再起動すると別のサービスのSidekiqデーモンが落ちてしまいます。これを解消するためには、起動スクリプトを変更します。これはGitLab側とGitLab-CI側は同じことをやります。
script/background_jobsファイルを編集します。
git@www1167uf:~/gitlab/script$ diff background_jobs background_jobs.orig 21,27c21 < # pkill -u $gitlab_user -f sidekiq < if [ -f "$sidekiq_pid_path" ]; then < spid=$(cat "$sidekiq_pid_path") < else < spid=0 < fi < kill -0 "$spid" 2>/dev/null --- > pkill -u $gitlab_user -f sidekiq
これでうまくいくはずです。GitLab-CI画面が出て、GitLabのユーザーでログインできたら、一旦インストール完了です。


GitLab-CI-Runnerはバックグラウンドで動いていて、実際にビルドスクリプトを実行する役割を果たします。もうここに来たら、イントール自体はあまり難しくありません。本家サイトのインストールガイドに従ってインストールします。
本家サイトのインストールガイド
https://gitlab.com/gitlab-org/gitlab-ci-runner/blob/master/README.md
しかし、なぜか弊社環境では、起動スクリプトで起動がうまくできませんでした。意味不明ですけど、ちょっと我慢して手動で以下のようにサーバーが再起動されるたびに、GitLab-Ci-Runnerを起動しています。
su git cd /home/git/gitlab-ci-runner/ nohup bundle exec ./bin/runner &
ここで、GitLab-CI画面でRunnerの確認ができます。

GitLabとGitLab-CIの連携がよく出来ているので、GitLab側でプロジェクトを作成したら、自動的にGitLab−CI側にもSyncされています。GitLab-CIトップ画面にすべてそのユーザーが見えるすべてのプロジェクトが表示されます。ビルド対象にするには、単純に右の「Add」をクリックするだけです。非常に簡単です。
PHPプロジェクトのビルドのための設定は極めて簡単です。
Build stepsにはantにするだけです。下には実際のAntスクリプトの内容を掲載致します。

また、ビルド失敗時にはエラーメールが飛ばされるように設定するといいですね。いつ、なぜ失敗するかエンジニアに知らせて、直してもらうことにすごく意味が成します。

これで弊社のYiiFramework PHPプロジェクトのビルドファイル内容はこんな感じです。build.xmlファイルはプロジェクトのルートフォルダに配置すれば、GitLab-CIでantを実行してくれるだけでOKです。
<?xml version="1.0" encoding="UTF-8"?>
<project name="PHP Project CI" default="build">
<!--<target name="build"
depends="prepare,phpunit,lint,phploc,pdepend,phpmd-ci,phpcs-ci,phpcpd,phpdox,phpcb,post-build"/> -->
<target name="build"
depends="prepare,phpunit,post-build"/>
<target name="build-parallel"
depends="prepare,lint,tools-parallel,phpunit,phpcb"/>
<target name="tools-parallel" description="Run tools in parallel">
<parallel threadCount="2">
<sequential>
<antcall target="pdepend"/>
<antcall target="phpmd-ci"/>
</sequential>
<antcall target="phpcpd"/>
<antcall target="phpcs-ci"/>
<antcall target="phploc"/>
<antcall target="phpdox"/>
</parallel>
</target>
<target name="clean" description="Cleanup build artifacts">
<delete dir="${basedir}/build/api"/>
<delete dir="${basedir}/build/code-browser"/>
<delete dir="${basedir}/build/coverage"/>
<delete dir="${basedir}/build/logs"/>
<delete dir="${basedir}/build/pdepend"/>
</target>
<target name="prepare" depends="clean" description="Prepare for build">
<tstamp>
<format property="now.time" pattern="yyyyMMddhhmmssSSS"/>
</tstamp>
<mkdir dir="${basedir}/build/api"/>
<mkdir dir="${basedir}/build/code-browser"/>
<mkdir dir="${basedir}/build/coverage"/>
<mkdir dir="${basedir}/build/logs"/>
<mkdir dir="${basedir}/build/pdepend"/>
<mkdir dir="${basedir}/build/phpdox"/>
<!-- Make db migrate -->
<copy file="${basedir}/build/db.php" tofile="${basedir}/protected/config/db.php" overwrite="true"/>
<!-- <copy file="${basedir}/build/params.php" tofile="${basedir}/protected/config/params.php" overwrite="true"/> -->
<copy file="${basedir}/build/WebTestCase.php" tofile="${basedir}/protected/tests/WebTestCase.php" overwrite="true"/>
<copy file="${basedir}/build/cache.php" tofile="${basedir}/protected/config/cache.php" overwrite="true"/>
<exec executable="php">
<arg line="${basedir}/protected/yiic" />
<arg line="migrate --interactive=0" />
</exec>
<!-- Chmod 777 for assets and protected/runtime -->
<chmod dir="${basedir}/assets" perm="777" />
<chmod dir="${basedir}/protected/runtime" perm="777" />
</target>
<target name="post-build" description="Execute some things after build">
<!-- Move libs folders from /tmp -->
<!--
<move todir="${basedir}/protected/vendor">
<fileset dir="/tmp/vendor.${now.time}"/>
</move>
<move todir="${basedir}/protected/extensions">
<fileset dir="/tmp/extensions.${now.time}"/>
</move>
-->
</target>
<target name="lint" description="Perform syntax check of sourcecode files">
<apply executable="php" failonerror="true">
<arg value="-l" />
<fileset dir="${basedir}/protected">
<include name="commands/**/*.php" />
<include name="components/**/*.php" />
<include name="config/**/*.php" />
<include name="controllers/**/*.php" />
<include name="messages/**/*.php" />
<include name="migrations/**/*.php" />
<include name="models/**/*.php" />
<include name="modules/**/*.php" />
<include name="tests/**/*.php" />
<include name="views/**/*.php" />
<modified />
</fileset>
</apply>
</target>
<target name="phploc" description="Measure project size using PHPLOC">
<exec executable="phploc">
<arg value="--log-csv" />
<arg value="${basedir}/build/logs/phploc.csv" />
<arg path="${basedir}/protected" />
</exec>
</target>
<target name="pdepend" description="Calculate software metrics using PHP_Depend">
<exec executable="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}/protected" />
</exec>
</target>
<target name="phpmd"
description="Perform project mess detection using PHPMD and print human readable output. Intended for usage on the command line before committing.">
<exec executable="phpmd">
<arg path="${basedir}/protected" />
<arg value="text" />
<arg value="${basedir}/build/phpmd.xml" />
</exec>
</target>
<target name="phpmd-ci" description="Perform project mess detection using PHPMD creating a log file for the continuous integration server">
<exec executable="phpmd">
<arg path="${basedir}/protected" />
<arg value="xml" />
<arg value="${basedir}/build/phpmd.xml" />
<arg value="--reportfile" />
<arg value="${basedir}/build/logs/pmd.xml" />
</exec>
</target>
<target name="phpcs"
description="Find coding standard violations using PHP_CodeSniffer and print human readable output. Intended for usage on the command line before committing.">
<exec executable="phpcs">
<arg value="--standard=${basedir}/build/phpcs.xml" />
<arg path="${basedir}/protected" />
</exec>
</target>
<target name="phpcs-ci" description="Find coding standard violations using PHP_CodeSniffer creating a log file for the continuous integration server">
<exec executable="phpcs" output="/dev/null">
<arg value="--report=checkstyle" />
<arg value="--report-file=${basedir}/build/logs/checkstyle.xml" />
<arg value="--standard=${basedir}/build/phpcs.xml" />
<arg path="${basedir}/protected" />
</exec>
</target>
<target name="phpcpd" description="Find duplicate code using PHPCPD">
<exec executable="phpcpd">
<arg value="--log-pmd" />
<arg value="${basedir}/build/logs/pmd-cpd.xml" />
<arg path="${basedir}/protected" />
</exec>
</target>
<target name="phpdox" description="Generate API documentation using phpDox">
<exec executable="phpdox">
<arg line="--file ${basedir}/build/phpdox.xml" />
</exec>
</target>
<target name="phpunit" description="Run unit tests with PHPUnit">
<exec executable="phpunit" failonerror="true">
<arg line="--configuration ${basedir}/protected/tests/phpunit.xml" />
<arg line="--log-junit ${basedir}/build/logs/junit.xml" />
<arg line="--coverage-clover ${basedir}/build/logs/clover.xml" />
<arg line="${basedir}/protected/tests/unit" />
</exec>
<exec executable="phpunit" failonerror="true">
<arg line="--configuration ${basedir}/protected/tests/phpunit.xml" />
<arg line="--log-junit ${basedir}/build/logs/junit1.xml" />
<arg line="--coverage-clover ${basedir}/build/logs/clover1.xml" />
<arg line="${basedir}/protected/tests/functional" />
</exec>
<!-- Move libs folders to /tmp -->
<!--
<move todir="/tmp/vendor.${now.time}">
<fileset dir="${basedir}/protected/vendor"/>
</move>
<move todir="/tmp/extensions.${now.time}">
<fileset dir="${basedir}/protected/extensions"/>
</move>
-->
</target>
<target name="phpcb" description="Aggregate tool output with PHP_CodeBrowser">
<exec executable="phpcb">
<arg value="--log" />
<arg path="${basedir}/build/logs" />
<arg value="--source" />
<arg path="${basedir}/protected" />
<arg value="--output" />
<arg path="${basedir}/build/code-browser" />
</exec>
</target>
</project>
実際にはビルド結果はこんな感じ
■成功時


■失敗時


その際はエラーメールも飛ばされます。

GitLabとGitLab-CIを導入して間もないですが、すごくよいと思います。なぜならば
- 管理は簡単。GITコマンドはいちいち打たなくてもOK
- GITHUBフローを利用して開発できる(Merge Request、Code Review等)
- GitLab-CIでどのコミットに関しても、どのブランチに関してもビルドが自動的に走らせる。Merge RequestのブランチはまずビルドOKが条件
等です。
現在弊社の開発フローはこんな感じです。
- プロジェクトスタート時、マネージャーはRedmineプロジェクトを作成する
- 開発リーダはプロジェクトレポジトリをGITLABにて作成し、参加開発者をメンバーにする
- 開発用のdevelopブランチとリリース用のmasterブランチの2つが作成される
- 開発者はdevelopブランチから自分用ブランチを作成する。開発は基本自分用ブランチ上で開発する。
- 機能の開発が終わったら、担当者は現developブランチから自分用ブランチにマージしてからMerge Requestを出す
- Merge RequestがOKでした、開発コードはdevelopブランチにマージされる
ルールとしては、開発者は自分のコミットでCIのビルドが壊れたら、絶対に責任を持って対処します。また、その状態であれば、Merge Requestができないことになっています。
個人としては、GitLabを使うことで、品質向上できるのはいくつか考えられます。
- しっかりCIビルドOKしたら、コードがマージされる。壊れたコードの事前発見
- コードレビューすることで、コードの品質向上を図る。
- コードの見える化によって、開発者でも自分のコードが見られるから恥せずに書かないと思うようになる
- Merge Request機能により、しっかりと機能とその実装コードがレビュー、テストされるから品質が上がる
等です。
GITLABに感謝です。これからも使わせていただきます。
Leave a Comment