您的位置:首页 > 其它

可方便扩展的JIRA Rest Web API的封装调用

2015-09-25 13:38 471 查看
JIRA是一个缺陷跟踪管理系统,被广泛应用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪和敏捷管理等工作领域,当我们需要把第三方业务系统集成进来时,可以调用他的API。

JIRA本身的API非常强大,但它是一个底层的API体系,并不是一个易用的接口,如果要开发和拓展,所以需要我们二次包装。

jira官方为解决这个问题,推出了方便强大的javaclientlibrary(目前只有java客户端库,没有.Net类库)

jira的RestAPI最新文档官网.

JIRA6.4.12RESTAPIdocumentation

https://docs.atlassian.com/jira/REST/latest/

JIRARESTAPITutorials:

https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis/jira-rest-api-tutorials

如果是编写java桌面或web应用,jira提供了更方便的方式(Client类库),JIRARESTJavaClientisaJavalibrary(usablefromanyJVMlanguage)whichallowstoeasilytalktoanyJIRA4.2+instanceusingnew(andstillevolving)RESTAPI.

JIRAJavaClientlibrary

https://ecosystem.atlassian.net/wiki/display/JRJC/Home

如果使用Client类库,可以方便应用各种现成的jira实体类(如项目、问题、备注、自定义字段......),不需要再重复造轮子,大幅提升效率。

首先,必须要了解JIRAapi的接口结构,其中<resource-name>可以理解成api的方法,比如project,就是项目信息,user就是用户信息,issue就是问题信息....

1

http://hostname/rest/<api-name>/<api-version>/<resource-name>


JIRA'sRESTAPIisprovidedbyapluginthatisanchoredundertheURIpathcomponent
/rest/
.Hence,ifyourJIRAsiteisrunningat:

还先要搞清楚jiraapi的认证体系,摘自官网:

thefirststepinusingtheJIRARESTAPIistoauthenticateauseraccountwithyourJIRAsite.ForthepurposesofthistutorialwewilluseHTTPBASICAuthentication,butanyauthenticationthatworksagainstJIRAwillworkagainsttheRESTAPI.Thisincludes:

OAuth

HTTPCookies

TrustedApplications

os_username/os_passwordqueryparameters

为方便使用,我们采用BasicAuth

BasicAuthheaders

Ifyouneedtoyoumayconstructandsendbasicauthheadersyourself.Todothisyouneedtoperformthefollowingsteps:

Buildastringoftheformusername:password

Base64encodethestring

Supplyan"Authorization"headerwithcontent"Basic"followedbytheencodedstring.Forexample,thestring"fred:fred"encodesto"ZnJlZDpmcmVk"inbase64,soyouwouldmaketherequestasfollows.

一个curl的例子,注意红色字符串是对“username:password”的Base64编码
curl-D--XGET-H"Authorization:BasicZnJlZDpmcmVk"-H"Content-Type:application/json""http://kelpie9:8081/rest/api/2/issue/QA-31"

搞清楚了BasicAuth,用C#进行代码实现,写了一个用于ASP.NETMVC的包装类,方便重复调用。

1、C#实现的API包装类


