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

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

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

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

jira的Rest API  最新文档官网.

JIRA 6.4.12 REST API documentation

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

JIRA REST API Tutorials:

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

 

如果是编写java桌面或web应用,jira提供了更方便的方式(Client类库),JIRA REST Java Client is a Java library (usable from any JVM language) which allows to easily talk to any JIRA 4.2+ instance using new (and still evolving) REST API.

JIRA Java Client library 

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

 

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

 

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

1
http://hostname/rest/<api-name>/<api-version>/<resource-name>
JIRA's REST API is provided by a plugin that is anchored under the URI path component  /rest/. Hence, if your JIRA site is running at:


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

 the first step in using the JIRA REST API is to authenticate a user account with your JIRA site. For the purposes of this tutorial we will use HTTP BASIC Authentication, but any authentication that works against JIRA will work against the REST API. This includes:

  1. OAuth
  2. HTTP Cookies
  3. Trusted Applications
  4. os_username/os_password query parameters

为方便使用,我们采用Basic Auth

Basic Auth headers

If you need to you may construct and send basic auth headers yourself. To do this you need to perform the following steps:

  1. Build a string of the form username:password
  2. Base64 encode the string
  3. Supply an "Authorization" header with content "Basic " followed by the encoded string. For example, the string "fred:fred" encodes to "ZnJlZDpmcmVk" in base64, so you would make the request as follows.
一个curl的例子,注意红色字符串是对“username:password”的Base64编码
curl -D- -X GET -H "Authorization: Basic ZnJlZDpmcmVk" -H "Content-Type: application/json" "http://kelpie9:8081/rest/api/2/issue/QA-31"

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

1、C#实现的API包装类

复制代码
 

public class JiraApi
{
private string m_Username;
private string m_Password;

public JiraApi(string username, string password)
{
m_Username = username;
m_Password = password;
}

/// <summary>
/// 处理post请求,执行新建、编辑、删除等操作
/// </summary>
/// <param name="sData">json输入字符</param>
/// <param name="uri">api的具体地址,一般是baseurl + 业务处理资源关键字</param>
/// <returns>Jira返回的WebResponse输出</returns>
public string DoPost(string sData, string uri)
{
Uri address = new Uri(uri);
HttpWebRequest request;
//HttpWebResponse response1 = null;
StreamReader sr;
string returnXML = string.Empty;
if (address == null) { throw new ArgumentNullException("address"); }
try
{
request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/json";
string base64Credentials = GetEncodedCredentials();
request.Headers.Add("Authorization", "Basic " + base64Credentials);
//request.Credentials = new NetworkCredential(sUsername, sPassword);
if (sData != null)
{
byte[] byteData = UTF8Encoding.UTF8.GetBytes(sData);
request.ContentLength = byteData.Length;
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
using (HttpWebResponse response1 = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response1.GetResponseStream());
string str = reader.ReadToEnd();
return str;

}
}
return "error";

}
catch (WebException wex)
{

if (wex.Response != null)
{

using (HttpWebResponse errorResponse = (HttpWebResponse)wex.Response)
{
try
{
string sError = string.Format("The server returned '{0}' with the status code {1} ({2:d}).",
errorResponse.StatusDescription, errorResponse.StatusCode,
errorResponse.StatusCode);
sr = new StreamReader(errorResponse.GetResponseStream(), Encoding.UTF8);
returnXML = sr.ReadToEnd();
return returnXML;

}
finally
{
if (errorResponse != null) errorResponse.Close();
}
}
}
else
{
//throw new Exception(wex.Message);
return wex.Message;

}
}
}

 

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

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

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

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

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

HttpWebResponse response = request.GetResponse() as HttpWebResponse;

string result = string.Empty;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}

return result;

}

private string GetEncodedCredentials()
{
string mergedCredentials = string.Format("{0}:{1}", m_Username, m_Password);
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
return Convert.ToBase64String(byteCredentials);
}
}

调用方法:查询Get

复制代码

/// <summary>
/// 查询jira的项目情况
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Page_Load(object sender, EventArgs e)
{
JiraApi manager = new JiraApi(Config.User, Config.Password);
Response.Write(manager.DoQuery("project"));
}

 

调用方法:提交Post

复制代码

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
JiraApi api = new JiraApi(Config.User, Config.Password);
//对问题添加备注
SubmitComment(api, Request.QueryString["issue"], Request.QueryString["comment"]);
}
}
/// <summary>
/// 添加问题的备注
/// </summary>
/// <param name="jm">JiraApi实例</param>
/// <param name="issue">问题的关键字,比如SomeIssue-18</param>
/// <param name="comment">备注的内容</param>
private void SubmitComment(JiraApi api, string issue, string comment)
{
string sData = string.Format("{\"body\": \"{0}\"}", comment);
string uri = Config.BaseURL + string.Format("issue/{0}/comment", issue);
Response.Write(api.DoPost(sData, uri));
}

 

 

