1. 記事一覧 >
  2. ブログ記事
category logo

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」と称します。


「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は考慮外です。


構成

構成は以下です。
GitLab-Download-App 構成図


Web サーバーは何でも良く、例えば、GitLab が使っている Nginx を利用して、以下のように GitLab 同居でも構いません。
GitLab-Download-App GitLab同居 構成図

これについて、実現手順は、別記事で紹介しています。→「GitLabバンドルnginxを利用してphpの独自Webアプリを同居させる手順


仕組み

GitLab API 利用

画面からサーバーに指示を出し、サーバーからのみ GitLab API を利用しています。
これにより、GitLab API トークンが画面に露出することは有りません。
GitLab APIトークンが画面に露出することは有りません 図


画面から直接 GitLab API を利用する以下の作りの場合、画面を解析するとトークンが分かるため、トークンは、サーバー内に設定し、サーバー内でのみ読み込む作りとしました。
(まずい例)

画面から直接GitLab APIを利用する 図


一覧表示

プロジェクト/commit/タグの一覧情報は、初回表示時に projects.json という全プロジェクト/commit/タグ情報の json を作成して、以降、それを使って表示しています。 そのため、プロジェクト、commit が大量にあると、初回表示だけ時間がかかります。

プロジェクト/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の自動更新がうまくいっていないと思われる場合は、「最新に更新」ボタンを押すと、projects.jsonが強制的に更新されます。


WebHook

projects.json の更新は、WebHook を使って、commit があった時に追加されるようにもしています。
WebHook 図

これにより、リポジトリの状況をほぼリアルタイムで追随します。(万一壊れても、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

commit履歴並び順 図


ダウンロード

GitLab API の [GitLab URL]/api/v4/projects/[プロジェクトid]/repository/tree
を再帰的に実行し、パスを把握し、
[GitLab URL]/api/v4/projects/[プロジェクトid]/repository/files/[パス]/raw
を使用して、実体ファイルを取得しています。

「GitLab-Download-App」


ダウンロード 図


このとき、
[GitLab URL]/api/v4/projects/:id/repository/commits/[コミットID]/diff
で過去までさかのぼって、削除されたことの把握と最終コミット日時を把握し、touch されてダウンロードされるようになっています。

削除されたことの把握と最終コミット日時を把握し、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 をクリックします。
右上のアイコンクリック→Preferenceをクリック


アクセストークンをクリックします。
アクセストークンをクリック


以下の権限のアクセストークンを取得します。
名前: GitLab Download App(任意)
有効期限日: 未入力(無期限)
スコープ: read_api
「Create personal access token」をクリックします。
「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"では登録できません。

loading...