publicclassJiraApi
{
privatestringm_Username;
privatestringm_Password;

publicJiraApi(stringusername,stringpassword)
{
m_Username=username;
m_Password=password;
}

///<summary>
///处理post请求,执行新建、编辑、删除等操作
///</summary>
///<paramname="sData">json输入字符</param>
///<paramname="uri">api的具体地址,一般是baseurl+业务处理资源关键字</param>
///<returns>Jira返回的WebResponse输出</returns>
publicstringDoPost(stringsData,stringuri)
{
Uriaddress=newUri(uri);
HttpWebRequestrequest;
//HttpWebResponseresponse1=null;
StreamReadersr;
stringreturnXML=string.Empty;
if(address==null){thrownewArgumentNullException("address");}
try
{
request=WebRequest.Create(address)asHttpWebRequest;
request.Method="POST";
request.ContentType="application/json";
stringbase64Credentials=GetEncodedCredentials();
request.Headers.Add("Authorization","Basic"+base64Credentials);
//request.Credentials=newNetworkCredential(sUsername,sPassword);
if(sData!=null)
{
byte[]byteData=UTF8Encoding.UTF8.GetBytes(sData);
request.ContentLength=byteData.Length;
using(StreampostStream=request.GetRequestStream())
{
postStream.Write(byteData,0,byteData.Length);
}
using(HttpWebResponseresponse1=request.GetResponse()asHttpWebResponse)
{
StreamReaderreader=newStreamReader(response1.GetResponseStream());
stringstr=reader.ReadToEnd();
returnstr;

}
}
return"error";

}
catch(WebExceptionwex)
{

if(wex.Response!=null)
{

using(HttpWebResponseerrorResponse=(HttpWebResponse)wex.Response)
{
try
{
stringsError=string.Format("Theserverreturned'{0}'withthestatuscode{1}({2:d}).",
errorResponse.StatusDescription,errorResponse.StatusCode,
errorResponse.StatusCode);
sr=newStreamReader(errorResponse.GetResponseStream(),Encoding.UTF8);
returnXML=sr.ReadToEnd();
returnreturnXML;

}
finally
{
if(errorResponse!=null)errorResponse.Close();
}
}
}
else
{
//thrownewException(wex.Message);
returnwex.Message;

}
}
}

///<summary>
///处理get请求,执行查询操作
///</summary>
///<paramname="resource">输入的业务处理资源关键字,必填项</param>
///<paramname="argument">参数,用于获取具体查询操作,非必填项</param>
///<paramname="data">暂时没用处,非必填项</param>
///<paramname="method">默认为GET,非必填项</param>
///<returns></returns>
publicstringDoQuery(
stringresource,
stringargument=null,
stringdata=null,
stringmethod="GET")
{
stringurl=string.Format("{0}{1}/",Config.BaseURL,resource.ToString());

if(argument!=null)
{
url=string.Format("{0}{1}/",url,argument);
}

HttpWebRequestrequest=WebRequest.Create(url)asHttpWebRequest;
request.ContentType="application/json";
request.Method=method;

if(data!=null)
{
using(StreamWriterwriter=newStreamWriter(request.GetRequestStream()))
{
writer.Write(data);
}
}

stringbase64Credentials=GetEncodedCredentials();
request.Headers.Add("Authorization","Basic"+base64Credentials);

HttpWebResponseresponse=request.GetResponse()asHttpWebResponse;

stringresult=string.Empty;
using(StreamReaderreader=newStreamReader(response.GetResponseStream()))
{
result=reader.ReadToEnd();
}

returnresult;

}

privatestringGetEncodedCredentials()
{
stringmergedCredentials=string.Format("{0}:{1}",m_Username,m_Password);
byte[]byteCredentials=UTF8Encoding.UTF8.GetBytes(mergedCredentials);
returnConvert.ToBase64String(byteCredentials);
}
}

调用方法:查询Get

///<summary>
///查询jira的项目情况
///</summary>
///<paramname="sender"></param>
///<paramname="e"></param>
protectedvoidPage_Load(objectsender,EventArgse)
{
JiraApimanager=newJiraApi(Config.User,Config.Password);
Response.Write(manager.DoQuery("project"));
}

调用方法:提交Post

protectedvoidPage_Load(objectsender,EventArgse)
{
if(!IsPostBack)
{
JiraApiapi=newJiraApi(Config.User,Config.Password);
//对问题添加备注
SubmitComment(api,Request.QueryString["issue"],Request.QueryString["comment"]);
}
}
///<summary>
///添加问题的备注
///</summary>
///<paramname="jm">JiraApi实例</param>
///<paramname="issue">问题的关键字,比如SomeIssue-18</param>
///<paramname="comment">备注的内容</param>
privatevoidSubmitComment(JiraApiapi,stringissue,stringcomment)
{
stringsData=string.Format("{\"body\":\"{0}\"}",comment);
stringuri=Config.BaseURL+string.Format("issue/{0}/comment",issue);
Response.Write(api.DoPost(sData,uri));
}

2、JAVAClient类库实现的APIDEMO



packagejiraTEST;

importjava.net.URI;
importjava.net.URISyntaxException;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.List;
importjava.util.Map;
importjava.util.concurrent.ExecutionException;

importorg.apache.commons.codec.binary.Base32;
importorg.joda.time.DateTime;

