SingerでGitLabのデータをサクッと抜いて可視化してみた
はじめに
こんにちは。テスト自動化アーキテクトの森川です。
本日はETLツールを用いてGitリポジトリから定量的な情報の抽出と可視化をします。リポジトリ管理はGitLab、ETLツールにはSingerを用います。
きっかけ
エンジニアを評価するための参考値としてリポジトリの情報を抽出したい。
クラウド版やエンタープライズ版ならばGitLab謹製の集計機能が使えるようだが、あいにく対象プロダクトはオンプレ・コミュニティ版GitLabだった。
Findy Teamというサービスをご紹介いただいた。とても良さげだったが、これまたオンプレGitLabには対応していないらしい。
(2022/12 記事執筆時点)
これは自力でやってみたほうが早そうだ。
Singerとは
Singerはあらゆるデータを「Taps」と呼ばれるスクリプトで取り込み、「Targets」と呼ばれるスクリプトでDWH(データウェアハウス)に書き込むOSSのETLフレームワーク。
すべてのデータをJson形式でやりとりし、言語はPythonで構成される。
OSS上にさまざまなサービスの「Taps」と「Targets」が公開されていて、エコシステムとして確立している。
singer-io/getting-started: This repository is a getting started guide to Singer.
Tapsにはtap-gitlabを用いてGitLab APIからデータを抽出する。
DWHとしてはpostgtes dbを用意したのでTargetsにはsinger-target-postgresを用いる。
数多あるETLツールからSingerを選んだのは、この手の領域ではPythonの相性がよさそうだと思ったから。それだけです。
構成イメージ
※ BIツールにはMetabaseを採用した。
tap-gitlabで抽出できるAPI
tap-gitlabで抽出できるGitLab APIは限られていて、以下の8本のみ
Branches
Commits
Issues
Projects
Project milestones
Users
Groups
Group Milestones
GitLabの公開APIは大量にあり、MergeRequestやGitlab Runnerまわりなど既に足りない雰囲気。
APIを追加する方法については、あとで少し触れましょう。
環境構築
検証は以下の環境で行った。
環境
WSL : Ubuntu22.02LTS
Python: 3.9.13
singer-python: 5.0.4
tap-gitlab: v0.5.1
target-postgres: 0.2.4
※ postgre dbとmetabaseはそれぞれ起動済
ディレクトリ
├── CHANGELOG.md
├── Dockerfile
├──...
├── config 👈 定義ファイル達が入る
│ ├── config.json
│ └── db-config.json
├── docker-compose.yml
├── setup.cfg
├── setup.py
└── tap_gitlab
├── __init__.py 👈 コアファイル
└── schemas 👈 データスキーマ達が入る
├── branches.json
...
└── users.json
セットアップ
singer-io/tap-gitlabをClone
直接pip installでもインストールできます。git cloneしているのは後で手をいれるため
Dockerfileを作成
FROM python:3.9
USER root
RUN apt-get -y update
RUN apt-get -y install locales vim && \
localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm
RUN pip install strict-rfc3339 \
singer-target-postgres
docker-compose.ymlを作成
version: '3.3'
services:
python3:
restart: always
build: .
container_name: 'singer-gitlab'
working_dir: '/root/opt'
tty: true
volumes:
- $PWD/config:/root/opt/config
- $PWD/tap_gitlab:/root/opt/tap_gitlab
- $PWD/setup.py:/root/opt/setup.py
config/config.jsonにGitLabの情報を記載する
{
"api_url": "GitLab url",
"private_token": "GitLab Access Token",
"groups": "グループ名",
"projects": "プロジェクト名(グループ名/プロジェクト名)",
"start_date": "抽出の下限日"
}
事前に権限付与済のAPI Tokenを取得しておきましょう
グループ名、プロジェクト名は半角スペースで列挙可能
config/db-config.jsonにpostgres DBの接続情報を記載する
{
"postgres_host": "db host",
"postgres_port": 5432,
"postgres_database": "db_name",
"postgres_username": "username",
"postgres_password": "password",
"postgres_schema": "db_schema"
}
インストール
# コンテナ起動
docker-compose up -d
# 中に入る
docker exec -it singer-gitlab bash
# install
cd /root/opt/tap-gitlab
pip install -e .
インストールに成功すると下記のようになります。
Installing collected packages: tap-gitlab
Attempting uninstall: tap-gitlab
Found existing installation: tap-gitlab 0.5.1
Uninstalling tap-gitlab-0.5.1:
Successfully uninstalled tap-gitlab-0.5.1
Running setup.py develop for tap-gitlab
Successfully installed tap-gitlab-0.5.1
データ抽出
まずJson出力してみます。
docker exec -it singer-gitlab sh -c "tap-gitlab -c config/config.json"
InfoログとJsonデータが出力され最後に"INFO Sync complete"となれば正常です。
次にDBに出力します。パイプでtarget-postgresをつなぐだけです。
docker exec -it singer-gitlab sh -c "tap-gitlab -c config/config.json | target-postgres -c config/db-config.json"
postgores db上に12個の新規テーブルが作成されていれば成功。
可視化してみる
Metabaseとpostgres dbを接続して適当にクエリを設定してビジュアライズします。
ETLで生成されるデータベーススキーマはschema内のJsonに準ずるのでそちらを見ながらクエリを組めば良いだけです。
Metabaseの使い方については数多のブログサイトがありますのでそちらをご覧ください。
APIが足りない
コミット数やブランチ数は取得できましたが、肝心のMerge Request情報が無いです。
自力で足してみましょう。
段取りとしては以下の通り。
APIのデータスキーマJsonを作成してschemaに追加
tap_gitlab/__init__.pyにスキーマ定義とAPIをTapするメソッドを追加
その他修正
まずGitLabのMerge Requests APIを直に叩いてスキーマを調べます。
大量のプロパティを持っているので必要なデータのみに絞ります。
tap_gitlab/schema/merge_requests.json
{
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"iid": {
"type": "integer"
},
"project_id": {
"type": "integer"
},
...中略
"merge_when_pipeline_succeeds": {
"type": [
"null",
"boolean"
]
}
}
}
"tap_gitlab/init.py"に追記していきます。
# スキーマ読み込みを追記(L70あたり)
'merge_requests': {
'url': '/projects/{}/merge_requests',
'schema': load_schema('merge_requests'),
'key_properties': ['id'],
},
# API読み込みメソッドの追加(L230 "sync_group"の後ろ)
def sync_merge_request(project):
url = get_url('merge_requests', project['id'])
with Transformer(pre_hook=format_timestamp) as transformer:
for row in gen_request(url):
flatten_id(row, 'merged_by') 👈 ユーザ情報は入れ子なのでフラットなユーザIDに強制変換
flatten_id(row, 'closed_by')
flatten_id(row, 'merge_user')
flatten_id(row, 'assignee')
flatten_id(row, 'author')
transformed_row = transformer.transform(
row, RESOURCES['merge_requests']['schema']
)
if row['updated_at'] >= get_start('project_{}'.format(project['id'])):
singer.write_record(
'merge_requests', transformed_row, time_extracted=utils.now()
)
Metabaseで可視化してみるとこんな感じです。
ここから月別推移や、チーム別の数値を見ていくと、定量的な評価のネタになる気がしますね。
※ コードはGitHubにあげています。本家にもプルリク済。
enabeld to tap merge requests · tomoo-morikawa/tap-gitlab@d46f0b3
ついでにMerge Requetsのchanges APIを用いて変更コード行数をTapする変更も載せておきます。
こちらはMRごとにAPIクエリが実行されるので負荷や所要時間は要注意です。
count change lines on merge request · tomoo-morikawa/tap-gitlab@0e67436
Tapの実装ベストプラクティスについてはこちらに詳しく書かれています。
getting-started/BEST_PRACTICES.md at master · singer-io/getting-started
所感
Singerと公開されているTaps/Targetsを用いることで、データ抽出からDBテーブル生成まで簡単にできることがわかりました。
足りないAPIについてもスキーマJsonと簡単な抽出コードを書くだけなのはお手軽で良いです。
今後の課題としてはDevOpsのFour Keysメトリクスのような複合的な定量値や、複数リポジトリを対象としたデータ抽出(今の仕組みだとDBテーブルの共存ができない。)をしてみたいです。
そのためにはJiraとの連携やCATのようなテスト管理ツールとの連携も必要になりそうです。
今回の構成とは逆に、JiraのダッシュボードにETLで取得したデータを表示させる、なんていうのもありかもしれません。
Singerのエコシステムは250以上のさまざまなサービスと連携可能ですので可能性は広がりますね。
「可視化してみた」と謳っておきながら、Metabaseまわりの説明が薄かったので、そこは次回に記事にてご説明させていただきます。
ご容赦くださいませ。
実運用の際に気をつけたいこと
実行タイミング: cronで定時実行されるようにしたい
断面データ: ETLツールは断面データを可視化できることが強みの一つ。データの種類によっては推移を追いかけるようにカスタマイズしたほうがよいでしょう
負荷: Tap対象にはそれなりの負荷がかかります。時間帯や取得範囲の設定などの配慮が必要でしょう
尚、このあたりのお世話をおまかせできるサービスが世の中にはたくさんあります。
SingerベースだとMeltanoというオールインワンなサービスが公開されています。
参考
お問合せはお気軽に
https://service.shiftinc.jp/contact/
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/
PHOTO:UnsplashのDima Solomin