2、JAVA Client类库实现的API DEMO

 
          
package jiraTEST;

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

import org.apache.commons.codec.binary.Base32;
import org.joda.time.DateTime;

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

public class CvteJiraDemo {

    public static String BaseURL = "http://jira-test:8080/";
    public static String User = "admin";
    public static String Password = "admin";
    private static URI jiraServerUri = URI
            .create("http://jira-test/rest/api/2/");
    private static boolean quiet = false;
    private static final long BUG_TYPE_ID = 1L; // JIRA magic value
    private static final long TASK_TYPE_ID = 3L; // JIRA magic value
    private static final DateTime DUE_DATE = new DateTime();
    private static final String PRIORITY = "Trivial";
    private static final String DESCRIPTION = "description";

    

    public static void main(String[] args) throws InterruptedException,
            ExecutionException {

        final AsynchronousJiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
        URI jiraServerUri;
        try {
            jiraServerUri = new URI(BaseURL);
            final JiraRestClient restClient = (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 (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {

        }
    }
    
    private static void println(Object o) {
        if (!quiet) {
            System.out.println(o);
        }
    }

    private static void parseArgs(String[] argsArray) throws URISyntaxException {
        final List<String> args = Lists.newArrayList(argsArray);
        if (args.contains("-q")) {
            quiet = true;
            args.remove(args.indexOf("-q"));
        }

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

    private static Transition getTransitionByName(
            Iterable<Transition> transitions, String transitionName) {
        for (Transition transition : transitions) {
            if (transition.getName().equals(transitionName)) {
                return transition;
            }
        }
        return null;
    }

    // 得到所有项目信息
    private static void getAllProjects(final JiraRestClient restClient)
            throws InterruptedException, 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 {
        }
    }

    // 得到单一项目信息
    private static void getProject(final JiraRestClient restClient,
            String porjectKEY) throws InterruptedException, ExecutionException {
        try {

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

        } finally {
        }
    }

    // 得到单一问题信息
    private static void getIssue(final JiraRestClient restClient,
            String issueKEY) throws InterruptedException, ExecutionException {
        try {

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

        } finally {
        }
    }
    
    // 创建问题
    public static BasicIssue createIssue(final JiraRestClient jiraRestClient,
            IssueInput newIssue) {
        BasicIssue basicIssue = jiraRestClient.getIssueClient()
                .createIssue(newIssue).claim();
        return basicIssue;
    }
    
    //添加备注到问题
    public static void addCommentToIssue(final JiraRestClient jiraRestClient,Issue issue, String comment) {
        IssueRestClient issueClient = jiraRestClient.getIssueClient();
        issueClient.addComment(issue.getCommentsUri(), Comment.valueOf(comment)).claim();
    }
    
    
    //删除问题,目前找不到对应API
    public static void deleteIssue(final JiraRestClient jiraRestClient, Issue issue) {
        IssueRestClient issueClient = jiraRestClient.getIssueClient();
        //issueClient.deleteIssue(issue.getKey(), false).claim();
    }

    //通过标题获取问题
    public static Iterable findIssuesByLabel(final JiraRestClient jiraRestClient, String label) {
        SearchRestClient searchClient = jiraRestClient.getSearchClient();
        String jql = "labels%3D"+label;
        com.atlassian.jira.rest.client.domain.SearchResult results = ((SearchRestClient) jiraRestClient).searchJql(jql).claim();
        return results.getIssues();
    }

    //通过KEY获取问题
    public static Issue findIssueByIssueKey(final JiraRestClient jiraRestClient, String issueKey) {
        SearchRestClient searchClient = jiraRestClient.getSearchClient();
        String jql = "issuekey = \"" + issueKey + "\"";
        SearchResult results = searchClient.searchJql(jql).claim();
        return (Issue) results.getIssues().iterator().next();
    }

    // 创建问题 :仅有简单问题名称
    private static void addIssue(final JiraRestClient restClient,
            String porjectKEY, String issueName) throws InterruptedException,
            ExecutionException {
        try {
            IssueInputBuilder builder = new IssueInputBuilder(porjectKEY,
                    TASK_TYPE_ID, issueName);
            builder.setDescription("issue description");
            final IssueInput input = builder.build();

            try {
                // create issue
                final IssueRestClient client = restClient.getIssueClient();
                final BasicIssue issue = client.createIssue(input).claim();
                final Issue actual = client.getIssue(issue.getKey()).claim();
                System.out.println(actual);
            } finally {
                if (restClient != null) {
                    // restClient.close();
                }
            }

        } finally {
        }
    }

    // 创建问题 :包含自定义字段
    private static void addIssueComplex(final JiraRestClient restClient,
            String porjectKEY, String issueName) throws InterruptedException,
            ExecutionException {
        try {
            IssueInputBuilder builder = new IssueInputBuilder(porjectKEY,
                    TASK_TYPE_ID, issueName);
            builder.setDescription("issue description");
            // 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 = new HashMap<String, Object>();
            user1.put("name", "admin");
            Map<String, Object> user2 = new HashMap<String, Object>();
            user2.put("name", "wangxn");            
            ArrayList peoples = new ArrayList();
            peoples.add(user1);
            peoples.add(user2);
            builder.setFieldValue("customfield_10047", peoples); 
            
            //设定父问题
            Map<String, Object> parent = new HashMap<String, Object>();
            parent.put("key", "FEEDBACK-25");
            FieldInput parentField = new FieldInput("parent", new ComplexIssueInputFieldValue(parent));
            builder.setFieldInput(parentField);

            final IssueInput input = builder.build();
            try {
                final IssueRestClient client = restClient.getIssueClient();
                final BasicIssue issue = client.createIssue(input).claim();
                final Issue actual = client.getIssue(issue.getKey()).claim();
                System.out.println(actual);
            } finally {
                if (restClient != null) {
                    // restClient.close();
                }
            }

        } finally {
        }
    }

    
    //获取问题的所有字段
    private static void getIssueFields(final JiraRestClient restClient,
            String issueKEY) throws InterruptedException, ExecutionException {
        try {

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

        } finally {
        }
    }

}
 
          

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: JIRA REST API是指JIRA软件提供的一组可以通过HTTP请求进行访问的API,开发人员可以使用这些API来与JIRA进行交互,以便于对其进行自动化管理或者扩展其功能。 通过JIRA REST API,可以对JIRA上的数据进行增删改查,包括用户、问题、工作流等,可以在外部系统中操作JIRA,实现自动化集成。此外,JIRA REST API还可以用于获取有关问题、项目和其他相关数据的报告。 JIRA REST API的意义在于,它允许开发人员在自己的应用程序中使用JIRA的数据,提高工作效率和协作效率,使得更多的业务流程可以自动化。 ### 回答2: JIRA REST API是一种用于与JIRA软件进行交互的编程接口,它允许开发人员通过发送HTTP请求来执行各种操作,如创建、更新、删除和检索JIRA项目、问题、评论等。 JIRA REST API的意义在于它提供了一种灵活、可扩展的方式来集成和扩展JIRA软件。通过使用这个API,我们可以通过编程方式自动化执行JIRA操作,而不需要手动操作JIRA界面。这可以显著提高工作效率,减少人工操作的错误和重复性工作,同时提供更好的系统可管理性。 JIRA REST API的应用范围非常广泛。例如,开发人员可以使用API自动创建和更新JIRA任务,将其与其他系统集成,如持续集成工具、版本控制系统等。同时,通过API,开发人员可以从JIRA中获取问题和项目的详细信息,并将其用于数据分析、报告生成等用途。 另外,除了开发人员,普通用户也可以通过JIRA REST API来实现自己的定制需求。他们可以使用API来创建和更新问题,管理自己的任务和项目等。这为用户提供了更多灵活性和便利性,使他们能够根据自己的工作需要进行个性化配置和管理。 总之,JIRA REST API是一个重要的工具,它能够帮助开发人员和用户与JIRA软件进行交互,实现自动化、集成和定制化的需求。它可以提高工作效率,减少错误和重复性工作,并提供更好的系统可管理性。 ### 回答3: JIRA REST APIJIRA软件提供的一种用于与其他应用程序集成的接口,通过发送HTTP请求和接收JSON响应,可以实现对JIRA软件的数据和功能进行操作和访问。 JIRA REST API的意义主要体现在以下几个方面: 1. 数据交互:通过REST API,可以方便地将JIRA软件中的数据与其他应用程序进行交互和共享。例如,可以根据需要从JIRA获取任务数据,将其与其他系统中的数据进行关联,实现项目管理、任务分配等功能。 2. 自动化操作:利用JIRA REST API,可以编写脚本或开发自动化工具,实现对JIRA的自动化操作。例如,可以编写Python脚本来自动创建JIRA任务、更新任务状态等,节省了手动操作的时间与精力。 3. 扩展功能:通过JIRA REST API,开发人员可以在JIRA软件的基础上构建自己的应用程序或插件,扩展JIRA的功能。例如,可以开发一个自定义的JIRA报表工具,根据项目需求生成特定的报表。 4. 效率提升:利用JIRA REST API可以方便地集成其他工具或系统,实现数据的互通与共享。这可以帮助团队成员提高工作效率,减少重复性工作的产生。 总而言之,JIRA REST API的出现使得JIRA软件在与其他系统集成和扩展功能方面变得更加灵活和强大,帮助用户更好地管理项目和任务,提高工作效率。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值