yano3nora
8/3/2017 - 12:26 PM

[ci: jenkins] #jenkins #ci #phpunit

[ci: jenkins] #jenkins #ci #phpunit

Overview

簡単に言うとビルド・デプロイ・テスト・バグ検出なんかをまとめて「ジョブ」として登録し自動化できる開発支援(継続的インテグレーション=継続的なシステムの結合状態を維持する)ツール。Java製。

Jenkins ホームDIR ( /var/lib/jenkins/ ) 配下に Workspace と呼ばれる作業用ディレクトリを形成 ( workspace/{JOB_NAME} ) し、Gitサーバから Pull したソースをその中でビルドする。

Why we're want ?

  • チケット発行時の「設計:デザイン」
  • チケット追記による「時系:タイムライン」
    • Slackやメールの引用
    • 確定事項や共有ファイルなど
  • GitHubFlowで「作業:コミット」
  • ビルド自動実行による「検査:テスト」
  • 実装者ロジックとテストの「報告:レポート」
  • 再現&結合可能状態での「検証:レビュー」
  • ビルドエラー→差戻の「状態:ステータス」
  • 最終マージ・デプロイで「納品:リリース」

上記一連の流れについて多くを自動化・再現可能・常時結合状態にしてくれることで、高速な「XP:設計→開発→再設計」を可能にするためのもの(CI:常時結合・継続的インテグレーション)。Redmineのチケットによるタスク管理/Gitによる世代管理/Vagrantによる環境管理に加えて導入することで、VMにJenkins建ててソース管理したJenkins設定/ジョブ設定ファイルを飲ませて全部OKだった場合のみDevelopブランチにPR申請。PR受付時ブランチを取り込み自VMでビルドチェック&ソースレビューを行いOKだった場合のみMergeしてチケット消化扱い。吐かれたログやドキュメントについて開発者にチケ添付してもらう....的な運用が可能。

Refs

Official : https://jenkins.io/ Wiki : https://wiki.jenkins-ci.org/

Should be careful ?

  • ステージング/本番環境ではGitサーバ連携実行
  • 開発環境(ローカルVM)では手動実行にする
  • Jenkinsの開発・カスタマイズをやりすぎない
    • GUIによる設定なのでメンテナンス性低い
    • 〃なので再現性が低い→再構築できない
    • 〃なので差分管理できない
  • 1つの Jenkins を複数&同一権限で共有
    • 好き勝手プラグインを入れると依存がすごい
    • ジョブ数が増えて優先順位がわからなくなる
    • 各自で構築し一人1台で設定共有する?
  • ビルド環境をその場しのぎで変更しまくる
    • わざわざ設けた制限を自分たちでカスタム?
    • チームメンバ間で現在の状態を共有できない
  • https://goo.gl/CTD2bc

Installation

Install Jenkins to Linux

$ yum install -y java #1.8.0-openjdk
$ wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
$ rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
$ yum install -y jenkins graphviz graphviz-graphs graphviz-gd graphviz-devel postfix gcc ImageMagick ImageMagick-devel 
$ service jenkins start
$ service postfix start
$ cat /var/lib/jenkins/secrets/initialAdminPassword # コピって初回ページ張り付け
# plugin はオススメを選択 (Sagested Plugins)

Git association ( with Vagrant )

When build Jenkins in guest os by VM, you need to install Git on the guest os and have to exchange public key for SSH from the Jenkins server of the guest OS to the Git server on outside network.

Process

$ cd /var/lib/jenkins
$ sudo -u jenkins ssh-keygen -t rsa
$ chown -R jenkins:jenkins .ssh/
$ chmod 400 .ssh/id_rsa
$ cat .ssh/id_rsa.pub
# ↑をコピってGitサーバ自垢へ鍵情報付与
$ cat .ssh/id_rsa
# ↑をコピってJenkinsのCredentials登録
# テスト接続で knownhosts 追加
$ sudo -u jenkins ssh -T git.ampware.jp
# permission denied は無視してよい
# 多分 vagrant ssh によるユーザすり替えにより権限がもにょっている
# Jenkins 以下 Plugin を有効にしておく
# - Git plugin
# - Gitbucket plugin

Phing for PHP project #phing

Process

