SonarQubeでPHPのコードを静的解析する

  • 91
    Like
  • 0
    Comment

SonarQubeはオープンソースの静的解析ツール

一言で言うと「コードのダメな部分を教えてくれるやつ」です。LGPLライセンス。
下のようなこんな感じでコード品質の推移が一覧できます。また、コードごとに何が悪いのか、どう直すべきなのかを見ることができます。(画像はDrupalの解析結果
スクリーンショット 2016-06-06 10.57.38.png

オンプレ環境で使えるのがメリットで、GitHubで個人のプロジェクトを解析するなら、各種静的解析SaaSを使うのが簡単なのでおすすめです。

PHP向け静的解析SaaSの主観的比較 (Scrutinizer, SensioLabsInsight, CodeClimate) - Qiita

公式サイト:SonarQube™

簡単に試したい

公式の利用例 を見るか、公式のサンプルを使ってみてください。自分でDBの設定をしなくても試すことができます。
Get Started in Two Minutes - SonarQube Documentation - SonarQube

上のサンプルを動かしてみて自分のプロジェクトに使ってみたい人だけ以下を読んで下さい。

以降では、以下の準備がされていることを仮定します。

  • SonarQubeを動かす適当なサーバがある
  • 手元に解析対象のPHPのソースコードがある

SonarQubeで自分のプロジェクトを解析する

この記事で達成すること、および手順の概要

SonarQubeは大きく2つのモジュールに分かれています。

  • DBへ解析結果を書き込んだりWeb上で解析結果を閲覧するためのSonarQube Server
  • 静的解析を行うSonarQube scanner(runner)

まず公式ドキュメントなどの手順に従って、これらのソフトウェアを導入します。

その後、Jenkinsにより静的解析の実行を自動化します(例えば1日1回解析を回す、などができるようになります。ただ、これだけならcrontabで実行するほうが簡単です。次のステップをするための準備です)。
さらにGitHubと連携し、プルリクエストにフックしてJenkinsでSonarQubeを動かし、静的解析の結果をGitHub上にコメントとして表示することでコードレビューに活用できるようにします。

静的解析ツールをCIに取り入れるために、ぜひGitHub連携まで設定してみてください。ここまでやれば静的解析ツールを入れるメリットを多く享受できると思います(GitHubのレビューベースで開発を進めている場合)。
プルリク時に自動的にコードのよくない箇所を指摘してもらうことができるようになるので、それを直すことでコード品質が改善できます
また、コード品質を定量的に扱う指標が得られるため、目標設定に便利です。計測できない目標を立てるのは困難ですし、計測なくして他人に納得してもらうのはもっと難しいです。

必要なスペックやミドルウェア

公式ドキュメントによると、RAMは効率的に動かすためには最低でも2GB、さらにOS用に1GB必要なようです。コードベースの規模も関係あるかも知れませんが、2GB程度しか割り振らなくても動きました。

SonarQubeの起動にはJavaランタイム環境が必要です。また、Webのインタフェースで解析結果を表示するためのDBも必要です。
そこで、まず公式サイトを参考にJREとMySQLを導入します。
(ySQL以外も対応しているので詳しくは公式を参照してください。)

Requirements - SonarQube Documentation - SonarQube

Javaランタイム環境の導入

最新版のSonarQube 5.6以降はJava8が必須になりました。

yum install java-1.8.0-openjdk-devel

MySQLの導入

MySQL 5.7のインストール

今回はMySql 5.7を導入する。

sudo rpm -Uvh  http://dev.mysql.com/get/mysql57-community-release-el6-8.noarch.rpm
yum install mysql-community-server

MySql 5.7ではセキュリティ面が向上しているが、テストのための簡単なパスワードははじかれてしまうので、セキュリティレベルを下げる。
/etc/my.confに以下を追記する。

secure-file-priv = ""
validate_password_policy=LOW # パスワードがダメダメでも許可する

SonarQubeで利用するユーザを作成する

CREATE USER 'sonar'@'localhost' IDENTIFIED BY 'YOUR_PASSWORD';
GRANT ALL PRIVILEGES ON sonar.* TO 'sonar'@'localhost';
CREATE DATABASE sonar;
FLUSH PRIVILEGES;

ユーザ一覧の確認

select Host, User, Password from mysql.user;

豆知識:MySQL 5.7だとPasswordカラムは存在しない。
参考: MySQLのユーザー一覧を確認 | cloudpack技術情報サイト

SonarQube Serverの導入

wget "https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-5.5.zip"
unzip sonarqube-5.5.zip
mv sonarqube-5.5 /etc
ln -s /etc/sonarqube-5.5 /etc/sonarqube

service sonar start でSonarQubeのサーバーをスタートできるようにするためにシンボリックリンクを作成する

sudo ln -s /etc/sonarqube/bin/linux-x86-64/sonar.sh /etc/init.d/sonar

以後、サーバーが落ちたらこのコマンドを打って再起動します。
この時点ではSonarQubeからMySQLを利用することはできません。設定をしていきましょう。
デフォルトではH2が使われますが、DBの設定ができてない状態で起動するとエラーでプロセスが静かに死にます。
service sonar console で実行時のログを見ることができます。
起動時のエラーなどは /etc/sonarqube/logs 以下に保存されているのでなにか変だったら確認するとよいです。
初回実行時はDBのマイグレーションで数分の時間がかかりました。ログにエラーが出ていない場合は気長に待ちましょう。

SonarQube ServerをMySQLと接続する

sudo vim /etc/sonarqube/conf/sonar.properties

MySQLの設定をした際のパスワード等を入力します。

sonar.jdbc.username=sonar
sonar.jdbc.password=YOUR_PASSWORD
#----- MySQL 5.x
# Only InnoDB storage engine is supported (not myISAM).
# Only the bundled driver is supported. It can not be changed.
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance

SonarQube Scannerのインストール

下記リンクから最新版を引っ張ってくる。

wget "https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-2.6.1.zip"
unzip sonar-scanner-2.6.1.zip
mv sonar-scanner-2.6.1 /etc
ln -s /etc/sonar-scanner-2.6.1 /etc/sonar-scanner

Analyzing with SonarQube Scanner - Scanners - SonarQube

PHP Pluginの導入

service sonar startでServerを立ち上げていると、デフォルトの設定ではhttp://[Sonarが動いているサーバのドメイン]:9000でWebインタフェースにアクセスすることができます。そのままではPHPは解析できないので、プラグインをインストールします。
ページトップのバーから Administration > System > Update Center > Available からPHPをインストールします。

解析対象のファイル等の設定

解析リポジトリのrootにsonar-project.propertiesというファイルを作り、解析対象のディレクトリ等を指定します。
指定/除外の方法の詳細は以下のページを参考下さい。

Narrowing the Focus - SonarQube Documentation - SonarQube

なお、Jenkinsで連携する場合はJenkinsのプラグイン側でsonar-project.properties内容を指定することができます。

cat sonar-project.properties
# must be unique in a given SonarQube instance
sonar.projectKey=YOUR:PROJECT_KEY #このキーが重複するとDBの結果が上書きされるので、ユニークなものにすること
# this is the name displayed in the SonarQube UI
sonar.projectName=YOUR_PROJECT_NAME # Webインタフェースに出てくる名前
sonar.projectVersion=1.0

# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# Since SonarQube 4.2, this property is optional if sonar.modules is set.
# If not set, SonarQube starts looking for source code from the directory containing
# the sonar-project.properties file.
sonar.sources=.

# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8

# inclusions
sonar.inclusions=./hoge/** # 解析に含めたいディレクトリ

静的解析の実行

/etc/sonar-runner/bin/sonar-scanner

解析が終了すると、 http://[Sonarが動いているサーバのドメイン]:9000YOUR_PROJECT_NAME という項目が生成され、コードごとに次のような情報を見ることができます(一例)。

  • コードの修正すべき点
  • なぜそのコードが修正するべきなのか?という解説

なお、解析のルールはデフォルトではPSR(PHPのコーディングや階層構造の規約)を含む独自のものになっています。
なので、バグじゃないっぽいのに小うるさくバグと言われたりします

SonarQubeをJenkinsから実行できるようにする

できるようになること

  • Jenkinsのジョブとして解析を実行できるようになる

手順

基本的に以下の資料のとおりに進める。補足的情報のみ記す。
Jenkins + SonarQube で PHPコードメトリクス計測! - 長生村本郷Engineers'Blog
Installing SonarQube with Jenkins integration for a PHP project · Cvuorinen.net

Jenkinsのインストール

sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
yum install jenkins

最新版はJenkinsで確認して下さい

Jenkinsの起動

sudo service jenkins start

Jenkinsユーザを解析対象のリポジトリにアクセスできるようにする

[解析対象のリポジトリ/settings/keys]にアクセスします。そして、Jenkinsユーザの公開鍵をdeploy-keysに登録します。

SonarQubeへのGitHub Pluginの導入

Web UIで Administration > System > Update Center > Available からGitHubプラグインを導入する。
Jenkinsの設定で利用するため、Security > User から authentication token を取得しておく。

JenkinsにSonarQubeのPluginを入れ、解析ジョブを作成する

下記のサイトの「Jenkins 側準備」節を参考に設定します。

Jenkins + SonarQube で PHPコードメトリクス計測! - 長生村本郷Engineers'Blog

この際、先に作成した、解析対象のrootにあるsonar-project.propertiesを削除し、設定をJenkinsに転載します。

ジョブ作成時にRepositoryのCredentialsにJenkinsユーザの鍵を登録します。
(追加 > 種類 > SSHユーザ名と秘密鍵とすると設定できる)

GitHubのプルリクエスト時にコメントできるようにする

できるようになること

  • GitHubのプルリクエストにフックして静的解析をすることができる
  • 静的解析をした結果をGitHubに自動的に書き込むことでコードレビューの手間を減らし、またコード品質を保つ

注意点

トークンを登録したユーザのアカウントでコメントがつけられますが、SonarQubeの解析が走るたびに前のコメントは削除され、最新のコメントが付きます。
この際に登録したユーザのコメントはSonarQubeがつけたものかどうかにかかわらず全て消されてしまうため、レビューを通常行わないユーザ(Botユーザなど)のトークンで設定するようにして下さい。

GitHub Pull Request Builderの導入

SonarQubeで解析を走らせるためには解析対象のプルリクエストの番号を指定する必要があります。
プルリクエストの番号をいちいち手で指定する運用はめんどくさすぎるので、動的に取得して指定する必要があります。GitHub Pull Request Builderを使うと簡単に取得できるので設定を頑張ります。

JenkinsのプラグインからGitHub Pull Request Builderをインストールします。
設定を以下の捕捉を参考にやっていきます。

GitHub Pull Request Builder Plugin の多すぎる設定項目を補足してみる - Qiita

アクセストークンの自動生成がうまくいかない場合

手動でGitHubのアクセストークンを取得します。
GitHubにアクセスして、Settings(右上の歯車アイコン) > Applications > Personal access tokens でトークンを作成します。
この際 public_repo, user, repo:status, read:org, notifications, admir:repo_hook にチェックを入れます。
(notificationは必要ないかもしれません)
Jenkinsの管理 > システムの設定 のGitHub Pull Request Builderセクションにある「追加」ボタンをクリックして鍵を追加します。その際ドロップダウンから secret text を選択しアクセストークンを入力します。

プルリクエストが来た際にフックするように設定ファイルに追記する

ジョブのビルド > Execute Sonarqube Scanner > Analysis propertiesの末尾に次を追加します

# GitHub Integration
sonar.github.repository=your_user/your_repository # 解析対象のリポジトリ
sonar.github.pullRequest=${ghprbPullId} # GitHub Pull Request Builderの変数
sonar.analysis.mode=preview

その他はまったこと

Jenkinsで見た時マークアップが崩れる

HTMLがそのまま出ているときは、Jenkins > グローバルセキュリティの設定 > マークアップ記法 で Safe HTML を選択すると見栄えが良くなる。

GitHubの通知(Commit Status Context)が"default"と"sonarqube"の2つがでたことによって、もとから回していたCIの"default"の通知が消えた

SonarQube導入前の時点で、ビルド時にCommit status contexitで"default"と表示するようなツールを使っていると起こる問題。
commit statusの表示名のデフォルト値が"default"で、この表示名は複数のアプリケーションでかぶると、後に実行されたものが上書きするっぽい。

GitHub の Deployments API を使ったデプロイのワークフローのイメージ - Sexually Knowing

ジョブの設定から、ビルドトリガ > Trigger Setup > statusContextのデフォルト値が'default'らしいのでこれを変更するとcommit statusの表示名が変更できます。これをdefault以外のユニークなキーにしておきましょう。

Commit statusの表示が同内容のものが2つ出る

なぜ出るのかはよくわからないのですが、同じものが出ているので1つにしたいですよね。
上で設定したキーをデフォルトのものと同じ sonarqube にすると上書きされるので1つになります。

jenkins と ghprb,github commit status を使った仕事が楽になる 10 の設定 | Aiming 開発者ブログ

GitHub上のインラインコメントがうざいのでつけないようにしたい

http:[SonarQubeが動いているサーバ]:9000/settings?category=github から Disable issue reporting as inline comments を true に設定する
GitHub上のコメントは修正をpushすると自動的に消えるなどけっこう考えられているので、うざくてもつけたほうがいいと思います。

PHPの ** を含むコードを解析できない

PHP5.6から利用できる、べき乗の演算子ですが、これがあるとエラーを吐いて無視されているようです。
SonarQubeのPHPプラグインの使っているモジュールに起因するバグっぽい。直接的にissueにはあがっていないのであげたい。
PHP Plugin自体はPHP7にも対応しています。

追記:チケットが爆誕していました
https://jira.sonarsource.com/browse/SONARPHP-691