diff --git a/README.md b/README.md index f58e16e..dd9aca4 100644 --- a/README.md +++ b/README.md @@ -279,30 +279,27 @@ public class Example { https://docs.atlassian.com/jira-software/REST/cloud/ ### Agile supported calls ### - 1. [AgileClient](src/main/java/net/rcarz/jiraclient/agile/AgileClient.java) - 1. GET /rest/agile/1.0/board - 1. GET /rest/agile/1.0/board/{boardId} - 1. GET /rest/agile/1.0/sprint/{sprintId} - 1. GET /rest/agile/1.0/issue/{issueIdOrKey} - 1. [Board](src/main/java/net/rcarz/jiraclient/agile/Board.java) - 1. GET /rest/agile/1.0/board - 1. GET /rest/agile/1.0/board/{boardId} - 1. GET /rest/agile/1.0/board/{boardId}/sprint - 1. [Sprint](src/main/java/net/rcarz/jiraclient/agile/Sprint.java) - 1. GET /rest/agile/1.0/sprint/{sprintId} - 1. GET /rest/agile/1.0/board/{boardId}/sprint - 1. [Issue](src/main/java/net/rcarz/jiraclient/agile/Issue.java) - 1. GET /rest/agile/1.0/issue/{issueIdOrKey} - - 1. To implement - 1. -- GET /rest/agile/1.0/board/{boardId}/backlog - 1. -- GET /rest/agile/1.0/board/{boardId}/epic - 1. -- GET /rest/agile/1.0/board/{boardId}/epic/{epicId}/issue - 1. -- GET /rest/agile/1.0/board/{boardId}/epic/none/issue - 1. -- GET /rest/agile/1.0/board/{boardId}/sprint/{sprintId}/issue - 1. -- GET /rest/agile/1.0/epic/{epicIdOrKey}/issue - 1. -- GET /rest/agile/1.0/epic/none/issue - 1. -- GET /rest/agile/1.0/sprint/{sprintId}/issue +| Class | Method | REST Call | +| ----- | ------ | --------- | +| [AgileClient](src/main/java/net/rcarz/jiraclient/agile/AgileClient.java) | ```List getBoards()``` | GET /rest/agile/1.0/board | +| | ```Board getBoard(long id)``` | GET /rest/agile/1.0/board/{boardId} | +| | ```Sprint getSprint(long id)``` | GET /rest/agile/1.0/sprint/{sprintId} | +| | ```Epic getEpic(long id)``` | GET /rest/agile/1.0/epic/{epicId} | +| | ```Issue getIssue(long id)``` | GET /rest/agile/1.0/issue/{issueId} | +| | ```Issue getIssue(String key)``` | GET /rest/agile/1.0/issue/{issueKey} | +| [Board](src/main/java/net/rcarz/jiraclient/agile/Board.java) | ``` static List getAll(RestClient restclient)``` | GET /rest/agile/1.0/board | +| | ```static Board get(RestClient restclient, long id)``` | GET /rest/agile/1.0/board/{boardId} | +| | ```List getSprints()``` | GET /rest/agile/1.0/board/{boardId}/sprint | +| * | ```List getEpics()``` | GET /rest/agile/1.0/board/{boardId}/epic +| * | ```List getBacklog()``` | GET /rest/agile/1.0/board/{boardId}/backlog +| * | ```List getIssuesWithoutEpic()``` | GET /rest/agile/1.0/board/{boardId}/epic/none/issue +| [Sprint](src/main/java/net/rcarz/jiraclient/agile/Sprint.java) | ``` static Sprint get(RestClient restclient, long sprintId)``` | GET /rest/agile/1.0/sprint/{sprintId} | +| | ```static List getAll(RestClient restclient, long boardId)``` | GET /rest/agile/1.0/board/{boardId}/sprint | +| * | ```List getIssues()``` | GET /rest/agile/1.0/sprint/{sprintId}/issue | +| [Epic](src/main/java/net/rcarz/jiraclient/agile/Epic.java) | ```static Epic get(RestClient restclient, long id)``` | GET /rest/agile/1.0/epic/{epicId} | +| * | ```List getIssues()``` | GET /rest/agile/1.0/epic/{epicId}/issue | +| [Issue](src/main/java/net/rcarz/jiraclient/agile/Issue.java) | ```static Issue get(RestClient restclient, long id)``` | GET /rest/agile/1.0/issue/{issueId} | +| | ```static Issue get(RestClient restclient, String key)``` | GET /rest/agile/1.0/issue/{issueKey} | diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java index e51ee80..0aef07b 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java @@ -28,6 +28,7 @@ import java.util.List; /** * An Agile extension to the JIRA client. * + * @author pldupont * @see "https://docs.atlassian.com/jira-software/REST/cloud/" */ public class AgileClient { diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java index 24c608a..a0414fd 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java @@ -25,18 +25,16 @@ import net.rcarz.jiraclient.RestClient; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONObject; -import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.math.NumberUtils; import java.lang.reflect.Constructor; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * A base class for Agile resources. * + * @author pldupont * @see "https://docs.atlassian.com/jira-software/REST/cloud/" */ public abstract class AgileResource { @@ -51,15 +49,16 @@ public abstract class AgileResource { private long id = 0; private String name; private String self; - private Map attributes = new HashMap(); + private JSONObject attributes = new JSONObject(); /** * Creates a new Agile resource. * * @param restclient REST client instance * @param json JSON payload + * @throws JiraException when the retrieval fails */ - public AgileResource(RestClient restclient, JSONObject json) { + public AgileResource(RestClient restclient, JSONObject json) throws JiraException { this.restclient = restclient; if (json != null) { deserialize(json); @@ -73,8 +72,9 @@ public abstract class AgileResource { * @param r a JSONObject instance * @param restclient REST client instance * @return a Resource instance or null if r isn't a JSONObject instance + * @throws JiraException when the retrieval fails */ - private static T getResource( + protected static T getResource( Class type, Object r, RestClient restclient) throws JiraException { if (!(r instanceof JSONObject)) { @@ -101,26 +101,29 @@ public abstract class AgileResource { * @param type Resource data type * @param ra a JSONArray instance * @param restclient REST client instance + * @param listName The name of the list of items from the JSON result. * @return a list of Resources found in ra + * @throws JiraException when the retrieval fails */ - private static List getResourceArray( - Class type, Object ra, RestClient restclient) throws JiraException { + protected static List getResourceArray( + Class type, Object ra, RestClient restclient, String listName) throws JiraException { if (!(ra instanceof JSONObject)) { throw new JiraException("JSON payload is malformed"); } JSONObject jo = (JSONObject) ra; - if (!jo.containsKey("values") || !(jo.get("values") instanceof JSONArray)) { + if (!jo.containsKey(listName) || !(jo.get(listName) instanceof JSONArray)) { throw new JiraException(type.getSimpleName() + " result is malformed"); } List results = new ArrayList(); - for (Object v : (JSONArray) jo.get("values")) { + for (Object v : (JSONArray) jo.get(listName)) { T item = getResource(type, v, restclient); - if (item != null) + if (item != null) { results.add(item); + } } return results; @@ -130,10 +133,28 @@ public abstract class AgileResource { * Retrieves all boards visible to the session user. * * @param restclient REST client instance + * @param type The type of the object to deserialize. + * @param url The URL to call. * @return a list of boards * @throws JiraException when the retrieval fails */ - static List list(RestClient restclient, Class type, String url) throws JiraException { + static List list( + RestClient restclient, Class type, String url) throws JiraException { + return list(restclient, type, url, "values"); + } + + /** + * Retrieves all boards visible to the session user. + * + * @param restclient REST client instance + * @param type The type of the object to deserialize. + * @param url The URL to call. + * @param listName The name of the list of items in the JSON response. + * @return a list of boards + * @throws JiraException when the retrieval fails + */ + static List list( + RestClient restclient, Class type, String url, String listName) throws JiraException { JSON result; try { @@ -145,7 +166,8 @@ public abstract class AgileResource { return getResourceArray( type, result, - restclient + restclient, + listName ); } @@ -172,6 +194,44 @@ public abstract class AgileResource { ); } + /** + * Extract from a sub list the Resource array, if present. + * + * @param type Resource data type + * @param subJson a JSONObject instance + * @param resourceName The name of the list of items from the JSON result. + * @param The type of Agile resource to return. + * @return The list of resources if present. + * @throws JiraException when the retrieval fails + */ + List getSubResourceArray( + Class type, JSONObject subJson, String resourceName) throws JiraException { + List result = null; + if (subJson.containsKey(resourceName)) { + result = getResourceArray(type, subJson.get(resourceName), getRestclient(), resourceName + "s"); + } + return result; + } + + /** + * Extract from a sub list the Resource, if present. + * + * @param type Resource data type + * @param subJson a JSONObject instance + * @param resourceName The name of the item from the JSON result. + * @param The type of Agile resource to return. + * @return The resource if present. + * @throws JiraException when the retrieval fails + */ + T getSubResource( + Class type, JSONObject subJson, String resourceName) throws JiraException { + T result = null; + if (subJson.containsKey(resourceName)) { + result = getResource(type, subJson.get(resourceName), getRestclient()); + } + return result; + } + /** * @return Internal JIRA ID. */ @@ -186,6 +246,13 @@ public abstract class AgileResource { return name; } + /** + * @param name Setter for the resource name. In some case, the name is called something else. + */ + void setName(String name) { + this.name = name; + } + /** * @return The resource URL. */ @@ -206,47 +273,36 @@ public abstract class AgileResource { * @param name The name of the attribute to retrieve. * @return The value of the attribute. */ - String getAttribute(String name) { + public Object getAttribute(String name) { return (String) attributes.get(name); } - /** - * Retrieve the specified attribute as a generic object. - * - * @param name The name of the attribute to retrieve. - * @return The value of the attribute. - */ - int getAttributeAsInt(String name) { - return NumberUtils.toInt(getAttribute(name), 0); - } - - /** - * Retrieve the specified attribute as a generic object. - * - * @param name The name of the attribute to retrieve. - * @return The value of the attribute. - */ - boolean getAttributeAsBoolean(String name) { - return BooleanUtils.toBoolean(getAttribute(name)); - } - /** * Deserialize the json to extract standard attributes and keep a reference of * other attributes. * * @param json The JSON object to read. */ - protected void deserialize(JSONObject json) { + void deserialize(JSONObject json) throws JiraException { id = getLong(json.get("id")); name = Field.getString(json.get("name")); self = Field.getString(json.get("self")); + addAttributes(json); + } + + /** + * Allow to add more attributes. + * + * @param json The json object to extract attributes from. + */ + void addAttributes(JSONObject json) { attributes.putAll(json); } long getLong(Object o) { if (o instanceof Integer || o instanceof Long) { - return Field.getInteger(o); + return Field.getLong(o); } else if (o instanceof String && NumberUtils.isDigits((String) o)) { return NumberUtils.toLong((String) o, 0L); } else { diff --git a/src/main/java/net/rcarz/jiraclient/agile/Board.java b/src/main/java/net/rcarz/jiraclient/agile/Board.java index fae1a0a..4db6aec 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Board.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Board.java @@ -33,8 +33,6 @@ import java.util.List; */ public class Board extends AgileResource { - private static final String ATTR_TYPE = "type"; - private String type; /** @@ -43,7 +41,7 @@ public class Board extends AgileResource { * @param restclient REST client instance * @param json JSON payload */ - protected Board(RestClient restclient, JSONObject json) { + protected Board(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } @@ -71,9 +69,9 @@ public class Board extends AgileResource { } @Override - protected void deserialize(JSONObject json) { + protected void deserialize(JSONObject json) throws JiraException { super.deserialize(json); - type = Field.getString(json.get(ATTR_TYPE)); + type = Field.getString(json.get("type")); } /** @@ -91,15 +89,28 @@ public class Board extends AgileResource { return Sprint.getAll(getRestclient(), getId()); } -// /** -// * Retrieves the backlog data for this rapid view. -// * -// * @return the backlog -// * -// * @throws JiraException when the retrieval fails -// */ -// public Backlog getBacklogData() throws JiraException { -// return Backlog.get(restclient, this); -// } + /** + * @return All issues in the Board backlog. + * @throws JiraException when the retrieval fails + */ + public List getBacklog() throws JiraException { + return AgileResource.list(getRestclient(), Issue.class, RESOURCE_URI + "board/" + getId() + "/backlog", "issues"); + } + + /** + * @return All issues without epic in the Board . + * @throws JiraException when the retrieval fails + */ + public List getIssuesWithoutEpic() throws JiraException { + return AgileResource.list(getRestclient(), Issue.class, RESOURCE_URI + "board/" + getId() + "/epic/none/issue", "issues"); + } + + /** + * @return All epics associated to the Board. + * @throws JiraException when the retrieval fails + */ + public List getEpics() throws JiraException { + return AgileResource.list(getRestclient(), Epic.class, RESOURCE_URI + "board/" + getId() + "/epic"); + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Comment.java b/src/main/java/net/rcarz/jiraclient/agile/Comment.java index 256cab2..7557fdb 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Comment.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Comment.java @@ -1,10 +1,32 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.rcarz.jiraclient.agile; +import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; import net.sf.json.JSONObject; /** - * Created by pldupont on 2016-05-20. + * Represents an Agile Comment. + * + * @author pldupont */ public class Comment extends AgileResource { @@ -14,7 +36,7 @@ public class Comment extends AgileResource { * @param restclient REST client instance * @param json JSON payload */ - public Comment(RestClient restclient, JSONObject json) { + public Comment(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Epic.java b/src/main/java/net/rcarz/jiraclient/agile/Epic.java index 8445e84..f0f657c 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Epic.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Epic.java @@ -1,22 +1,46 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.rcarz.jiraclient.agile; import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; import net.sf.json.JSONObject; +import java.util.List; + /** - * Created on 2016-05-20. + * Represents an Agile Epic. + * * @author pldupont */ public class Epic extends AgileResource { + private Issue issue; + /** * Creates a new Agile resource. * * @param restclient REST client instance * @param json JSON payload */ - public Epic(RestClient restclient, JSONObject json) { + public Epic(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } @@ -31,4 +55,24 @@ public class Epic extends AgileResource { public static Epic get(RestClient restclient, long id) throws JiraException { return AgileResource.get(restclient, Epic.class, RESOURCE_URI + "epic/" + id); } + + /** + * @param refresh If true, will fetch the information from JIRA, otherwise use the cached info. + * @return The Issue representation of this Epic. + * @throws JiraException when the retrieval fails + */ + public Issue asIssue(boolean refresh) throws JiraException { + if (this.issue == null || refresh) { + this.issue = Issue.get(getRestclient(), getId()); + } + return this.issue; + } + + /** + * @return All issues in the Epic. + * @throws JiraException when the retrieval fails + */ + public List getIssues() throws JiraException { + return AgileResource.list(getRestclient(), Issue.class, RESOURCE_URI + "epic/" + getId() + "/issue", "issues"); + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Issue.java b/src/main/java/net/rcarz/jiraclient/agile/Issue.java index 7851ea0..5b2c4a8 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Issue.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Issue.java @@ -1,22 +1,68 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.rcarz.jiraclient.agile; +import net.rcarz.jiraclient.Field; import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; import net.sf.json.JSONObject; +import java.util.Date; +import java.util.List; + /** - * Created on 2016-05-20. + * Represents an Agile Issue. + * * @author pldupont */ public class Issue extends AgileResource { + private String key; + private boolean flagged; + private Sprint sprint; + private List closedSprints; + private String description; + private Project project; + private List comments; + private Epic epic; + private List worklogs; + private TimeTracking timeTracking; + private IssueType issueType; + private Status status; + private Resolution resolution; + private Date created; + private Date updated; + private Priority priority; + private User assignee; + private User creator; + private User reporter; + private String environment; + + /** * Creates a new Agile Issue resource. * * @param restclient REST client instance * @param json JSON payload */ - public Issue(RestClient restclient, JSONObject json) { + public Issue(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } @@ -43,4 +89,117 @@ public class Issue extends AgileResource { public static Issue get(RestClient restclient, String key) throws JiraException { return AgileResource.get(restclient, Issue.class, RESOURCE_URI + "issue/" + key); } + + @Override + protected void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + this.key = Field.getString(json.get("key")); + + // Extract from Field sub JSONObject + if (json.containsKey("fields")) { + JSONObject fields = (JSONObject) json.get("fields"); + setName(Field.getString(fields.get("summary"))); + this.flagged = Field.getBoolean(fields.get("flagged")); + this.sprint = getSubResource(Sprint.class, fields, "sprint"); + this.closedSprints = getSubResourceArray(Sprint.class, fields, "closedSprint"); + this.description = Field.getString(fields.get("description")); + this.project = getSubResource(Project.class, fields, "project"); + this.comments = getSubResourceArray(Comment.class, fields, "comment"); + this.epic = getSubResource(Epic.class, fields, "epic"); + this.worklogs = getSubResourceArray(Worklog.class, fields, "worklog"); + this.timeTracking = getSubResource(TimeTracking.class, fields, "timetracking"); + this.environment = Field.getString(fields.get("environment")); + this.issueType = getSubResource(IssueType.class, fields, "issuetype"); + this.status = getSubResource(Status.class, fields, "status"); + this.resolution = getSubResource(Resolution.class, fields, "resolution"); + this.created = Field.getDateTime(fields.get("created")); + this.updated = Field.getDateTime(fields.get("updated")); + this.priority = getSubResource(Priority.class, fields, "priority"); + this.assignee = getSubResource(User.class, fields, "assignee"); + this.creator = getSubResource(User.class, fields, "creator"); + this.reporter = getSubResource(User.class, fields, "reporter"); + + addAttributes(fields); + } + } + + public String getKey() { + return key; + } + + public boolean isFlagged() { + return flagged; + } + + public Sprint getSprint() { + return sprint; + } + + public List getClosedSprints() { + return closedSprints; + } + + public String getDescription() { + return description; + } + + public Project getProject() { + return project; + } + + public List getComments() { + return comments; + } + + public Epic getEpic() { + return epic; + } + + public List getWorklogs() { + return worklogs; + } + + public TimeTracking getTimeTracking() { + return timeTracking; + } + + public IssueType getIssueType() { + return issueType; + } + + public Status getStatus() { + return status; + } + + public Resolution getResolution() { + return resolution; + } + + public Date getCreated() { + return created; + } + + public Date getUpdated() { + return updated; + } + + public Priority getPriority() { + return priority; + } + + public User getAssignee() { + return assignee; + } + + public User getCreator() { + return creator; + } + + public User getReporter() { + return reporter; + } + + public String getEnvironment() { + return environment; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/IssueType.java b/src/main/java/net/rcarz/jiraclient/agile/IssueType.java new file mode 100644 index 0000000..c677f08 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/IssueType.java @@ -0,0 +1,42 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.JiraException; +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Represents an Agile IssueType. + * + * @author pldupont + */ +public class IssueType extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public IssueType(RestClient restclient, JSONObject json) throws JiraException { + super(restclient, json); + } +} diff --git a/src/main/java/net/rcarz/jiraclient/agile/Priority.java b/src/main/java/net/rcarz/jiraclient/agile/Priority.java new file mode 100644 index 0000000..9cc7df0 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Priority.java @@ -0,0 +1,42 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.JiraException; +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Represents an Agile Priority. + * + * @author pldupont + */ +public class Priority extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public Priority(RestClient restclient, JSONObject json) throws JiraException { + super(restclient, json); + } +} diff --git a/src/main/java/net/rcarz/jiraclient/agile/Project.java b/src/main/java/net/rcarz/jiraclient/agile/Project.java index 2607c66..a7f673a 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Project.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Project.java @@ -1,10 +1,32 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.rcarz.jiraclient.agile; +import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; import net.sf.json.JSONObject; /** - * Created by pldupont on 2016-05-20. + * Represents an Agile Project. + * + * @author pldupont */ public class Project extends AgileResource { @@ -14,7 +36,7 @@ public class Project extends AgileResource { * @param restclient REST client instance * @param json JSON payload */ - public Project(RestClient restclient, JSONObject json) { + public Project(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Resolution.java b/src/main/java/net/rcarz/jiraclient/agile/Resolution.java new file mode 100644 index 0000000..b1c6c86 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Resolution.java @@ -0,0 +1,42 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.JiraException; +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Represents an Agile Resolution. + * + * @author pldupont + */ +public class Resolution extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public Resolution(RestClient restclient, JSONObject json) throws JiraException { + super(restclient, json); + } +} diff --git a/src/main/java/net/rcarz/jiraclient/agile/Sprint.java b/src/main/java/net/rcarz/jiraclient/agile/Sprint.java index 00f58e0..ac20f63 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Sprint.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Sprint.java @@ -34,12 +34,6 @@ import java.util.List; */ public class Sprint extends AgileResource { - private static final String ATTR_STATE = "state"; - private static final String ATTR_ORIGIN_BOARD_ID = "originBoardId"; - private static final String ATTR_START_DATE = "startDate"; - private static final String ATTR_END_DATE = "endDate"; - private static final String ATTR_COMPLETE_DATE = "completeDate"; - private String state; private long originBoardId; private Date startDate; @@ -52,7 +46,7 @@ public class Sprint extends AgileResource { * @param restclient REST client instance * @param json JSON payload */ - protected Sprint(RestClient restclient, JSONObject json) { + protected Sprint(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } @@ -80,14 +74,22 @@ public class Sprint extends AgileResource { return AgileResource.list(restclient, Sprint.class, RESOURCE_URI + "board/" + boardId + "/sprint"); } + /** + * @return All issues in the Sprint. + * @throws JiraException when the retrieval fails + */ + public List getIssues() throws JiraException { + return AgileResource.list(getRestclient(), Issue.class, RESOURCE_URI + "sprint/" + getId() + "/issue", "issues"); + } + @Override - protected void deserialize(JSONObject json) { + protected void deserialize(JSONObject json) throws JiraException { super.deserialize(json); - state = Field.getString(json.get(ATTR_STATE)); - originBoardId = getLong(json.get(ATTR_ORIGIN_BOARD_ID)); - startDate = Field.getDateTime(json.get(ATTR_START_DATE)); - endDate = Field.getDateTime(json.get(ATTR_END_DATE)); - completeDate = Field.getDateTime(json.get(ATTR_COMPLETE_DATE)); + state = Field.getString(json.get("state")); + originBoardId = getLong(json.get("originBoardId")); + startDate = Field.getDateTime(json.get("startDate")); + endDate = Field.getDateTime(json.get("endDate")); + completeDate = Field.getDateTime(json.get("completeDate")); } public String getState() { diff --git a/src/main/java/net/rcarz/jiraclient/agile/Status.java b/src/main/java/net/rcarz/jiraclient/agile/Status.java new file mode 100644 index 0000000..a8aec67 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Status.java @@ -0,0 +1,42 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.JiraException; +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Represents an Agile Status. + * + * @author pldupont + */ +public class Status extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public Status(RestClient restclient, JSONObject json) throws JiraException { + super(restclient, json); + } +} diff --git a/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java b/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java index 54b8d88..4a7acf4 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java +++ b/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java @@ -1,10 +1,32 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.rcarz.jiraclient.agile; +import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; import net.sf.json.JSONObject; /** - * Created by pldupont on 2016-05-20. + * Represents an Agile TimeTracking. + * + * @author pldupont */ public class TimeTracking extends AgileResource { @@ -14,7 +36,7 @@ public class TimeTracking extends AgileResource { * @param restclient REST client instance * @param json JSON payload */ - public TimeTracking(RestClient restclient, JSONObject json) { + public TimeTracking(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/User.java b/src/main/java/net/rcarz/jiraclient/agile/User.java new file mode 100644 index 0000000..0cebeea --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/User.java @@ -0,0 +1,42 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.JiraException; +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Represents an Agile User. + * + * @author pldupont + */ +public class User extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public User(RestClient restclient, JSONObject json) throws JiraException { + super(restclient, json); + } +} diff --git a/src/main/java/net/rcarz/jiraclient/agile/Worklog.java b/src/main/java/net/rcarz/jiraclient/agile/Worklog.java index 7112079..6a8d7f5 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Worklog.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Worklog.java @@ -1,10 +1,32 @@ +/** + * 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 + * version 2.1 of the License, or (at your option) any later version. + *

+ * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.rcarz.jiraclient.agile; +import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; import net.sf.json.JSONObject; /** - * Created by pldupont on 2016-05-20. + * Represents an Agile Worklog. + * + * @author pldupont */ public class Worklog extends AgileResource { @@ -14,7 +36,7 @@ public class Worklog extends AgileResource { * @param restclient REST client instance * @param json JSON payload */ - public Worklog(RestClient restclient, JSONObject json) { + public Worklog(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy index 20d00c1..3691f99 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy @@ -72,11 +72,111 @@ class AbstractResourceTest { } + static void "Assert equals to Project 10000"(Project project) { + assertThat project, new IsNot<>(new IsNull()) + assertThat project.getId(), new IsEqual(JSONResources.PROJECT_ID) + assertThat project.getName(), new IsEqual(JSONResources.PROJECT_NAME) + assertThat project.getSelfURL(), new IsEqual(JSONResources.PROJECT_SELF) + + } + + static void "Assert equals to Comment 9999"(Comment comment) { + assertThat comment, new IsNot<>(new IsNull()) + assertThat comment.getId(), new IsEqual(JSONResources.ISSUE_COMMENT_ID) + assertThat comment.getName(), new IsNull() + assertThat comment.getSelfURL(), new IsEqual(JSONResources.ISSUE_COMMENT_SELF) + + } + + static void "Assert equals to TimeTracking"(TimeTracking timeTracking) { + assertThat timeTracking, new IsNot<>(new IsNull()) + assertThat timeTracking.getId(), new IsEqual(0L) + assertThat timeTracking.getName(), new IsNull() + assertThat timeTracking.getSelfURL(), new IsNull() + + } + + static void "Assert equals to IssueType"(IssueType issueType) { + assertThat issueType, new IsNot<>(new IsNull()) + assertThat issueType.getId(), new IsEqual(JSONResources.ISSUE_TYPE_ID) + assertThat issueType.getName(), new IsEqual(JSONResources.ISSUE_TYPE_NAME) + assertThat issueType.getSelfURL(), new IsEqual(JSONResources.ISSUE_TYPE_SELF) + } + + static void "Assert equals to Status"(Status status) { + assertThat status, new IsNot<>(new IsNull()) + assertThat status.getId(), new IsEqual(JSONResources.ISSUE_STATUS_ID) + assertThat status.getName(), new IsEqual(JSONResources.ISSUE_STATUS_NAME) + assertThat status.getSelfURL(), new IsEqual(JSONResources.ISSUE_STATUS_SELF) + } + + static void "Assert equals to Resolution"(Resolution resolution) { + assertThat resolution, new IsNot<>(new IsNull()) + assertThat resolution.getId(), new IsEqual(JSONResources.ISSUE_RESOLUTION_ID) + assertThat resolution.getName(), new IsEqual(JSONResources.ISSUE_RESOLUTION_NAME) + assertThat resolution.getSelfURL(), new IsEqual(JSONResources.ISSUE_RESOLUTION_SELF) + } + + static void "Assert equals to Priority"(Priority priority) { + assertThat priority, new IsNot<>(new IsNull()) + assertThat priority.getId(), new IsEqual(JSONResources.ISSUE_PRIORITY_ID) + assertThat priority.getName(), new IsEqual(JSONResources.ISSUE_PRIORITY_NAME) + assertThat priority.getSelfURL(), new IsEqual(JSONResources.ISSUE_PRIORITY_SELF) + } + + static void "Assert equals to User"(User user) { + assertThat user, new IsNot<>(new IsNull()) + assertThat user.getId(), new IsEqual(0L) + assertThat user.getName(), new IsEqual(JSONResources.USER_NAME) + assertThat user.getSelfURL(), new IsEqual(JSONResources.USER_SELF) + } + + static void "Assert equals to Worklog 100028"(Worklog worklog) { + assertThat worklog, new IsNot<>(new IsNull()) + assertThat worklog.getId(), new IsEqual(JSONResources.ISSUE_WORKLOG_ID) + assertThat worklog.getName(), new IsNull() + assertThat worklog.getSelfURL(), new IsEqual(JSONResources.ISSUE_WORKLOG_SELF) + } + static void "Assert equals to Issue 10001"(Issue issue) { assertThat issue, new IsNot<>(new IsNull()) assertThat issue.getId(), new IsEqual(JSONResources.ISSUE_ID) assertThat issue.getName(), new IsNull() assertThat issue.getSelfURL(), new IsEqual(JSONResources.ISSUE_SELF) + assertThat issue.getKey(), new IsEqual(JSONResources.ISSUE_KEY) + assertThat issue.isFlagged(), new IsEqual(JSONResources.ISSUE_FLAGGED) + "Assert equals to Sprint ${issue.getSprint().getId()}"(issue.getSprint()) + assertThat issue.getClosedSprints(), new IsNot<>(new IsNull<>()) + assertThat issue.getClosedSprints().size(), new IsEqual(3) + assertThat issue.getDescription(), new IsEqual(JSONResources.ISSUE_DESCRIPTION) + "Assert equals to Project ${issue.getProject().getId()}"(issue.getProject()) + assertThat issue.getComments(), new IsNot<>(new IsNull<>()) + assertThat issue.getComments().size(), new IsEqual(1) + "Assert equals to Comment ${issue.getComments().get(0).getId()}"(issue.getComments().get(0)) + "Assert equals to Epic ${issue.getEpic().getId()}"(issue.getEpic()) + "Assert equals to TimeTracking"(issue.getTimeTracking()) + assertThat issue.getWorklogs(), new IsNot<>(new IsNull<>()) + assertThat issue.getWorklogs().size(), new IsEqual(1) + "Assert equals to Worklog ${issue.getWorklogs().get(0).getId()}"(issue.getWorklogs().get(0)) + assertThat issue.getEnvironment(), new IsEqual(JSONResources.ISSUE_ENVIRONMENT) + "Assert equals to IssueType"(issue.getIssueType()) + "Assert equals to Status"(issue.getStatus()) + "Assert equals to Resolution"(issue.getResolution()) + assertThat issue.getCreated(), new IsEqual(JSONResources.ISSUE_CREATED) + assertThat issue.getUpdated(), new IsEqual(JSONResources.ISSUE_UPDATED) + "Assert equals to User"(issue.getAssignee()) + "Assert equals to User"(issue.getCreator()) + "Assert equals to User"(issue.getReporter()) + "Assert equals to Priority"(issue.getPriority()) + + + } + + static void "Assert equals to Issue 10010"(Issue issue) { + assertThat issue, new IsNot<>(new IsNull()) + assertThat issue.getId(), new IsEqual(JSONResources.BLANK_ISSUE1_ID) + assertThat issue.getName(), new IsNull() + assertThat issue.getSelfURL(), new IsEqual(JSONResources.BLANK_ISSUE1_SELF) } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy index 4061331..edadc19 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy @@ -3,6 +3,7 @@ package net.rcarz.jiraclient.agile import net.rcarz.jiraclient.JiraException import net.rcarz.jiraclient.RestClient import net.rcarz.jiraclient.RestException +import net.sf.json.JSONObject import net.sf.json.JSONSerializer import org.hamcrest.core.IsEqual import org.hamcrest.core.IsNot @@ -74,18 +75,56 @@ class BoardTest extends AbstractResourceTest { @Test void "Given a valid Board, when calling getSprints(), then receive a list of Sprints."() { RestClient mockRestClient = "given a REST Client"() - when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/${JSONResources.BOARD_ID}")) - .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD)) + Board mockBoard = new Board(mockRestClient, JSONSerializer.toJSON(JSONResources.BOARD) as JSONObject) when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/${JSONResources.BOARD_ID}/sprint")) .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_SPRINTS)) - Board board = Board.get(mockRestClient, JSONResources.BOARD_ID); - "Assert equals to Board ${JSONResources.BOARD_ID}"(board) - - List sprints = board.getSprints(); + List sprints = mockBoard.getSprints(); assertThat sprints, new IsNot<>(new IsNull()) assertThat sprints.size(), new IsEqual(2) "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprints.get(0)) } + + @Test + void "Given a valid Board, when calling getEpics(), then receive a list of Epics."() { + RestClient mockRestClient = "given a REST Client"() + Board mockBoard = new Board(mockRestClient, JSONSerializer.toJSON(JSONResources.BOARD) as JSONObject) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/${JSONResources.BOARD_ID}/epic")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_EPICS)) + + List epics = mockBoard.getEpics(); + + assertThat epics, new IsNot<>(new IsNull()) + assertThat epics.size(), new IsEqual(2) + "Assert equals to Epic ${JSONResources.EPIC_ID}"(epics.get(0)) + } + + @Test + void "Given a valid Board, when calling getBacklog(), then receive a list of Issues."() { + RestClient mockRestClient = "given a REST Client"() + Board mockBoard = new Board(mockRestClient, JSONSerializer.toJSON(JSONResources.BOARD) as JSONObject) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/${JSONResources.BOARD_ID}/backlog")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_ISSUES)) + + List backlog = mockBoard.getBacklog(); + + assertThat backlog, new IsNot<>(new IsNull()) + assertThat backlog.size(), new IsEqual(4) + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(backlog.get(0)) + } + + @Test + void "Given a valid Board, when calling getIssuesWithoutEpic(), then receive a list of Issues."() { + RestClient mockRestClient = "given a REST Client"() + Board mockBoard = new Board(mockRestClient, JSONSerializer.toJSON(JSONResources.BOARD) as JSONObject) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/${JSONResources.BOARD_ID}/epic/none/issue")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_ISSUES)) + + List issues = mockBoard.getIssuesWithoutEpic(); + + assertThat issues, new IsNot<>(new IsNull()) + assertThat issues.size(), new IsEqual(4) + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issues.get(0)) + } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy index bae381b..ae01803 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy @@ -3,11 +3,16 @@ package net.rcarz.jiraclient.agile import net.rcarz.jiraclient.JiraException import net.rcarz.jiraclient.RestClient import net.rcarz.jiraclient.RestException +import net.sf.json.JSONObject import net.sf.json.JSONSerializer +import org.hamcrest.core.IsEqual +import org.hamcrest.core.IsNot +import org.hamcrest.core.IsNull import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException +import static org.junit.Assert.assertThat import static org.mockito.Mockito.when /** @@ -41,4 +46,64 @@ class EpicTest extends AbstractResourceTest { Epic.get(mockRestClient, 666); } + + @Test + void "Given an epic without the issue cache, when calling asIssue(false), then call the REST Api."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/" + JSONResources.EPIC_ID)) + .thenReturn(JSONSerializer.toJSON(JSONResources.ISSUE)) + Epic mockEpic = new Epic(mockRestClient, JSONSerializer.toJSON(JSONResources.EPIC) as JSONObject) + + assertThat mockEpic.issue, new IsNull() + Issue issue = mockEpic.asIssue(false) + + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + assertThat mockEpic.issue, new IsNot<>(new IsNull()) + } + + @Test + void "Given an epic with the issue cache, when calling asIssue(false), then use the cache version."() { + RestClient mockRestClient = "given a REST Client"() + Epic mockEpic = new Epic(mockRestClient, JSONSerializer.toJSON(JSONResources.EPIC) as JSONObject) + Issue mockIssue = new Issue(mockRestClient, JSONSerializer.toJSON(JSONResources.ISSUE) as JSONObject) + mockEpic.issue = mockIssue + + assertThat mockEpic.issue, new IsNot<>(new IsNull()) + Issue issue = mockEpic.asIssue(false) + + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + assertThat mockEpic.issue, new IsNot<>(new IsNull()) + assert mockEpic.issue == mockIssue + } + + @Test + void "Given an epic with the issue cache, when calling asIssue(true), then call the REST Api."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/" + JSONResources.EPIC_ID)) + .thenReturn(JSONSerializer.toJSON(JSONResources.ISSUE)) + Epic mockEpic = new Epic(mockRestClient, JSONSerializer.toJSON(JSONResources.EPIC) as JSONObject) + Issue mockIssue = new Issue(mockRestClient, JSONSerializer.toJSON(JSONResources.ISSUE) as JSONObject) + mockEpic.issue = mockIssue + + assertThat mockEpic.issue, new IsNot<>(new IsNull()) + Issue issue = mockEpic.asIssue(true) + + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + assertThat mockEpic.issue, new IsNot<>(new IsNull()) + assert mockEpic.issue != mockIssue + } + + @Test + void "Given a valid Epic, when calling getIssues(), then receive a list of Issues."() { + RestClient mockRestClient = "given a REST Client"() + Epic mockEpic = new Epic(mockRestClient, JSONSerializer.toJSON(JSONResources.EPIC) as JSONObject) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "epic/${JSONResources.EPIC_ID}/issue")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_ISSUES)) + + List issues = mockEpic.getIssues(); + + assertThat issues, new IsNot<>(new IsNull()) + assertThat issues.size(), new IsEqual(4) + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issues.get(0)) + } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy index 67870f2..16e3bd9 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy @@ -64,4 +64,15 @@ class IssueTest extends AbstractResourceTest { Issue.get(mockRestClient, "HSP-2"); } + + @Test + void "Given an issue empty, when calling Issue.get(id), then deserialize properly."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/" + JSONResources.BLANK_ISSUE1_ID)) + .thenReturn(JSONSerializer.toJSON(JSONResources.BLANK_ISSUE1)) + + Issue issue = Issue.get(mockRestClient, JSONResources.BLANK_ISSUE1_ID); + + "Assert equals to Issue ${JSONResources.BLANK_ISSUE1_ID}"(issue) + } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy index 922c60c..9fa59e6 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy @@ -85,40 +85,35 @@ interface JSONResources { }, "done": ${EPIC_DONE} }""" + String LIST_OF_EPICS = """{ + "maxResults": 2, + "startAt": 1, + "total": 5, + "isLast": false, + "values": [ + ${EPIC}, + { + "id": 37, + "self": "http://www.example.com/jira/rest/agile/1.0/epic/13", + "name": "epic 2", + "summary": "epic 2 summary", + "color": { + "key": "color_2" + }, + "done": false + } + ] +}""" - long ISSUE_ID = 10001L - String ISSUE_SELF = "http://www.example.com/jira/rest/agile/1.0/board/92/issue/10001" - String ISSUE_KEY = "HSP-1" - String ISSUE = """{ - "expand": "", - "id": "${ISSUE_ID}", - "self": "${ISSUE_SELF}", - "key": "${ISSUE_KEY}", - "fields": { - "flagged": true, - "sprint": { - "id": ${SPRINT_ID}, - "self": "http://www.example.com/jira/rest/agile/1.0/sprint/${SPRINT_ID}", - "state": "future", - "name": "sprint 2" - }, - "closedSprints": [ - { - "id": 23, - "self": "http://www.example.com/jira/rest/agile/1.0/sprint/23", - "state": "closed", - "name": "sprint 1", - "startDate": "2015-04-11T15:22:00.000+10:00", - "endDate": "2015-04-20T01:22:00.000+10:00", - "completeDate": "2015-04-20T11:04:00.000+10:00" - } - ], - "description": "example bug report", - "project": { - "self": "http://www.example.com/jira/rest/api/2/project/EX", - "id": "10000", - "key": "EX", - "name": "Example", + long PROJECT_ID = 10000L + String PROJECT_KEY = "EX" + String PROJECT_NAME = "Example" + String PROJECT_SELF = "http://www.example.com/jira/rest/api/2/project/${PROJECT_KEY}" + String PROJECT = """{ + "self": "${PROJECT_SELF}", + "id": "${PROJECT_ID}", + "key": "${PROJECT_KEY}", + "name": "${PROJECT_NAME}", "avatarUrls": { "48x48": "http://www.example.com/jira/secure/projectavatar?size=large&pid=10000", "24x24": "http://www.example.com/jira/secure/projectavatar?size=small&pid=10000", @@ -131,57 +126,41 @@ interface JSONResources { "name": "FIRST", "description": "First Project Category" } - }, - "comment": [ - { - "self": "http://www.example.com/jira/rest/api/2/issue/10010/comment/10000", - "id": "10000", - "author": { - "self": "http://www.example.com/jira/rest/api/2/user?username=fred", - "name": "fred", - "displayName": "Fred F. User", - "active": false - }, - "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.", - "updateAuthor": { - "self": "http://www.example.com/jira/rest/api/2/user?username=fred", - "name": "fred", - "displayName": "Fred F. User", - "active": false - }, - "created": "2016-03-21T15:26:17.875+0100", - "updated": "2016-03-21T15:26:17.878+0100", - "visibility": { - "type": "role", - "value": "Administrators" - } - } - ], - "epic": { - "id": 37, - "self": "http://www.example.com/jira/rest/agile/1.0/epic/23", - "name": "epic 1", - "summary": "epic 1 summary", - "color": { - "key": "color_4" - }, - "done": true - }, - "worklog": [ - { - "self": "http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000", - "author": { - "self": "http://www.example.com/jira/rest/api/2/user?username=fred", - "name": "fred", - "displayName": "Fred F. User", - "active": false - }, - "updateAuthor": { - "self": "http://www.example.com/jira/rest/api/2/user?username=fred", - "name": "fred", - "displayName": "Fred F. User", - "active": false - }, + }""" + + String USER_NAME = "Example" + String USER_SELF = "https://www.example.com/rest/api/2/user?username=${USER_NAME}" + String USER = """{ + "self" : "${USER_SELF}", + "name" : "${USER_NAME}", + "key" : "pldupont", + "emailAddress" : "pldupont@example.com", + "avatarUrls" : { + "48x48" : "https://www.example.com/secure/useravatar?ownerId=pldupont&avatarId=11828", + "24x24" : "https://www.example.com/secure/useravatar?size=small&ownerId=pldupont&avatarId=11828", + "16x16" : "https://www.example.com/secure/useravatar?size=xsmall&ownerId=pldupont&avatarId=11828", + "32x32" : "https://www.example.com/secure/useravatar?size=medium&ownerId=pldupont&avatarId=11828" + }, + "displayName" : "Pierre-Luc Dupont", + "active" : true, + "timeZone" : "America/New_York" + }""" + + String ISSUE_TIMETRACKING = """{ + "originalEstimate": "10m", + "remainingEstimate": "3m", + "timeSpent": "6m", + "originalEstimateSeconds": 600, + "remainingEstimateSeconds": 200, + "timeSpentSeconds": 400 + }""" + + long ISSUE_WORKLOG_ID = 100028L + String ISSUE_WORKLOG_SELF = "http://www.example.com/jira/rest/api/2/issue/10010/worklog${ISSUE_WORKLOG_ID}" + String ISSUE_WORKLOG = """{ + "self": "${ISSUE_WORKLOG_SELF}", + "author": ${USER}, + "updateAuthor": ${USER}, "comment": "I did some work here.", "updated": "2016-03-21T15:26:17.882+0100", "visibility": { @@ -191,19 +170,290 @@ interface JSONResources { "started": "2016-03-21T15:26:17.881+0100", "timeSpent": "3h 20m", "timeSpentSeconds": 12000, - "id": "100028", + "id": "${ISSUE_WORKLOG_ID}", "issueId": "10002" - } - ], + }""" + + long ISSUE_COMMENT_ID = 9999L + String ISSUE_COMMENT_SELF = "http://www.example.com/jira/rest/api/2/issue/10010/comment/${ISSUE_COMMENT_ID}" + String ISSUE_COMMENT = """{ + "self": "${ISSUE_COMMENT_SELF}", + "id": "9999", + "author": ${USER}, + "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.", + "updateAuthor": ${USER}, + "created": "2016-03-21T15:26:17.875+0100", + "updated": "2016-03-21T15:26:17.878+0100", + "visibility": { + "type": "role", + "value": "Administrators" + } + }""" + long ISSUE_TYPE_ID = 1L + String ISSUE_TYPE_NAME = "Bug" + String ISSUE_TYPE_SELF = "https://jira.acquisio.com/rest/api/2/issuetype/${ISSUE_TYPE_ID}" + String ISSUE_TYPE = """{ + "self" : "${ISSUE_TYPE_SELF}", + "id" : "${ISSUE_TYPE_ID}", + "description" : "A problem which impairs or prevents the functions of the product.", + "iconUrl" : "https://www.example.com/images/icons/issuetypes/bug.png", + "name" : "${ISSUE_TYPE_NAME}", + "subtask" : false + }""" + long ISSUE_RESOLUTION_ID = 6L + String ISSUE_RESOLUTION_NAME = "Not a bug" + String ISSUE_RESOLUTION_SELF = "https://jira.acquisio.com/rest/api/2/resolution/${ISSUE_RESOLUTION_ID}" + String ISSUE_RESOLUTION = """{ + "self" : "${ISSUE_RESOLUTION_SELF}", + "id" : "${ISSUE_RESOLUTION_ID}", + "description" : "The problem is not a problem", + "name" : "${ISSUE_RESOLUTION_NAME}" + }""" + + long ISSUE_STATUS_ID = 6L + String ISSUE_STATUS_NAME = "Closed" + String ISSUE_STATUS_SELF = "https://www.example.com/rest/api/2/status/${ISSUE_STATUS_ID}" + String ISSUE_STATUS = """{ + "self" : "${ISSUE_STATUS_SELF}", + "description" : "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", + "iconUrl" : "https://www.example.com/images/icons/statuses/closed.png", + "name" : "${ISSUE_STATUS_NAME}", + "id" : "${ISSUE_STATUS_ID}", + "statusCategory" : { + "self" : "https://www.example.com/rest/api/2/statuscategory/3", + "id" : 3, + "key" : "done", + "colorName" : "green", + "name" : "Done" + } + }""" + long ISSUE_PRIORITY_ID = 2L + String ISSUE_PRIORITY_NAME = "Critical" + String ISSUE_PRIORITY_SELF = "https://www.example.com/rest/api/2/priority/${ISSUE_PRIORITY_ID}" + String ISSUE_PRIORITY = """{ + "self" : "${ISSUE_PRIORITY_SELF}", + "iconUrl" : "https://www.example.com/images/icons/priorities/critical.png", + "name" : "${ISSUE_PRIORITY_NAME}", + "id" : "${ISSUE_PRIORITY_ID}" + }""" + long ISSUE_ID = 10001L + String ISSUE_SELF = "http://www.example.com/jira/rest/agile/1.0/board/92/issue/10001" + String ISSUE_KEY = "HSP-1" + boolean ISSUE_FLAGGED = true + String ISSUE_DESCRIPTION = "example bug report" + String ISSUE_ENVIRONMENT = "PROD" + String ISSUE_CREATED_STR = "2016-05-11T10:58:01.000-0400" + Date ISSUE_CREATED = Field.getDateTime(ISSUE_CREATED_STR) + String ISSUE_UPDATED_STR = "2016-05-30T14:20:29.000-0400" + Date ISSUE_UPDATED = Field.getDateTime(ISSUE_UPDATED_STR) + String ISSUE = """{ + "expand": "", + "id": "${ISSUE_ID}", + "self": "${ISSUE_SELF}", + "key": "${ISSUE_KEY}", + "fields": { + "flagged": ${ISSUE_FLAGGED}, + "sprint": ${SPRINT}, + "closedSprint": { + "closedSprints": [ + { + "id": 21, + "self": "http://www.example.com/jira/rest/agile/1.0/sprint/21", + "state": "closed", + "name": "sprint 1", + "startDate": "2015-04-11T15:22:00.000+10:00", + "endDate": "2015-04-20T01:22:00.000+10:00", + "completeDate": "2015-04-20T11:04:00.000+10:00" + }, + { + "id": 22, + "self": "http://www.example.com/jira/rest/agile/1.0/sprint/22", + "state": "closed", + "name": "sprint 1", + "startDate": "2015-04-11T15:22:00.000+10:00", + "endDate": "2015-04-20T01:22:00.000+10:00", + "completeDate": "2015-04-20T11:04:00.000+10:00" + }, + { + "id": 23, + "self": "http://www.example.com/jira/rest/agile/1.0/sprint/23", + "state": "closed", + "name": "sprint 1", + "startDate": "2015-04-11T15:22:00.000+10:00", + "endDate": "2015-04-20T01:22:00.000+10:00", + "completeDate": "2015-04-20T11:04:00.000+10:00" + } + ] + }, + "description": "${ISSUE_DESCRIPTION}", + "project": ${PROJECT}, + "comment": { + "comments" : [ + ${ISSUE_COMMENT} + ] + }, + "epic": ${EPIC}, + "worklog": { + "worklogs": [ + ${ISSUE_WORKLOG} + ] + }, "updated": 1, - "timetracking": { - "originalEstimate": "10m", - "remainingEstimate": "3m", - "timeSpent": "6m", - "originalEstimateSeconds": 600, - "remainingEstimateSeconds": 200, - "timeSpentSeconds": 400 - } + "timetracking": ${ISSUE_TIMETRACKING}, + "environment": "${ISSUE_ENVIRONMENT}", + "issuetype" : ${ISSUE_TYPE}, + "resolution" : ${ISSUE_RESOLUTION}, + "assignee" : ${USER}, + "creator" : ${USER}, + "reporter" : ${USER}, + "created" : "${ISSUE_CREATED_STR}", + "updated" : "${ISSUE_UPDATED_STR}", + "status" : ${ISSUE_STATUS}, + "priority" : ${ISSUE_PRIORITY}, } }""" + + long BLANK_ISSUE1_ID = 10010 + String BLANK_ISSUE1_SELF = "http://www.example.com/jira/rest/agile/1.0/board/92/issue/${BLANK_ISSUE1_ID}" + String BLANK_ISSUE1_KEY = "HSP-1" + String BLANK_ISSUE1 = """{ + "expand": "", + "id": "${BLANK_ISSUE1_ID}", + "self": "${BLANK_ISSUE1_SELF}", + "key": "${BLANK_ISSUE1_KEY}", +}""" + + long BLANK_ISSUE2_ID = 10011 + String BLANK_ISSUE2_SELF = "http://www.example.com/jira/rest/agile/1.0/board/92/issue/${BLANK_ISSUE2_ID}" + String BLANK_ISSUE2_KEY = "HSP-1" + String BLANK_ISSUE2 = """{ + "expand": "", + "id": "${BLANK_ISSUE2_ID}", + "self": "${BLANK_ISSUE2_SELF}", + "key": "${BLANK_ISSUE2_KEY}", + "fields": { + "flagged": false, + } +}""" + + String LIST_OF_ISSUES = """{ + "expand": "names,schema", + "startAt": 0, + "maxResults": 50, + "total": 1, + "issues": [ + ${ISSUE}, + ${BLANK_ISSUE1}, + ${BLANK_ISSUE2}, + { + "expand": "", + "id": "10005", + "self": "http://www.example.com/jira/rest/agile/1.0/board/92/issue/10005", + "key": "HSP-9", + "fields": { + "flagged": true, + "sprint": ${SPRINT}, + "closedSprint" : { + "closedSprints": [ + { + "id": 37, + "self": "http://www.example.com/jira/rest/agile/1.0/sprint/23", + "state": "closed", + "name": "sprint 1", + "startDate": "2015-04-11T15:22:00.000+10:00", + "endDate": "2015-04-20T01:22:00.000+10:00", + "completeDate": "2015-04-20T11:04:00.000+10:00" + } + ] + }, + "description": "example bug report", + "project": { + "self": "http://www.example.com/jira/rest/api/2/project/EX", + "id": "10000", + "key": "EX", + "name": "Example", + "avatarUrls": { + "48x48": "http://www.example.com/jira/secure/projectavatar?size=large&pid=10000", + "24x24": "http://www.example.com/jira/secure/projectavatar?size=small&pid=10000", + "16x16": "http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000", + "32x32": "http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000" + }, + "projectCategory": { + "self": "http://www.example.com/jira/rest/api/2/projectCategory/10000", + "id": "10000", + "name": "FIRST", + "description": "First Project Category" + } + }, + "comment": { + "comments": [ + { + "self": "http://www.example.com/jira/rest/api/2/issue/10010/comment/10000", + "id": "10000", + "author": { + "self": "http://www.example.com/jira/rest/api/2/user?username=fred", + "name": "fred", + "displayName": "Fred F. User", + "active": false + }, + "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget venenatis elit. Duis eu justo eget augue iaculis fermentum. Sed semper quam laoreet nisi egestas at posuere augue semper.", + "updateAuthor": { + "self": "http://www.example.com/jira/rest/api/2/user?username=fred", + "name": "fred", + "displayName": "Fred F. User", + "active": false + }, + "created": "2016-03-21T15:26:17.875+0100", + "updated": "2016-03-21T15:26:17.878+0100", + "visibility": { + "type": "role", + "value": "Administrators" + } + } + ] + }, + "epic": ${EPIC}, + "worklog": { + "worklogs": [ + { + "self": "http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000", + "author": { + "self": "http://www.example.com/jira/rest/api/2/user?username=fred", + "name": "fred", + "displayName": "Fred F. User", + "active": false + }, + "updateAuthor": { + "self": "http://www.example.com/jira/rest/api/2/user?username=fred", + "name": "fred", + "displayName": "Fred F. User", + "active": false + }, + "comment": "I did some work here.", + "updated": "2016-03-21T15:26:17.882+0100", + "visibility": { + "type": "group", + "value": "jira-developers" + }, + "started": "2016-03-21T15:26:17.881+0100", + "timeSpent": "3h 20m", + "timeSpentSeconds": 12000, + "id": "100028", + "issueId": "10002" + } + ] + }, + "updated": 1, + "timetracking": { + "originalEstimate": "10m", + "remainingEstimate": "3m", + "timeSpent": "6m", + "originalEstimateSeconds": 600, + "remainingEstimateSeconds": 200, + "timeSpentSeconds": 400 + } + } + } + ] +}""" } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy index 05ffd32..494f301 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy @@ -3,6 +3,7 @@ package net.rcarz.jiraclient.agile import net.rcarz.jiraclient.JiraException import net.rcarz.jiraclient.RestClient import net.rcarz.jiraclient.RestException +import net.sf.json.JSONObject import net.sf.json.JSONSerializer import org.hamcrest.core.IsEqual import org.hamcrest.core.IsNot @@ -70,4 +71,18 @@ class SprintTest extends AbstractResourceTest { Sprint.get(mockRestClient, 666); } + + @Test + void "Given a valid Sprint, when calling getIssues(), then receive a list of Issues."() { + RestClient mockRestClient = "given a REST Client"() + Sprint mockSprint = new Sprint(mockRestClient, JSONSerializer.toJSON(JSONResources.SPRINT) as JSONObject) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/${JSONResources.SPRINT_ID}/issue")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_ISSUES)) + + List issues = mockSprint.getIssues(); + + assertThat issues, new IsNot<>(new IsNull()) + assertThat issues.size(), new IsEqual(4) + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issues.get(0)) + } }