Install required libs
$ yum install gcc ImageMagick ImageMagick-devel -y
$ touch /etc/php.d/imagick.ini
$ echo extension=imagick.so > /etc/php.d/imagick.ini
Install plugins to Jenkins
  • php
  • Phing
  • Clover PHP
  • Clover plugin
  • Coverage/Complexity Scatter Plot PlugIn
Install Phing to project by composer
"require-dev": {
  "phing/phing": "2.*",
  "phpunit/phpunit": "*",
  "phpmd/phpmd": "*",
  "sebastian/phpcpd": "*",
  "squizlabs/php_codesniffer": "*",
  "apigen/apigen": "*",
  "satooshi/php-coveralls": "*",
  "psy/psysh": "@stable",
},
  "scripts": {
    "build": "vendor/bin/phing build",
}

$ ./composer.phar install
Create setting XML
<!-- App/build.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project name="Prebuild" default="build">
  <target name="build" depends="prepare, phpcs, phpmd, phpcpd, phpunit"/>
  <target name="prepare">
    <delete dir="build" includeemptydirs="true"/>
    <delete dir="build/logs" includeemptydirs="true"/>
    <delete dir="build/clover" includeemptydirs="true"/>
    <mkdir dir="build"/>
    <mkdir dir="build/logs"/>
    <mkdir dir="build/clover"/>
  </target>
  <target name="phpcs" description="Generate phpcs.xml">
    <exec executable="vendor/bin/phpcs" output="build/phpcs.xml">
      <arg line= "
        --report=checkstyle
        --standard=PSR2
        --extensions=php
        src" />
    </exec>
  </target>
  <target name="phpmd" description="Generate phpmd.xml">
    <phpmd rulesets="cleancode,codesize,controversial,design,naming,unusedcode" pharlocation="vendor/bin/phpcs">
      <fileset dir="src">
        <include name="**/*.php" />
        <exclude name="**/*Test.php" />
      </fileset>
      <formatter type="xml" outfile="build/phpmd.xml" />
    </phpmd>
  </target>
  <target name="phpcpd" description="Generate phpcpd.xml">
    <phpcpd pharlocation="vendor/bin/phpcpd">
      <fileset dir="src">
        <include name="**/*.php" />
        <exclude name="**/*Test.php" />
      </fileset>
      <formatter type="pmd" outfile="build/phpcpd.xml" />
    </phpcpd>
  </target>
  <target name="phpunit" description="Generate phpunit.xml">
    <exec executable="vendor/bin/phpunit">
      <arg line="
        --configuration=phpunit.xml
        --coverage-clover=build/logs/clover.xml
        --coverage-html=build/clover
        --coverage-xml=build/logs/junit.xml
        tests
      "/>
    </exec>
  </target>
</project>

