GitLabのAPIを利用して、ユーザが参照できるプロジェクト一覧を作成する

GitLab上で、誰がどのプロジェクトを参照可能かを一覧化したかったので、GitLabのAPIを利用して一覧化してみます。

GitLab Community Editionを利用して確認しました。

GItLabのAPI

APIの情報は下記ドキュメントにまとまっています。

認証方法はいくつかありますが、今回はPersonal access tokenを利用してアクセスしてみます。Personal access tokenはUser Settingsから作成可能です。

Scopeはapiにしました。

グループメンバーの取得

プロジェクトを参照できるのは、下記の2パターンとなります。

  1. 上位のグループのメンバー
  2. プロジェクトのメンバー

そのため、単にプロジェクトのメンバーの情報だけでアクセス可否が決まるのではなく、グループのメンバーの情報も考慮する必要があります。

ということで、まずはAPIでグループ一覧を取得します。

GET http://gitlab.example.com/api/v4/groups?access_token=<access token>

下記のようにグループ一覧が取得できました。

[
  {
    "id": 5,
    "web_url": "http://gitlab.example.com/groups/group1",
    "name": "group1",
    "path": "group1",
    "description": "",
    "visibility": "private",
    "share_with_group_lock": false,
    "require_two_factor_authentication": false,
    "two_factor_grace_period": 48,
    "project_creation_level": "developer",
    "auto_devops_enabled": null,
    "subgroup_creation_level": "maintainer",
    "emails_disabled": null,
    "lfs_enabled": true,
    "avatar_url": null,
    "request_access_enabled": true,
    "full_name": "group1",
    "full_path": "group1",
    "parent_id": null
  },
  {
    "id": 6,
    "web_url": "http://gitlab.example.com/groups/group2",
    "name": "group2",
    "path": "group2",
    "description": "",
    "visibility": "private",
    "share_with_group_lock": false,
    "require_two_factor_authentication": false,
    "two_factor_grace_period": 48,
    "project_creation_level": "developer",
    "auto_devops_enabled": null,
    "subgroup_creation_level": "maintainer",
    "emails_disabled": null,
    "lfs_enabled": true,
    "avatar_url": null,
    "request_access_enabled": true,
    "full_name": "group2",
    "full_path": "group2",
    "parent_id": null
  }
]

ここからさらにグループのメンバーを取得します。

GET http://gitlab.example.com/api/v4/groups/5/members?access_token=<access token>
[
  {
    "id": 1,
    "name": "Administrator",
    "username": "root",
    "state": "active",
    "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
    "web_url": "http://gitlab.example.com/root",
    "access_level": 50,
    "expires_at": null
  },
  {
    "id": 3,
    "name": "user2",
    "username": "user2",
    "state": "active",
    "avatar_url": "https://www.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=80&d=identicon",
    "web_url": "http://gitlab.example.com/user2",
    "access_level": 30,
    "expires_at": null
  }
]

これを繰り返し取得することによって、各グループのメンバー一覧が作成できます。

プロジェクトメンバーの取得

プロジェクト一覧を取得します。なお、グループから辿っていく方法もありますが、ユーザが持つプロジェクトも含めたかったので、プロジェクト一覧から辿るようにしました。

GET http://gitlab.example.com/api/v4/projects?simple=true&access_token=<access token>

プロジェクト一覧は下記のようになります。