importcom.atlassian.jira.rest.client.IssueRestClient;
importcom.atlassian.jira.rest.client.JiraRestClient;
importcom.atlassian.jira.rest.client.SearchRestClient;
importcom.atlassian.jira.rest.client.domain.BasicIssue;
importcom.atlassian.jira.rest.client.domain.BasicProject;
importcom.atlassian.jira.rest.client.domain.BasicUser;
importcom.atlassian.jira.rest.client.domain.Comment;
importcom.atlassian.jira.rest.client.domain.Field;
importcom.atlassian.jira.rest.client.domain.Issue;
importcom.atlassian.jira.rest.client.domain.Project;
importcom.atlassian.jira.rest.client.domain.SearchResult;
importcom.atlassian.jira.rest.client.domain.Transition;
importcom.atlassian.jira.rest.client.domain.input.ComplexIssueInputFieldValue;
importcom.atlassian.jira.rest.client.domain.input.FieldInput;
importcom.atlassian.jira.rest.client.domain.input.IssueInput;
importcom.atlassian.jira.rest.client.domain.input.IssueInputBuilder;
importcom.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
importcom.atlassian.util.concurrent.Promise;
importcom.google.common.collect.Lists;

publicclassCvteJiraDemo{

publicstaticStringBaseURL="http://jira-test:8080/";
publicstaticStringUser="admin";
publicstaticStringPassword="admin";
privatestaticURIjiraServerUri=URI
.create("http://jira-test/rest/api/2/");
privatestaticbooleanquiet=false;
privatestaticfinallongBUG_TYPE_ID=1L;//JIRAmagicvalue
privatestaticfinallongTASK_TYPE_ID=3L;//JIRAmagicvalue
privatestaticfinalDateTimeDUE_DATE=newDateTime();
privatestaticfinalStringPRIORITY="Trivial";
privatestaticfinalStringDESCRIPTION="description";

publicstaticvoidmain(String[]args)throwsInterruptedException,
ExecutionException{

finalAsynchronousJiraRestClientFactoryfactory=newAsynchronousJiraRestClientFactory();
URIjiraServerUri;
try{
jiraServerUri=newURI(BaseURL);
finalJiraRestClientrestClient=(JiraRestClient)factory
.createWithBasicHttpAuthentication(jiraServerUri,User,
Password);
getAllProjects(restClient);
getProject(restClient,"DEMO");
getIssue(restClient,"FEEDBACK-14");
getIssueFields(restClient,"FEEDBACK-27");
addIssue(restClient,"FEEDBACK","AAAAB");
addIssueComplex(restClient,"FEEDBACK",DUE_DATE.toString());

}catch(URISyntaxExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}finally{

}
}

privatestaticvoidprintln(Objecto){
if(!quiet){
System.out.println(o);
}
}

privatestaticvoidparseArgs(String[]argsArray)throwsURISyntaxException{
finalList<String>args=Lists.newArrayList(argsArray);
if(args.contains("-q")){
quiet=true;
args.remove(args.indexOf("-q"));
}

if(!args.isEmpty()){
jiraServerUri=newURI(args.get(0));
}
}

privatestaticTransitiongetTransitionByName(
Iterable<Transition>transitions,StringtransitionName){
for(Transitiontransition:transitions){
if(transition.getName().equals(transitionName)){
returntransition;
}
}
returnnull;
}

//得到所有项目信息
privatestaticvoidgetAllProjects(finalJiraRestClientrestClient)
throwsInterruptedException,ExecutionException{
try{

Promise<Iterable<BasicProject>>list=restClient
.getProjectClient().getAllProjects();
Iterable<BasicProject>a=list.get();
Iterator<BasicProject>it=a.iterator();
while(it.hasNext()){
System.out.println(it.next());
}

}finally{
}
}

//得到单一项目信息
privatestaticvoidgetProject(finalJiraRestClientrestClient,
StringporjectKEY)throwsInterruptedException,ExecutionException{
try{

Projectproject=restClient.getProjectClient()
.getProject(porjectKEY).get();
System.out.println(project);

}finally{
}
}

//得到单一问题信息
privatestaticvoidgetIssue(finalJiraRestClientrestClient,
StringissueKEY)throwsInterruptedException,ExecutionException{
try{

Promise<Issue>list=restClient.getIssueClient()
.getIssue(issueKEY);
Issueissue=list.get();
System.out.println(issue);

}finally{
}
}

//创建问题
publicstaticBasicIssuecreateIssue(finalJiraRestClientjiraRestClient,
IssueInputnewIssue){
BasicIssuebasicIssue=jiraRestClient.getIssueClient()
.createIssue(newIssue).claim();
returnbasicIssue;
}

//添加备注到问题
publicstaticvoidaddCommentToIssue(finalJiraRestClientjiraRestClient,Issueissue,Stringcomment){
IssueRestClientissueClient=jiraRestClient.getIssueClient();
issueClient.addComment(issue.getCommentsUri(),Comment.valueOf(comment)).claim();
}

//删除问题,目前找不到对应API
publicstaticvoiddeleteIssue(finalJiraRestClientjiraRestClient,Issueissue){
IssueRestClientissueClient=jiraRestClient.getIssueClient();
//issueClient.deleteIssue(issue.getKey(),false).claim();
}

//通过标题获取问题
publicstaticIterablefindIssuesByLabel(finalJiraRestClientjiraRestClient,Stringlabel){
SearchRestClientsearchClient=jiraRestClient.getSearchClient();
Stringjql="labels%3D"+label;
com.atlassian.jira.rest.client.domain.SearchResultresults=((SearchRestClient)jiraRestClient).searchJql(jql).claim();
returnresults.getIssues();
}

//通过KEY获取问题
publicstaticIssuefindIssueByIssueKey(finalJiraRestClientjiraRestClient,StringissueKey){
SearchRestClientsearchClient=jiraRestClient.getSearchClient();
Stringjql="issuekey=\""+issueKey+"\"";
SearchResultresults=searchClient.searchJql(jql).claim();
return(Issue)results.getIssues().iterator().next();
}

//创建问题:仅有简单问题名称
privatestaticvoidaddIssue(finalJiraRestClientrestClient,
StringporjectKEY,StringissueName)throwsInterruptedException,
ExecutionException{
try{
IssueInputBuilderbuilder=newIssueInputBuilder(porjectKEY,
TASK_TYPE_ID,issueName);
builder.setDescription("issuedescription");
finalIssueInputinput=builder.build();

try{
//createissue
finalIssueRestClientclient=restClient.getIssueClient();
finalBasicIssueissue=client.createIssue(input).claim();
finalIssueactual=client.getIssue(issue.getKey()).claim();
System.out.println(actual);
}finally{
if(restClient!=null){
//restClient.close();
}
}

}finally{
}
}

//创建问题:包含自定义字段
privatestaticvoidaddIssueComplex(finalJiraRestClientrestClient,
StringporjectKEY,StringissueName)throwsInterruptedException,
ExecutionException{
try{
IssueInputBuilderbuilder=newIssueInputBuilder(porjectKEY,
TASK_TYPE_ID,issueName);
builder.setDescription("issuedescription");
//builder.setFieldValue("priority",ComplexIssueInputFieldValue.with("name",PRIORITY));
//单行文本
builder.setFieldValue("customfield_10042","单行文本测试");

//单选字段
builder.setFieldValue("customfield_10043",ComplexIssueInputFieldValue.with("value","一般"));

//数值自定义字段
builder.setFieldValue("customfield_10044",100.08);

//用户选择自定义字段
builder.setFieldValue("customfield_10045",ComplexIssueInputFieldValue.with("name","admin"));
//用户选择自定义字段(多选)
Map<String,Object>user1=newHashMap<String,Object>();
user1.put("name","admin");
Map<String,Object>user2=newHashMap<String,Object>();
user2.put("name","wangxn");
ArrayListpeoples=newArrayList();
peoples.add(user1);
peoples.add(user2);
builder.setFieldValue("customfield_10047",peoples);

//设定父问题
Map<String,Object>parent=newHashMap<String,Object>();
parent.put("key","FEEDBACK-25");
FieldInputparentField=newFieldInput("parent",newComplexIssueInputFieldValue(parent));
builder.setFieldInput(parentField);

finalIssueInputinput=builder.build();
try{
finalIssueRestClientclient=restClient.getIssueClient();
finalBasicIssueissue=client.createIssue(input).claim();
finalIssueactual=client.getIssue(issue.getKey()).claim();
System.out.println(actual);
}finally{
if(restClient!=null){
//restClient.close();
}
}

}finally{
}
}

//获取问题的所有字段
privatestaticvoidgetIssueFields(finalJiraRestClientrestClient,
StringissueKEY)throwsInterruptedException,ExecutionException{
try{

Promise<Issue>list=restClient.getIssueClient()
.getIssue(issueKEY);
Issueissue=list.get();
Iterable<Field>fields=issue.getFields();
Iterator<Field>it=fields.iterator();
while(it.hasNext()){
System.out.println(it.next());
}

}finally{
}
}

}





                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: