2019-02-10 追記: SonarQubeではなくPHPStanで同様のことをする記事も書きました。いま個人開発ならこちらがを選ぶことも多そうです。
SonarQubeはオープンソースの静的解析ツール
一言で言うと「コードのダメな部分を教えてくれるやつ」です。LGPLライセンス。
下のようなこんな感じでコード品質の推移が一覧できます。また、コードごとに何が悪いのか、どう直すべきなのかを見ることができます。(画像はDrupalの解析結果)
オンプレ環境で使えるのがメリットで、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)
まず公式ドキュメントなどの手順に従って、これらのソフトウェアを導入します。
- Installing the Server - SonarQube Documentation - SonarQube
- 【PHP】 PHPでの静的解析 SonarQubeを使ってみた - 旅するえんじにあ - Engineers to Travel -
- centos6.xにsonarqubeをインストール - m_shige1979のささやかな抵抗と欲望の日々
- Installing SonarQube on Ubuntu | dev.mamikon.net
その後、Jenkinsにより静的解析の実行を自動化します(例えば1日1回解析を回す、などができるようになります。ただ、これだけならcrontabで実行するほうが簡単です。次のステップをするための準備です)。
さらにGitHubと連携し、プルリクエストにフックしてJenkinsでSonarQubeを動かし、静的解析の結果をGitHub上にコメントとして表示することでコードレビューに活用できるようにします。
静的解析ツールをCIに取り入れるために、ぜひGitHub連携まで設定してみてください。ここまでやれば静的解析ツールを入れるメリットを多く享受できると思います(GitHubのレビューベースで開発を進めている場合)。
プルリク時に自動的にコードのよくない箇所を指摘してもらうことができるようになるので、それを直すことでコード品質が改善できます。
また、コード品質を定量的に扱う指標が得られるため、目標設定に便利です。計測できない目標を立てるのは困難ですし、計測なくして他人に納得してもらうのはもっと難しいです。
追記(2018-10-30):GitHubのコメント連携は有償になりました
GitHubにコメントしてくれるためのPluginは非推奨になりました。
もし使いたい場合有償のDeveloper Editionを使ってくださいという方針のようです。
haya14busa/reviewdog: Automated code review tool integrated with any code analysis tools regardless of programming languageを使えば似たようなことができるかもしれません(未検証)
必要なスペックやミドルウェア
公式ドキュメントによると、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が動いているサーバのドメイン]:9000
に YOUR_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