4.GitHub Flow遵守状況検出システム及び可視化用Webアプリの実装
本章では,GitHub Flow遵守状況検出システムと,その結果を可視化するWebアプリの実装の詳細について述べる.
4.1 GitHub Flowルールの遵守状況検出システム
4.1.1 アーキテクチャ
本システムのアーキテクチャを図4.1.1-1に示す.
図4.1.1-1 アーキテクチャ
Pyhonを用いて,GitHub上に存在する分析対象となるリポジトリとプルリクエストの情報を収集・加工しMySQLに格納した.なお,リポジトリはgit logコマンド9,プルリクエストはGitHubAPI10を用いて収集する.この一連の処理は管理者が設定した一定の周期で実行される.
4.1.2 データベースの構造
本システムでは,MySQLデータベースを利用して,コミット及びプルリクエストの情報を管理した.以降では,システム上で使用したデータベースのテーブル構造及び,データを格納の方法を示す.
4.1.2.1 commit
このテーブルは,コミットの情報を格納するためのものである.R1',R2',R3’,R4',R5'の判定に使用する.
表 4.1.2.1-1 commitテーブル
キー名 | データ型 | 内容 | git pretty format |
---|---|---|---|
sha | CHAR(40) | コミットのハッシュ | %H |
repoUser | VARCHAR(100) | リポジトリを保持しているユーザ名もしくは組織名 | |
repoName | VARCHAR(100) | リポジトリの名前 | |
author | VARCHAR(100) | コミットを始めに編集した人 | %an |
commiter | VARCHAR(100) | コミットした人 | %cn |
date | DATETIME | コミットした日時(UTC) | %cd |
comment | VARCHAR(300) | コミットのコメント | %s |
branchTag | VARCHAR(100) | ブランチのタグ | %D |
merge | TINYINT(1) | マージコミットなら1,そうでないなら0 | |
masterCommit | TINYINT(1) | masterでコミットされていたら1,そうでないならNULL |
これらのデータはgit logコマンドをmasterブランチで実行することで収集する.
まず,マージコミット以外のデータを収集するコマンドを以下に示す.また,mergeキーには0を格納する.
git log --all --no-merges --date=iso --pretty=format:%H,%an,%cn,%cd,%s
--no-merges
オプションはマージコミットを除くためのもので,--date=ios
は日時をios形式で出力するためのものである.また,--pretty
オプションで,出力書式を指定する.出力書式と対応するキーはテーブルのgit pretty formatに示した.
次に,マージコミットのデータを収集するコマンドを以下に示す.また,mergeキーに1を格納する.
git log --all --merges --date=iso --pretty=format:%H,%an,%cn,%cd
--merges
オプションは,マージコミットのみを出力するためのものである.
そして,masterブランチに存在するコミットのデータを収集するコマンドを以下に示す.また,masterCommitキーを1に更新する.
git log --first-parent --no-merges --date=iso --pretty=format:%H
--first-parent
オプションは,マージコミットのマージ元を非表示にするものである.したがって,ここで出力されるコミットはmasterブランチに存在するコミットとなる.
最後に,ブランチポインタのデータを収集するコマンドを以下に示す.
git log --all --pretty=format:%H,%D
このコマンドで出力されるのは,ブランチポインタ及びtag情報である.格納するのはブランチポインタのみであるため,tagを除去してからbranchTagキーを更新する.
4.1.2.2 pushCommit
このテーブルは,pushされた日時を格納するためのものである.R3’の判定に使用する.
表 4.1.2.2-1 pushCommitテーブル
キー名 | データ型 | 内容 | git pretty format |
---|---|---|---|
sha | CHAR(40) | コミットのハッシュ | %H |
repoUser | VARCHAR(100) | リポジトリを保持しているユーザ名もしくは組織名 | |
repoName | VARCHAR(100) | リポジトリの名前 | |
date | DATETIME | コミットした日時(UTC) | %cd |
storeDate | DATETIME | コミットした日時(UTC) | |
firstFlag | TINYINT(1) | リポジトリで最初に格納されたコミットかどうか.最初であるなら1,そうでないなら0 |
これらのデータはgit logコマンドをmasterブランチで実行することで収集する.
git log --all --date=iso --pretty=format:%H,%cd
4.1.2.3 commitParent
このテーブルは,コミットの親関係を格納するためのものである.R2’の判定に使用する.
表 4.1.2.3-1 commitParentテーブル
キー名 | データ型 | 内容 | git pretty format |
---|---|---|---|
sha | CHAR(40) | コミットのハッシュ | %H |
repoUser | VARCHAR(100) | リポジトリを保持しているユーザ名もしくは組織名 | |
repoName | VARCHAR(100) | リポジトリの名前 | |
number | INT(10) | 親のid.1から増えていく. | |
parent | CHAR(40) | parent --- parentのハッシュ | %P |
これらのデータはgit logコマンドをmasterブランチで実行することで収集する.
git log --all --pretty=format:%H,%P
4.1.2.4 PullRequest
このテーブルは,プルリクエストの情報を格納するためのものである.R4’,R5'の判定に使用する.
表 4.1.2.4-1 PullRequestテーブル
キー名 | データ型 | 内容 | jsonキー |
---|---|---|---|
sha | CHAR(40) | コミットのハッシュ | merge_commit_sha |
repoUser | VARCHAR(100) | リポジトリを保持しているユーザ名もしくは組織名 | |
repoName | VARCHAR(100) | リポジトリの名前 | |
pullNumber | INT(10) | プルリクエストのナンバー | number |
userName | VARCHAR(100) | プルリクエストをした人 | user['login'] |
date | DATETIME | プルリクエストされた日時(UTC) | created_at |
comment | VARCHAR(300) | プルリクエストのコメント | title |
head | VARCHAR(100) | マージ元ブランチ | head['label'] |
base | VARCHAR(100) | マージ先ブランチ | base['label'] |
mergeFlag | TINYINT(1) | マージされていたら1,そうでないなら0GitHubが自動でマージしたなら0(マージコミットが生成されない) |
これらのデータはGitHub Apiを使用して収集する.表4.1.2.4-1のjsonキーは,GitHub Apiから返されるデータとキー名で対応している.このデータを収集するための,URLを以下に示す.:owner
にはリポジトリを保持しているユーザもしくは組織名,:repo
にはリポジトリ名を指定する.
https://api.github.com/repos/:owner/:repo/pulls
mergeFlagキーは,マージが行われているかを区別するものである.ブランチを連続して作成し,最後に作成したブランチでマージを行うと,全てのブランチのプルリクエストがCloseとなる.この場合,最後のブランチ以外のプルリクエストの merge_commit_sha
には,プルリクエストを送ったブランチポインタが指しているコミットのハッシュが格納される.これをマージと扱わないよう,プルリクエストでマージされるコミット一覧に merge_commit_sha
が含まれていれば,mergeFlagキーに0を格納し,そうでなければ1を格納する.なお,プルリクエストでマージされるコミット一覧は以下のURLで取得する.:number
には,プルリクエスのナンバーを指定する.
https://api.github.com/repos/:owner/:repo/pulls/:number/commits
4.1.2.5 PullRequestMessage
このテーブルは,プルリクエストへのレビューコメントの情報を格納するためのものである.R5'の判定に使用する.
表 4.1.2.5-1 PullMessageテーブル
キー名 | データ型 | 内容 | jsonキー |
---|---|---|---|
repoUser | VARCHAR(100) | リポジトリを保持しているユーザ名もしくは組織名 | |
repoName | VARCHAR(100) | リポジトリの名前 | |
pullNumber | INT(10) | プルリクエストのナンバー | |
messageId | VARCHAR(100) | メッセージID | id |
userName | VARCHAR(100) | メッセージした人 | user['login'] |
date | DATETIME | メッセージされた日時(UTC) | created_at |
message | VARCHAR(300) | メッセージの内容 | body |
これらのデータはGitHub Apiを使用して収集し,整形して格納する.このデータを収集するための,URLは以下のものである.
https://api.GitHub.com/repos/:owner/:repo/issues/:number/comments
また,4.2.4項のPullRequestで取得したデータも対応したキーに格納する.
4.1.3 ルールの判定
4.1.2項で示したデータベースに対してSQL文を実行することで,それぞれのルールを判定する.以降では,それぞれのルールに対しての,遵守及び違反と判定するためのSQLを示す.
4.1.3.1 R1':R1’:初期コミット以外にmaster ブランチに直接コミットしてはいけない
ルールを違反しているコミットを求めるSQLを示す.出力は,初期コミットとマージコミットを除いて,masterブランチに直接コミットされたものである.
SELECT *
FROM gtDeveloperApp.commit
INNER JOIN gtDeveloperApp.commitParent USING (sha, repoUser, repoName)
WHERE merge = 0
AND parent IS NOT NULL
AND masterCommit = 1;
ルールを遵守しているコミットを求めるSQLを示す.出力は,初期コミットとマージコミットを除いて,masterブランチ以外にコミットされたものである.
SELECT *
FROM gtDeveloperApp.commit
INNER JOIN gtDeveloperApp.commitParent USING (sha, repoUser, repoName)
WHERE merge = 0
AND parent IS NOT NULL
AND masterCommit IS NULL;
4.1.3.2 R2’:すべてのブランチがmaster ブランチから作られている
R2'の判定には,以下のアルゴリズムを使用する.
- Step1:全てのコミットを収集する.
- Step2:Step1で得られたコミットについて,そのコミットを指しているブランチポインタの数,子コミットの数,そのコミットから派生したマージコミットの数,をカウントする.
- Step3:Step1で得られたコミットについて,Step2で得られた数を用いて以下の計算を行う.「そのコミットを指しているブランチポインタの数 + 子コミットの数 - そのコミットから派生したマージコミットの数 - 1」.これはそのコミットから作成されたブランチ数となる.
- Step4:Step3で求めたブランチ作成数が1以上のコミットが,masterブランチに存在するかしないかでR2'の判定を行う.
ルールを違反しているコミットを求めるSQLを示す.出力は,masterブランチ以外のブランチから作成している場合の作成元コミットと,そのコミットから作成されたブランチ数などである.
SELECT *, (childNum + branchTagNum - 1) AS branchNum
FROM (
SELECT *,
(
SELECT COUNT(*)
FROM gtDeveloperApp.commitParent AS par
INNER JOIN gtDeveloperApp.commit USING(sha, repoUser, repoName)
WHERE (merge != 1 OR number = 1)
AND com.sha = par.parent
) AS childNum,
CASE WHEN branchTag IS NULL THEN 0
WHEN branchTag IS NOT NULL THEN CAST((LENGTH(branchTag) - LENGTH(REPLACE(branchTag, ', ', ''))) / LENGTH(', ') + 1 AS UNSIGNED)
END AS branchTagNum
FROM gtDeveloperApp.commit AS com
) AS X
HAVING branchNum >= 1 AND masterCommit IS NULL;
ルールを遵守しているコミットを求めるSQLを示す.出力は,masterブランチから作成している場合の作成元コミットと,そのコミットから作成されたブランチ数などである.
SELECT *, (childNum + branchTagNum - 1) AS branchNum
FROM (
SELECT *,
(
SELECT COUNT(*)
FROM gtDeveloperApp.commitParent AS par
INNER JOIN gtDeveloperApp.commit USING(sha, repoUser, repoName)
WHERE (merge != 1 OR number = 1)
AND com.sha = par.parent
) AS childNum,
CASE WHEN branchTag IS NULL THEN 0
WHEN branchTag IS NOT NULL THEN CAST((LENGTH(branchTag) - LENGTH(REPLACE(branchTag, ', ', ''))) / LENGTH(', ') + 1 AS UNSIGNED)
END AS branchTagNum
FROM gtDeveloperApp.commit AS com
) AS X
HAVING branchNum >= 1 AND masterCommit = 1;
4.1.3.3 R3’:ローカルリポジトリ上に作成したブランチに対するコミットをリモートリポジトリに定期的にプッシュする
前提として,チェックを1時間毎に行い,コミットから24 時間以内にプッシュするものとしてR3’ が運用されているものとする.
ルールを違反しているコミットを求めるSQLを示す.出力は,リポジトリで最初に格納されたコミットを除いて,指定した24時間を超過してプッシュを行ったものである.
SELECT *
FROM gtDeveloperApp.pushCommit
WHERE firstFlag != 1
AND storeDate >= INTERVAL 1 DAY + date;
ルールを遵守しているコミットを求めるSQLを示す.これは,リポジトリで最初に格納されたコミットを除いて,指定した24時間内にプッシュを行ったものである.
SELECT *
FROM gtDeveloperApp.pushCommit
WHERE sha NOT IN (
SELECT sha
FROM gtDeveloperApp.pushCommit
WHERE firstFlag != 1
AND storeDate >= INTERVAL 1 DAY + date
)
AND firstFlag != 1;
4.1.3.4 R4’:master ブランチにマージを行う際には必ずプルリクエストを作成する
ルールを違反しているプルリクエスト及びマージコミット求めるSQLを示す.出力は,masterに対してのマージでプルリクエストを作成していないものである.
SELECT *
FROM gtDeveloperApp.commit
WHERE masterCommit = 1
AND merge = 1
AND sha NOT IN (
SELECT sha
FROM gtDeveloperApp.commit
INNER JOIN gtDeveloperApp.PullRequest USING (sha, repoUser, repoName)
WHERE masterCommit = 1
AND mergeFlag = 1
);
ルールを遵守しているプルリクエスト及びマージコミット求めるSQLを示す.出力は,masterに対してのマージでプルリクエストを作成しているものである.
SELECT *
FROM gtDeveloperApp.commit
INNER JOIN gtDeveloperApp.PullRequest USING (sha, repoUser, repoName)
WHERE masterCommit = 1
AND mergeFlag = 1;
4.1.3.5 R5’:プルリクエストの内容をmaster ブランチにマージする際には必ず第3 者によるレビューを受ける
ルールを違反しているプルリクエスト,プルリクエストのレビューコメント及びマージコミット求めるSQLを示す.出力は,masterに対してのマージのプルリクエストで,マージ前にプルリクエストを作成した人以外のレビューコメントが行われなかったものである.
SELECT *
FROM gtDeveloperApp.commit
INNER JOIN gtDeveloperApp.PullRequest USING (sha, repoUser, repoName)
WHERE masterCommit = 1
AND mergeFlag = 1
AND NOT (repoUser, repoName, pullNumber) IN (
SELECT DISTINCT pr.repoUser, pr.repoName, pr.pullNumber
FROM gtDeveloperApp.PullRequest AS pr
INNER JOIN gtDeveloperApp.PullRequestMessage USING (repoUser, repoName, pullNumber)
INNER JOIN gtDeveloperApp.commit USING (sha, repoUser, repoName)
WHERE mergeFlag = 1
AND masterCommit = 1
AND PullRequestMessage.date < commit.date
AND pr.userName != PullRequestMessage.userName
);
ルールを遵守しているプルリクエスト,プルリクエストのレビューコメント及びマージコミット求めるSQLを示す.出力は,masterに対してのマージのプルリクエストで,マージ前にプルリクエストを作成した人以外のレビューコメントが行われたものである.
SELECT DISTINCT pr.*
FROM gtDeveloperApp.PullRequest AS pr
INNER JOIN gtDeveloperApp.PullRequestMessage USING (repoUser, repoName, pullNumber)
INNER JOIN gtDeveloperApp.commit USING (sha, repoUser, repoName)
WHERE mergeFlag = 1
AND masterCommit = 1
AND PullRequestMessage.date < commit.date
AND pr.userName != PullRequestMessage.userName;
4.2 GitHub Flow遵守状況可視化用Webアプリ
4.2.1 アーキテクチャ
本Webアプリのアーキテクチャを図4.1-1に示す.
図4.2-1 アーキテクチャ
4.1節で格納されたデータベースからGitHub Flow遵守状況をJava及びMyBatis11を使用して取得し,その結果DWR(Direct Web Remoting)12を通してHTML,JavaScript,jQueryを用いて可視化した.また,表示部分のスタイルは,CSS及びCanvsJS13で指定している.
4.2.2 Webアプリのもつ機能
図4.2.1-1に,本Webアプリの各ページ及びページ推移を示す.
図4.2.2-1 各ページ及びページ推移
はじめに表示されているのは,図4.2.2-1の上部にある,リポジトリ,ユーザ,ルールのタブである.リポジトリタブ上にマウスオーバーすると閲覧可能なリポジトリ一覧のリンク表示され,ユーザタブ上では閲覧可能なユーザ名のリンク表示される.ルールタブでは,改定前及び改定後のGitHub Flowの説明14,GitHub Flow遵守状況可視化用Webアプリを解説したページ15へのリンクが表示される.
以降では,リポジトリへのリンク,ユーザへのリンク,各ルールへのリンクをクリックした際に表示されるコンテンツについて述べる.
4.2.2.1 リポジトリ
リポジトリタブからリポジトリを選択すると,選択したリポジトリについてのGitHub Flow遵守状況をリポジトリに参加しているユーザごとに確認することが出来る.なお,違反率は100%積み上げグラフで表示される.また,ルールを違反している場合は,ルール違反の原因となるコミットやプルリクエストへのリンクが表示される.図4.2.2.1-1に,リポジトリ選択後の画面を示す.
図4.2.2.1-1 リポジトリ選択後の画面
4.2.2.2 ユーザ
ユーザタブからユーザを選択すると,選択したユーザが参加している全リポジトリのGitHub Flow遵守状況をリポジトリごとに確認することが出来る.リポジトリ画面と同様,違反率は100%積み上げグラフで表示され,ルール違反があればその原因となるコミットやプルリクエストへのリンクが表示される.図4.2.2.2-1に,ユーザ選択後の画面を示す.
図4.2.2.2-1 ユーザ選択後の画面
4.2.2.3 ルール
ルールタブからGitHub Flowについての説明を選択すると,GitHub Flowの改定前及び改定後の説明が表示される.それぞれのルールについて,どのような行為が違反となるかを図で示した.図4.2.2.3-1に,GitHub Flowについての説明ページの画面を示す.
図4.2.2.3-1 GitHub Flowについての説明ページ
ルールタブから,Webアプリの両方についての説明を選択すると,それぞれのタブで表示されるコンテンツとその説明が表示される.図4.2.2.3-2に,Webアプリの利用法についての説明ページの画面を示す.
図4.2.2.3-2 Webアプリの利用法についての説明ページ
9. コミット履歴の閲覧, https://git-scm.com/book/ja/v1/Git-%E3%81%AE%E5%9F%BA%E6%9C%AC-%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88%E5%B1%A5%E6%AD%B4%E3%81%AE%E9%96%B2%E8%A6%A7 ↩
10. GitHub API v3, https://developer.github.com/v3/ ↩
11. MyBatis, http://www.mybatis.org/mybatis-3/ja/ ↩
12. DWR, http://directwebremoting.org/dwr/index.html ↩
13. CanvasJS, https://canvasjs.com/ ↩
14. GitHub FlowMeeting, https://igakilab.gitbooks.io/devexpprogammanual/content/githubflowmeeting.html ↩
15. WebTool, https://igakilab.gitbooks.io/devexpprogammanual/content/webtool.html ↩