- 記事一覧 >
- ブログ記事
GitLab APIを利用した一括ダウンロードWebアプリを作った
はじめに
GitLab API を利用した一括ダウンロードWebアプリを php で作りました。GitHub に公開しています。→ リポジトリ:itc-lab / gitlab-download-app
「Developer's Download Helper」という拡張機能があるのは知っているのですが、過去にさかのぼってダウンロードしたり、.tar.gz でダウンロードしたかったり、他にもこういう仕様であって欲しいというところが出てきて、いっそのこと作ることにしました。
...一番大きいモチベーション → 弊社では、Araxis Merge
というソフトで diff を見てマージするということをよくやっています。一度ダウンロードして、現在、1つ前、2つ前の3者間比較も良くやりますので、素早くダウンロードして比較できるのは助かります。
以降、itc-lab / gitlab-download-appのことを「GitLab-Download-App」と称します。
【特徴】
git コマンドではなく、GUI で以下の事が全てできます。(git の知識は必要ありません。)
・グループ/プロジェクトの全ブランチ、タグ名、Commit 日時を一覧表示できる。
・過去の commit をダウンロードできる。
・.tar.gz または .zip でまとめてダウンロードできる。
・1つ前の commit との差分だけダウンロードができる。
・タグを選択してダウンロードができる。
・commit の内容(メッセージ)を素早く確認できる。
・アーカイブファイルの owner:group を指定してダウンロードできる(.tar.gz の場合)
今後の課題ですが、アカウントによる権限制御は、今のところ仕様にありません。トークンを取得した人の権限で一覧表示、ダウンロードできます。
GitLab-Download-Appは、MITライセンスです。自由に使用、改変していただいても構いませんが、GitLab-Download-Appの使用により、何らかの問題が生じても、一切責任を負いません。
別記事「Ubuntu 20.04.2.0にGitLabをインストール」のようなオンプレミスのGitLabを想定しています。クラウド版GitLabは考慮外です。
構成
Web サーバーは何でも良く、例えば、GitLab が使っている Nginx を利用して、以下のように GitLab 同居でも構いません。
これについて、実現手順は、別記事で紹介しています。→「GitLabバンドルnginxを利用してphpの独自Webアプリを同居させる手順」
仕組み
GitLab API 利用
画面からサーバーに指示を出し、サーバーからのみ GitLab API を利用しています。
これにより、GitLab API トークンが画面に露出することは有りません。
画面から直接 GitLab API を利用する以下の作りの場合、画面を解析するとトークンが分かるため、トークンは、サーバー内に設定し、サーバー内でのみ読み込む作りとしました。
(まずい例)
↓
一覧表示
プロジェクト/commit/タグの一覧情報は、初回表示時に projects.json という全プロジェクト/commit/タグ情報の json を作成して、以降、それを使って表示しています。 そのため、プロジェクト、commit が大量にあると、初回表示だけ時間がかかります。
projects.json の更新は、スクリプト単体でも行えるようにしました。cron で設定できます。
0 * * * * cd /opt/gitlab-download-app/www/html && /usr/bin/php refresh_projects_json.php
cron に設定するスクリプトを以下のように事前に直接実行しておけば、初回表示に時間がかかることは有りません。
# su - www-data -s /bin/bash -c "cd /opt/gitlab-download-app/www/html && /usr/bin/php refresh_projects_json.php"
タグ一覧画面も projects.json を読み込んで表示しています。
projects.json
の自動更新がうまくいっていないと思われる場合は、「最新に更新」ボタンを押すと、projects.json
が強制的に更新されます。
WebHook
projects.json の更新は、WebHook を使って、commit があった時に追加されるようにもしています。
これにより、リポジトリの状況をほぼリアルタイムで追随します。(万一壊れても、cron で仕掛けたrefresh_projects_json.php
により、刷新されます。)
commit 履歴並び順
GitLab API の[GitLab URL]/api/v4/projects/[プロジェクトid]/repository/commits
から取得したコミット履歴順です。(新しい方が一番上)order
パラメータでcommitted_date
などでソートされた結果を得られるのですが、何も指定しない場合、commits API のデフォルトになり、GitLab の画面と同等の結果が得られるようです。
結果、git log --topo-order
の順序に従っているようです。
参考:git log Commit Ordering
ダウンロード
GitLab API の
[GitLab URL]/api/v4/projects/[プロジェクトid]/repository/tree
を再帰的に実行し、パスを把握し、[GitLab URL]/api/v4/projects/[プロジェクトid]/repository/files/[パス]/raw
を使用して、実体ファイルを取得しています。
このとき、[GitLab URL]/api/v4/projects/:id/repository/commits/[コミットID]/diff
で過去までさかのぼって、削除されたことの把握と最終コミット日時を把握し、touch されてダウンロードされるようになっています。
.tar.gz/.zip キャッシュ
.tar.gz/.zip ダウンロードは、特に全体取得の場合、時間がかかります。そのため、同じプロジェクト、commit 日時の場合、GitLab API から取得せず、サーバーに置かれた.tar.gz/.zip を取得するように、キャッシュを持たせる仕組みとしました。
.tar.gz/.zip のファイル名は、gitlab.zip or gitlab.tar.gz 固定です。
「プロジェクト名を含んでダウンロード」にチェックが有る場合、.tar.gz/.zip 作成時に、[プロジェクト名]/ファイル群で圧縮されます。
「プロジェクト名を含んでダウンロード」チェック無し例:
$ unzip -l gitlab.zip
Archive: gitlab.zip
Length Date Time Name
--------- ---------- ----- ----
0 2021-12-13 21:55 app/
0 2021-12-13 21:55 app/views/
0 2021-12-13 21:55 app/views/welcome/
24 2020-12-19 01:28 app/views/welcome/index.html.erb
「プロジェクト名を含んでダウンロード」チェック有り例:
$ unzip -l gitlab.zip
Archive: gitlab.zip
Length Date Time Name
--------- ---------- ----- ----
0 2021-12-13 21:55 TEST Project1/
0 2021-12-13 21:55 TEST Project1/app/
0 2021-12-13 21:55 TEST Project1/app/views/
0 2021-12-13 21:55 TEST Project1/app/views/welcome/
24 2020-12-19 01:28 TEST Project1/app/views/welcome/index.html.erb
ログ
ログは、/tmp
に出力されます。refresh_projects_json.php
以外は、apache 経由で起動するため、systemctl の起動設定がPrivateTmp = true
になっている場合、以下のようなパスに出力されます。
その場合、apache を再起動すると、消えます。
ログパス例:
/tmp/systemd-private-717c61a6a51440c3912e8e8d0fbabc78-apache2.service-WMlg6f/tmp/update_projects_json.log
/tmp/systemd-private-717c61a6a51440c3912e8e8d0fbabc78-apache2.service-WMlg6f/tmp/proxyproc.log
/tmp/systemd-private-717c61a6a51440c3912e8e8d0fbabc78-apache2.service-WMlg6f/tmp/gitlab-download-app.log
インストール方法
php の Web アプリとして動作すれば良く、全くこの通りである必要はありません。
Apache の場合のインストール方法を書きます。
Ubuntu 20.04.2.0 LTSの場合です。CentOS等は手順が異なります。
Apacheとphpのインストールについては、別記事「Ubuntu 20.04.2.0にapache2,php,postgresqlをインストール」で丁寧めに説明していますので、細かい説明は省略して書きます。
ここでは、全て以下のように表記します。
GitLabサーバーFQDN:
gitlab.itccorporation.jp
GitLab Download AppサーバーFQDN:
gitlab-download-app.itccorporation.jp
apacheインストール
timezone とロケールを調整しておきます。
# apt update
# timedatectl set-timezone Asia/Tokyo
# apt install -y language-pack-ja
# update-locale LANG=ja_JP.UTF8
hosts に GitLab-Download-App と GitLab のホスト名を登録します。
# vi /etc/hosts
192.168.12.200 gitlab-download-app.itccorporation.jp
192.168.12.111 gitlab.itccorporation.jp
今回 GitLab-Download-App を/opt/gitlab-download-app/www/html
にインストールするため、DocumentRoot を変更します。
# vi /etc/apache2/sites-available/000-default.conf
ServerName gitlab-download-app.itccorporation.jp
DocumentRoot /var/www/html
↓
DocumentRoot /opt/gitlab-download-app/www/html
# vi /etc/apache2/apache2.conf
<Directory /var/www/>
↓
#<Directory /var/www/>
<Directory /opt/gitlab-download-app/www/>
# systemctl restart apache2
アクセストークン取得
Administrator か、全プロジェクト見られる人で、GitLab(ここでは、http://gitlab.itccorporation.jp/
)にアクセスして、右上のアイコンクリック →Preference をクリックします。
以下の権限のアクセストークンを取得します。
名前: GitLab Download App
(任意)
有効期限日: 未入力
(無期限)
スコープ: read_api
「Create personal access token」をクリックします。
→ 以降、アクセストークン:YRPfTcCL4Brx7YwyhJEo
として進めていきます。
アクセストークンは、二度と表示されなくなりますので、画面を残したままにするか、メモ帳などにコピーペーストしておく必要があります。
GitLab Download Appセットアップ
apache の実行ユーザーを確認します。
# grep -E "APACHE_RUN_(USER|GROUP)" /etc/apache2/envvars
export APACHE_RUN_USER=www-data
export APACHE_RUN_GROUP=www-data
GitLab Download App を/opt/gitlab-download-app/www/html
に配置します。
# mkdir -p /opt/gitlab-download-app/www
# git clone https://github.com/itc-lab/gitlab-download-app.git
# mv gitlab-download-app /opt/gitlab-download-app/www/html
# chown -R www-data:www-data /opt/gitlab-download-app/www/html
GitLab Download App 用のキャッシュディレクトリを作成します。
# mkdir /opt/gitlab-download-app/cache
# chown root:root /opt/gitlab-download-app/cache
# chmod 1777 /opt/gitlab-download-app/cache
設定を調整します。
# vi /opt/gitlab-download-app/www/html/config.json
{
"url": "http://gitlab.itccorporation.jp/",
"ignore_commit_message": [],
"mark_commit_message": [["Merge branch", "*"]],
"ignore_file_name": ["^\\.gitkeep", "^\\.gitignore"],
"cache_projects": 1,
"max_message_length": 500,
"group": "daemon",
"user": "daemon"
}
おのおの以下の意味です。
{
"url": GitLabのURL,
"ignore_commit_message": commitメッセージにこの単語が含まれていた場合、一覧に表示しない。,
"mark_commit_message": commitメッセージにこの単語が含まれている場合、commit日時の前にマークを表示(単語,マークの順セットで記述),
"ignore_file_name": このファイルをダウンロード対象に含めない。,
"cache_projects": 1以外の場合、キャッシュを無効にする。,
"max_message_length": commitメッセージの表示を500文字までとする。,
"group": .tar.gzのgroup,
"user": .tar.gzのuser
}
アクセストークンを設定します。
# vi /opt/gitlab-download-app/www/html/function.inc
define("ACCESS_TOKEN", "YRPfTcCL4Brx7YwyhJEo");
プロジェクト/commit 一覧のキャッシュファイル/opt/gitlab-download-app/cache/projects.json
を作成しておきます。
# su - www-data -s /bin/bash -c "cd /opt/gitlab-download-app/www/html && /usr/bin/php refresh_projects_json.php"
※初回アクセスで作成しても良いです。
プロジェクト/commit 一覧のキャッシュファイル更新処理を crontab に登録します。
# crontab -u www-data -e
0 * * * * cd /opt/gitlab-download-app/www/html && /usr/bin/php refresh_projects_json.php
System Hooks 設定
プロジェクトごとに WebHook を設定できますが、全体に効くように System Hooks を使います。
【 WebHook 】
「WebHook」とは、データ更新などのイベントが発生したら、外部のアプリやサービスに通知を送り、連携する仕組みのことです。「WebHook」は、GitLabに限らない用語で、「System Hooks」の方は、GitLab用語でシステム全体のイベントを捉えるWebHookのことのようです。
管理者エリア → システムフック にて
URL: http://gitlab-download-app.itccorporation.jp/update_projects_json.php
Secret token: 空白
トリガー: プッシュイベント
とTag push events
SSL verification: Enable SSL verificationチェック無し
とし、「システムフックの追加」ボタンをクリックします。
これにより、projectcs.json
がプロジェクト作成、commit、push に追随し、常に、GitLab の状態= GitLab Download App の状態になります。
万が一追随しきれなかった場合、crontab のrefresh_projects_json.php
にて GitLab の状態= GitLab Download App の状態になります。
利用例
おまけ
WebHook のところで、システムフックを登録する手順がありますが、最初、プロジェクト全てに WebHook の設定をしていかないといけないと思いました。
結局、システムフック1個登録するだけでしたが、プロジェクト全てに WebHook の設定ができるツールを作成しましたので、gist.githubに公開しました。
PHP 版:https://gist.github.com/itc-lab/dd3635dabae2bbfc633c9cbf1323d251
Python 版:https://gist.github.com/itc-lab/357ad01f5fbc5ea6929109784198913d
PHP 版:
# php gitlab-add-hook.php testgroup1/test-project1
Python 版:
# python3 gitlab-add-hook.py testgroup1/test-project1
とすると、プロジェクトtestgroup1/test-project1
に WebHook が登録されます。登録される WebHook の内容は、ソースコードに直書きです。
引数は、プロジェクトの name space です。
引数無しの場合、全プロジェクトに同じ WebHook が登録されます。
トークンのスコープは、"api"が必要です。"read_api"では登録できません。
その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。