Redmineã®CSVãã¤ã³ãã¼ãããæ©è½ã¯ä¾¿å©ãªãã§ããã親ãã±ããã¨åãã±ãããåæã«ç»é²ã§ããªãã®ãè¾ãã¨ãããããã§ä»åã¯Redmineã®RESTfulAPIãå©ç¨ãããã°ã©ã ãããã±ãããç»é²ããæ¹æ³ãã¾ã¨ãã¾ãã
æºå
ã¾ãã¯Redmineä¸ã§RESTful APIãå©ç¨ã§ããç¶æ ã確èªãã¾ãã
Redmineã®ç®¡çè 権éã®ããã¦ã¼ã¶ã¼ã§ãã°ã¤ã³ããã管çãâãè¨å®ãâãAPIãã¨ãã©ãã¾ãããRESTã«ããWebãµã¼ãã¹ãæå¹ã«ãããã«ãã§ãã¯ãä»ãã¦ããã°OKãä»åã¯PHPããå©ç¨ããã®ã§JSONPã®ãã§ãã¯ã¯å¤ãã¦ãã¦ãæ§ãã¾ããã
次ã«APIãå®è¡ããã¦ã¼ã¶ã¼ã®ãAPIã¢ã¯ã»ã¹ãã¼ããåå¾ãã¾ãã å½è©²ã¦ã¼ã¶ã¼ã§Redmineã¸ãã°ã¤ã³ããå¾ã«ãå人è¨å®ããã¼ã¸ã®å³å´ã«ãããAPIã¢ã¯ã»ã¹ãã¼ãã®ã表示ããã¯ãªãã¯ããã¨è±æ°åãçµã¿åããã£ãé·ãæååã表示ããã¾ãã®ã§ãããã¡ã¢ãã¾ãã
APIã¢ã¯ã»ã¹ãã¼ããããã¨ä½ã§ãåºæ¥ã¦ãã¾ãã®ã§ãå¤é¨ã«æ¼ããå ´åã®ãã¨ãèæ ®ããAPIãå®è¡ããã¦ã¼ã¶ã¼ã¯æ¨©éãåå ããã¸ã§ã¯ãã¯å¿ è¦æå°éã«ããå°ç¨ã®ã¦ã¼ã¶ã¼ãä½ããã¨ããããããã¾ãã
ããããã®ã¯ééãã¦GitHubãªã©ã®å ¬éãªãã¸ããªã«ããã¡ãã£ãã¨ããã¤ãã§ããããããã«ä»äºã§ãã£ã¦ããå ´åã¯ä¸ã èãã«ããã§ãããå人çãªããã¸ã§ã¯ãã®å ´åã¯ã注æãã
ãã±ãããä½æãã
åç
ãã±ãããæ°è¦ã«ä½æããAPIã¯é常ã«ã·ã³ãã«ãªä½ãã§ã/issues.json?key=(APIã¢ã¯ã»ã¹ãã¼)
ã«POSTã¡ã½ããã§é¡åãåªå
度ãªã©ã®å¿
è¦ãªæ
å ±ãéä¿¡ããã ãã§ããæ¡å¼µåã®é¨åã¯jsonã§ããã°JSONãxmlã§ããã°XMLã§ããåããåºæ¥ã¾ãã
ã½ã¼ã¹ã³ã¼ã
å®éã«ãã£ã¦ã¿ãæ¹ãæ©ãã§ããã以ä¸ãã½ã¼ã¹ã³ã¼ãã§ããç¹ã«ã©ã¤ãã©ãªãªã©ã¯å©ç¨ãã¦ããªãã®ã§ããã®ã¾ã¾ã³ãããCLIãªã©ã§å®è¡å¯è½ã§ããå®æ°ã®é¨åã¯ãèªèº«ã®ç°å¢ã«åããã¦å¤æ´ãã¦ãã ããã
ããã§ã¯JSONã§Redmineãµã¼ãã¨ããåããè¡ã£ã¦ãã¾ãã
<?php /** * Redmineã«ãã±ãããä½æãã * * @author M.Katsube * @version 1.0.0 */ //----------------------------------- // å®æ° //----------------------------------- // Redmineã稼åãã¦ããURL define('END_POINT', 'https://redmine.example.com'); // APIãå®è¡ããã¦ã¼ã¶ã¼ã®APIã¢ã¯ã»ã¹ãã¼ define('TOKEN', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); //----------------------------------- // å®è¡ //----------------------------------- // URLä½æ $url = sprintf('%s/issues.json?key=%s', END_POINT, TOKEN); // ãªã¯ã¨ã¹ãå®è¡ $result = sendPostRequest($url, [ 'issue' => [ 'project_id' => 1, // ããã¸ã§ã¯ã 'subject' => 'APIãã¹ã', // é¡å // 以ä¸ã¯ä»»æã§æå®ãã //'description' => '', // 説ææ //'tracker_id' => '', // ãã©ãã«ã¼ //'status_id' => '', // ã¹ãã¼ã¿ã¹ //'priority_id' => '', // åªå 度 //'category_id' => '', // ã«ãã´ãª //'fixed_version_id' => '', // 対象ãã¼ã¸ã§ã³ //'assigned_to_id' => '', // æ å½è //'parent_issue_id' => '', // 親ãã±ãã //'custom_fields' => '', // ã«ã¹ã¿ã ãã£ã¼ã«ã //'watcher_user_ids' => '', // ã¦ã©ããã£ã¼(ã¦ã¼ã¶ã¼ID) v2.3.0ã //'is_private' => '', // ãã©ã¤ãã¼ããã±ããã«ããã true or false //'estimated_hours' => '' // äºå®å·¥æ° ] ]); // ã¬ã¹ãã³ã¹ã人éãè¦ãããå å·¥ãã¦è¡¨ç¤º $json = json_decode($result); echo json_encode($json, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); /** * cURLã§POSTéä¿¡ãè¡ã * * @param [string] $url - 'http://example.com/' * @param [array] $query - é£æ³é åã§ã¯ã¨ãªã¼ãæå® * @return [string|boolean] - æå: åå¾çµæ, 失æ: false */ function sendPostRequest($url, $query){ // cURLåæå $ch = curl_init(); // cURLãªãã·ã§ã³è¨å® curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, // ã¬ã¹ãã³ã¹å 容ãcurl_exec()ã®æ»ãå¤ã¨ãã¦è¿å´ãã CURLOPT_POSTFIELDS => json_encode($query) ]); // ãªã¯ã¨ã¹ããå®è¡ $res = curl_exec($ch); curl_close($ch); return($res); }
å®è¡ãã
å ã»ã©ã®ã½ã¼ã¹ã³ã¼ããã³ãããã¦ä¿åãããã以ä¸ã®ããã«ãã®ã¾ã¾å®è¡ãã¾ãã
$ php create_issue.php
æ£å¸¸ã«å¦çãå®äºããã¨ä»¥ä¸ã®ããã«æçµçã«ç»é²ããããã±ããã®å 容ãJSONã§è¿ããã¾ãããã®JSONãå©ç¨ããAPIã®æ»ãå¤ã®IDãåå¾ãåãã±ãããä½æãããã¨ãã§ãã¾ãã
{ "issue": { "id": 123, "project": { "id": 1, "name": "究極ã®ãã£ã¼ãã³ä½æããã¸ã§ã¯ã" }, "tracker": { "id": 6, "name": "éçº" }, "status": { "id": 1, "name": "æ°è¦" }, "priority": { "id": 2, "name": "ä¸" }, "author": { "id": 20, "name": "WS åé¨éº»å£äºº" }, "fixed_version": { "id": 1, "name": "ãã¼ã¸ã§ã³1.0.0" }, "parent": { "id": 10 }, "subject": "ææãè²·ãã«è¡ã", "description": "", "start_date": "2020-10-20", "due_date": null, "done_ratio": 0, "is_private": false, "estimated_hours": null, "total_estimated_hours": null, "created_on": "2020-10-20T11:34:02Z", "updated_on": "2020-10-20T11:34:02Z", "closed_on": null } }
ãã¾ã
ããã¸ã§ã¯ãidã調ã¹ã
以ä¸ã®ãããªURLã«APIã¢ã¯ã»ã¹ãã¼ãæå®ãã¦ã¢ã¯ã»ã¹ããã¨ããã¸ã§ã¯ãä¸è¦§ãJSONã§è¿ããã¾ãã
https://redmine.example.com/projects.json?key=xxxxxxxxxxxxxxxxxxxx
以ä¸ã®ãããªJSONã«ãªãã¾ãã®ã§ãidã®é¨åã®æ°åãåèã«ãã¾ãã
{ projects: [ { id: 1, name: "究極ã®ãã£ã¼ãã³ä½æããã¸ã§ã¯ã", identifier: "ultimatefriedrice", description: "ãã£ã¼ãã³ä½ããï¼", status: 1, is_public: false, inherit_members: false, custom_fields: [ { id: 1, name: "Slack Channel", value: "" } ], created_on: "2020-09-17T02:27:43Z", updated_on: "2020-09-25T07:16:42Z" }, //(ç¥)
DoSæ»æç¶æ ã«ãªãã®ãé¿ãã
ãµã³ãã«ã®ã³ã¼ãã§ã¯1åã ããããªã¯ã¨ã¹ããéã£ã¦ãã¾ããããå®éã«ã¯ãã¡ã¤ã«ãªã©ã«è¨é²ããããã±ããä¸è¦§ãã¾ã¨ãã¦ç»é²ããã±ã¼ã¹ã§å©ç¨ãããã¨æãã¾ãããã®ããã«ä¾ãã°æ°ç¾ä»¶ã®ãã±ãããç»é²ãããããªå ´åã¯ãå¦çã®éä¸ã«sleep()
ãæãã§ãµã¼ããé©åº¦ã«ä¼ã¾ãã¦ãã ããããããå¿ããã¨ä¸éå端ãªDoSæ»æç¶æ
ã«ãªãã¾ãï½
<?php for( $i=0; $i<count($tickets); $i++ ){ // ãã±ããç»é²å¦ç $result = sendPostRequest($url, $tickets[$i]); // 3åæ¯ã«1ç§ä¼ã if( ($i % 3) === 0 ){ sleep(1); } }
親ãã±ãããæå®ã§ããªã
APIãå®è¡ããRedmineä¸ã®ã¦ã¼ã¶ã¼ã®æ¨©éãæå°éã«ãããã£ãã®ã§ãã¼ã«ããReporterãã«ãã¦ããã®ã§ããããã®ãã¼ã«ã¯ããã©ã«ãã§åãã±ããã®ç®¡çãã§ããªãè¨å®ã«ãªã£ã¦ãã¾ããããããã°ã©ã ä¸ããæå®ãã¦ãç¡è¦ããã¾ãï¼ã¨ã©ã¼ã«ã¯ãªãã¾ããï¼ã
å½åãããç¥ããªãã£ãã®ã§ãã£ã¡ãããããã¾ããï½ ãã¼ã«ããDeveloperãã«å¤æ´ããã解決ããã®ã§ã¾ããã¨æã£ããããããªç´°ãã権éè¨å®ã§ããã¨ã¯æããªãã ï½