JIRA REST API ---- JAVA

最近在搞自動化監控,有一項功能就是監測到異常情況時自動創建jira工單,於是乎對JIRA REST API 做了一些調研,其提供兩種使用方式,一種是在項目中引入客戶端封裝包jira-rest-java-client-2.0.0-m2.jar,另一種是直接使用JIRA REST API 提供的curl命令行方式處理。

參考資料:https://docs.atlassian.com/jira/REST/7.0-SNAPSHOT

 

一。第一種方式jira-rest-java-client-2.0.0-m2.jar

 

<repositories>
  <repository>
    <id>central</id>
    <name>Atlassian Public Repository</name>
    <layout>default</layout>
    <url>https://maven.atlassian.com/content/groups/public/</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
</repositories>
<dependency>
			<groupId>com.atlassian.jira</groupId>
			<artifactId>jira-rest-java-client</artifactId>
			<version>2.0.0-m2</version>
		</dependency>

             

 

 

這種方式參考資料不好找,我基本是通過查看api一點點摸索的,而且需要引入許多第三方依賴包,相對第二種方式過於繁瑣,這裏只做了常用的方法封裝,相關jar包見附件:

package com.nq.common;

import java.net.URI;
import java.net.URISyntaxException;

import com.atlassian.jira.rest.client.JiraRestClient;
import com.atlassian.jira.rest.client.JiraRestClientFactory;
import com.atlassian.jira.rest.client.domain.BasicIssue;
import com.atlassian.jira.rest.client.domain.Issue;
import com.atlassian.jira.rest.client.domain.IssueType;
import com.atlassian.jira.rest.client.domain.SearchResult;
import com.atlassian.jira.rest.client.domain.Transition;
import com.atlassian.jira.rest.client.domain.User;
import com.atlassian.jira.rest.client.domain.input.IssueInput;
import com.atlassian.jira.rest.client.domain.input.IssueInputBuilder;
import com.atlassian.jira.rest.client.domain.input.TransitionInput;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;

/**
 * jira java工具類
 * jira-rest-java-client-2.0.0-m2.jar
 * @author hanqunfeng
 *
 */
public class JiraUtil {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
//			JiraUtil.getIssue("NQCP-35");
			// JiraUtil.createIssue("NQCP", 1l, "工單詳細信息<br>工單詳細信息",
			// "工單主題", "username");
			// JiraUtil.printAllIssueType();

			// JiraUtil.changeIssueStatus("NQCP-35", 2);
			// JiraUtil.getUser("username");
			
			//查詢用戶負責的所有工單
			JiraUtil.searchIssues("assignee=username");
			System.out.println("*****************************");
			JiraUtil.searchIssues("assignee=username order by duedate");
			System.out.println("*****************************");
			JiraUtil.searchIssues("assignee=username order by issueType");
			System.out.println("*****************************");
			//從0開始數,從第5條開始,取兩條
//			JiraUtil.searchIssues("assignee=username",5,2);
//			
//			System.out.println("*****************************");
//			JiraUtil.searchIssues("project=NQCP");
			
			

		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	static JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
	static String uri = "http://jira.local.com/jira";
	static String user = "username";
	static String pwd = "password";
	static JiraRestClient restClient;

	/**
	 * 獲得jira的客戶端
	 * 
	 * @return JiraRestClient
	 * @throws URISyntaxException
	 */
	static JiraRestClient getJiraRestClient() throws URISyntaxException {
		if (restClient == null) {
			URI jiraServerUri = new URI(uri);
			restClient = factory.createWithBasicHttpAuthentication(
					jiraServerUri, user, pwd);
		}
		return restClient;
	}