<!-- App/phpunit.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
    colors="true"
    processIsolation="false"
    stopOnFailure="false"
    syntaxCheck="false"
    bootstrap="./tests/bootstrap.php"
    >
    <php>
        <ini name="memory_limit" value="-1"/>
        <ini name="apc.enable_cli" value="1"/>
    </php>
    <logging>
      <log type="coverage-html" target="./build/clover" title="phpunit"
        charset="UTF-8" yui="true" highlight="true"
        lowUpperBound="35" highLowerBound="70"/>
      <log type="coverage-clover" target="./build/logs/clover.xml"/>
      <log type="junit" target="./build/logs/junit.xml" logIncompleteSkipped="false"/>
    </logging>
    <!-- Add any additional test suites you want to run here -->
    <testsuites>
        <testsuite name="App Test Suite">
            <directory>./tests/TestCase</directory>
        </testsuite>
        <!-- Add plugin test suites here. -->
    </testsuites>
 
    <!-- Setup a listener for fixtures -->
    <listeners>
        <listener
        class="\Cake\TestSuite\Fixture\FixtureInjector"
        file="./vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureInjector.php">
            <arguments>
                <object class="\Cake\TestSuite\Fixture\FixtureManager" />
            </arguments>
        </listener>
    </listeners>
 
    <!-- Ignore vendor tests in code coverage reports -->
    <filter>
        <whitelist>
            <directory suffix=".php">./src/</directory>
            <directory suffix=".php">./plugins/*/src/</directory>
        </whitelist>
    </filter>
</phpunit>

Doxygen for Documentation #doxygen

https://goo.gl/sVQUlk

Process

  1. $ yum install -y doxygen
  2. Jenkins > Plugin Manager > Doxygen plugin 追加
  3. Jenkins > Global Tool Configuration > Doxygen > Doxygen追加
  4. 名前はなんでもよい「default」とか?
  5. パスに /usr/bin/doxygen
    • 警告は無視してOK
    • 設定したら Save
  6. (初回) 設定ファイル生成&編集
    • e.g.) $ cd /var/www/App
    • e.g.) $ doxygen -g

Doxyfile

# 変更箇所のみ
PROJECT_NAME = プロジェクト名
PROJECT_NUMBER = バージョン番号
# 出力先ディレクトリを指定
OUTPUT_DIRECTORY = .
OUTPUT_LANGUAGE = Japanese
# JavaDocスタイルのコメント利用
JAVADOC_AUTOBRIEF = YES
# コメントが付いていなくてもドキュメント化
EXTRACT_ALL = YES
# 標準出力へメッセージ出力する
QUIET = YES
# 入力ディレクトリ
INPUT = .
# 対象とするファイル
FILE_PATTERNS = *.php *.ctp
# サブ・ディレクトリまで検索
RECURSIVE = YES
# LATEX形式の出力をしない
GENERATE_LATEX = NO
# dot でグラフィック表示
HAVE_DOT = YES
DOT_PATH = /usr/bin

SchemaSpy for DB

What is ?

https://github.com/schemaspy/schemaspy http://d.hatena.ne.jp/TrinityT/20120620/1340179412

Global Tool Configration

# JDK 
Name: default
->Install automatically
# Doxygen
Name: default
Path: /usr/bin/doxygen
# Git
Name: default
Path: git
# Phing
Name: default
Path: /var/www/App/vendor/phing/phing
PHP: (blank)

How to use ?

Boilerplate of Jenkins job

# General
    - Project name: Prebuild
    - Description: Entry job of all build process.
    - Options: (none)
# GitBucket
    - URL: gitbucket url
        -  http://domain/gitbucket/owner/p**_***
- Enable hyperlink to the issue: true
# Source Code Management
    - Git
        - Repositories: ssh://git.ampware.jp:29418/**
        - Credentials: (your jenkins ssh credential)
        - Branches to build: */master, */develop, */feature-***
        - Repository browser: Auto
        - Additional Behaviours: -
# Build Triggers (when not VM)
    - Build when a change is pushed to GitBucket
    - ( set webhook of gitbucket project )
        - http://host:8080/gitbucket-webhook/
        - http://host:8080/jenkins/gitbucket-webhook/
# Build Environment
    - Delete workspace before build starts: false ( or true )
# Build
    - Generate documentation using Doxygen
        - Doxygen installation: default
        - Doxyfile path: Doxyfile
    - Kick compsoer scripts (build&test)
        - cd /var/lib/jenkins/workspace/Prebuild/App
        - /var/www/App/composer.phar install
        - /var/www/App/composer.phar build --dev
    - Kick npm scripts (build&test)
        - cd/var/lib/jenkins/workspace/Prebuild
        - npm install (stub)
        - npm run test (stub)
# Post-build Actions
    - Publish Doxygen (path: Doxyfile)
    - Publish Checkstyle: App/build/phpcs.xml
    - Publish PMD: App/build/phpmd.xml
    - Publish duplicate: App/build/phpcpd.xml
    - Publish Clover PHP
        - CloverXMLLocation: App/build/logs/clover.xml
        - PublishHtmlReport: App/build/clover
    - E-mail Notification: your-email@example.com
        - ( allow: nobody@nowhere.localdomain )

Job & Build Pipeline

http://qiita.com/nyasba/items/eea459e97a56c5d43fce

Monitoring Server by Jmeter

http://confluence.sharuru07.jp/pages/viewpage.action?pageId=2883643

UI test with #selenium

http://blog.cybozu.io/entry/8113 http://qiita.com/ootaken/items/26d37cb34d3b575277e0 https://ics.media/entry/6031 http://blog.trident-qa.com/2013/05/so-many-seleniums/#sec4 https://ics.media/entry/6031 http://qiita.com/edo_m18/items/ba7d8a95818e9c0552d9