1
0
Fork 0

Merge pull request #9 from rcarz/master

Merge from rcarz
master
Kyle Chaplin 2013-10-08 19:05:58 -07:00
commit 42a9d66492
5 changed files with 350 additions and 44 deletions

View File

@ -1,2 +1,3 @@
Bob Carroll <bob.carroll@alum.rit.edu> @rcarz
Kyle Chaplin <chaplinkyle@gmail.com> @chaplinkyle
Alesandro Lang <info@alesandro-lang.com> @alesandroLang

View File

@ -105,6 +105,7 @@ public class Example {
add("foo");
add("bar");
}})
.field(Field.PRIORITY, Field.valueById("1")) /* you can also set the value by ID */
.execute();
/* You can also update values with field operations. */

View File

@ -69,6 +69,47 @@ public final class Field {
}
}
/**
* Allowed value types.
*/
public enum ValueType {
KEY("key"), NAME("name"), ID_NUMBER("id");
private String value;
private ValueType(String value) {
this.value = value;
}
};
/**
* Value and value type pair.
*/
public static final class ValueTuple {
public final String type;
public final Object value;
/**
* Initialises the value tuple.
*
* @param type
* @param value
*/
public ValueTuple(String type, Object value) {
this.type = type;
this.value = value;
}
/**
* Initialises the value tuple.
*
* @param type
* @param value
*/
public ValueTuple(ValueType type, Object value) {
this(type.value, value);
}
}
public static final String ASSIGNEE = "assignee";
public static final String ATTACHMENT = "attachment";
public static final String COMMENT = "comment";
@ -424,7 +465,12 @@ public final class Field {
type.equals("user") || type.equals("version")) {
JSONObject json = new JSONObject();
json.put("name", val.toString());
if (val instanceof ValueTuple) {
ValueTuple tuple = (ValueTuple)val;
json.put(tuple.type, tuple.value.toString());
} else
json.put(ValueType.NAME.value, val.toString());
result.add(json.toString());
} else if (type.equals("string"))
@ -491,12 +537,22 @@ public final class Field {
} else if (m.type.equals("issuetype") || m.type.equals("priority") ||
m.type.equals("user") || m.type.equals("resolution")) {
JSONObject json = new JSONObject();
json.put("name", value.toString());
if (value instanceof ValueTuple) {
ValueTuple tuple = (ValueTuple)value;
json.put(tuple.type, tuple.value.toString());
} else
json.put(ValueType.NAME.value, value.toString());
return json.toString();
} else if (m.type.equals("project") || m.type.equals("issuelink")) {
JSONObject json = new JSONObject();
json.put("key", value.toString());
if (value instanceof ValueTuple) {
ValueTuple tuple = (ValueTuple)value;
json.put(tuple.type, tuple.value.toString());
} else
json.put(ValueType.KEY.value, value.toString());
return json.toString();
} else if (m.type.equals("string")) {
@ -524,5 +580,38 @@ public final class Field {
return json.toString();
}
/**
* Create a value tuple with value type of key.
*
* @param key The key value
*
* @return a value tuple
*/
public static ValueTuple valueByKey(String key) {
return new ValueTuple(ValueType.KEY, key);
}
/**
* Create a value tuple with value type of name.
*
* @param key The name value
*
* @return a value tuple
*/
public static ValueTuple valueByName(String name) {
return new ValueTuple(ValueType.NAME, name);
}
/**
* Create a value tuple with value type of ID number.
*
* @param key The ID number value
*
* @return a value tuple
*/
public static ValueTuple valueById(String id) {
return new ValueTuple(ValueType.ID_NUMBER, id);
}
}

View File

