GitLab API 利用
Personal Access Token を利用して GitLab API をたたく方法メモ と golang で実際に GitLab API を利用するサンプル。
GitLab API
Personal Access Token
GitLab API を利用するためにまずは Personal Access Token を取得する。取得方法は、こちらがとても分かりやすい。Personal Access Token は HTTPリクエストのヘッダか URL Query に埋め込んで利用する。
$ curl https://gitlab.example.com/api/v4/projects?private_token=<your_access_token>
or
$ curl --header "Private-Token: <your_access_token>" https://gitlab.example.com/api/v4/projects
URL など
URL(API v4)
-
["https://" + [GitLabのHost] + "/api/v4/"] から始まるURLを利用。
その後ろに "projects/:id/" とか "groups/:id/" とかで続けると id 指定したprojectやgroupの情報をGETしたり、POSTでそのprojectやgroupの操作ができる。
Group and project members API
注意:取得できるレコード数 (19/5/30 追記)
pagination により、デフォルトで取得できるレコード数が 20 の場合があるので注意。
$ curl --header "Private-Token: <your_access_token>" https://gitlab.example.com/api/v4/projects/
上記だと、Token を作成したユーザがアクセスできる Project 数が 20 より多い場合、全ての情報が取得できず 20 個までしか情報を取得できない。全ての情報を取得するには、URLクエリーに page=n (n は 1 から始まる) を指定して JSON 配列が空になるまで n をインクリメントするなどが必要となる。
$ curl --header "Private-Token: <your_access_token>" https://gitlab.example.com/api/v4/projects/page=1
$ curl --header "Private-Token: <your_access_token>" https://gitlab.example.com/api/v4/projects/page=2
$ curl --header "Private-Token: <your_access_token>" https://gitlab.example.com/api/v4/projects/page=3
...
projects, gorups の [:id]
id には int かパス形式の string を指定することが可能。
- int型の id: Webブラウザ でGitLabにアクセスすると確認できる。(Projectのページを開くと表示される Project ID が該当。)
- string型の id: 例えば、"hoge/foo/bar" という階層構造の "bar" を指定したい場合 "/" を "%2F" に置換した値 ("hoge%2Ffoo%2Fbar") を利用。
"https://" + [GitLabのHost] + "/api/v4/projects/hoge%2Ffoo%2Fbar"
FireFoxなどのWebブラウザで、上記の URL にアクセスすると GET で返される JSON形式が確認できる。
curlで確認
$ curl https://gitlab.com/api/v4/projects/tsuyuzaki%2Ftsuyu_p1?private_token=abcdefghijk
{"id":11704151,"description":"","name":"tsuyu_p1","name_with_namespace":"tsuyuzaki / tsuyu_p1","path":"tsuyu_p1","path_with_namespace":"tsuyuzaki/tsuyu_p1","created_at":"2019-04-05T23:47:52.231Z","default_branch":null,"tag_list":[],"ssh_url_to_repo":"git@gitlab.com:tsuyuzaki/tsuyu_p1.git","http_url_to_repo":"https://gitlab.com/tsuyuzaki/tsuyu_p1.git","web_url":"https://gitlab.com/tsuyuzaki/tsuyu_p1","readme_url":null,"avatar_url":null,"star_count":0,"forks_count":0,"last_activity_at":"2019-04-05T23:47:52.231Z","namespace":{"id":4955386,"name":"tsuyuzaki","path":"tsuyuzaki","kind":"user","full_path":"tsuyuzaki","parent_id":null},"_links":{"self":"https://gitlab.com/api/v4/projects/11704151","issues":"https://gitlab.com/api/v4/projects/11704151/issues","merge_requests":"https://gitlab.com/api/v4/projects/11704151/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/11704151/repository/branches","labels":"https://gitlab.com/api/v4/projects/11704151/labels","events":"https://gitlab.com/api/v4/projects/11704151/events","members":"https://gitlab.com/api/v4/projects/11704151/members"},"archived":false,"visibility":"private","owner":{"id":3803336,"name":"tsuyuzaki","username":"tsuyuzaki","state":"active","avatar_url":"https://secure.gravatar.com/avatar/c03b2bddcaa4fb6d943e72ab23964a0f?s=80\u0026d=identicon","web_url":"https://gitlab.com/tsuyuzaki"},"resolve_outdated_diff_discussions":false,"container_registry_enabled":true,"issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":3803336,"import_status":"none","import_error":null,"open_issues_count":0,"runners_token":"WibD8zxQ-WsTjk1FmAZU","public_jobs":true,"ci_config_path":null,"shared_with_groups":[{"group_id":4958170,"group_name":"tsuyu_group","group_full_path":"tsuyu_group","group_access_level":30,"expires_at":null}],"only_allow_merge_if_pipeline_succeeds":false,"request_access_enabled":false,"only_allow_merge_if_all_discussions_are_resolved":false,"printing_merge_request_link_enabled":true,"merge_method":"merge","permissions":{"project_access":{"access_level":40,"notification_level":3},"group_access":null},"mirror":false,"external_authorization_classification_label":""}
Project に Member として Group 追加するPOST の例
こちらを参照。
- URL: "https://"+host+"/api/v4/projects/"+[:id]+"/share"
-
Body(JSON): {id: string or int, group_id: int, group_access: int, expires_at: string}
- group_access は 10,20,30,40,50 のいずれか。expires_at は指定しなくてもよい。
{"id":"tsuyuzaki%2Ftsuyu_p1","group_id":4958170,"group_access":30,"expires_at":""}
サンプル
以下のサンプルを作成。
- Group が Member に追加されている Project 一覧を取得するサンプル
- 複数 Group、複数 User を Member として一括登録するサンプル
Group が Member に追加されている Project 一覧を取得するサンプル
引数に Personal Access Token と Group の URL を渡すと指定した Group が Member に追加されている ProjectURL の一覧を取得するコード。
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"strings"
)
type Node struct {
ID int
WebURL string `json:"web_url"`
}
type GroupInfo struct {
SharedProjects []*Node `json:"shared_projects"`
}
func main() {
if len(os.Args) != 3 {
fmt.Println("Please input your token and GroupURL.")
return
}
url, err := url.Parse(os.Args[2])
if err != nil {
fmt.Fprintf(os.Stderr, "url.Parse error [%v]", err)
return
}
prjID, ok := toStrID(url.Path)
if !ok {
return
}
req, err := http.NewRequest(
"GET",
"https://"+url.Host+"/api/v4/groups/"+prjID,
nil)
if err != nil {
fmt.Fprintf(os.Stderr, "http.NewRequest error[%v]\n", err)
return
}
req.Header.Set("Private-Token", os.Args[1])
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Fprintf(os.Stderr, "client.Do error[%v]\n", err)
return
}
defer resp.Body.Close()
var result GroupInfo
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
fmt.Fprintf(os.Stderr, "Decode error[%v]\n", err)
return
}
for _, p := range result.SharedProjects {
fmt.Println(p.WebURL)
}
}
func toStrID(path string) (string, bool) {
if path == "" {
fmt.Println("Invalid Path")
return "", false
}
if path[0] == '/' {
return strings.Replace(path[1:], `/`, `%2F`, -1), true
} else {
return strings.Replace(path, `/`, `%2F`, -1), true
}
}
実行
$ go build getprjs.go
$ getprjs.exe xyzabcdefg https://gitlab.com/tsuyu_group
https://gitlab.com/tsuyuzaki/tsuyu_p1
複数 Group、複数 User を Member として一括登録するサンプル
サンプル
以下の2つの機能を有します。
- 複数 User を、複数の Group に Member として一括登録する。
- 複数 Group を、複数の Project に Member として一括登録する。
実行
ExcelがインストールされたWindows上で実行してください。
$ go build postto.go
$ postto.exe [g or p] <Personal Access Token>
- 第一引数に g 指定すると 1. の機能が、p 指定すると 2. の機能が利用できます。
- posttoを実行すると、groups.csv または、users.csv というファイルが Excel で開かれるので、以下の形式の CSV を記述してください。(# から始まる行は読み飛ばします。)
- プログラム実行ディレクトリに groups/users.csv というファイルがなければ作成し、ファイルが存在すれば、その CSV ファイルが開かれます。
[Group1のURL],[AccessLevel(10/20/30 or 40)],[UserName1],[UserName2],...
[Group2のURL],[AccessLevel(10/20/30 or 40)],[UserName1],[UserName2],[UserName3],...
...
CSV を上書きして、Excelを閉じると、各行の Group に、同一の行で指定された AccessLevel の Role で User が一括で追加されます。
[Project1のURL],[GroupAccess(10/20/30/40 or 50)],[Group1のURL],[Group2のURL],...
[Project2のURL],[GroupAccess(10/20/30/40 or 50)],[Group1のURL],[Group2のURL],[Group3のURL],...
...
CSV を上書きして、Excelを閉じると、各行の Project の Member に、同一の行で指定された GroupAccess の Role で Group が一括で追加されます。
Role の詳細はこちら参照。
10 => Guest access
20 => Reporter access
30 => Developer access
40 => Maintainer access
50 => Owner access # Only valid for groups