更新履歴
・[2016/09/26] 記事公開
・[2017/04/17] APIに変更があったので一通りチェックして更新
2016/10/28にリポジトリ単位だけでなくOrganization単位でプロジェクトを作ることができるようになっていました。
Introducing Projects for Organizations
(実はこの記事書いたもののまだ実用はしていなかったので知らなかったです。)
それに伴ってプロジェクトの取得方法などが変わっています。
どこがどう変わったかについては編集履歴を参照してください。
はじめに
2016/9/15にGitHubで大型アップデートがありましたね。
早速その中のProjectsを使ってみました。
プルリクをカード化してカラムに並べて置けるので、例えばプルリクの進捗を管理するのに良さそうです。
(もともとラベルで進捗を管理していますが、全体を見通すことはできていませんでした。)
ですが、例えばカードを移動させた時に通知してくれるような機能は今の所ないようなので、アクセスしないことには状況がわかりません。
そこで、とりあえずGitHub APIにProject用のAPIがないか探してみたらありました。
(ただし2017/4/17現在も試験運用中のため、今後も機能追加・変更の可能性があります。)
Preview the new Projects API | GitHub Developer Guide
Projects | GitHub Developer Guide
今までGitHub APIを使ったことない私ですが、Projects APIを使って何ができるか試してみます。
使用言語
Google Apps Scriptを使って試してみようと思います。
(GASのサーバーレスで自動実行可能なところ好きです。)
GitHub APIを使うための準備
Personal Access Tokensにアクセスしてトークンを取得します。
(なんかすでに4か月前にHelp example
のトークンを取得済みのようですが、心当たりがありません・・・;)
とりあえずGenerate new token
を押します。
トークンの説明を入力してスコープを選択したら、最後にあるGenerate token
を押します。
(私は今後他のことにも使うかもしれないと思ったので、とりあえず全てにチェックを入れておきました。)
するとトークンが表示されます。
クリップボードのアイコンを押すとコピーされます。
これで準備完了です。
次から早速使ってみたいと思います。
プロジェクトのCRUD
一部OrganizaitonのものかリポジトリのものかによってAPIパスや取得内容が異なる。
実行コード例
リポジトリプロジェクト一覧取得
List repository projects
リポジトリプロジェクト一覧を取得できる。
function getProjectList() {
var header = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"headers" : headers
}
var url = "https://api.github.com/repos/オーナー名/リポジトリ名/projects?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
Organizationプロジェクト一覧取得
List organization projects
Organizationプロジェクト一覧を取得できる。
function getProjectList() {
var header = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"headers" : headers
}
var url = "https://api.github.com/orgs/Organization名/projects?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
プロジェクト取得
List a project
Organizaiton/リポジトリ問わず指定したプロジェクトIDのプロジェクトを取得できる。
存在しないIDを指定すると404が返ってくる。
参加していない団体のものも同様?
function getProject() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"headers" : headers
}
var url = "https://api.github.com/projects/プロジェクトID?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
リポジトリプロジェクト作成
Create a repository projectt
payloadでJSONを渡せばプロジェクトの作成ができる。
nameは必須だがbodyはなくても良い。
(これはブラウザで作成する時も同様。)
function createProject() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"name": "プロジェクトタイトル",
"body": "説明"
});
var options = {
"method" : "POST",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/repos/オーナー名/リポジトリ名/projects?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
Organizationプロジェクト作成
Create a organization projectt
payloadでJSONを渡せばプロジェクトの作成ができる。
nameは必須だがbodyはなくても良い。
(これはブラウザで作成する時も同様。)
function createProject() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"name": "プロジェクトタイトル",
"body": "説明"
});
var options = {
"method" : "POST",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/orgs/Organization名/projects?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
プロジェクト更新(タイトル・説明変更/close/open)
Update a project
Organizaiton/リポジトリ問わずpayloadでJSONを渡せばプロジェクトの更新ができる。
作成はPOST
だったが更新はPATCH
。
キーは全て任意。(キーがないJSONや存在しないキーを含むJSONでもOK)
存在しないIDを指定すると404が返ってくる。
参加していない団体のものも同様?
close済みプロジェクトを再度closeしようとしてもエラーにはならない。
(openも同様)
ちなみにclose済みプロジェクトに対する操作はWeb・API共に可能。
キー | 値 |
---|---|
name | プロジェクトタイトル |
body | 説明 |
state | プロジェクトのステータス open もしくは closed それ以外を指定すると422になる |
function createProject() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"name": "プロジェクトタイトル",
"body": "説明",
"status": "ステータス"
});
var options = {
"method" : "POST",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/projects/プロジェクトID?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
指定例と実行結果
name | body | state | 実行結果 |
---|---|---|---|
同じ | 同じ | 同じ | 何も変わらず |
違う | 違う | 違う | 全て変わる |
同じ | 違う | 同じ | 説明だけ変わる |
同じ | 違う | なし | 説明だけ変わる |
なし | 違う | なし | 説明だけ変わる |
なし | 違う | 同じ | 説明だけ変わる |
違う | なし | なし | タイトルだけ変わる |
なし | なし | 違う | ステータスだけ変わる |
なし | 違う | 違う | 説明とステータスが変わる |
違う | なし | 違う | タイトルとステータスが変わる |
プロジェクト削除
Delete a project
Organizaiton/リポジトリ問わずIDを指定してDELETEで実行するとプロジェクトを削除できる。
削除したIDとOrganizationもしくはリポジトリでの番号は永久欠番になり、そのプロジェクトへアクセスしようとすると404になる。
また、APIで存在しないIDなどを指定しても404が返ってくる。
参加していない団体のものも同様?
function deleteProject() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"method" : "DELETE",
"headers" : headers
}
var url = "https://api.github.com/projects/プロジェクトID?access_token=取得したトークン";
UrlFetchApp.fetch(url, options);
}
取得できるリポジトリプロジェクトの内容
リポジトリプロジェクトの情報、下記JSON。
一覧の場合はそれの配列で削除の場合は何もなし。
リポジトリのプロジェクトを作成した人の情報豊富。
(ただしほぼAPIのURL)
最終更新日時はタイトルや説明の更新だけでなく、そのプロジェクト内のカラムやカードに対してCRUDを実行した場合も含む。
{
"owner_url":"https://api.github.com/repos/オーナー名/リポジトリ名",
"url":"https://api.github.com/repos/sen-corporation/オーナー名/projects/リポジトリ内でのプロジェクト番号",
"id":プロジェクトID,
"name":"プロジェクトタイトル",
"body":"説明",
"number":リポジトリ内でのプロジェクト番号,
"creator":{
"login":"作成者のアカウント名",
"id":作成者のID,
"avatar_url":"https://avatars1.githubusercontent.com/u/作成者のID?v=3",
"gravatar_id":"",
"url":"https://api.github.com/users/作成者のアカウント名",
"html_url":"https://github.com/作成者のアカウント名",
"followers_url":"https://api.github.com/users/作成者のアカウント名/followers",
"following_url":"https://api.github.com/users/作成者のアカウント名/following{/other_user}",
"gists_url":"https://api.github.com/users/作成者のアカウント名/gists{/gist_id}",
"starred_url":"https://api.github.com/users/作成者のアカウント名/starred{/owner}{/repo}",
"subscriptions_url":"https://api.github.com/users/作成者のアカウント名/subscriptions",
"organizations_url":"https://api.github.com/users/作成者のアカウント名/orgs",
"repos_url":"https://api.github.com/users/作成者のアカウント名/repos",
"events_url":"https://api.github.com/users/作成者のアカウント名/events{/privacy}",
"received_events_url":"https://api.github.com/users/作成者のアカウント名/received_events",
"type":"User",
"site_admin":サイト管理者かどうか
},
"created_at":"作成日時(ISO 8601形式 UTC)",
"updated_at":"更新日時(ISO 8601形式 UTC)"
}
取得できる Organizationプロジェクトの内容
Organizationプロジェクトの情報、下記JSON。
一覧の場合はそれの配列で削除の場合は何もなし。
リポジトリのプロジェクトを作成した人の情報豊富。
(ただしほぼAPIのURL)
最終更新日時はタイトルや説明の更新だけでなく、そのプロジェクト内のカラムやカードに対してCRUDを実行した場合も含む。
{
"owner_url":"https://api.github.com/orgs/Organization名",
"url":"https://api.github.com/projects/プロジェクトID",
"html_url":"https://github.com/orgs/Organization名/projects/Organization内でのプロジェクト番号",
"columns_url":"https://api.github.com/projects/プロジェクトID/columns",
"id":プロジェクトID,
"name":"プロジェクトタイトル",
"body":"説明",
"number":Organization内でのプロジェクト番号,
"creator":{
"login":"作成者のアカウント名",
"id":作成者のID,
"avatar_url":"https://avatars1.githubusercontent.com/u/作成者のID?v=3",
"gravatar_id":"",
"url":"https://api.github.com/users/作成者のアカウント名",
"html_url":"https://github.com/作成者のアカウント名",
"followers_url":"https://api.github.com/users/作成者のアカウント名/followers",
"following_url":"https://api.github.com/users/作成者のアカウント名/following{/other_user}",
"gists_url":"https://api.github.com/users/作成者のアカウント名/gists{/gist_id}",
"starred_url":"https://api.github.com/users/作成者のアカウント名/starred{/owner}{/repo}",
"subscriptions_url":"https://api.github.com/users/作成者のアカウント名/subscriptions",
"organizations_url":"https://api.github.com/users/作成者のアカウント名/orgs",
"repos_url":"https://api.github.com/users/作成者のアカウント名/repos",
"events_url":"https://api.github.com/users/作成者のアカウント名/events{/privacy}",
"received_events_url":"https://api.github.com/users/作成者のアカウント名/received_events",
"type":"User",
"site_admin":サイト管理者かどうか
},
"created_at":"作成日時(ISO 8601形式 UTC)",
"updated_at":"更新日時(ISO 8601形式 UTC)"
}
カラムのCRUD
Organizaiton/リポジトリ問わず同じ方法で実行できる。
実行コード例
カラム一覧取得
List project columns
プロジェクトIDを指定してカラム一覧を取得できる。
function getColmunList() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"headers" : headers
}
var url = "https://api.github.com/projects/プロジェクトID/columns?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
カラム取得
Get a project column
カラムIDを指定してカラムを取得できる。
プロジェクト番号等の指定は不要。
IDはカラム一覧から取得できる。
IDはGitHub全体でユニークな値が設定されている。
function getColumn() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"headers" : headers
}
var url = "https://api.github.com/projects/columns/カラムID?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
カラム作成
Create a column
payloadでJSONを渡せばカラムの作成ができる。
function createColumn() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"name": "カラム名"
});
var options = {
"method" : "POST",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/projects/プロジェクトID/columns?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
カラム更新
Update a column
payloadでJSONを渡せばカラムの更新ができる。
作成はPOSTだったが更新はPATCH。
存在しないIDを指定すると404が返ってくる。
参加していない団体のものも同様?
function updateColumn() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"name": "新しいカラム名"
});
var options = {
"method" : "PATCH",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/projects/columns/カラムID?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
カラム削除
Delete a column
カラムIDを指定してDELETEで実行するとカラムを削除できる。
存在しないIDを指定すると404が返ってくる。
参加していない団体のものも同様?
function deleteColumn() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"method" : "DELETE",
"headers" : headers
}
var url = "https://api.github.com/projects/columns/カラムID?access_token=取得したトークン";
UrlFetchApp.fetch(url, options);
}
カラム移動
Move a column
positionを指定してカラムを移動できる。
afterに指定するカラムIDは当然同じプロジェクトのものでないといけない。
指定できる値 | 概要 |
---|---|
first | 先頭に移動 |
last | 最後に移動 |
after:カラムID | カラムIDの後に移動 |
function moveColumns() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"position": "after:カラムID"
});
var options = {
"method" : "POST",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/projects/columns/カラムID?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
取得できるデータ
カラムの情報、下記JSON。
一覧の場合はそれの配列で削除の場合は何もなし、移動の場合は空JSON。
カラムを作成した人の情報は入っていない。
最終更新日時はnameの更新だけでなく、そのカラム内のカードに対してCRUDを実行した場合も含む。
{
"url":"https://api.github.com/projects/columns/カラムID",
"project_url":"https://api.github.com/projects/プロジェクトID",
"cards_url":"https://api.github.com/projects/columns/プロジェクトID/cards",
"id":カラムID,
"name":"カラム名",
"created_at":"作成日時(ISO 8601形式 UTC)",
"updated_at":"最終更新日時(ISO 8601形式 UTC)"
}
カードのCRUD
Organizaiton/リポジトリ問わず同じ方法で実行できる。
実行コード
カード一覧取得
List project cards
指定したカラムIDにあるカード一覧を取得できる。
function getCardList() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"headers" : headers
}
var url = "https://api.github.com/projects/columns/カラムID/cards?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
カード取得
List a project card
指定したカードIDの情報を取得できる。
プロジェクトIDやカラムID等の指定は不要。
IDは一覧から取得できる。
IDはGitHub全体でユニークな値が設定されている。
function getCard() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"headers" : headers
}
var url = "https://api.github.com/projects/columns/cards/カードID?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
カード作成
Create a project card
payloadでJSONを渡せばプロジェクトの作成ができる。
キーはnoteもしくはcontent_idとcontent_typeを指定する。
issueやプルリクのIDはそれぞれのAPIより取得できる。
Pull Requests | GitHub Developer Guide
Issues | GitHub Developer Guide
キーの指定を間違えると422が返ってくる。
noteとcontent_*を同時に指定することはできない。
誤ったcontent_idを指定しているとnoteを指定しないことはできないと言われる。
(私は番号を指定してしてエラーになって悩んでしまった。)
キー | 値 |
---|---|
note | ノートやタイトル |
content_id | issueID もしくは プルリクID |
content_type | "Issue" もしくは "PullRequest" |
function createCard() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"note": "ノートやタイトル"
});
var options = {
"method" : "POST",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/projects/columns/カラムID/cards?access_token=取得したトークン";
return JSON.parse(UrlFetchApp.fetch(url, options));
}
カード更新
Update a project card
指定したカードIDのnoteを書き換えることができる。
一応issueやプルリクのカードのnoteも書き換えることができる、
IDは一覧から取得できる。
function updateCard() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"note" : "新しいノートやタイトル"
});
var options = {
"method" : "PATCH",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/projects/columns/cards/カードID?access_token=取得したトークン";
var project = JSON.parse(UrlFetchApp.fetch(url, options));
Logger.log(JSON.stringify(project));
}
カード削除
Delete a project card
カードIDを指定してDELETEで実行するとカードを削除できる。
issueやプルリクのカードを削除しても、プロジェクトに載らなくなるだけでそれ自体が削除されるわけではない。
存在しない番号やリポジトリに関係ない番号を指定しても404が返ってくる。
function deleteCard() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var options = {
"method" : "DELETE",
"headers" : headers
}
var url = "https://api.github.com/projects/columns/cards/カードID?access_token=取得したトークン";
UrlFetchApp.fetch(url, options);
}
カード移動
Move a project card
positionやcolmun_idを指定してカラムを移動できる。
afterに指定するカードIDは当然同じプロジェクトのものでないといけない。
positionは必須だがcolmun_idはなくても良い。
キー | 値 |
---|---|
position | top, buttom, after:カードID |
colmun_id | 移動先のカラムID |
function moveColumns() {
var headers = {
"Accept" : "application/vnd.github.inertia-preview+json"
};
var payload = JSON.stringify({
"position" : "top",
"column_id" : カラムID
});
var options = {
"method" : "POST",
"headers" : headers,
"payload" : payload
}
var url = "https://api.github.com/projects/columns/cards/カードID/moves?access_token=取得したトークン";
UrlFetchApp.fetch(url, options);
}
取得できるデータ
カードの情報、下記JSON。
一覧の場合はそれの配列で削除の場合は何もなし、移動の場合は空JSON。
カードを作成した人の情報豊富。
(ただしほぼAPIのURL)
{
"url":"https://api.github.com/projects/columns/cards/カードID",
"column_url":"https://api.github.com/projects/columns/カラムID",
"id":カードID,
"note":"ノートやタイトル",
"creator":{
"login":"作成者のアカウント名",
"id":作成者のID,
"avatar_url":"https://avatars1.githubusercontent.com/u/作成者のID?v=3",
"gravatar_id":"",
"url":"https://api.github.com/users/作成者のアカウント名",
"html_url":"https://github.com/作成者のアカウント名",
"followers_url":"https://api.github.com/users/作成者のアカウント名/followers",
"following_url":"https://api.github.com/users/作成者のアカウント名/following{/other_user}",
"gists_url":"https://api.github.com/users/作成者のアカウント名/gists{/gist_id}",
"starred_url":"https://api.github.com/users/作成者のアカウント名/starred{/owner}{/repo}",
"subscriptions_url":"https://api.github.com/users/作成者のアカウント名/subscriptions",
"organizations_url":"https://api.github.com/users/作成者のアカウント名/orgs",
"repos_url":"https://api.github.com/users/作成者のアカウント名/repos",
"events_url":"https://api.github.com/users/作成者のアカウント名/events{/privacy}",
"received_events_url":"https://api.github.com/users/作成者のアカウント名/received_events",
"type":"User",
"site_admin":サイト管理者かどうか
},
"created_at":"作成日時(ISO 8601形式 UTC)",
"updated_at":"最終更新日時(ISO 8601形式 UTC)"
}
{
"url":"https://api.github.com/projects/columns/cards/カードID",
"column_url":"https://api.github.com/projects/columns/カラムID",
"id":カードID,
"note":null,
"creator":{
"login":"作成者のアカウント名",
"id":作成者のID,
"avatar_url":"https://avatars1.githubusercontent.com/u/作成者のID?v=3",
"gravatar_id":"",
"url":"https://api.github.com/users/作成者のアカウント名",
"html_url":"https://github.com/作成者のアカウント名",
"followers_url":"https://api.github.com/users/作成者のアカウント名/followers",
"following_url":"https://api.github.com/users/作成者のアカウント名/following{/other_user}",
"gists_url":"https://api.github.com/users/作成者のアカウント名/gists{/gist_id}",
"starred_url":"https://api.github.com/users/作成者のアカウント名/starred{/owner}{/repo}",
"subscriptions_url":"https://api.github.com/users/作成者のアカウント名/subscriptions",
"organizations_url":"https://api.github.com/users/作成者のアカウント名/orgs",
"repos_url":"https://api.github.com/users/作成者のアカウント名/repos",
"events_url":"https://api.github.com/users/作成者のアカウント名/events{/privacy}",
"received_events_url":"https://api.github.com/users/作成者のアカウント名/received_events",
"type":"User",
"site_admin":サイト管理者かどうか
},
"created_at":"作成日時(ISO 8601形式 UTC)",
"updated_at":"最終更新日時(ISO 8601形式 UTC)",
"content_url":"https://api.github.com/repos/オーナー名/リポジトリ名/issues/issueIDもしくはプルリクID"
}
まとめ
ProjectsのAPIを使えばProjectをプログラムで操作することができるが、カードからissueを作ることはできないようだ。
だが、まだ試験運用中のようなので、今後もシステム含めこれからやれることが増えるかもしれない。
- プロジェクト
- 一覧取得
- 取得
- 作成
- 更新(タイトル・説明変更/close/open)
- 削除
- カラム
- 一覧取得
- 取得
- 作成
- 更新
- 削除
- 移動
- カード
- 一覧取得
- 取得
- 作成
- 既にあるプルリクやissueからカード作成
- 更新
- 削除
- 移動
- カードをissue化
ちなみに、カラムやカードの操作を行なった場合はページリロードしなくても反映される。
(プルリクのブランチにpushした場合と同様。)
あとがき
GitHubをあれこれ見ている間にWebhooksを見つけました。
更新を受け取るならそれだなと思いましたが、Project操作に関するものは今の所ありませんでした。
ただ、こうしてAPIで一通りの動作ができることはわかったので、定期的に状態をチェックして変更があったかどうか調べるくらいはできるなと思いました。
あとは、Webhooksでプルリクにラベルが貼られたことなどを検知してカードを自動移動させるのもできそうです。
(2017/7/17追記)確認したところProject関連のWebhooksができていたので、いつか試して記事にします。
参考資料
Projects | GitHub Developer Guide
公式ページ。
成功時のステータスコードなど本記事では扱っていない内容もあります。
GitHub APIでユーザー情報を取得する - Qiita
この記事のおかげでGitHub APIの使い方がわかりました。
kz800さんありがとうございました。