@ -51,15 +51,54 @@ public class Issue extends Resource {
}
/**
* Executes the create action.
* Executes the create action (issue includes all fields).
*
* @throws JiraException when the create fails
*/
public Issue execute() throws JiraException {
return executeCreate(null);
}
/**
* Executes the create action and specify which fields to retrieve.
*
* @param includedFields Specifies which issue fields will be included
* in the result.
* <br>Some examples how this parameter works:
* <ul>
* <li>*all - include all fields</li>
* <li>*navigable - include just navigable fields</li>
* <li>summary,comment - include just the summary and comments</li>
* <li>*all,-comment - include all fields</li>
* </ul>
*
* @throws JiraException when the create fails
*/
public Issue execute(String includedFields) throws JiraException {
return executeCreate(includedFields);
}
/**
* Executes the create action and specify which fields to retrieve.
*
* @param includedFields Specifies which issue fields will be included
* in the result.
* <br>Some examples how this parameter works:
* <ul>
* <li>*all - include all fields</li>
* <li>*navigable - include just navigable fields</li>
* <li>summary,comment - include just the summary and comments</li>
* <li>*all,-comment - include all fields</li>
* </ul>
*
* @throws JiraException when the create fails
*/
private Issue executeCreate(String includedFields) throws JiraException {
JSONObject fieldmap = new JSONObject();
if (fields.size() == 0)
if (fields.size() == 0) {
throw new JiraException("No fields were given for create");
}
for (Map.Entry<String, Object> ent : fields.entrySet()) {
Object newval = Field.toJson(ent.getKey(), ent.getValue(), createmeta);
@ -77,11 +116,16 @@ public class Issue extends Resource {
throw new JiraException("Failed to create issue", ex);
}
if (!(result instanceof JSONObject) || !((JSONObject)result).containsKey("key") ||
!(((JSONObject)result).get("key") instanceof String))
if (!(result instanceof JSONObject) || !((JSONObject) result).containsKey("key")
|| !(((JSONObject) result).get("key") instanceof String)) {
throw new JiraException("Unexpected result on create issue");
}
return Issue.get(restclient, (String)((JSONObject)result).get("key"));
if (includedFields != null) {
return Issue.get(restclient, (String) ((JSONObject) result).get("key"), includedFields);
} else {
return Issue.get(restclient, (String) ((JSONObject) result).get("key"));
}
}
/**
@ -633,24 +677,26 @@ public class Issue extends Resource {
public FluentCreate createSubtask() throws JiraException {
return Issue.create(restclient, getProject().getKey(), "Sub-task")
.field("parent", getKey());
.field("parent", getKey());
}
private static JSONObject realGet(RestClient restclient, String key)
throws JiraException {
private static JSONObject realGet(RestClient restclient, String key, Map<String, String> queryParams)
throws JiraException {
JSON result = null;
try {
result = restclient.get(getRestUri(key));
URI uri = restclient.buildURI(RESOURCE_URI + "issue/" + key, queryParams);
result = restclient.get(uri);
} catch (Exception ex) {
throw new JiraException("Failed to retrieve issue " + key, ex);
}
if (!(result instanceof JSONObject))
if (!(result instanceof JSONObject)) {
throw new JiraException("JSON payload is malformed");
}
return (JSONObject)result;
return (JSONObject) result;
}
/**
@ -659,48 +705,114 @@ public class Issue extends Resource {
* @param restclient REST client instance
* @param key Issue key (PROJECT-123)
*
* @return an issue instance
* @return an issue instance (issue includes all navigable fields)
*
* @throws JiraException when the retrieval fails
*/
public static Issue get(RestClient restclient, String key)
throws JiraException {
throws JiraException {
return new Issue(restclient, realGet(restclient, key));
return new Issue(restclient, realGet(restclient, key, new HashMap<String, String>()));
}
/**
* Retrieves the given issue record.
*
* @param restclient REST client instance
*
* @param key Issue key (PROJECT-123)
*
* @param includedFields Specifies which issue fields will be included in
* the result.
* <br>Some examples how this parameter works:
* <ul>
* <li>*all - include all fields</li>
* <li>*navigable - include just navigable fields</li>
* <li>summary,comment - include just the summary and comments</li>
* <li>*all,-comment - include all fields</li>
* </ul>
*
* @return an issue instance
*
* @throws JiraException when the retrieval fails
*/
public static Issue get(RestClient restclient, String key, final String includedFields)
throws JiraException {
Map<String, String> queryParams = new HashMap<String, String>() {
{
put("fields", includedFields);
}
};
return new Issue(restclient, realGet(restclient, key, queryParams));
}
/**
* Search for issues with the given query.
*
* @param restclient REST client instance
*
* @param jql JQL statement
*
* @return a search result structure with results (issues include all
* navigable fields)
*
* @throws JiraException when the search fails
*/
public static SearchResult search(RestClient restclient, String jql)
throws JiraException {
return search(restclient, jql, null);
}
/**
* Search for issues with the given query and specify which fields to
* retrieve.
*
* @param restclient REST client instance
*
* @param jql JQL statement
*
* @param includedFields Specifies which issue fields will be included in
* the result.
* <br>Some examples how this parameter works:
* <ul>
* <li>*all - include all fields</li>
* <li>*navigable - include just navigable fields</li>
* <li>summary,comment - include just the summary and comments</li>
* <li>*all,-comment - include all fields</li>
* </ul>
*
* @return a search result structure with results
*
* @throws JiraException when the search fails
*/
public static SearchResult search(RestClient restclient, String jql)
throws JiraException {
public static SearchResult search(RestClient restclient, String jql, String includedFields)
throws JiraException {
final String j = jql;
JSON result = null;
try {
URI searchUri = restclient.buildURI(
RESOURCE_URI + "search",
new HashMap<String, String>() {{
Map<String, String> queryParams = new HashMap<String, String>() {
{
put("jql", j);
}});
}
};
if (includedFields != null) {
queryParams.put("fields", includedFields);
}
URI searchUri = restclient.buildURI(RESOURCE_URI + "search", queryParams);
result = restclient.get(searchUri);
} catch (Exception ex) {
throw new JiraException("Failed to search issues", ex);
}
if (!(result instanceof JSONObject))
if (!(result instanceof JSONObject)) {
throw new JiraException("JSON payload is malformed");
}
SearchResult sr = new SearchResult();
Map map = (Map)result;
Map map = (Map) result;
sr.start = Field.getInteger(map.get("startAt"));
sr.max = Field.getInteger(map.get("maxResults"));
@ -711,12 +823,40 @@ public class Issue extends Resource {
}
/**
* Reloads issue data from the JIRA server.
* Reloads issue data from the JIRA server (issue includes all navigable
* fields).
*
* @throws JiraException when the retrieval fails
*/
public void refresh() throws JiraException {
JSONObject result = realGet(restclient, key);
JSONObject result = realGet(restclient, key, new HashMap<String, String>());
deserialise(result);
}
/**
* Reloads issue data from the JIRA server and specify which fields to
* retrieve.
*
* @param includedFields Specifies which issue fields will be included in
* the result.
* <br>Some examples how this parameter works:
* <ul>
* <li>*all - include all fields</li>
* <li>*navigable - include just navigable fields</li>
* <li>summary,comment - include just the summary and comments</li>
* <li>*all,-comment - include all fields</li>
* </ul>
*
* @throws JiraException when the retrieval fails
*/
public void refresh(final String includedFields) throws JiraException {
Map<String, String> queryParams = new HashMap<String, String>() {
{
put("fields", includedFields);
}
};
JSONObject result = realGet(restclient, key, queryParams);
deserialise(result);
}

View File

@ -1,7 +1,7 @@
/**
* jira-client - a simple JIRA REST client
* Copyright (c) 2013 Bob Carroll (bob.carroll@alum.rit.edu)
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@ -20,10 +20,11 @@
package net.rcarz.jiraclient;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.http.impl.client.DefaultHttpClient;
/**
@ -56,7 +57,7 @@ public class JiraClient {
if (creds != null)
username = creds.getLogonName();
}
}
/**
* Creates a new issue in the given project.
@ -69,7 +70,7 @@ public class JiraClient {
* @throws JiraException when something goes wrong
*/
public Issue.FluentCreate createIssue(String project, String issueType)
throws JiraException {
throws JiraException {
return Issue.create(restclient, project, issueType);
}
@ -79,7 +80,7 @@ public class JiraClient {
*
* @param key Issue key (PROJECT-123)
*
* @return an issue instance
* @return an issue instance (issue includes all fields)
*
* @throws JiraException when something goes wrong
*/
@ -87,27 +88,101 @@ public class JiraClient {
return Issue.get(restclient, key);
}
/**
* Retreives the issue with the given key.
*
* @param key Issue key (PROJECT-123)
*
* @param includedFields Specifies which issue fields will be included in
* the result.
* <br>Some examples how this parameter works:
* <ul>
* <li>*all - include all fields</li>
* <li>*navigable - include just navigable fields</li>
* <li>summary,comment - include just the summary and comments</li>
* <li>*all,-comment - include all fields</li>
* </ul>
*
* @return an issue instance
*
* @throws JiraException when something goes wrong
*/
public Issue getIssue(String key, String includedFields) throws JiraException {
return Issue.get(restclient, key, includedFields);
}
/**
* Search for issues with the given query.
*
* @param jql JQL statement
*
* @return a search result structure with results (issues include all
* navigable fields)
*
* @throws JiraException when the search fails
*/
public Issue.SearchResult searchIssues(String jql)
throws JiraException {
return Issue.search(restclient, jql);
}
/**
* Search for issues with the given query and specify which fields to
* retrieve.
*
* @param jql JQL statement
*
* @param includedFields Specifies which issue fields will be included in
* the result.
* <br>Some examples how this parameter works:
* <ul>
* <li>*all - include all fields</li>
* <li>*navigable - include just navigable fields</li>
* <li>summary,comment - include just the summary and comments</li>
* <li>*all,-comment - include all fields</li>
* </ul>
*
*
* @return a search result structure with results
*
* @throws JiraException when the search fails
*/
public Issue.SearchResult searchIssues(String jql)
throws JiraException {
public Issue.SearchResult searchIssues(String jql, String includedFields)
throws JiraException {
return Issue.search(restclient, jql);
return Issue.search(restclient, jql, includedFields);
}
/**
*
* @return a list of all priorities available in the Jira installation
* @throws JiraException
*/
public List<Priority> getPriorities() throws JiraException {
try {
URI uri = restclient.buildURI(Resource.RESOURCE_URI + "priority");
JSON response = restclient.get(uri);
JSONArray prioritiesArray = JSONArray.fromObject(response);
List<Priority> priorities = new ArrayList<Priority>(prioritiesArray.size());
for (int i = 0; i < prioritiesArray.size(); i++) {
JSONObject p = prioritiesArray.getJSONObject(i);
priorities.add(new Priority(restclient, p));
}
return priorities;
} catch (Exception ex) {
throw new JiraException(ex.getMessage(), ex);
}
}
/**
* Get a list of options for a custom field
*
* @param field field id
* @param project Key of the project context
* @param issueType Name of the issue type
* @param issueType Name of the issue type
*
* @return a search result structure with results
*
@ -117,18 +192,18 @@ public class JiraClient {
JSONObject createMetadata = (JSONObject) Issue.getCreateMetadata(restclient, project, issueType);
JSONObject fieldMetadata = (JSONObject) createMetadata.get(field);
List<CustomFieldOption> customFieldOptions = Field.getResourceArray(
CustomFieldOption.class,
fieldMetadata.get("allowedValues"),
CustomFieldOption.class,
fieldMetadata.get("allowedValues"),
restclient
);
return customFieldOptions;
}
/**
* Get a list of options for a components
*
* @param project Key of the project context
* @param issueType Name of the issue type
* @param issueType Name of the issue type
*
* @return a search result structure with results
*
@ -138,8 +213,8 @@ public class JiraClient {
JSONObject createMetadata = (JSONObject) Issue.getCreateMetadata(restclient, project, issueType);
JSONObject fieldMetadata = (JSONObject) createMetadata.get(Field.COMPONENTS);
List<Component> componentOptions = Field.getResourceArray(
Component.class,
fieldMetadata.get("allowedValues"),
Component.class,
fieldMetadata.get("allowedValues"),
restclient
);
return componentOptions;