[
  {
    "id": 3,
    "description": "",
    "name": "my-project",
    "name_with_namespace": "Administrator / my-project",
    "path": "my-project",
    "path_with_namespace": "root/my-project",
    "created_at": "2019-11-16T13:48:47.727Z",
    "default_branch": null,
    "tag_list": [],
    "ssh_url_to_repo": "git@gitlab.example.com:root/my-project.git",
    "http_url_to_repo": "http://gitlab.example.com/root/my-project.git",
    "web_url": "http://gitlab.example.com/root/my-project",
    "readme_url": null,
    "avatar_url": null,
    "star_count": 0,
    "forks_count": 0,
    "last_activity_at": "2019-11-16T13:48:47.727Z",
    "namespace": {
      "id": 1,
      "name": "Administrator",
      "path": "root",
      "kind": "user",
      "full_path": "root",
      "parent_id": null,
      "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
      "web_url": "http://gitlab.example.com/root"
    }
  },
  {
    "id": 2,
    "description": "",
    "name": "project-b",
    "name_with_namespace": "group1 / project-b",
    "path": "project-b",
    "path_with_namespace": "group1/project-b",
    "created_at": "2019-11-16T13:48:11.161Z",
    "default_branch": null,
    "tag_list": [],
    "ssh_url_to_repo": "git@gitlab.example.com:group1/project-b.git",
    "http_url_to_repo": "http://gitlab.example.com/group1/project-b.git",
    "web_url": "http://gitlab.example.com/group1/project-b",
    "readme_url": null,
    "avatar_url": null,
    "star_count": 0,
    "forks_count": 0,
    "last_activity_at": "2019-11-16T13:48:11.161Z",
    "namespace": {
      "id": 5,
      "name": "group1",
      "path": "group1",
      "kind": "group",
      "full_path": "group1",
      "parent_id": null,
      "avatar_url": null,
      "web_url": "http://gitlab.example.com/groups/group1"
    }
  },
  {
    "id": 1,
    "description": "",
    "name": "project-a",
    "name_with_namespace": "group1 / project-a",
    "path": "project-a",
    "path_with_namespace": "group1/project-a",
    "created_at": "2019-11-16T13:44:20.849Z",
    "default_branch": null,
    "tag_list": [],
    "ssh_url_to_repo": "git@gitlab.example.com:group1/project-a.git",
    "http_url_to_repo": "http://gitlab.example.com/group1/project-a.git",
    "web_url": "http://gitlab.example.com/group1/project-a",
    "readme_url": null,
    "avatar_url": null,
    "star_count": 0,
    "forks_count": 0,
    "last_activity_at": "2019-11-16T13:44:20.849Z",
    "namespace": {
      "id": 5,
      "name": "group1",
      "path": "group1",
      "kind": "group",
      "full_path": "group1",
      "parent_id": null,
      "avatar_url": null,
      "web_url": "http://gitlab.example.com/groups/group1"
    }
  }
]

ここからさらにプロジェクトのメンバーを取得します。

GET http://gitlab.example.com/api/v4/projects/1/members?access_token=<access token>
[
  {
    "id": 2,
    "name": "user1",
    "username": "user1",
    "state": "active",
    "avatar_url": "https://www.gravatar.com/avatar/111d68d06e2d317b5a59c2c6c5bad808?s=80&d=identicon",
    "web_url": "http://gitlab.example.com/user1",
    "access_level": 40,
    "expires_at": null
  }
]

この情報に、さらに上位のグループのメンバーの情報を付与することによって、プロジェクトにアクセス可能なユーザ一覧を作ることができます。

おわりに

今回調べた情報を元にツールを作成予定です。作成出来たら追記します。

ShortcutKey2URLでショートカット一覧のエクスポート、インポートに対応しました

要望のあったショートカット一覧のエクスポート、インポートに対応しました。

Firefox版(v4.3.0)、Chrome版(v1.3.0)ともに対応しています。(Chrome版は、この記事を書いているタイミングでは審査待ちです)

Firefox版、Chrome版ともにフォーマットは同じですので、相互で移行が可能になりました。

f:id:onozaty:20191028214240p:plain

JavaScriptでファイルのインポート、エクスポートを実装する

Chrome/Firefoxの拡張機能で、設定をインポート、エクスポートする機能が欲しいといった要望があったので、まずはどんな感じにインポート、エクスポートすれば良いんだっけ、、ってことでJavaScriptで簡単なサンプル書いてみました。

コード

下記のようなHTMLを用意します。インポート、エクスポート用のボタンがあって、インポートしたものを表示するエリアを用意しておきます。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <button type="button" id="inputFile">Import</button>
    <pre><code id="contents"></code></pre>
    <button type="button" id="outputFile">Export</button>
    <script src="file.js"></script>
  </body>
</html>

JavaScriptは下記のような感じで。

