This library allows you to interact with a Jira instance and choose which HTTP client to use. It is also easily extendable, allowing you to have custom clients and issues classes. All requests are performed asynchronously and return a CompletableFuture. The serialization and deserialization of domain objects are performed using Jackson.
Presently, it supports the following HTTP clients:
- Java HTTP client (included since Java 11)
- Apache HTTP client 5.4
- OkHttp client 4.12
- Vert.x client 4.5
Note that this library has been tested with a Jira instance version 9.12.
The dependency is available in maven central (see badge for version):
<dependency>
<groupId>com.chavaillaz</groupId>
<artifactId>jira-client</artifactId>
</dependency>
Don't forget to also declare the HTTP client you want to use as a dependency (see below), as it is only indicated as optional in the project, to avoid gathering them all together despite the fact that only one is needed.
It does not require any dependency (already in Java).
It requires the following dependency:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.4.x</version>
</dependency>
It requires the following dependency:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.x</version>
</dependency>
It requires the following dependency:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>4.5.x</version>
</dependency>
- IssueApi -
Everything for issues, including comments, links, transitions, attachments and work logs
- Issues
addIssue(Issue issue)
getIssue(String issueKey)
getIssue(String issueKey, Set<IssueExpand> flags)
getIssue(String issueKey, Set<IssueExpand> flags, Set<String> fields)
getIssueOptional(String issueKey)
getIssueOptional(String issueKey, Set<IssueExpand> flags)
getIssueOptional(String issueKey, Set<IssueExpand> flags, Set<String> fields)
updateIssue(Issue issue)
deleteIssue(String issueKey)
assignIssue(String issueKey, User user)
unassignIssue(String issueKey)
getTransitions(String issueKey)
doTransition(String issueKey, IssueTransition transition)
- Comments
getComments(String issueKey)
getComments(String issueKey, Integer startAt, Integer maxResults)
getComments(String issueKey, Integer startAt, Integer maxResults, Set<CommentExpand> flags)
getComment(String issueKey, String id)
getComment(String issueKey, String id, Set<CommentExpand> flags)
getCommentOptional(String issueKey, String id)
getCommentOptional(String issueKey, String id, Set<CommentExpand> flags)
addComment(String issueKey, Comment comment)
updateComment(String issueKey, Comment comment)
deleteComment(String issueKey, String id)
- Votes
addVote(String issueKey)
getVotes(String issueKey)
- Watchers
getWatchers(String issueKey)
addWatcher(String issueKey, String username)
deleteWatcher(String issueKey, String username)
- Work Logs
addWorkLog(String issueKey, WorkLog workLog)
getWorkLogs(String issueKey)
getWorkLog(String issueKey, String id)
getWorkLogOptional(String issueKey, String id)
updateWorkLog(String issueKey, WorkLog workLog)
deleteWorkLog(String issueKey, String id)
- Attachments
getAttachment(String id)
getAttachmentOptional(String id)
getAttachmentContent(String url)
addAttachment(String issueKey, File... files)
deleteAttachment(String id)
- Remote Links
getRemoteLinks(String issueKey)
getRemoteLink(String issueKey, String id)
getRemoteLinkOptional(String issueKey, String id)
addRemoteLink(String issueKey, RemoteLink remoteLink)
updateRemoteLink(String issueKey, RemoteLink remoteLink)
deleteRemoteLink(String issueKey, String id)
- Issue Links
getIssueLink(String id)
getIssueLinkOptional(String id)
addIssueLink(Link link)
deleteIssueLink(String id)
- Issues
- SearchApi -
Everything for searches, including filters
- Searches
getIssues(Set<String> issuesKey)
getIssues(Set<String> issuesKey, Set<String> fields)
searchIssues(String jql)
searchIssues(String jql, Integer startAt, Integer maxResults)
searchIssues(String jql, Integer startAt, Integer maxResults, Set<IssueExpand> expand)
searchIssues(String jql, Integer startAt, Integer maxResults, Set<IssueExpand> expand, Set<String> fields)
- Filters
addFilter(Filter filter)
getFilter(String id)
getFilterOptional(String id)
getFavoriteFilters()
updateFilter(String id, Filter filter)
deleteFilter(String id)
- Searches
- ProjectApi -
Everything for projects, including components, versions, statuses and roles
addProject(ProjectChange project)
getProjects()
getProjects(boolean includeArchived, String expand)
getProject(String projectKey)
getProjectOptional(String projectKey)
getProjectVersions(String projectKey)
getProjectComponents(String projectKey)
getProjectStatuses(String projectKey)
getProjectRoles(String projectKey)
updateProject(String projectKey, ProjectChange project)
deleteProject(String projectKey)
- UserApi -
Everything for users
getUsers(String search)
getUsers(String search, Integer startAt, Integer maxResults, Boolean includeInactive)
getAssignableUsers(String search, String key)
getAssignableUsers(String search, String key, Integer startAt, Integer maxResults, Boolean includeInactive)
getUser(String username)
getUserOptional(String username)
getCurrentUser()
Instantiate the Jira client of your choice by giving your Jira instance URL. Depending on your needs, you may also want
to add authentication with a personal access token (PAT) using withTokenAuthentication
or with username and password
using withUserAuthentication
method. If you need to connect via a proxy, you can specify it with withProxy
. Below
an example for each HTTP client:
JiraClient<Issue> client = JiraClient.javaClient("https://jira.mycompany.com")
.withUserAuthentication("myUsername","myPassword")
.withProxy("http://proxy.mycompany.com:1234");
JiraClient<Issue> client = JiraClient.apacheClient("https://jira.mycompany.com")
.withUserAuthentication("myUsername","myPassword")
.withProxy("http://proxy.mycompany.com:1234");
JiraClient<Issue> client = JiraClient.okHttpClient("https://jira.mycompany.com")
.withUserAuthentication("myUsername","myPassword")
.withProxy("http://proxy.mycompany.com:1234");
JiraClient<Issue> client = JiraClient.vertxClient("https://jira.mycompany.com")
.withUserAuthentication("myUsername","myPassword")
.withProxy("http://proxy.mycompany.com:1234");
From this JiraClient
you will then be able to get the desired APIs described in the feature chapter.
When requesting a list of elements, the client returns an object encapsulating this list, sometimes with more pieces of information depending on the Jira endpoint called. From this object, you can iterate directly on its child elements as in the example below:
Consumer<Filter> deleteFilter = filter -> client.getSearchClient().deleteFilter(filter.getId());
client.getSearchClient().getFavoriteFilters()
.thenAccept(filters -> filters.forEach(deleteFilter));
If your project has custom fields for issues, you have two choices in order to get and set them.
First possibility, simply use issue.getFields().getCustomFields().get("customfield_12345")
to get the field and
issue.getFields().getCustomFields().put("customfield_12345", value)
to set a value for this field.
Second possibility, create a new class extending Fields
to hide the custom fields identifiers and interact with Jira
in a more understandable way:
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class CompanyFields extends Fields {
@JsonProperty("customfield_12345")
private User businessEngineer;
...
}
A new Issue
class will also be needed to override the fields
attribute:
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class CompanyIssue extends Issue {
private CompanyFields fields;
}
Finally, specify it when instantiating the JiraClient
, for example with Apache HTTP client:
JiraClient<CompanyIssue> client = new ApacheHttpJiraClient<>("https://jira.mycompany.com", CompanyIssue.class);
Please be aware that both solutions cannot live together as when you have attributes in the class for your fields, it
will then not be in the customFields
map (containing all the unmapped fields).
If you have a feature request or found a bug, you can:
- Write an issue
- Create a pull request
The code style is based on the default one from IntelliJ, except for the following cases:
Imports are ordered as follows:
- All static imports in a block
- Java non-static imports in a block
- All non-static imports in a block
A single blank line separates every block. Within each block the imported names appear in alphabetical sort order. Wildcard imports, static or otherwise, are not used.
The attributes of domain classes are ordered alphabetically.
This project is under Apache 2.0 License.