Author
樋口 晃Akira Higuchi
このエントリーは、 Atlassian(JIRA , Confluence, Trello, Bitbucket)のTips Advent Calendar 2017 - Qiitaの3日目です
こんにちは。リックソフトのプリセールス担当の樋口です。私は日々、新規のお客様や既存のお客様とお話ししています。よく聞かれる質問 No.1 は
- Jiraの課題を複数人で担当する場合はどうしたら良いのですか?
です。「担当者は一人しか登録できないので、代替案としましてはカスタムフィールドを作成しまして云々。。」という話をします。その他で多い質問は、
- JIRA に他のシステムから課題を作成したり、他システムからJIRAの情報を参照するにはどうしたらよいでしょうか?
です。その場合、「JIRA には REAT API が用意されていますので、ご利用下さい」と説明します。この説明で「あ~、RESTが使えるんですか、RESTでパコーンとデータをPOSTすれば、バシッと課題が作られるのですね」と言われたりすることが有ります。「参照する場合、条件指定したりできますか?」「はい、JQLを指定できますので。。。」「あ~ そうすると、JQLを指定すれば条件に合致する課題をズルズルッと引っ張ってこられる訳ですね。それは、良いですね!!」と言って頂ける場合が有ります。ですが、あまり馴染みのない方も居ますので、説明に時間がかかったりする事も有ります。そんな時は何か説明が簡単にできる日本語の資料が有ればなあと思っておりました。今日は、私のプリセールス活動を楽にするために ブログを書かせて頂きます。JIRAをアプリケーションで利用したい方のお役に立てれば幸いです。
REST API ドキュメント
REST API を利用すると、データの「追加、更新、検索、削除」ができます。それぞれ、HTTP メソッドの POST / PUT / GET / DELETE に対応しています。JIRA も同様です。ご存知の通り、Atlassian は色々な情報を公開してくれる会社です。JIra のREST APIの説明は下記のURLで参照できます。
上記のドキュメントを見ると下記の事が解ります。
- REST APIのURL構造は、http://hostname/rest/
/ / - ただし、JIRAにコンテキストパスとして jira が設定されている場合は、http://hostname/jira/rest/
/ / となる。 - api-name, api-version, resource-name については、参照したい情報(課題の情報か、ユーザー情報か)によって変わります。下記に記載されています。
- 上記は最新バージョンです。ご利用のJIRAのバージョンに合わせて、https://docs.atlassian.com/jira/REST/ から選んで下さい。
- 上記のドキュメントを見ればわかりますが、殆ど api-nameは "api", api-version は "2" です。変わるのは resource-name だけです。
- ただし、JIRAにコンテキストパスとして jira が設定されている場合は、http://hostname/jira/rest/
- 認証は、OAuth、HTTP クッキー、信頼されたアプリケーション、ユーザー名とパスワード が可能。
- データの形式は json 形式
などという事が解ります。
今回は、パスワード認証でJIRAの課題を検索するサンプルと、課題を作成するサンプルをご紹介します。
課題を参照してみる
課題を検索する場合は、https://docs.atlassian.com/jira/REST/server/#api/2/search-search を参照すると、 「/rest/api/2/search」を GET メソッドで利用すれば良い事が解ります。利用できるパラメータには、下記の物が有ります。
パラメータ名 | 型 | 説明 |
---|---|---|
jql | 文字型 | JQL 問合せ文字列 |
startAt | 数字型 | 取得する検索結果の開始位置(0ベース) |
maxResults | 数字型 | 最大取得件数 |
fields | 文字型 | 取得するフィールドをカンマ区切りで指定。 |
下記の条件で課題を検索するURLを組んでみましょう。
項目 | 値 |
---|---|
JIRAのBaseURL | https://test-server.localdomain/jira |
検索結果の最大件数 | 50 |
検索文字列(JQL) | project=RSAF |
検索するフィールド | 課題タイプ、プロジェクト、要約、担当者、関係者(customfield_10600)、更新日 |
URLは、下記の様になります。
- https://test-server.localdomain/jira/rest/api/2/search?maxResults=4&fields=issuetype,project,summary,description,assignee&jql=PROJECT=RSAF
fields=の後のフィールド名は英語で指定するので上記の通りとなります。英語名が不明な場合は、ユーザープロファイルで言語設定を英語にする事で、Jiraの画面が英語になりますので確認できます。カスタムフィールドの場合は、
- customfield_<数字>
という形式で指定します。上記の数字は、カスタムフィールドのIDです。管理画面でカスタムフィールドの構成を参照した時のURLの末尾の数字で確認できます。
- 例:https://test-server.localdomain/jira/secure/admin/ConfigureCustomField!default.jspa?customFieldId=10203
上記のURLを試す簡単な方法は、ブラウザーでURLを参照する事です。最新のFireFoxだと、整形されて綺麗に表示されます。Chromeの場合は、アドオンを追加する事で成形済みのJSONフォーマットで参照する事ができます。
また、これを Linux の curl コマンドで実行する場合は下記の通りとなります。admin:password は JIRA にログイン可能なユーザー名とパスワードです。この例では、python を使って、json を成形して標準出力にアウトプットします。
# curl -u admin:password 'https://test-server.localdomain/jira/rest/api/2/search?
maxResults=4&fields=issuetype,project,summary,description,assignee,customfield_10203&jql=assignee=higuchi' | python -c 'import sys,json;print
次に REST API を利用して課題を検索する簡単なプログラムを作ってみます。JSONは色々なプログラムで処理できます。今回は Python を使ってみます。
ブラウザーで確認した検索結果のデータは、最初に
- expand: "schema,names",
- startAt: 0, <= 開始件数
- maxResults: 50, <= 最大検索件数
- total: 5, <= 取得できた件数
が並んでいます。次に issues というオブジェクトが有り、これが大括弧("[]") なので配列という事が解ります。issues の配列は、total の件数分続きます。id(課題の内部ID) や key(課題キー)は
- id: "12001",
- key: "RSAF-5",
というシンプルに表現されていますが、担当者は
- assignee: {
- self: "https://test-server.localdomain/jira/rest/api/2/user?username=admin",
- name: "admin",
- key: "admin",
- emailAddress: "higuchi+admin@ricksoft.jp",
- avatarUrls: {
- 48x48: "https://test-server.localdomain/jira/secure/useravatar?ownerId=admin&avatarId=10700",
- 24x24: "https://test-server.localdomain/jira/secure/useravatar?size=small&ownerId=admin&avatarId=10700",
- 16x16: "https://test-server.localdomain/jira/secure/useravatar?size=xsmall&ownerId=admin&avatarId=10700",
- 32x32: "https://test-server.localdomain/jira/secure/useravatar?size=medium&ownerId=admin&avatarId=10700",
- },
- displayName: "管理者",
- active: true,
- timeZone: "Asia/Tokyo",
- },
という少々複雑な構造になっています。このため、プログラムから 担当者のユーザー名を利用する場合は、assgnee => name, 担当者のフルネームには assgnee => displayName という形式でアクセスする必要が有ります。サンプルは下記の様になります。
#!/usr/bin/python # coding: utf-8 import requests import json from datetime import datetime BASE_URL="https://test-server.localdomain/jira" JQL="project=RSAF" FIELDS="issuetype,project,summary,description,assignee,customfield_10600,created,updated" AUTH=("admin, "xxiduryr") HEADERS = {"content-type":"application/json"} # 課題の検索 # http://JiraのサーバーURL/rest/api/2/search?maxResults=4&fields=[フィールドをカンマ区切りで指定]&jql=[検索条件] # (HTTP メソッドは get ) def search_issues(jql, fields): response = requests.get( BASE_URL + "/rest/api/2/search", auth=AUTH, params={"maxResults":50, "fields":fields, "jql":jql}) #http ステータスのチェック response.raise_for_status() return response # main function if __name__ == "__main__": print ("-------------- start --------------------") response = search_issues(JQL, FIELDS) response_data = response.json() if response_data["total"] == 0: print ("データが有りません") issues = response_data["issues"] for issue in issues: fields = issue["fields"] assignee = fields["assignee"] participants = fields["customfield_10600"] assgneeName = "" if assignee is not None: assgneeName = assignee["displayName"] participantValue = "[]" if participants is not None: participantValue = "[" for participant in participants: participantValue += participant["displayName"] + "," participantValue += "]" print (issue["key"] + "," + fields["summary"] + "," + assgneeName + "," + fields["created"] + "," + fields["updated"] + "," + participantValue) print ("-------------- end ----------------------")
上記のサンプルの customfield_10600 というフィールドはマルチ・ユーザーピッカーです。このため、participants は配列となり、 for participant in participants: でループ処理しています。これを実行すると、下記の様な表示となります。
-------------- start --------------------
RSAF-5,テスト課題,,2017-12-01T15:21:05.000+0900,2017-12-01T15:21:05.000+0900,[網野 勉,木下太郎,]
RSAF-4,見積もり作成,森 秀一,2017-12-01T15:14:22.000+0900,2017-12-01T15:15:45.000+0900,[]
RSAF-3,Excel, PPT等 MS系ソフトの対応,,2017-11-07T14:58:57.000+0900,2017-11-07T14:58:57.000+0900,[]
RSAF-2,アルフレスコの動画を確認,管理者,2017-11-07T14:43:48.000+0900,2017-11-07T14:47:37.000+0900,[]
RSAF-1,アルフレスコのPDFファイルを確認,管理者,2017-11-07T13:20:23.000+0900,2017-11-07T14:43:21.000+0900,[]
-------------- end ----------------------
課題を作成してみる
次に課題を作成してみます。https://docs.atlassian.com/jira/REST/7.6.0/#api/2/issue-createIssue を参照すると、/api/2/issue を put メソッドで実行すれば良い事が解ります。また、このリソースに課題キーを指定して
- https://test-server.localdomain/jira/rest/api/2/issue/RSAF-11
などとすると、作成済の課題を参照できます。JIRAの内部 id やデータ構造が json 形式で 参照できるので、参考になるかと思います。今回は下記の項目を指定して課題を作成してみます。
項目名 | 値 |
---|---|
プロジェクト | RSAF |
要約 | Advent Calendar 2017 |
課題タイプ | タスク |
担当者 | higuchi |
報告者 | higuchi |
優先度 | Medium |
説明 | Advent Calendar 2017 3日目様のサンプル課題です。 |
この条件で課題を作成する場合、JSON データは下記の様になります。
{
"fields":{
"project":{
"key": "RSAF"
},
"summary": "Advent Calendar 2017",
"issuetype": {
"name": "Task"
},
"assignee": {
"name": "higuchi"
},
"reporter": {
"name": "higuchi"
},
"priority": {
"id": "3"
},
"description": "Advent Calendar 2017 3日目用のサンプル課題です。"
}
}
上記の例では priority(優先度)を id で指定していますが、issuetype は name で指定しています。id と name はどちらでも良く、priority の指定を "name":"Medium" としても同じ結果となります。この JSON をファイルに (createIssue.json) に保存して、 Linux の curl コマンドでJIRA に POSTすると、下記の様に課題を生成する事ができます。(生々しい情報は xxxxxxxxxxx で隠しています)
$ curl -D- -u admin:password -X POST --data '@createIssue.json' -H "Content-Type: application/json"'https://test-server.localdomain/jira' HTTP/1.1 201 Server: nginx Date: Sat, 02 Dec 2017 09:42:47 GMT Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive X-AREQUESTID: xxxxxxxxxx X-ASEN: SEN-xxxxxxxxxxxxxx Set-Cookie: JSESSIONID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx X-Seraph-LoginReason: OUT Set-Cookie: crowd.token_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; Path=/; HttpOnly X-Seraph-LoginReason: OK Set-Cookie: atlassian.xsrf.token=xxxxxxxxxxxxxxx|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|lin;path=/jira;Secure X-ASESSIONID: xxxxxxx X-AUSERNAME: admin Cache-Control: no-cache, no-store, no-transform X-Content-Type-Options: nosniff {"id":"12108","key":"RSAF-14","self":"https://test-server.localdomain/jira/rest/api/2/issue/12108"}
最後の1行は課題からのレスポンスで、 RSAF-14 という課題が作成された事が解ります。
課題を作成する Python のサンプルは下記の様になります。
#!/usr/bin/python # coding: utf-8 import requests import json from datetime import datetime BASE_URL="https://test-server.localdomain/jira" JQL="project=RSAF" FIELDS="issuetype,project,summary,description,assignee,customfield_10600,created,updated" AUTH=("admin", "password") HEADERS = {"content-type":"application/json"} # 課題の作成 # http://JiraのサーバーURL/rest/api/2/issue # (HTTP メソッドは post ) def create_issue(): json_data = create_json_data() response = requests.post( BASE_URL + "/rest/api/2/issue", auth=AUTH, data = json.dumps(json_data), headers=HEADERS) response.raise_for_status() return response # json データの生成
def create_json_data(): payload = { "fields": { "project": { "key": "RSAF" }, "summary": "Advent Calendar 2017", "issuetype": { "id": "10301" }, "assignee": { "name": "higuchi" }, "reporter": { "name": "higuchi" }, "priority": { "id": "3" }, "description": "Advent Calendar 2017 3日目用のサンプル課題です。" } } return payload # main function if __name__ == "__main__": print ("-------------- start --------------------") response = create_issue() response_data = response.json() print ("課題が作成されました:" + response_data["key"]) print ("-------------- end ----------------------")
最後に
以前、REST API で Confleunce のページを生成 というブログを書きました。直ぐにJIRA の方も書くつもりだったのですが、1年半も放置してしまいました。今回、AUGの Advent Calendar のおかげでやっと記事にする事ができました。ありがとうございました。少しでも皆様のお役にたてれば幸いです。
リックソフトでは評価ライセンスを発行しています。
ご不明な点がございましたらお気軽にお問い合わせください。