	/**
	 * 獲得工單信息
	 * 
	 * @param issueKey
	 *            工單key,比如:NQCP-5
	 * @throws URISyntaxException
	 */
	public static Issue getIssue(String issueKey) throws URISyntaxException {
		Issue issue = null;
		JiraRestClient restClient = getJiraRestClient();
		// get issue through issueKey
		try {
			issue = restClient.getIssueClient().getIssue(issueKey).claim();

			// 打印工單後續的工作流
			Iterable<Transition> iter = restClient.getIssueClient()
					.getTransitions(issue).claim();
			for (Transition transition : iter) {
				System.out.println(transition);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 打印工單明細
		System.out.println(issue);
		return issue;

	}
	
	
	/**
	 * 檢索工單
	 * @param jql 
	 *      
	 * @return
	 * @throws URISyntaxException
	 */
	public static Iterable<BasicIssue> searchIssues(String jql) throws URISyntaxException{
		JiraRestClient restClient = getJiraRestClient();
		SearchResult searchResutl = restClient.getSearchClient().searchJql(jql).claim();
		Iterable<BasicIssue> iter = searchResutl.getIssues();
		for (BasicIssue baseIssue : iter) {
			System.out.println(baseIssue);
		}
		return iter;
	}
	
	/**
	 * 檢索工單
	 * @param jql
	 * @param startIndex
	 * @param maxResults
	 * @return
	 * @throws URISyntaxException
	 */
	public static Iterable<BasicIssue> searchIssues(String jql,int startIndex, int maxResults) throws URISyntaxException{
		JiraRestClient restClient = getJiraRestClient();
		SearchResult searchResutl = restClient.getSearchClient().searchJql(jql,maxResults,startIndex).claim();
		Iterable<BasicIssue> iter = searchResutl.getIssues();
		for (BasicIssue baseIssue : iter) {
			System.out.println(baseIssue);
		}
		return iter;
	}
	

	/**
	 * 打印jira系統中已經創建的全部issueType
	 * issuetype/
	 * 
	 * @throws URISyntaxException
	 */
	public static Iterable<IssueType> printAllIssueType() throws URISyntaxException {
		JiraRestClient restClient = getJiraRestClient();
		Iterable<IssueType> iter = restClient.getMetadataClient()
				.getIssueTypes().claim();
		for (IssueType issueType : iter) {
			System.out.println(issueType);
		}
		return iter;

	}

	/**
	 * 創建一個新工單
	 * 
	 * @param projectKey
	 *            項目key,比如:NQCP
	 * @param issueType
	 *            工單類型,來源於printAllIssueType()的id
	 * @param description
	 *            工單描述
	 * @param summary
	 *            工單主題
	 * @param assignee
	 *            工單負責人
	 * @throws URISyntaxException
	 */
	public static BasicIssue createIssue(String projectKey, Long issueType,
			String description, String summary, String assignee)
			throws URISyntaxException {

		JiraRestClient restClient = getJiraRestClient();

		IssueInputBuilder issueBuilder = new IssueInputBuilder(projectKey,
				issueType);

		issueBuilder.setDescription(description);
		issueBuilder.setSummary(summary);
		if (getUser(assignee) != null) {

			issueBuilder.setAssigneeName(assignee);
		}
		IssueInput issueInput = issueBuilder.build();

		BasicIssue bIssue = null;
		try {
			bIssue = restClient.getIssueClient().createIssue(issueInput)
					.claim();
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println(bIssue);
		return bIssue;
	}

	/**
	 * 獲取用戶信息
	 * 
	 * @param username
	 * @return
	 * @throws URISyntaxException
	 */
	public static User getUser(String username) throws URISyntaxException {
		JiraRestClient restClient = getJiraRestClient();
		User user = null;
		try {
			user = restClient.getUserClient().getUser(username).claim();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(user);
		return user;
	}

	/**
	 * 改變工單workflow狀態 issue的workflow是不可以隨便改變的,必須按照流程圖的順序進行改變,具體如下:
	 * 
	 * 當前狀態 :說明                      變更流程id:說明 >> 變更後狀態
          1:open,開放                          1)4:start progress >> in progerss 2)5:resolve issue >> resolved 3)2:close issue >> closed 
          3:in progerss 正在處理                1)301:stop progress >> open 2)5:resolve issue >> resolved 3)2:close issue >> closed 
          4:resolved 已解決                     1)701:close issue >> closed 2)3:reopen issue >> reopened 
          5:reopened 重新打開                   1)4:start progress >> in progerss 2)5:resolve issue >> resolved 3)2:close issue >> closed 
          6:closed 已關閉                       1)3:reopen issue >> reopened
	 * 
	 * 
	 * 可通過如下方式查看當前工單的後續工作流程: Iterable<Transition> iter =
	 * restClient.getIssueClient().getTransitions(issue).claim();
	 * 
	 * for (Transition transition : iter) { System.out.println(transition); }
	 * 
	 * 輸出結果:當前工單狀態是 5:reopened 重新打開 Transition{id=4, name=Start Progress,
	 * fields=[]} Transition{id=5, name=Resolve Issue,
	 * fields=[Field{id=fixVersions, isRequired=false, type=array},
	 * Field{id=resolution, isRequired=true, type=resolution}]} Transition{id=2,
	 * name=Close Issue, fields=[Field{id=fixVersions, isRequired=false,
	 * type=array}, Field{id=resolution, isRequired=true, type=resolution}]}
	 * 
	 * 
	 * @param issuekey
	 *            工單key
	 * @param statusId
	 *            變更流程id
	 * @param fields
	 *            隨狀態需要傳遞的參數,可以爲空
	 * @throws URISyntaxException
	 */
	public static void changeIssueStatus(String issuekey, int statusId)
			throws URISyntaxException {

		JiraRestClient restClient = getJiraRestClient();

		Issue issue = getIssue(issuekey);
		if (issue != null) {
			TransitionInput tinput = new TransitionInput(statusId);
			restClient.getIssueClient().transition(issue, tinput);
		}

		// try {
		// Thread.sleep(3000);//因爲是異步處理,所以狀態是延遲變更的,暫停一下可以看到狀態已經變更了
		// issue = getIssue(issuekey);
		// System.out.println(issue.getStatus());
		// } catch (InterruptedException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }

	}

}

 

二。JIRA REST API

 這種方式使用curl命令進行處理,幾乎涵蓋了所有的jira處理,這裏也只對常用的功能進行的封裝。

接口中的 2 可以使用 latest 替代。http://localhost:9080/rest/api/latest/issue/ORCM-1 《==》 http://localhost:9080/rest/api/2/issue/ORCM-1

package com.nq.common;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * JIRA REST API 工具類
 * https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis/jira-rest-api-tutorials
 * https://docs.atlassian.com/jira/REST/7.0-SNAPSHOT/
 * @author hanqunfeng
 *
 */
public class JiraAPIUtil {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		// JiraAPIUtil.getIssue("NQCP-35");

//		Map<String, String> map = new HashMap<String, String>();
//		map.put("assignee", "{\"name\":\"username\"}");
//		JiraAPIUtil.createIssue("NQCP", "Bug", "哈哈哈啊哈哈", "測試01", map);

		// Map<String,String> map = new HashMap<String,String>();
		// map.put("assignee", "{\"name\":\"username\"}");
		// map.put("summary", "\"summary00002\"");
		// JiraAPIUtil.editIssue("NQCP-38", map);
		
//		JiraAPIUtil.searchIssues("assignee=username");
//		System.out.println("*****************************");
//		JiraAPIUtil.searchIssues("assignee=username+order+by+duedate");
//		System.out.println("*****************************");
		
//		JiraAPIUtil.addComments("NQCP-39", "123456哈哈哈哈");
//		JiraAPIUtil.deleteIssueByKey("NQCP-38");
		JiraAPIUtil.addAttachment("NQCP-39", "d://myfile01.txt");  //linux路徑:   /home/boss/myfile.txt
	}

	static String uri = "http://jira.local.com/jira";
	static String user = "username";
	static String pwd = "password";
	static String osname = System.getProperty("os.name").toLowerCase();

	/**
	 * 執行shell腳本
	 * 
	 * @param command
	 * @return
	 * @throws IOException
	 */
	private static String executeShell(String command) throws IOException {
		StringBuffer result = new StringBuffer();
		Process process = null;
		InputStream is = null;
		BufferedReader br = null;
		String line = null;
		try {

			if (osname.indexOf("windows") >= 0) {
				process = new ProcessBuilder("cmd.exe", "/c", command).start();
				System.out.println("cmd.exe /c " + command); //安裝Cygwin,使windows可以執行linux命令
			} else {
				process = new ProcessBuilder("/bin/sh", "-c", command).start();
				System.out.println("/bin/sh -c " + command);
			}

			is = process.getInputStream();
			br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

			while ((line = br.readLine()) != null) {
				System.out.println(line);
				result.append(line);
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			br.close();
			process.destroy();
			is.close();
		}

		return result.toString();
	}

	/**
	 * 活動工單信息
	 * 
	 * @param issueKey
	 *            工單key
	 * @return
	 * @throws IOException
	 */
	public static String getIssue(String issueKey) throws IOException {

		String command = "curl -D- -u " + user + ":" + pwd
				+ " -X GET -H \"Content-Type: application/json\" \"" + uri
				+ "/rest/api/2/issue/" + issueKey + "\"";

		String issueSt = executeShell(command);

		return issueSt;

	}

	/**
	 * 創建工單
	 * 
	 * @param projectKey
	 *            項目key
	 * @param issueType
	 *            工單類型 name
	 * @param description
	 *            工單描述
	 * @param summary
	 *            工單主題
	 * @param assignee
	 *            工單負責人
	 * @param map
	 *            工單參數map,key爲參數名稱,value爲參數值,參數值必須自帶雙引號 比如: map.put("assignee",
	 *            "{\"name\":\"username\"}"); map.put("summary",
	 *            "\"summary00002\"");
	 * @return
	 * @throws IOException
	 */
	public static String createIssue(String projectKey, String issueType,
			String description, String summary,
			Map<String, String> map) throws IOException {
		String fields = "";
		if (map != null && map.size() > 0) {
			StringBuffer fieldsB = new StringBuffer();
			for (Map.Entry<String, String> entry : map.entrySet()) {
				fieldsB.append(",\"").append(entry.getKey()).append("\":")
						.append(entry.getValue());
			}
			fields = fieldsB.toString();
		}

		String command = "curl -D- -u " + user + ":" + pwd
				+ " -X POST  --data '{\"fields\": {\"project\":{ \"key\": \""
				+ projectKey + "\"},\"summary\": \"" + summary
				+ "\",\"description\": \"" + description
				+ "\",\"issuetype\": {\"name\": \"" + issueType + "\"}"
				+ fields + "}}' -H \"Content-Type: application/json\" \"" + uri
				+ "/rest/api/2/issue/\"";

		String issueSt = executeShell(command);

		return issueSt;
	}

	/**
	 * 更新工單
	 * 
	 * @param issueKey
	 *            工單key
	 * @param map
	 *            工單參數map,key爲參數名稱,value爲參數值,參數值必須自帶雙引號 比如: map.put("assignee",
	 *            "{\"name\":\"username\"}"); map.put("summary",
	 *            "\"summary00002\"");
	 * @return
	 * @throws IOException
	 */
	public static String editIssue(String issueKey, Map<String, String> map)
			throws IOException {

		StringBuffer fieldsB = new StringBuffer();
		for (Map.Entry<String, String> entry : map.entrySet()) {
			fieldsB.append("\"").append(entry.getKey()).append("\":")
					.append(entry.getValue()).append(",");
		}
		String fields = fieldsB.toString();
		fields = fields.substring(0, fields.length() - 1);

		String command = "curl -D- -u " + user + ":" + pwd
				+ " -X PUT   --data '{\"fields\": { " + fields
				+ "}}' -H \"Content-Type: application/json\" \"" + uri
				+ "/rest/api/2/issue/" + issueKey + "\"";

		String issueSt = executeShell(command);

		return issueSt;
	}
	
	
	
	/**
	 * 查詢工單
	 * @param jql
	 * assignee=username
	 * assignee=username&startAt=2&maxResults=2
	 * assignee=username+order+by+duedate
	 * project=projectKey+order+by+duedate&fields=id,key
	 * @return
	 * @throws IOException
	 */
	public static String searchIssues(String jql) throws IOException{
		String command = "curl -D- -u " + user + ":" + pwd
				+ " -X GET -H \"Content-Type: application/json\" \"" + uri
				+ "/rest/api/2/search?jql=" + jql + "\"";

		String issueSt = executeShell(command);

		return issueSt;
	}
	
	
	/**
	 * 爲工單增加註釋說明
	 * @param issueKey 工單key
	 * @param comment  註釋說明
	 * @return
	 * @throws IOException
	 */
	public static String addComments(String issueKey,String comments) throws IOException{
		String command = "curl -D- -u " + user + ":" + pwd
				+ " -X PUT   --data '{\"update\": { \"comment\": [ { \"add\": { \"body\":\""+comments+"\" } } ] }}' -H \"Content-Type: application/json\" \"" + uri
				+ "/rest/api/2/issue/" + issueKey + "\"";

		String issueSt = executeShell(command);

		return issueSt;
	}
	
	
	/**
	 * 刪除工單
	 * @param issueKey 工單key
	 * @return
	 * @throws IOException
	 */
	public static String deleteIssueByKey(String issueKey) throws IOException{
		String command = "curl -D- -u " + user + ":" + pwd
				+ " -X DELETE -H \"Content-Type: application/json\" \"" + uri
				+ "/rest/api/2/issue/" + issueKey + "\"";

		String issueSt = executeShell(command);

		return issueSt;
	}
	
	
	/**
	 * 上傳附件
	 * @param issueKey 工單key
	 * @param filepath 文件路徑
	 * @return
	 * @throws IOException
	 */
	public static String addAttachment(String issueKey,String filepath) throws IOException{
		String command = "curl -D- -u " + user + ":" + pwd
				+ " -X POST -H \"X-Atlassian-Token: nocheck\"  -F \"file=@"+filepath+"\" \"" + uri
				+ "/rest/api/2/issue/" + issueKey + "/attachments\"";

		String issueSt = executeShell(command);

		return issueSt;
	}

}

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章