let currentContents = '';
const displayElement = document.getElementById('contents');

document.getElementById('inputFile').addEventListener('click', (e) => {
  const fileInput = document.createElement('input');
  fileInput.type = 'file';
  fileInput.setAttribute('hidden', true);

  fileInput.addEventListener('change', (e) => {
    const file = e.target.files[0];
  
    const reader = new FileReader();
    reader.onload = (e) => {
      const fileContents = e.target.result;
      displayElement.textContent = fileContents;
      currentContents = fileContents;
    }
    reader.readAsText(file);
  }, false);
  
  document.body.appendChild(fileInput);
  fileInput.click();
  fileInput.remove();
}, false);


document.getElementById('outputFile').addEventListener('click', (e) => {
  const downloadLink = document.createElement('a');
  downloadLink.download = 'export.txt';
  downloadLink.href = URL.createObjectURL(new Blob([currentContents], { 'type' : 'text/plain' }));
  downloadLink.setAttribute('hidden', true);

  document.body.appendChild(downloadLink);
  downloadLink.click();
  downloadLink.remove();
}, false);

インポートのボタンが押下された際に、ファイル選択用のinput要素を生成してclickを呼び出してファイル選択ダイアログを表示させます。
ファイルが選択されたら、それをFileReaderを使って読みだして表示します。

エクスポートのボタンが押下されたら、BlobからURLを生成し、それをリンクとしてa要素を生成してclickといった流れでダウンロードさせています。

Firefoxだとbody配下に入れないとclickが効かないので、body.appendChildしてremoveといったことをやっています。

動作

とりあえずFirefox、Chrome、Edgeの最新バージョンで動作することを確認済みです。

f:id:onozaty:20191014010546g:plain

Redmine: View customize plugin の v2.5.0 をリリースしました

View customize plugin の v2.5.0 をリリースしました。

今回のリリースでの変更点は下記の2つとなります。

ViewCustomize.context にユーザの最終ログイン日時を追加

Pull requestをいただき、ViewCustomize.context.user.lastLoginOnで最終ログイン日時を参照できるようにしました。
利用するシチュエーションはあまり無いのかもしれませんが、下記の問題を対応するために使いたいとのことだったので、今回対応することとしました。

ISO 8601形式の文字列として取得できます。

f:id:onozaty:20191006234414p:plain

APIアクセスキーの自動生成をオプションとして提供

APIアクセスキーの自動生成をオプションとして指定できるようにしました。

プラグインの設定画面から設定できます。

f:id:onozaty:20191006234921p:plain

APIアクセスキーは、個人設定画面のAPIアクセスキーの「表示」リンクを初めて押下したタイミングで生成されます。そのため、View cutomizeでユーザのAPIアクセスキーを使う場合には、各ユーザに操作してもらう必要があったのですが、このオプションをONにすると、存在しない場合に自動で生成するようになるため、各ユーザでの操作は不要になります。

redmine-issue-loader のバージョン2.1.0をリリースしました

CSVを読み込んでRedmineのチケットを新規作成、更新するツール、redmine-issue-loaderのバージョン2.1.0をリリースしました。

対象のフィールドを増やして欲しいとの要望があったので、今回下記のフィールドを追加しました。これで全部対応できたはず、、

  • 担当者
  • 対象バージョン
  • 開始日
  • 期日
  • 進捗率
  • 予定工数
  • プライベート

詳しい利用方法は下記の日本語READMEをご参照ください。

ShortcutKey2URL for Chrome のバージョン1.2.0をリリースしました

ShortcutKey2URL for Chrome のバージョン1.2.0をリリースしました。

ShortcutKey2URL は、ショートカットキーを使用してURLを開いたり、移動したり、JavaScriptを実行できる拡張機能です。

スタートアップキーであらかじめ設定しておいた動作の一覧を表示し、次のキーでその動作を実行します。

f:id:onozaty:20171018003430p:plain

今回のバージョンより、Script欄にjavascriptスキームのまま書けるようになりました。Firefox版で先に対応しているものですが、ブックマークレットの内容をそのまま書く方が多いようで、嵌る人が多かった箇所になります。