弊社は前から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