From 93d7d520318145360d7fa461b5d7e2146393d6d1 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Thu, 19 May 2016 09:30:36 -0400 Subject: [PATCH 01/11] Adding the Agile API to the project. First draft --- .gitignore | 5 + pom.xml | 6 + .../rcarz/jiraclient/agile/AgileClient.java | 68 +++++ .../rcarz/jiraclient/agile/AgileResource.java | 253 ++++++++++++++++++ .../net/rcarz/jiraclient/agile/Board.java | 105 ++++++++ .../net/rcarz/jiraclient/agile/Sprint.java | 169 ++++++++++++ 6 files changed, 606 insertions(+) create mode 100644 src/main/java/net/rcarz/jiraclient/agile/AgileClient.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/AgileResource.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Board.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Sprint.java diff --git a/.gitignore b/.gitignore index 39ab9cd..c203071 100644 --- a/.gitignore +++ b/.gitignore @@ -154,3 +154,8 @@ nb-configuration.xml Session.vim .netrwhist *~ + +### Acquisio related test ### +*AcquisioTest.java +*AcquisioTest.groovy +credentials.groovy diff --git a/pom.xml b/pom.xml index 31d727c..2e92a80 100644 --- a/pom.xml +++ b/pom.xml @@ -85,6 +85,12 @@ test + + org.codehaus.groovy + groovy-all + 2.4.6 + test + diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java new file mode 100644 index 0000000..2a294c4 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java @@ -0,0 +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.JiraClient; +import net.rcarz.jiraclient.JiraException; +import net.rcarz.jiraclient.RestClient; + +import java.util.List; + +/** + * An Agile extension to the JIRA client. + */ +public class AgileClient { + + private RestClient restclient = null; + + /** + * Creates an Agile client. + * + * @param jira JIRA client + */ + public AgileClient(JiraClient jira) { + restclient = jira.getRestClient(); + } + + /** + * Retreives the board with the given ID. + * + * @param id Board ID + * + * @return a Board instance + * + * @throws JiraException when something goes wrong + */ + public Board getBoard(int id) throws JiraException { + return Board.get(restclient, id); + } + + /** + * Retreives all boards visible to the session user. + * + * @return a list of boards + * + * @throws JiraException when something goes wrong + */ + public List getBoards() throws JiraException { + return Board.getAll(restclient); + } +} + diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java new file mode 100644 index 0000000..4734e69 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java @@ -0,0 +1,253 @@ +/** + * 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.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. + * + * @see "https://docs.atlassian.com/jira-software/REST/cloud/" + */ +public abstract class AgileResource { + + public static final String ATTR_ID = "id"; + public static final String ATTR_NAME = "name"; + public static final String ATTR_SELF = "self"; + + protected static final String RESOURCE_URI = "/rest/agile/1.0/"; + + private RestClient restclient = null; + private int id = 0; + private String name; + private String self; + private Map attributes = new HashMap(); + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public AgileResource(RestClient restclient, JSONObject json) { + this.restclient = restclient; + if (json != null) { + deserialize(json); + } + } + + /** + * @return Internal JIRA ID. + */ + public int getId() { + return id; + } + + /** + * @return The resource name. + */ + public String getName() { + return name; + } + + /** + * @return The resource URL. + */ + public String getSelfURL() { + return self; + } + + /** + * @return The REST client used to access the current resource. + */ + protected RestClient getRestclient() { + return restclient; + } + + /** + * Retrieve the specified attribute as a generic object. + * + * @param name The name of the attribute to retrieve. + * @return The value of the attribute. + */ + public String 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. + */ + public 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. + */ + public 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) { + Map map = json; + + id = Field.getInteger(map.get("id")); + name = Field.getString(map.get("name")); + self = Field.getString(map.get("self")); + attributes.putAll(map); + } + + @Override + public String toString() { + return String.format("%s{id=%s, name='%s'}", getClass().getSimpleName(), id, name); + } + + /** + * Gets an Agile resource from the given object. + * + * @param type Resource data type + * @param r a JSONObject instance + * @param restclient REST client instance + * @return a Resource instance or null if r isn't a JSONObject instance + */ + private static T getResource( + Class type, Object r, RestClient restclient) throws JiraException { + + if (!(r instanceof JSONObject)) { + throw new JiraException("JSON payload is malformed"); + } + + T result = null; + + if (!((JSONObject) r).isNullObject()) { + try { + Constructor constructor = type.getDeclaredConstructor(RestClient.class, JSONObject.class); + result = constructor.newInstance(restclient, r); + } catch (Exception e) { + throw new JiraException("Failed to deserialize object array."); + } + } + + return result; + } + + /** + * Gets a list of GreenHopper resources from the given object. + * + * @param type Resource data type + * @param ra a JSONArray instance + * @param restclient REST client instance + * @return a list of Resources found in ra + */ + private static List getResourceArray( + Class type, Object ra, RestClient restclient) 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)) { + throw new JiraException(type.getSimpleName() + " result is malformed"); + } + + List results = new ArrayList(); + + for (Object v : (JSONArray) jo.get("values")) { + T item = getResource(type, v, restclient); + if (item != null) + results.add(item); + } + + return results; + } + + /** + * Retrieves all boards visible to the session user. + * + * @param restclient REST client instance + * @return a list of boards + * @throws JiraException when the retrieval fails + */ + static List list(RestClient restclient, Class type, String url) throws JiraException { + + JSON result = null; + try { + result = restclient.get(url); + } catch (Exception ex) { + throw new JiraException("Failed to retrieve boards", ex); + } + + return getResourceArray( + type, + result, + restclient + ); + } + + /** + * Retrieves all boards visible to the session user. + * + * @param restclient REST client instance + * @return a list of boards + * @throws JiraException when the retrieval fails + */ + static T get(RestClient restclient, Class type, String url) throws JiraException { + + JSON result = null; + try { + result = restclient.get(url); + } catch (Exception ex) { + throw new JiraException("Failed to retrieve boards", ex); + } + + return getResource( + type, + result, + restclient + ); + } +} + diff --git a/src/main/java/net/rcarz/jiraclient/agile/Board.java b/src/main/java/net/rcarz/jiraclient/agile/Board.java new file mode 100644 index 0000000..77e6f2b --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Board.java @@ -0,0 +1,105 @@ +/** + * 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; + +/** + * Represents an Agile Board. + * + * @author pldupont + */ +public class Board extends AgileResource { + + public static final String ATTR_TYPE = "type"; + + /** + * Creates a rapid view from a JSON payload. + * + * @param restclient REST client instance + * @param json JSON payload + */ + protected Board(RestClient restclient, JSONObject json) { + super(restclient, json); + } + + /** + * Retrieves the given rapid view. + * + * @param restclient REST client instance + * @param id Internal JIRA ID of the rapid view + * @return a rapid view instance + * @throws JiraException when the retrieval fails + */ + public static Board get(RestClient restclient, int id) throws JiraException { + return AgileResource.get(restclient, Board.class, RESOURCE_URI + "board/" + id); + } + + /** + * Retrieves all boards visible to the session user. + * + * @param restclient REST client instance + * @return a list of boards + * @throws JiraException when the retrieval fails + */ + public static List getAll(RestClient restclient) throws JiraException { + return AgileResource.list(restclient, Board.class, RESOURCE_URI + "board"); + } + + /** + * @return The board type. + */ + public String getType() { + return getAttribute(ATTR_TYPE); + } + + public List getSprints() throws JiraException { + return AgileResource.list(getRestclient(), Sprint.class, RESOURCE_URI + "board/" + getId() + "/sprint"); + } + +// /** +// * Retrieves the sprint report for the given sprint. +// * +// * @param sprint Sprint to lookup +// * +// * @return the sprint report +// * +// * @throws JiraException when the retrieval fails +// */ +// public SprintReport getSprintReport(Sprint sprint) throws JiraException { +// return SprintReport.get(restclient, this, sprint); +// } +// +// /** +// * 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); +// } +} + diff --git a/src/main/java/net/rcarz/jiraclient/agile/Sprint.java b/src/main/java/net/rcarz/jiraclient/agile/Sprint.java new file mode 100644 index 0000000..b1c4b8b --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Sprint.java @@ -0,0 +1,169 @@ +/** + * 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.JSON; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; + +import java.util.List; + +/** + * Represents an Agile Sprint. + * + * @author pldupont + */ +public class Sprint extends AgileResource { + + public static final String ATTR_TYPE = "type"; + + /** + * Creates a rapid view from a JSON payload. + * + * @param restclient REST client instance + * @param json JSON payload + */ + protected Sprint(RestClient restclient, JSONObject json) { + super(restclient, json); + } + +// /** +// * Retrieves the given rapid view. +// * +// * @param restclient REST client instance +// * @param id Internal JIRA ID of the rapid view +// * @return a rapid view instance +// * @throws JiraException when the retrieval fails +// */ +// public static Sprint get(RestClient restclient, int id) throws JiraException { +// +// JSON result = null; +// +// try { +// result = restclient.get(RESOURCE_URI + "board/" + id); +// } catch (Exception ex) { +// throw new JiraException("Failed to retrieve sprint, from board " + id, ex); +// } +// +// if (!(result instanceof JSONObject)) { +// throw new JiraException("JSON payload is malformed"); +// } +// +// return new Sprint(restclient, (JSONObject) result); +// } +// +// /** +// * Retrieves all boards visible to the session user. +// * +// * @param restclient REST client instance +// * @return a list of boards +// * @throws JiraException when the retrieval fails +// */ +// public static List getAll(RestClient restclient) throws JiraException { +// +// JSON result = null; +// try { +// result = restclient.get(RESOURCE_URI + "board"); +// } catch (Exception ex) { +// throw new JiraException("Failed to retrieve boards", ex); +// } +// +// if (!(result instanceof JSONObject)) { +// throw new JiraException("JSON payload is malformed"); +// } +// +// JSONObject jo = (JSONObject) result; +// +// if (!jo.containsKey("views") || !(jo.get("views") instanceof JSONArray)) { +// throw new JiraException("Board result is malformed"); +// } +// +// return AgileField.getResourceArray( +// Sprint.class, +// jo.get("views"), +// restclient +// ); +// } + + /** + * @return The board type. + */ + public String getType() { + return getAttribute(ATTR_TYPE); + } + +// /** +// * Retrieves all sprints associated with this rapid view. +// * +// * @return a list of sprints +// * +// * @throws JiraException when the retrieval fails +// */ +// public List getSprints() throws JiraException { +// JSON result = null; +// +// try { +// result = restclient.get(RESOURCE_URI + "sprintquery/" + id); +// } catch (Exception ex) { +// throw new JiraException("Failed to retrieve sprints", ex); +// } +// +// if (!(result instanceof JSONObject)) +// throw new JiraException("JSON payload is malformed"); +// +// JSONObject jo = (JSONObject)result; +// +// if (!jo.containsKey("sprints") || !(jo.get("sprints") instanceof JSONArray)) +// throw new JiraException("Sprints result is malformed"); +// +// return AgileField.getResourceArray( +// Sprint.class, +// jo.get("sprints"), +// restclient +// ); +// } +// +// /** +// * Retrieves the sprint report for the given sprint. +// * +// * @param sprint Sprint to lookup +// * +// * @return the sprint report +// * +// * @throws JiraException when the retrieval fails +// */ +// public SprintReport getSprintReport(Sprint sprint) throws JiraException { +// return SprintReport.get(restclient, this, sprint); +// } +// +// /** +// * 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); +// } +} + From 69592a9d4e97b6d4d86d06ae189f7ec281e5ed6e Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Thu, 19 May 2016 11:24:06 -0400 Subject: [PATCH 02/11] Adding test for the Agile API --- AUTHORS.md | 1 + README.md | 35 ++++++++++++++++ .../rcarz/jiraclient/agile/AgileClient.java | 1 + .../rcarz/jiraclient/agile/AgileResource.java | 2 +- .../net/rcarz/jiraclient/agile/Board.java | 13 +++++- .../agile/AbstractResourceTest.groovy | 40 ++++++++++++++++++ .../jiraclient/agile/AgileClientTest.groovy | 39 ++++++++++++++++++ .../rcarz/jiraclient/agile/BoardTest.groovy | 41 +++++++++++++++++++ .../jiraclient/agile/JSONResources.groovy | 34 +++++++++++++++ 9 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy create mode 100644 src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy create mode 100644 src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy create mode 100644 src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy diff --git a/AUTHORS.md b/AUTHORS.md index 7defe0b..ff88050 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -3,3 +3,4 @@ Kyle Chaplin @chaplinkyle Alesandro Lang @alesandroLang Javier Molina @javinovich Joseph McCarthy +Pierre-Luc Dupont @pldupont diff --git a/README.md b/README.md index 483eeea..ec6afc6 100644 --- a/README.md +++ b/README.md @@ -274,3 +274,38 @@ public class Example { } } ``` + +## Agile Example ## +https://docs.atlassian.com/jira-software/REST/cloud/ + +```java +import java.util.List; + +import net.rcarz.jiraclient.BasicCredentials; +import net.rcarz.jiraclient.Issue; +import net.rcarz.jiraclient.JiraClient; +import net.rcarz.jiraclient.JiraException; +import net.rcarz.jiraclient.agile.Board; +import net.rcarz.jiraclient.agile.AgileClient; + +public class Example { + + public static void main(String[] args) { + + BasicCredentials creds = new BasicCredentials("batman", "pow! pow!"); + JiraClient jira = new JiraClient("https://jira.example.com/jira", creds); + AgileClient agileClient = new AgileClient(jira); + + try { + /* Retrieve all Boards */ + List allBoards = agileClient.getBoards(); + } catch (JiraException ex) { + System.err.println(ex.getMessage()); + + if (ex.getCause() != null) { + System.err.println(ex.getCause().getMessage()); + } + } + } +} +``` \ No newline at end of file diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java index 2a294c4..9877a01 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java @@ -27,6 +27,7 @@ import java.util.List; /** * An Agile extension to the JIRA client. + * @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 4734e69..4b3fd64 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java @@ -45,7 +45,7 @@ public abstract class AgileResource { public static final String ATTR_NAME = "name"; public static final String ATTR_SELF = "self"; - protected static final String RESOURCE_URI = "/rest/agile/1.0/"; + public static final String RESOURCE_URI = "/rest/agile/1.0/"; private RestClient restclient = null; private int id = 0; diff --git a/src/main/java/net/rcarz/jiraclient/agile/Board.java b/src/main/java/net/rcarz/jiraclient/agile/Board.java index 77e6f2b..a5ed0d9 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Board.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Board.java @@ -19,6 +19,7 @@ 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; @@ -34,8 +35,10 @@ public class Board extends AgileResource { public static final String ATTR_TYPE = "type"; + private String type; + /** - * Creates a rapid view from a JSON payload. + * Creates a Board from a JSON payload. * * @param restclient REST client instance * @param json JSON payload @@ -44,6 +47,12 @@ public class Board extends AgileResource { super(restclient, json); } + @Override + protected void deserialize(JSONObject json) { + super.deserialize(json); + type = Field.getString(json.get(ATTR_TYPE)); + } + /** * Retrieves the given rapid view. * @@ -71,7 +80,7 @@ public class Board extends AgileResource { * @return The board type. */ public String getType() { - return getAttribute(ATTR_TYPE); + return this.type; } public List getSprints() throws JiraException { diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy new file mode 100644 index 0000000..460c4bc --- /dev/null +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy @@ -0,0 +1,40 @@ +package net.rcarz.jiraclient.agile + +import net.rcarz.jiraclient.JiraClient +import net.rcarz.jiraclient.RestClient +import org.hamcrest.core.IsEqual +import org.hamcrest.core.IsNot +import org.hamcrest.core.IsNull + +import static org.junit.Assert.assertThat +import static org.mockito.Mockito.mock +import static org.mockito.Mockito.when + +/** + * Created by pldupont on 2016-05-19. + */ +class AbstractResourceTest { + AgileClient agileClient; + RestClient mockRestClient; + + void "given an Agile Client"() { + mockRestClient = mock RestClient.class + def mockJiraClient = mock JiraClient.class + when(mockJiraClient.getRestClient()).thenReturn(mockRestClient) + agileClient = new AgileClient(mockJiraClient) + } + + RestClient "given a REST Client"() { + mockRestClient = mock RestClient.class + return mockRestClient + } + + void "Assert equals to Board 84"(Board board) { + assertThat board, new IsNot<>(new IsNull()) + assertThat board.getId(), new IsEqual(JSONResources.BOARD_84_ID) + assertThat board.getName(), new IsEqual(JSONResources.BOARD_84_NAME) + assertThat board.getType(), new IsEqual(JSONResources.BOARD_84_TYPE) + assertThat board.getSelfURL(), new IsEqual(JSONResources.BOARD_84_SELF) + + } +} diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy new file mode 100644 index 0000000..91d95cf --- /dev/null +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy @@ -0,0 +1,39 @@ +package net.rcarz.jiraclient.agile + +import net.sf.json.JSONSerializer +import org.hamcrest.core.IsEqual +import org.hamcrest.core.IsNot +import org.hamcrest.core.IsNull +import org.junit.Test + +import static org.junit.Assert.assertThat +import static org.mockito.Mockito.when + +/** + * Created by pldupont on 2016-05-19. + */ +class AgileClientTest extends AbstractResourceTest { + + @Test + void "Given an agileClient, when calling getBoards(), then receive a list of Board."() { + "given an Agile Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_BOARDS)) + + List boards = agileClient.getBoards(); + + assertThat boards, new IsNot<>(new IsNull()) + assertThat boards.size(), new IsEqual(2) + } + + @Test + void "Given an agileClient, when calling getBoard(84), then receive one Board."() { + "given an Agile Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84")) + .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD_84)) + + Board board = agileClient.getBoard(84); + + assertThat board, new IsNot<>(new IsNull()) + } +} diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy new file mode 100644 index 0000000..66a0508 --- /dev/null +++ b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy @@ -0,0 +1,41 @@ +package net.rcarz.jiraclient.agile + +import net.rcarz.jiraclient.RestClient +import net.sf.json.JSONSerializer +import org.hamcrest.core.IsEqual +import org.hamcrest.core.IsNot +import org.hamcrest.core.IsNull +import org.junit.Test + +import static org.junit.Assert.assertThat +import static org.mockito.Mockito.when + +/** + * Created by pldupont on 2016-05-19. + */ +class BoardTest extends AbstractResourceTest { + + @Test + void "Given an RestClient, when calling getAll(), then receive a list of Board."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_BOARDS)) + + List boards = Board.getAll(mockRestClient); + + assertThat boards, new IsNot<>(new IsNull()) + assertThat boards.size(), new IsEqual(2) + "Assert equals to Board 84"(boards.get(0)) + } + + @Test + void "Given an agileClient, when calling getBoard(84), then receive one Board."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84")) + .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD_84)) + + Board board = Board.get(mockRestClient, 84); + + "Assert equals to Board 84"(board) + } +} diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy new file mode 100644 index 0000000..a262bd9 --- /dev/null +++ b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy @@ -0,0 +1,34 @@ +package net.rcarz.jiraclient.agile + +/** + * Created by pldupont on 2016-05-19. + */ +interface JSONResources { + + String BOARD_84 = """{ + "id": 84, + "self": "http://www.example.com/jira/rest/agile/1.0/board/84", + "name": "scrum board", + "type": "scrum" +}""" + String BOARD_84_SELF = "http://www.example.com/jira/rest/agile/1.0/board/84" + String BOARD_84_NAME = "scrum board" + String BOARD_84_TYPE = "scrum" + int BOARD_84_ID = 84 + + String LIST_OF_BOARDS = """{ + "maxResults": 2, + "startAt": 1, + "total": 5, + "isLast": false, + "values": [ + ${BOARD_84}, + { + "id": 92, + "self": "http://www.example.com/jira/rest/agile/1.0/board/92", + "name": "kanban board", + "type": "kanban" + } + ] +}""" +} From 04a1cbb6fa985f5df0119708cbc7728e4a2ccc00 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Thu, 19 May 2016 16:01:14 -0400 Subject: [PATCH 03/11] Adding test for the Board/Sprint resources --- .../rcarz/jiraclient/agile/AgileClient.java | 20 +- .../rcarz/jiraclient/agile/AgileResource.java | 4 +- .../net/rcarz/jiraclient/agile/Board.java | 19 +- .../net/rcarz/jiraclient/agile/Sprint.java | 180 ++++++------------ .../agile/AbstractResourceTest.groovy | 19 ++ .../jiraclient/agile/AgileClientTest.groovy | 14 ++ .../rcarz/jiraclient/agile/BoardTest.groovy | 56 +++++- .../jiraclient/agile/JSONResources.groovy | 37 ++++ .../rcarz/jiraclient/agile/SprintTest.groovy | 72 +++++++ 9 files changed, 282 insertions(+), 139 deletions(-) create mode 100644 src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java index 9877a01..948204b 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java @@ -1,17 +1,17 @@ /** * 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 @@ -65,5 +65,19 @@ public class AgileClient { public List getBoards() throws JiraException { return Board.getAll(restclient); } + + /** + * Retreives the sprint with the given ID. + * + * @param id Sprint ID + * + * @return a Sprint instance + * + * @throws JiraException when something goes wrong + */ + public Sprint getSprint(int id) throws JiraException { + return Sprint.get(restclient, id); + } + } diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java index 4b3fd64..bacb52a 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java @@ -217,7 +217,7 @@ public abstract class AgileResource { try { result = restclient.get(url); } catch (Exception ex) { - throw new JiraException("Failed to retrieve boards", ex); + throw new JiraException("Failed to retrieve a list of " + type.getSimpleName() + " : " + url, ex); } return getResourceArray( @@ -240,7 +240,7 @@ public abstract class AgileResource { try { result = restclient.get(url); } catch (Exception ex) { - throw new JiraException("Failed to retrieve boards", ex); + throw new JiraException("Failed to retrieve " + type.getSimpleName() + " : " + url, ex); } return getResource( diff --git a/src/main/java/net/rcarz/jiraclient/agile/Board.java b/src/main/java/net/rcarz/jiraclient/agile/Board.java index a5ed0d9..73463d1 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Board.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Board.java @@ -83,23 +83,14 @@ public class Board extends AgileResource { return this.type; } + /** + * @return All sprints related to the current board. + * @throws JiraException when the retrieval fails + */ public List getSprints() throws JiraException { - return AgileResource.list(getRestclient(), Sprint.class, RESOURCE_URI + "board/" + getId() + "/sprint"); + return Sprint.getAll(getRestclient(), getId()); } -// /** -// * Retrieves the sprint report for the given sprint. -// * -// * @param sprint Sprint to lookup -// * -// * @return the sprint report -// * -// * @throws JiraException when the retrieval fails -// */ -// public SprintReport getSprintReport(Sprint sprint) throws JiraException { -// return SprintReport.get(restclient, this, sprint); -// } -// // /** // * Retrieves the backlog data for this rapid view. // * diff --git a/src/main/java/net/rcarz/jiraclient/agile/Sprint.java b/src/main/java/net/rcarz/jiraclient/agile/Sprint.java index b1c4b8b..696378a 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Sprint.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Sprint.java @@ -19,12 +19,12 @@ package net.rcarz.jiraclient.agile; +import net.rcarz.jiraclient.Field; import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; -import net.sf.json.JSON; -import net.sf.json.JSONArray; import net.sf.json.JSONObject; +import java.util.Date; import java.util.List; /** @@ -34,7 +34,17 @@ import java.util.List; */ public class Sprint extends AgileResource { - public static final String ATTR_TYPE = "type"; + public static final String ATTR_STATE = "state"; + public static final String ATTR_ORIGIN_BOARD_ID = "originBoardId"; + public static final String ATTR_START_DATE = "startDate"; + public static final String ATTR_END_DATE = "endDate"; + public static final String ATTR_COMPLETE_DATE = "completeDate"; + + private String state; + private int originBoardId; + private Date startDate; + private Date endDate; + private Date completeDate; /** * Creates a rapid view from a JSON payload. @@ -46,124 +56,58 @@ public class Sprint extends AgileResource { super(restclient, json); } -// /** -// * Retrieves the given rapid view. -// * -// * @param restclient REST client instance -// * @param id Internal JIRA ID of the rapid view -// * @return a rapid view instance -// * @throws JiraException when the retrieval fails -// */ -// public static Sprint get(RestClient restclient, int id) throws JiraException { -// -// JSON result = null; -// -// try { -// result = restclient.get(RESOURCE_URI + "board/" + id); -// } catch (Exception ex) { -// throw new JiraException("Failed to retrieve sprint, from board " + id, ex); -// } -// -// if (!(result instanceof JSONObject)) { -// throw new JiraException("JSON payload is malformed"); -// } -// -// return new Sprint(restclient, (JSONObject) result); -// } -// -// /** -// * Retrieves all boards visible to the session user. -// * -// * @param restclient REST client instance -// * @return a list of boards -// * @throws JiraException when the retrieval fails -// */ -// public static List getAll(RestClient restclient) throws JiraException { -// -// JSON result = null; -// try { -// result = restclient.get(RESOURCE_URI + "board"); -// } catch (Exception ex) { -// throw new JiraException("Failed to retrieve boards", ex); -// } -// -// if (!(result instanceof JSONObject)) { -// throw new JiraException("JSON payload is malformed"); -// } -// -// JSONObject jo = (JSONObject) result; -// -// if (!jo.containsKey("views") || !(jo.get("views") instanceof JSONArray)) { -// throw new JiraException("Board result is malformed"); -// } -// -// return AgileField.getResourceArray( -// Sprint.class, -// jo.get("views"), -// restclient -// ); -// } - /** - * @return The board type. + * Retrieve all sprints related to the specified board. + * + * @param restclient REST client instance + * @param sprintId The Internal JIRA sprint ID. + * @return The sprint for the specified ID. + * @throws JiraException when the retrieval fails */ - public String getType() { - return getAttribute(ATTR_TYPE); + public static Sprint get(RestClient restclient, int sprintId) throws JiraException { + return AgileResource.get(restclient, Sprint.class, RESOURCE_URI + "sprint/" + sprintId); } -// /** -// * Retrieves all sprints associated with this rapid view. -// * -// * @return a list of sprints -// * -// * @throws JiraException when the retrieval fails -// */ -// public List getSprints() throws JiraException { -// JSON result = null; -// -// try { -// result = restclient.get(RESOURCE_URI + "sprintquery/" + id); -// } catch (Exception ex) { -// throw new JiraException("Failed to retrieve sprints", ex); -// } -// -// if (!(result instanceof JSONObject)) -// throw new JiraException("JSON payload is malformed"); -// -// JSONObject jo = (JSONObject)result; -// -// if (!jo.containsKey("sprints") || !(jo.get("sprints") instanceof JSONArray)) -// throw new JiraException("Sprints result is malformed"); -// -// return AgileField.getResourceArray( -// Sprint.class, -// jo.get("sprints"), -// restclient -// ); -// } -// -// /** -// * Retrieves the sprint report for the given sprint. -// * -// * @param sprint Sprint to lookup -// * -// * @return the sprint report -// * -// * @throws JiraException when the retrieval fails -// */ -// public SprintReport getSprintReport(Sprint sprint) throws JiraException { -// return SprintReport.get(restclient, this, sprint); -// } -// -// /** -// * 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); -// } + /** + * Retrieve all sprints related to the specified board. + * + * @param restclient REST client instance + * @param boardId The Internal JIRA board ID. + * @return The list of sprints associated to the board. + * @throws JiraException when the retrieval fails + */ + public static List getAll(RestClient restclient, int boardId) throws JiraException { + return AgileResource.list(restclient, Sprint.class, RESOURCE_URI + "board/" + boardId + "/sprint"); + } + + @Override + protected void deserialize(JSONObject json) { + super.deserialize(json); + state = Field.getString(json.get(ATTR_STATE)); + originBoardId = Field.getInteger(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)); + } + + public String getState() { + return state; + } + + public int getOriginBoardId() { + return originBoardId; + } + + public Date getStartDate() { + return startDate; + } + + public Date getEndDate() { + return endDate; + } + + public Date getCompleteDate() { + return completeDate; + } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy index 460c4bc..965c4e4 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy @@ -5,6 +5,7 @@ import net.rcarz.jiraclient.RestClient import org.hamcrest.core.IsEqual import org.hamcrest.core.IsNot import org.hamcrest.core.IsNull +import org.junit.Test import static org.junit.Assert.assertThat import static org.mockito.Mockito.mock @@ -35,6 +36,24 @@ class AbstractResourceTest { assertThat board.getName(), new IsEqual(JSONResources.BOARD_84_NAME) assertThat board.getType(), new IsEqual(JSONResources.BOARD_84_TYPE) assertThat board.getSelfURL(), new IsEqual(JSONResources.BOARD_84_SELF) + assertThat board.toString(), new IsEqual( + String.format("Board{id=%s, name='%s'}", + JSONResources.BOARD_84_ID, JSONResources.BOARD_84_NAME)) } + + void "Assert equals to Sprint 37"(Sprint sprint) { + assertThat sprint, new IsNot<>(new IsNull()) + assertThat sprint.getId(), new IsEqual(JSONResources.SPRINT_37_ID) + assertThat sprint.getName(), new IsEqual(JSONResources.SPRINT_37_NAME) + assertThat sprint.getSelfURL(), new IsEqual(JSONResources.SPRINT_37_SELF) + assertThat sprint.getState(), new IsEqual(JSONResources.SPRINT_37_STATE) + assertThat sprint.getOriginBoardId(), new IsEqual(JSONResources.SPRINT_37_ORIGIN_BOARD_ID) + assertThat sprint.getStartDate(), new IsEqual(JSONResources.SPRINT_37_START_DATE) + assertThat sprint.getEndDate(), new IsEqual(JSONResources.SPRINT_37_END_DATE) + assertThat sprint.getCompleteDate(), new IsEqual(JSONResources.SPRINT_37_COMPLETE_DATE) + assertThat sprint.toString(), new IsEqual( + String.format("Sprint{id=%s, name='%s'}", + JSONResources.SPRINT_37_ID, JSONResources.SPRINT_37_NAME)) + } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy index 91d95cf..80fbcc8 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy @@ -24,6 +24,7 @@ class AgileClientTest extends AbstractResourceTest { assertThat boards, new IsNot<>(new IsNull()) assertThat boards.size(), new IsEqual(2) + "Assert equals to Board 84"(boards.get(0)) } @Test @@ -35,5 +36,18 @@ class AgileClientTest extends AbstractResourceTest { Board board = agileClient.getBoard(84); assertThat board, new IsNot<>(new IsNull()) + "Assert equals to Board 84"(board) + } + + @Test + void "Given an agileClient, when calling getSprint(37), then receive one Sprint."() { + "given an Agile Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/37")) + .thenReturn(JSONSerializer.toJSON(JSONResources.SPRINT_37)) + + Sprint sprint = agileClient.getSprint(37); + + assertThat sprint, new IsNot<>(new IsNull()) + "Assert equals to Sprint 37"(sprint) } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy index 66a0508..4311a42 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy @@ -1,11 +1,18 @@ package net.rcarz.jiraclient.agile +import net.rcarz.jiraclient.JiraException import net.rcarz.jiraclient.RestClient +import net.rcarz.jiraclient.RestException import net.sf.json.JSONSerializer +import org.hamcrest.Description +import org.hamcrest.Matcher 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 org.mockito.internal.matchers.Contains import static org.junit.Assert.assertThat import static org.mockito.Mockito.when @@ -15,8 +22,11 @@ import static org.mockito.Mockito.when */ class BoardTest extends AbstractResourceTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Test - void "Given an RestClient, when calling getAll(), then receive a list of Board."() { + void "Given a RestClient, when calling getAll(), then receive a list of Board."() { RestClient mockRestClient = "given a REST Client"() when(mockRestClient.get(AgileResource.RESOURCE_URI + "board")) .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_BOARDS)) @@ -29,7 +39,19 @@ class BoardTest extends AbstractResourceTest { } @Test - void "Given an agileClient, when calling getBoard(84), then receive one Board."() { + void "Given a RestClient, when calling getAll() and use doesn't have access, then throws an 401 error."() { + RestException unauthorized = new RestException("Do not have access", 401, "Unauthorized") + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board")) + .thenThrow(unauthorized) + expectedException.expect(JiraException.class); + expectedException.expectMessage("Failed to retrieve a list of Board : /rest/agile/1.0/board"); + + List boards = Board.getAll(mockRestClient); + } + + @Test + void "Given a RestClient, when calling getBoard(84), then receive one Board."() { RestClient mockRestClient = "given a REST Client"() when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84")) .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD_84)) @@ -38,4 +60,34 @@ class BoardTest extends AbstractResourceTest { "Assert equals to Board 84"(board) } + + @Test + void "Given a RestClient, when calling getBoard(666), then throws an 404 error."() { + RestException unauthorized = new RestException("Do not have access", 404, "Unauthorized") + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/666")) + .thenThrow(unauthorized) + expectedException.expect(JiraException.class); + expectedException.expectMessage("Failed to retrieve Board : /rest/agile/1.0/board/666"); + + Board board = Board.get(mockRestClient, 666); + } + + @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/84")) + .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD_84)) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84/sprint")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_SPRINTS)) + + Board board = Board.get(mockRestClient, 84); + "Assert equals to Board 84"(board) + + List sprints = board.getSprints(); + + assertThat sprints, new IsNot<>(new IsNull()) + assertThat sprints.size(), new IsEqual(2) + "Assert equals to Sprint 37"(sprints.get(0)) + } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy index a262bd9..3f5bb18 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy @@ -1,5 +1,7 @@ package net.rcarz.jiraclient.agile +import net.rcarz.jiraclient.Field + /** * Created by pldupont on 2016-05-19. */ @@ -31,4 +33,39 @@ interface JSONResources { } ] }""" + + String SPRINT_37 = """{ + "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", + "originBoardId": 84 +}""" + int SPRINT_37_ID = 37 + String SPRINT_37_NAME = "sprint 1" + String SPRINT_37_SELF = "http://www.example.com/jira/rest/agile/1.0/sprint/23" + String SPRINT_37_STATE = "closed" + int SPRINT_37_ORIGIN_BOARD_ID = 84 + Date SPRINT_37_START_DATE = Field.getDateTime("2015-04-11T15:22:00.000+10:00") + Date SPRINT_37_END_DATE = Field.getDateTime("2015-04-20T01:22:00.000+10:00") + Date SPRINT_37_COMPLETE_DATE = Field.getDateTime("2015-04-20T11:04:00.000+10:00") + + String LIST_OF_SPRINTS = """{ + "maxResults": 2, + "startAt": 1, + "total": 5, + "isLast": false, + "values": [ + ${SPRINT_37}, + { + "id": 72, + "self": "http://www.example.com/jira/rest/agile/1.0/sprint/73", + "state": "future", + "name": "sprint 2" + } + ] +}""" } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy new file mode 100644 index 0000000..e310bf9 --- /dev/null +++ b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy @@ -0,0 +1,72 @@ +package net.rcarz.jiraclient.agile + +import net.rcarz.jiraclient.JiraException +import net.rcarz.jiraclient.RestClient +import net.rcarz.jiraclient.RestException +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 + +/** + * Created by pldupont on 2016-05-19. + */ +class SprintTest extends AbstractResourceTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + void "Given a RestClient, when calling getAll(), then receive a list of Sprint."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/" + JSONResources.SPRINT_37_ORIGIN_BOARD_ID + "/sprint")) + .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_SPRINTS)) + + List sprints = Sprint.getAll(mockRestClient, JSONResources.SPRINT_37_ORIGIN_BOARD_ID); + + assertThat sprints, new IsNot<>(new IsNull()) + assertThat sprints.size(), new IsEqual(2) + "Assert equals to Sprint 37"(sprints.get(0)) + } + + @Test + void "Given a RestClient, when calling getAll() and use doesn't have access, then throws an 401 error."() { + RestException unauthorized = new RestException("Do not have access", 401, "Unauthorized") + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/" + JSONResources.SPRINT_37_ORIGIN_BOARD_ID + "/sprint")) + .thenThrow(unauthorized) + expectedException.expect(JiraException.class); + expectedException.expectMessage("Failed to retrieve a list of Sprint : /rest/agile/1.0/board/" + JSONResources.SPRINT_37_ORIGIN_BOARD_ID + "/sprint"); + + List sprints = Sprint.getAll(mockRestClient, JSONResources.SPRINT_37_ORIGIN_BOARD_ID); + } + + @Test + void "Given a RestClient, when calling getSprint(84), then receive one Sprint."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/37")) + .thenReturn(JSONSerializer.toJSON(JSONResources.SPRINT_37)) + + Sprint sprint = Sprint.get(mockRestClient, 37); + + "Assert equals to Sprint 37"(sprint) + } + + @Test + void "Given a RestClient, when calling getSprint(666), then throws an 404 error."() { + RestException unauthorized = new RestException("Do not have access", 404, "Unauthorized") + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/666")) + .thenThrow(unauthorized) + expectedException.expect(JiraException.class); + expectedException.expectMessage("Failed to retrieve Sprint : /rest/agile/1.0/sprint/666"); + + Sprint sprint = Sprint.get(mockRestClient, 666); + } +} From f8267d7230db257430d966c5d18ba75f8b3e8d78 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Thu, 19 May 2016 16:37:44 -0400 Subject: [PATCH 04/11] Try markdown syntax --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ec6afc6..7b5c6b0 100644 --- a/README.md +++ b/README.md @@ -275,9 +275,15 @@ public class Example { } ``` -## Agile Example ## +## Agile API ## https://docs.atlassian.com/jira-software/REST/cloud/ +### Agile supported calls ### + 1. AgileClient + ..* GET /rest/agile/1.0/board + +### Agile Example ### + ```java import java.util.List; @@ -308,4 +314,5 @@ public class Example { } } } -``` \ No newline at end of file +``` + From 5789edf9724420527ec1834fc39851db4fd35a94 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Thu, 19 May 2016 16:41:20 -0400 Subject: [PATCH 05/11] Try markdown syntax --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b5c6b0..7c3bdcb 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ public class Example { https://docs.atlassian.com/jira-software/REST/cloud/ ### Agile supported calls ### - 1. AgileClient + 1. [AgileClient](../src/main/java/net/rcarz/jiraclient/agile/AgileClient.java) ..* GET /rest/agile/1.0/board ### Agile Example ### From 5bb62b50b1610623cdc01544ba5a31439b6f9b81 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Thu, 19 May 2016 16:42:26 -0400 Subject: [PATCH 06/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c3bdcb..4aa1e28 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ 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. [AgileClient](src/main/java/net/rcarz/jiraclient/agile/AgileClient.java) ..* GET /rest/agile/1.0/board ### Agile Example ### From 450ebb3a968db01d5935c07b4768e24bf4507897 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Thu, 19 May 2016 16:43:19 -0400 Subject: [PATCH 07/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4aa1e28..77268e0 100644 --- a/README.md +++ b/README.md @@ -280,7 +280,7 @@ https://docs.atlassian.com/jira-software/REST/cloud/ ### Agile supported calls ### 1. [AgileClient](src/main/java/net/rcarz/jiraclient/agile/AgileClient.java) - ..* GET /rest/agile/1.0/board + * GET /rest/agile/1.0/board ### Agile Example ### From 38f9fe441bde6f2a46051b2ca2ec201ceed2ba2f Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Mon, 30 May 2016 10:15:14 -0400 Subject: [PATCH 08/11] Adding Issue resource, with test. --- README.md | 25 ++- .../rcarz/jiraclient/agile/AgileResource.java | 12 +- .../net/rcarz/jiraclient/agile/Comment.java | 20 ++ .../java/net/rcarz/jiraclient/agile/Epic.java | 20 ++ .../rcarz/jiraclient/agile/Estimation.java | 7 + .../net/rcarz/jiraclient/agile/Issue.java | 47 +++++ .../net/rcarz/jiraclient/agile/Project.java | 20 ++ .../rcarz/jiraclient/agile/TimeTracking.java | 20 ++ .../net/rcarz/jiraclient/agile/Worklog.java | 20 ++ .../agile/AbstractResourceTest.groovy | 42 ++-- .../jiraclient/agile/AgileClientTest.groovy | 4 +- .../rcarz/jiraclient/agile/BoardTest.groovy | 7 +- .../rcarz/jiraclient/agile/IssueTest.groovy | 67 +++++++ .../jiraclient/agile/JSONResources.groovy | 185 +++++++++++++++--- .../rcarz/jiraclient/agile/SprintTest.groovy | 12 +- 15 files changed, 446 insertions(+), 62 deletions(-) create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Comment.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Epic.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Estimation.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Issue.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Project.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Worklog.java create mode 100644 src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy diff --git a/README.md b/README.md index 77268e0..b3d328c 100644 --- a/README.md +++ b/README.md @@ -280,7 +280,30 @@ https://docs.atlassian.com/jira-software/REST/cloud/ ### Agile supported calls ### 1. [AgileClient](src/main/java/net/rcarz/jiraclient/agile/AgileClient.java) - * GET /rest/agile/1.0/board + 1. GET /rest/agile/1.0/board + 1. GET /rest/agile/1.0/board/{boardId} + 1. GET /rest/agile/1.0/sprint/{sprintId} + 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. 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} + 1. -- GET /rest/agile/1.0/epic/{epicIdOrKey}/issue + 1. -- GET /rest/agile/1.0/epic/none/issue + 1. -- GET /rest/agile/1.0/issue/{issueIdOrKey} + 1. -- GET /rest/agile/1.0/issue/{issueIdOrKey}/estimation + 1. -- GET /rest/agile/1.0/sprint/{sprintId}/issue + + ### Agile Example ### diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java index bacb52a..9fb7e35 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java @@ -133,12 +133,22 @@ public abstract class AgileResource { protected void deserialize(JSONObject json) { Map map = json; - id = Field.getInteger(map.get("id")); + id = getInteger(map.get("id")); name = Field.getString(map.get("name")); self = Field.getString(map.get("self")); attributes.putAll(map); } + private int getInteger(Object o) { + if (o instanceof Integer) { + return Field.getInteger(o); + } else if (o instanceof String && NumberUtils.isDigits((String) o)) { + return NumberUtils.toInt((String) o, 0); + } else { + return 0; + } + } + @Override public String toString() { return String.format("%s{id=%s, name='%s'}", getClass().getSimpleName(), id, name); diff --git a/src/main/java/net/rcarz/jiraclient/agile/Comment.java b/src/main/java/net/rcarz/jiraclient/agile/Comment.java new file mode 100644 index 0000000..256cab2 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Comment.java @@ -0,0 +1,20 @@ +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Created by pldupont on 2016-05-20. + */ +public class Comment extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public Comment(RestClient restclient, JSONObject json) { + 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 new file mode 100644 index 0000000..0fc3b3f --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Epic.java @@ -0,0 +1,20 @@ +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Created by pldupont on 2016-05-20. + */ +public class Epic extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public Epic(RestClient restclient, JSONObject json) { + super(restclient, json); + } +} diff --git a/src/main/java/net/rcarz/jiraclient/agile/Estimation.java b/src/main/java/net/rcarz/jiraclient/agile/Estimation.java new file mode 100644 index 0000000..b864c65 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Estimation.java @@ -0,0 +1,7 @@ +package net.rcarz.jiraclient.agile; + +/** + * Created by pldupont on 2016-05-20. + */ +public class Estimation { +} diff --git a/src/main/java/net/rcarz/jiraclient/agile/Issue.java b/src/main/java/net/rcarz/jiraclient/agile/Issue.java new file mode 100644 index 0000000..d834995 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Issue.java @@ -0,0 +1,47 @@ +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 by pldupont on 2016-05-20. + */ +public class Issue extends AgileResource { + + /** + * Creates a new Agile Issue resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public Issue(RestClient restclient, JSONObject json) { + super(restclient, json); + } + + /** + * Retrieves the issue matching the ID. + * + * @param restclient REST client instance + * @param id Internal JIRA ID of the issue + * @return an issue instance + * @throws JiraException when the retrieval fails + */ + public static Issue get(RestClient restclient, int id) throws JiraException { + return AgileResource.get(restclient, Issue.class, RESOURCE_URI + "issue/" + id); + } + + /** + * Retrieves the issue matching the ID. + * + * @param restclient REST client instance + * @param key JIRA key of the issue + * @return an issue instance + * @throws JiraException when the retrieval fails + */ + public static Issue get(RestClient restclient, String key) throws JiraException { + return AgileResource.get(restclient, Issue.class, RESOURCE_URI + "issue/" + key); + } +} diff --git a/src/main/java/net/rcarz/jiraclient/agile/Project.java b/src/main/java/net/rcarz/jiraclient/agile/Project.java new file mode 100644 index 0000000..2607c66 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Project.java @@ -0,0 +1,20 @@ +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Created by pldupont on 2016-05-20. + */ +public class Project extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public Project(RestClient restclient, JSONObject json) { + 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 new file mode 100644 index 0000000..54b8d88 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java @@ -0,0 +1,20 @@ +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Created by pldupont on 2016-05-20. + */ +public class TimeTracking extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public TimeTracking(RestClient restclient, JSONObject json) { + 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 new file mode 100644 index 0000000..7112079 --- /dev/null +++ b/src/main/java/net/rcarz/jiraclient/agile/Worklog.java @@ -0,0 +1,20 @@ +package net.rcarz.jiraclient.agile; + +import net.rcarz.jiraclient.RestClient; +import net.sf.json.JSONObject; + +/** + * Created by pldupont on 2016-05-20. + */ +public class Worklog extends AgileResource { + + /** + * Creates a new Agile resource. + * + * @param restclient REST client instance + * @param json JSON payload + */ + public Worklog(RestClient restclient, JSONObject json) { + 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 965c4e4..b1f317b 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy @@ -5,7 +5,6 @@ import net.rcarz.jiraclient.RestClient import org.hamcrest.core.IsEqual import org.hamcrest.core.IsNot import org.hamcrest.core.IsNull -import org.junit.Test import static org.junit.Assert.assertThat import static org.mockito.Mockito.mock @@ -32,28 +31,41 @@ class AbstractResourceTest { void "Assert equals to Board 84"(Board board) { assertThat board, new IsNot<>(new IsNull()) - assertThat board.getId(), new IsEqual(JSONResources.BOARD_84_ID) - assertThat board.getName(), new IsEqual(JSONResources.BOARD_84_NAME) - assertThat board.getType(), new IsEqual(JSONResources.BOARD_84_TYPE) - assertThat board.getSelfURL(), new IsEqual(JSONResources.BOARD_84_SELF) + assertThat board.getId(), new IsEqual(JSONResources.BOARD_ID) + assertThat board.getName(), new IsEqual(JSONResources.BOARD_NAME) + assertThat board.getType(), new IsEqual(JSONResources.BOARD_TYPE) + assertThat board.getSelfURL(), new IsEqual(JSONResources.BOARD_SELF) assertThat board.toString(), new IsEqual( String.format("Board{id=%s, name='%s'}", - JSONResources.BOARD_84_ID, JSONResources.BOARD_84_NAME)) + JSONResources.BOARD_ID, JSONResources.BOARD_NAME)) } void "Assert equals to Sprint 37"(Sprint sprint) { assertThat sprint, new IsNot<>(new IsNull()) - assertThat sprint.getId(), new IsEqual(JSONResources.SPRINT_37_ID) - assertThat sprint.getName(), new IsEqual(JSONResources.SPRINT_37_NAME) - assertThat sprint.getSelfURL(), new IsEqual(JSONResources.SPRINT_37_SELF) - assertThat sprint.getState(), new IsEqual(JSONResources.SPRINT_37_STATE) - assertThat sprint.getOriginBoardId(), new IsEqual(JSONResources.SPRINT_37_ORIGIN_BOARD_ID) - assertThat sprint.getStartDate(), new IsEqual(JSONResources.SPRINT_37_START_DATE) - assertThat sprint.getEndDate(), new IsEqual(JSONResources.SPRINT_37_END_DATE) - assertThat sprint.getCompleteDate(), new IsEqual(JSONResources.SPRINT_37_COMPLETE_DATE) + assertThat sprint.getId(), new IsEqual(JSONResources.SPRINT_ID) + assertThat sprint.getName(), new IsEqual(JSONResources.SPRINT_NAME) + assertThat sprint.getSelfURL(), new IsEqual(JSONResources.SPRINT_SELF) + assertThat sprint.getState(), new IsEqual(JSONResources.SPRINT_STATE) + assertThat sprint.getOriginBoardId(), new IsEqual(JSONResources.SPRINT_ORIGIN_BOARD_ID) + assertThat sprint.getStartDate(), new IsEqual(JSONResources.SPRINT_START_DATE) + assertThat sprint.getEndDate(), new IsEqual(JSONResources.SPRINT_END_DATE) + assertThat sprint.getCompleteDate(), new IsEqual(JSONResources.SPRINT_COMPLETE_DATE) assertThat sprint.toString(), new IsEqual( String.format("Sprint{id=%s, name='%s'}", - JSONResources.SPRINT_37_ID, JSONResources.SPRINT_37_NAME)) + JSONResources.SPRINT_ID, JSONResources.SPRINT_NAME)) + } + + 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) + + } + + void "Assert equals to Issue HSP-1"(Issue issue) { + "Assert equals to Issue 10001"(issue) + } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy index 80fbcc8..7820536 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy @@ -31,7 +31,7 @@ class AgileClientTest extends AbstractResourceTest { void "Given an agileClient, when calling getBoard(84), then receive one Board."() { "given an Agile Client"() when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84")) - .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD_84)) + .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD)) Board board = agileClient.getBoard(84); @@ -43,7 +43,7 @@ class AgileClientTest extends AbstractResourceTest { void "Given an agileClient, when calling getSprint(37), then receive one Sprint."() { "given an Agile Client"() when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/37")) - .thenReturn(JSONSerializer.toJSON(JSONResources.SPRINT_37)) + .thenReturn(JSONSerializer.toJSON(JSONResources.SPRINT)) Sprint sprint = agileClient.getSprint(37); diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy index 4311a42..8ed3fa0 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy @@ -4,15 +4,12 @@ import net.rcarz.jiraclient.JiraException import net.rcarz.jiraclient.RestClient import net.rcarz.jiraclient.RestException import net.sf.json.JSONSerializer -import org.hamcrest.Description -import org.hamcrest.Matcher 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 org.mockito.internal.matchers.Contains import static org.junit.Assert.assertThat import static org.mockito.Mockito.when @@ -54,7 +51,7 @@ class BoardTest extends AbstractResourceTest { void "Given a RestClient, when calling getBoard(84), then receive one Board."() { RestClient mockRestClient = "given a REST Client"() when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84")) - .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD_84)) + .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD)) Board board = Board.get(mockRestClient, 84); @@ -77,7 +74,7 @@ class BoardTest extends AbstractResourceTest { 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/84")) - .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD_84)) + .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD)) when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84/sprint")) .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_SPRINTS)) diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy new file mode 100644 index 0000000..33ff1f4 --- /dev/null +++ b/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy @@ -0,0 +1,67 @@ +package net.rcarz.jiraclient.agile + +import net.rcarz.jiraclient.JiraException +import net.rcarz.jiraclient.RestClient +import net.rcarz.jiraclient.RestException +import net.sf.json.JSONSerializer +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException + +import static org.mockito.Mockito.when +import static org.mockito.Mockito.when + +/** + * Created by pldupont on 2016-05-20. + */ +class IssueTest extends AbstractResourceTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + void "Given a valid issue ID, when calling Issue.get(id), then receive one Issue."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/" + JSONResources.ISSUE_ID)) + .thenReturn(JSONSerializer.toJSON(JSONResources.ISSUE)) + + Issue issue = Issue.get(mockRestClient, JSONResources.ISSUE_ID); + + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + } + + @Test + void "Given an invalid issue ID, when calling getIssue(666), then throws an 404 error."() { + RestException unauthorized = new RestException("Do not have access", 404, "Unauthorized") + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/666")) + .thenThrow(unauthorized) + expectedException.expect(JiraException.class); + expectedException.expectMessage("Failed to retrieve Issue : /rest/agile/1.0/issue/666"); + + Issue issue = Issue.get(mockRestClient, 666); + } + + @Test + void "Given a valid issue Key, when calling Issue.get(key), then receive one Issue."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/" + JSONResources.ISSUE_KEY)) + .thenReturn(JSONSerializer.toJSON(JSONResources.ISSUE)) + + Issue issue = Issue.get(mockRestClient, JSONResources.ISSUE_KEY); + + "Assert equals to Issue ${JSONResources.ISSUE_KEY}"(issue) + } + + @Test + void "Given an invalid issue Key, when calling getIssue('HSP-2'), then throws an 404 error."() { + RestException unauthorized = new RestException("Do not have access", 404, "Unauthorized") + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/HSP-2")) + .thenThrow(unauthorized) + expectedException.expect(JiraException.class); + expectedException.expectMessage("Failed to retrieve Issue : /rest/agile/1.0/issue/HSP-2"); + + Issue issue = Issue.get(mockRestClient, "HSP-2"); + } +} diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy index 3f5bb18..3b8c90c 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy @@ -7,24 +7,24 @@ import net.rcarz.jiraclient.Field */ interface JSONResources { - String BOARD_84 = """{ - "id": 84, - "self": "http://www.example.com/jira/rest/agile/1.0/board/84", - "name": "scrum board", - "type": "scrum" + String BOARD_SELF = "http://www.example.com/jira/rest/agile/1.0/board/84" + String BOARD_NAME = "scrum board" + String BOARD_TYPE = "scrum" + int BOARD_ID = 84 + String BOARD = """{ + "id": ${BOARD_ID}, + "self": "${BOARD_SELF}", + "name": "${BOARD_NAME}", + "type": "${BOARD_TYPE}" }""" - String BOARD_84_SELF = "http://www.example.com/jira/rest/agile/1.0/board/84" - String BOARD_84_NAME = "scrum board" - String BOARD_84_TYPE = "scrum" - int BOARD_84_ID = 84 String LIST_OF_BOARDS = """{ "maxResults": 2, "startAt": 1, - "total": 5, - "isLast": false, + "total": 2, + "isLast": true, "values": [ - ${BOARD_84}, + ${BOARD}, { "id": 92, "self": "http://www.example.com/jira/rest/agile/1.0/board/92", @@ -34,32 +34,32 @@ interface JSONResources { ] }""" - String SPRINT_37 = """{ - "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", - "originBoardId": 84 + int SPRINT_ID = 37 + String SPRINT_NAME = "sprint 1" + String SPRINT_SELF = "http://www.example.com/jira/rest/agile/1.0/sprint/23" + String SPRINT_STATE = "closed" + int SPRINT_ORIGIN_BOARD_ID = BOARD_ID + Date SPRINT_START_DATE = Field.getDateTime("2015-04-11T15:22:00.000+10:00") + Date SPRINT_END_DATE = Field.getDateTime("2015-04-20T01:22:00.000+10:00") + Date SPRINT_COMPLETE_DATE = Field.getDateTime("2015-04-20T11:04:00.000+10:00") + String SPRINT = """{ + "id": ${SPRINT_ID}, + "self": "${SPRINT_SELF}", + "state": "${SPRINT_STATE}", + "name": "${SPRINT_NAME}", + "startDate": "${SPRINT_START_DATE}", + "endDate": "${SPRINT_END_DATE}", + "completeDate": "${SPRINT_COMPLETE_DATE}", + "originBoardId": ${BOARD_ID} }""" - int SPRINT_37_ID = 37 - String SPRINT_37_NAME = "sprint 1" - String SPRINT_37_SELF = "http://www.example.com/jira/rest/agile/1.0/sprint/23" - String SPRINT_37_STATE = "closed" - int SPRINT_37_ORIGIN_BOARD_ID = 84 - Date SPRINT_37_START_DATE = Field.getDateTime("2015-04-11T15:22:00.000+10:00") - Date SPRINT_37_END_DATE = Field.getDateTime("2015-04-20T01:22:00.000+10:00") - Date SPRINT_37_COMPLETE_DATE = Field.getDateTime("2015-04-20T11:04:00.000+10:00") String LIST_OF_SPRINTS = """{ "maxResults": 2, "startAt": 1, - "total": 5, - "isLast": false, + "total": 2, + "isLast": true, "values": [ - ${SPRINT_37}, + ${SPRINT}, { "id": 72, "self": "http://www.example.com/jira/rest/agile/1.0/sprint/73", @@ -68,4 +68,125 @@ interface JSONResources { } ] }""" + + int ISSUE_ID = 10001 + 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": 37, + "self": "http://www.example.com/jira/rest/agile/1.0/sprint/13", + "state": "future", + "name": "sprint 2" + }, + "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": [ + { + "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 + }, + "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 e310bf9..8ae4c1f 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy @@ -25,10 +25,10 @@ class SprintTest extends AbstractResourceTest { @Test void "Given a RestClient, when calling getAll(), then receive a list of Sprint."() { RestClient mockRestClient = "given a REST Client"() - when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/" + JSONResources.SPRINT_37_ORIGIN_BOARD_ID + "/sprint")) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/" + JSONResources.SPRINT_ORIGIN_BOARD_ID + "/sprint")) .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_SPRINTS)) - List sprints = Sprint.getAll(mockRestClient, JSONResources.SPRINT_37_ORIGIN_BOARD_ID); + List sprints = Sprint.getAll(mockRestClient, JSONResources.SPRINT_ORIGIN_BOARD_ID); assertThat sprints, new IsNot<>(new IsNull()) assertThat sprints.size(), new IsEqual(2) @@ -39,19 +39,19 @@ class SprintTest extends AbstractResourceTest { void "Given a RestClient, when calling getAll() and use doesn't have access, then throws an 401 error."() { RestException unauthorized = new RestException("Do not have access", 401, "Unauthorized") RestClient mockRestClient = "given a REST Client"() - when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/" + JSONResources.SPRINT_37_ORIGIN_BOARD_ID + "/sprint")) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/" + JSONResources.SPRINT_ORIGIN_BOARD_ID + "/sprint")) .thenThrow(unauthorized) expectedException.expect(JiraException.class); - expectedException.expectMessage("Failed to retrieve a list of Sprint : /rest/agile/1.0/board/" + JSONResources.SPRINT_37_ORIGIN_BOARD_ID + "/sprint"); + expectedException.expectMessage("Failed to retrieve a list of Sprint : /rest/agile/1.0/board/" + JSONResources.SPRINT_ORIGIN_BOARD_ID + "/sprint"); - List sprints = Sprint.getAll(mockRestClient, JSONResources.SPRINT_37_ORIGIN_BOARD_ID); + List sprints = Sprint.getAll(mockRestClient, JSONResources.SPRINT_ORIGIN_BOARD_ID); } @Test void "Given a RestClient, when calling getSprint(84), then receive one Sprint."() { RestClient mockRestClient = "given a REST Client"() when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/37")) - .thenReturn(JSONSerializer.toJSON(JSONResources.SPRINT_37)) + .thenReturn(JSONSerializer.toJSON(JSONResources.SPRINT)) Sprint sprint = Sprint.get(mockRestClient, 37); From cbcf089722a3bc444ef04a781bdc49c3ca87d7f9 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Mon, 30 May 2016 16:40:26 -0400 Subject: [PATCH 09/11] Adding Epic resource, with test. --- README.md | 7 +- src/main/java/net/rcarz/jiraclient/Field.java | 199 +++++++++--------- .../rcarz/jiraclient/agile/AgileClient.java | 48 ++++- .../rcarz/jiraclient/agile/AgileResource.java | 181 ++++++++-------- .../net/rcarz/jiraclient/agile/Board.java | 16 +- .../java/net/rcarz/jiraclient/agile/Epic.java | 16 +- .../rcarz/jiraclient/agile/Estimation.java | 7 - .../net/rcarz/jiraclient/agile/Issue.java | 7 +- .../net/rcarz/jiraclient/agile/Sprint.java | 20 +- .../agile/AbstractResourceTest.groovy | 52 +++-- .../jiraclient/agile/AgileClientTest.groovy | 54 ++++- .../rcarz/jiraclient/agile/BoardTest.groovy | 23 +- .../rcarz/jiraclient/agile/EpicTest.groovy | 44 ++++ .../rcarz/jiraclient/agile/IssueTest.groovy | 8 +- .../jiraclient/agile/JSONResources.groovy | 37 +++- .../rcarz/jiraclient/agile/SprintTest.groovy | 17 +- 16 files changed, 447 insertions(+), 289 deletions(-) delete mode 100644 src/main/java/net/rcarz/jiraclient/agile/Estimation.java create mode 100644 src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy diff --git a/README.md b/README.md index b3d328c..f58e16e 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,7 @@ https://docs.atlassian.com/jira-software/REST/cloud/ 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} @@ -290,17 +291,17 @@ https://docs.atlassian.com/jira-software/REST/cloud/ 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} 1. -- GET /rest/agile/1.0/epic/{epicIdOrKey}/issue 1. -- GET /rest/agile/1.0/epic/none/issue - 1. -- GET /rest/agile/1.0/issue/{issueIdOrKey} - 1. -- GET /rest/agile/1.0/issue/{issueIdOrKey}/estimation 1. -- GET /rest/agile/1.0/sprint/{sprintId}/issue diff --git a/src/main/java/net/rcarz/jiraclient/Field.java b/src/main/java/net/rcarz/jiraclient/Field.java index 87c0bdc..f38fb86 100644 --- a/src/main/java/net/rcarz/jiraclient/Field.java +++ b/src/main/java/net/rcarz/jiraclient/Field.java @@ -19,107 +19,24 @@ package net.rcarz.jiraclient; -import java.lang.Iterable; -import java.lang.UnsupportedOperationException; +import net.sf.json.JSONArray; +import net.sf.json.JSONNull; +import net.sf.json.JSONObject; + import java.sql.Timestamp; import java.text.ParsePosition; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.sf.json.JSONArray; -import net.sf.json.JSONObject; -import net.sf.json.JSONNull; +import java.util.*; /** * Utility functions for translating between JSON and fields. */ public final class Field { - /** - * Field metadata structure. - */ - public static final class Meta { - public boolean required; - public String type; - public String items; - public String name; - public String system; - public String custom; - public int customId; - } - - /** - * Field update operation. - */ - public static final class Operation { - public String name; - public Object value; - - /** - * Initialises a new update operation. - * - * @param name Operation name - * @param value Field value - */ - public Operation(String name, Object value) { - this.name = name; - this.value = value; - } - } - - /** - * Allowed value types. - */ - public enum ValueType { - KEY("key"), NAME("name"), ID_NUMBER("id"), VALUE("value"); - private String typeName; - - private ValueType(String typeName) { - this.typeName = typeName; - } - - @Override - public String toString() { - return typeName; - } - }; - - /** - * 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 != null ? value : JSONNull.getInstance()); - } - - /** - * Initialises the value tuple. - * - * @param type - * @param value - */ - public ValueTuple(ValueType type, Object value) { - this(type.toString(), value); - } - } - public static final String ASSIGNEE = "assignee"; public static final String ATTACHMENT = "attachment"; public static final String CHANGE_LOG = "changelog"; + ; public static final String CHANGE_LOG_ENTRIES = "histories"; public static final String CHANGE_LOG_ITEMS = "items"; public static final String COMMENT = "comment"; @@ -149,10 +66,8 @@ public final class Field { public static final String CREATED_DATE = "created"; public static final String UPDATED_DATE = "updated"; public static final String TRANSITION_TO_STATUS = "to"; - public static final String DATE_FORMAT = "yyyy-MM-dd"; public static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; - private Field() { } /** @@ -204,7 +119,7 @@ public final class Field { return results; } - + /** * Gets a list of remote links from the given object. * @@ -290,6 +205,24 @@ public final class Field { return result; } + /** + * Gets a long from the given object. + * + * @param i a Long or an Integer instance + * + * @return a long primitive or 0 if i isn't a Long or an Integer instance + */ + public static long getLong(Object i) { + long result = 0; + + if (i instanceof Long) + result = ((Long) i).longValue(); + if (i instanceof Integer) + result = ((Integer) i).intValue(); + + return result; + } + /** * Gets a generic map from the given object. * @@ -553,7 +486,7 @@ public final class Field { } else if (type.equals("string") && custom != null && (custom.equals("com.atlassian.jira.plugin.system.customfieldtypes:multicheckboxes") || custom.equals("com.atlassian.jira.plugin.system.customfieldtypes:multiselect"))) { - + realResult = new JSONObject(); ((JSONObject)realResult).put(ValueType.VALUE.toString(), realValue.toString()); } else if (type.equals("string")) @@ -658,7 +591,7 @@ public final class Field { else if (value instanceof TimeTracking) return ((TimeTracking) value).toJsonObject(); } else if (m.type.equals("number")) { - if(!(value instanceof java.lang.Integer) && !(value instanceof java.lang.Double) && !(value + if (!(value instanceof java.lang.Integer) && !(value instanceof java.lang.Double) && !(value instanceof java.lang.Float) && !(value instanceof java.lang.Long) ) { throw new JiraException("Field '" + name + "' expects a Numeric value"); @@ -722,5 +655,83 @@ public final class Field { public static ValueTuple valueById(String id) { return new ValueTuple(ValueType.ID_NUMBER, id); } + + /** + * Allowed value types. + */ + public enum ValueType { + KEY("key"), NAME("name"), ID_NUMBER("id"), VALUE("value"); + private String typeName; + + private ValueType(String typeName) { + this.typeName = typeName; + } + + @Override + public String toString() { + return typeName; + } + } + + /** + * Field metadata structure. + */ + public static final class Meta { + public boolean required; + public String type; + public String items; + public String name; + public String system; + public String custom; + public int customId; + } + + /** + * Field update operation. + */ + public static final class Operation { + public String name; + public Object value; + + /** + * Initialises a new update operation. + * + * @param name Operation name + * @param value Field value + */ + public Operation(String name, Object value) { + this.name = name; + 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 != null ? value : JSONNull.getInstance()); + } + + /** + * Initialises the value tuple. + * + * @param type + * @param value + */ + public ValueTuple(ValueType type, Object value) { + this(type.toString(), value); + } + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java index 948204b..e51ee80 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java @@ -27,6 +27,7 @@ import java.util.List; /** * An Agile extension to the JIRA client. + * * @see "https://docs.atlassian.com/jira-software/REST/cloud/" */ public class AgileClient { @@ -43,23 +44,20 @@ public class AgileClient { } /** - * Retreives the board with the given ID. + * Retrieves the board with the given ID. * * @param id Board ID - * * @return a Board instance - * * @throws JiraException when something goes wrong */ - public Board getBoard(int id) throws JiraException { + public Board getBoard(long id) throws JiraException { return Board.get(restclient, id); } /** - * Retreives all boards visible to the session user. + * Retrieves all boards visible to the session user. * * @return a list of boards - * * @throws JiraException when something goes wrong */ public List getBoards() throws JiraException { @@ -67,17 +65,47 @@ public class AgileClient { } /** - * Retreives the sprint with the given ID. + * Retrieves the sprint with the given ID. * * @param id Sprint ID - * * @return a Sprint instance - * * @throws JiraException when something goes wrong */ - public Sprint getSprint(int id) throws JiraException { + public Sprint getSprint(long id) throws JiraException { return Sprint.get(restclient, id); } + /** + * Retrieves the issue with the given ID. + * + * @param id Issue ID + * @return an Issue instance + * @throws JiraException when something goes wrong + */ + public Issue getIssue(long id) throws JiraException { + return Issue.get(restclient, id); + } + + /** + * Retrieves the issue with the given Key. + * + * @param key Issue Key + * @return an Issue instance + * @throws JiraException when something goes wrong + */ + public Issue getIssue(String key) throws JiraException { + return Issue.get(restclient, key); + } + + /** + * Retrieves the epic with the given ID. + * + * @param id Epic ID + * @return an Epic instance + * @throws JiraException when something goes wrong + */ + public Epic getEpic(long id) throws JiraException { + return Epic.get(restclient, id); + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java index 9fb7e35..24c608a 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java @@ -48,7 +48,7 @@ public abstract class AgileResource { public static final String RESOURCE_URI = "/rest/agile/1.0/"; private RestClient restclient = null; - private int id = 0; + private long id = 0; private String name; private String self; private Map attributes = new HashMap(); @@ -66,94 +66,6 @@ public abstract class AgileResource { } } - /** - * @return Internal JIRA ID. - */ - public int getId() { - return id; - } - - /** - * @return The resource name. - */ - public String getName() { - return name; - } - - /** - * @return The resource URL. - */ - public String getSelfURL() { - return self; - } - - /** - * @return The REST client used to access the current resource. - */ - protected RestClient getRestclient() { - return restclient; - } - - /** - * Retrieve the specified attribute as a generic object. - * - * @param name The name of the attribute to retrieve. - * @return The value of the attribute. - */ - public String 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. - */ - public 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. - */ - public 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) { - Map map = json; - - id = getInteger(map.get("id")); - name = Field.getString(map.get("name")); - self = Field.getString(map.get("self")); - attributes.putAll(map); - } - - private int getInteger(Object o) { - if (o instanceof Integer) { - return Field.getInteger(o); - } else if (o instanceof String && NumberUtils.isDigits((String) o)) { - return NumberUtils.toInt((String) o, 0); - } else { - return 0; - } - } - - @Override - public String toString() { - return String.format("%s{id=%s, name='%s'}", getClass().getSimpleName(), id, name); - } - /** * Gets an Agile resource from the given object. * @@ -223,7 +135,7 @@ public abstract class AgileResource { */ static List list(RestClient restclient, Class type, String url) throws JiraException { - JSON result = null; + JSON result; try { result = restclient.get(url); } catch (Exception ex) { @@ -246,7 +158,7 @@ public abstract class AgileResource { */ static T get(RestClient restclient, Class type, String url) throws JiraException { - JSON result = null; + JSON result; try { result = restclient.get(url); } catch (Exception ex) { @@ -259,5 +171,92 @@ public abstract class AgileResource { restclient ); } + + /** + * @return Internal JIRA ID. + */ + public long getId() { + return id; + } + + /** + * @return The resource name. + */ + public String getName() { + return name; + } + + /** + * @return The resource URL. + */ + public String getSelfURL() { + return self; + } + + /** + * @return The REST client used to access the current resource. + */ + protected RestClient getRestclient() { + return restclient; + } + + /** + * Retrieve the specified attribute as a generic object. + * + * @param name The name of the attribute to retrieve. + * @return The value of the attribute. + */ + String 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) { + + id = getLong(json.get("id")); + name = Field.getString(json.get("name")); + self = Field.getString(json.get("self")); + attributes.putAll(json); + } + + long getLong(Object o) { + if (o instanceof Integer || o instanceof Long) { + return Field.getInteger(o); + } else if (o instanceof String && NumberUtils.isDigits((String) o)) { + return NumberUtils.toLong((String) o, 0L); + } else { + return 0L; + } + } + + @Override + public String toString() { + return String.format("%s{id=%s, name='%s'}", getClass().getSimpleName(), id, name); + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Board.java b/src/main/java/net/rcarz/jiraclient/agile/Board.java index 73463d1..fae1a0a 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Board.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Board.java @@ -33,7 +33,7 @@ import java.util.List; */ public class Board extends AgileResource { - public static final String ATTR_TYPE = "type"; + private static final String ATTR_TYPE = "type"; private String type; @@ -47,12 +47,6 @@ public class Board extends AgileResource { super(restclient, json); } - @Override - protected void deserialize(JSONObject json) { - super.deserialize(json); - type = Field.getString(json.get(ATTR_TYPE)); - } - /** * Retrieves the given rapid view. * @@ -61,7 +55,7 @@ public class Board extends AgileResource { * @return a rapid view instance * @throws JiraException when the retrieval fails */ - public static Board get(RestClient restclient, int id) throws JiraException { + public static Board get(RestClient restclient, long id) throws JiraException { return AgileResource.get(restclient, Board.class, RESOURCE_URI + "board/" + id); } @@ -76,6 +70,12 @@ public class Board extends AgileResource { return AgileResource.list(restclient, Board.class, RESOURCE_URI + "board"); } + @Override + protected void deserialize(JSONObject json) { + super.deserialize(json); + type = Field.getString(json.get(ATTR_TYPE)); + } + /** * @return The board type. */ diff --git a/src/main/java/net/rcarz/jiraclient/agile/Epic.java b/src/main/java/net/rcarz/jiraclient/agile/Epic.java index 0fc3b3f..8445e84 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Epic.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Epic.java @@ -1,10 +1,12 @@ 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. + * Created on 2016-05-20. + * @author pldupont */ public class Epic extends AgileResource { @@ -17,4 +19,16 @@ public class Epic extends AgileResource { public Epic(RestClient restclient, JSONObject json) { super(restclient, json); } + + /** + * Retrieves the epic matching the ID. + * + * @param restclient REST client instance + * @param id Internal JIRA ID of the epic + * @return an epic instance + * @throws JiraException when the retrieval fails + */ + public static Epic get(RestClient restclient, long id) throws JiraException { + return AgileResource.get(restclient, Epic.class, RESOURCE_URI + "epic/" + id); + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Estimation.java b/src/main/java/net/rcarz/jiraclient/agile/Estimation.java deleted file mode 100644 index b864c65..0000000 --- a/src/main/java/net/rcarz/jiraclient/agile/Estimation.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.rcarz.jiraclient.agile; - -/** - * Created by pldupont on 2016-05-20. - */ -public class Estimation { -} diff --git a/src/main/java/net/rcarz/jiraclient/agile/Issue.java b/src/main/java/net/rcarz/jiraclient/agile/Issue.java index d834995..7851ea0 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Issue.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Issue.java @@ -4,10 +4,9 @@ import net.rcarz.jiraclient.JiraException; import net.rcarz.jiraclient.RestClient; import net.sf.json.JSONObject; -import java.util.List; - /** - * Created by pldupont on 2016-05-20. + * Created on 2016-05-20. + * @author pldupont */ public class Issue extends AgileResource { @@ -29,7 +28,7 @@ public class Issue extends AgileResource { * @return an issue instance * @throws JiraException when the retrieval fails */ - public static Issue get(RestClient restclient, int id) throws JiraException { + public static Issue get(RestClient restclient, long id) throws JiraException { return AgileResource.get(restclient, Issue.class, RESOURCE_URI + "issue/" + id); } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Sprint.java b/src/main/java/net/rcarz/jiraclient/agile/Sprint.java index 696378a..00f58e0 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Sprint.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Sprint.java @@ -34,14 +34,14 @@ import java.util.List; */ public class Sprint extends AgileResource { - public static final String ATTR_STATE = "state"; - public static final String ATTR_ORIGIN_BOARD_ID = "originBoardId"; - public static final String ATTR_START_DATE = "startDate"; - public static final String ATTR_END_DATE = "endDate"; - public static final String ATTR_COMPLETE_DATE = "completeDate"; + 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 int originBoardId; + private long originBoardId; private Date startDate; private Date endDate; private Date completeDate; @@ -64,7 +64,7 @@ public class Sprint extends AgileResource { * @return The sprint for the specified ID. * @throws JiraException when the retrieval fails */ - public static Sprint get(RestClient restclient, int sprintId) throws JiraException { + public static Sprint get(RestClient restclient, long sprintId) throws JiraException { return AgileResource.get(restclient, Sprint.class, RESOURCE_URI + "sprint/" + sprintId); } @@ -76,7 +76,7 @@ public class Sprint extends AgileResource { * @return The list of sprints associated to the board. * @throws JiraException when the retrieval fails */ - public static List getAll(RestClient restclient, int boardId) throws JiraException { + public static List getAll(RestClient restclient, long boardId) throws JiraException { return AgileResource.list(restclient, Sprint.class, RESOURCE_URI + "board/" + boardId + "/sprint"); } @@ -84,7 +84,7 @@ public class Sprint extends AgileResource { protected void deserialize(JSONObject json) { super.deserialize(json); state = Field.getString(json.get(ATTR_STATE)); - originBoardId = Field.getInteger(json.get(ATTR_ORIGIN_BOARD_ID)); + 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)); @@ -94,7 +94,7 @@ public class Sprint extends AgileResource { return state; } - public int getOriginBoardId() { + public long getOriginBoardId() { return originBoardId; } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy index b1f317b..20d00c1 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy @@ -2,6 +2,8 @@ package net.rcarz.jiraclient.agile import net.rcarz.jiraclient.JiraClient import net.rcarz.jiraclient.RestClient +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 @@ -11,7 +13,8 @@ import static org.mockito.Mockito.mock import static org.mockito.Mockito.when /** - * Created by pldupont on 2016-05-19. + * Created on 2016-05-19. + * @author pldupont */ class AbstractResourceTest { AgileClient agileClient; @@ -29,25 +32,30 @@ class AbstractResourceTest { return mockRestClient } - void "Assert equals to Board 84"(Board board) { + Issue "given an Issue"() { + mockRestClient = mock RestClient.class + return new Issue(mockRestClient, JSONSerializer.toJSON(JSONResources.ISSUE) as JSONObject) + } + + static void "Assert equals to Board 84"(Board board) { assertThat board, new IsNot<>(new IsNull()) - assertThat board.getId(), new IsEqual(JSONResources.BOARD_ID) - assertThat board.getName(), new IsEqual(JSONResources.BOARD_NAME) - assertThat board.getType(), new IsEqual(JSONResources.BOARD_TYPE) - assertThat board.getSelfURL(), new IsEqual(JSONResources.BOARD_SELF) + assertThat board.getId(), new IsEqual(JSONResources.BOARD_ID) + assertThat board.getName(), new IsEqual(JSONResources.BOARD_NAME) + assertThat board.getType(), new IsEqual(JSONResources.BOARD_TYPE) + assertThat board.getSelfURL(), new IsEqual(JSONResources.BOARD_SELF) assertThat board.toString(), new IsEqual( String.format("Board{id=%s, name='%s'}", JSONResources.BOARD_ID, JSONResources.BOARD_NAME)) } - void "Assert equals to Sprint 37"(Sprint sprint) { + static void "Assert equals to Sprint 37"(Sprint sprint) { assertThat sprint, new IsNot<>(new IsNull()) - assertThat sprint.getId(), new IsEqual(JSONResources.SPRINT_ID) - assertThat sprint.getName(), new IsEqual(JSONResources.SPRINT_NAME) - assertThat sprint.getSelfURL(), new IsEqual(JSONResources.SPRINT_SELF) - assertThat sprint.getState(), new IsEqual(JSONResources.SPRINT_STATE) - assertThat sprint.getOriginBoardId(), new IsEqual(JSONResources.SPRINT_ORIGIN_BOARD_ID) + assertThat sprint.getId(), new IsEqual(JSONResources.SPRINT_ID) + assertThat sprint.getName(), new IsEqual(JSONResources.SPRINT_NAME) + assertThat sprint.getSelfURL(), new IsEqual(JSONResources.SPRINT_SELF) + assertThat sprint.getState(), new IsEqual(JSONResources.SPRINT_STATE) + assertThat sprint.getOriginBoardId(), new IsEqual(JSONResources.SPRINT_ORIGIN_BOARD_ID) assertThat sprint.getStartDate(), new IsEqual(JSONResources.SPRINT_START_DATE) assertThat sprint.getEndDate(), new IsEqual(JSONResources.SPRINT_END_DATE) assertThat sprint.getCompleteDate(), new IsEqual(JSONResources.SPRINT_COMPLETE_DATE) @@ -56,15 +64,23 @@ class AbstractResourceTest { JSONResources.SPRINT_ID, JSONResources.SPRINT_NAME)) } - 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) + static void "Assert equals to Epic 23"(Epic epic) { + assertThat epic, new IsNot<>(new IsNull()) + assertThat epic.getId(), new IsEqual(JSONResources.EPIC_ID) + assertThat epic.getName(), new IsEqual(JSONResources.EPIC_NAME) + assertThat epic.getSelfURL(), new IsEqual(JSONResources.EPIC_SELF) } - void "Assert equals to Issue HSP-1"(Issue issue) { + 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) + + } + + static void "Assert equals to Issue HSP-1"(Issue issue) { "Assert equals to Issue 10001"(issue) } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy index 7820536..19ecf71 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy @@ -10,7 +10,8 @@ import static org.junit.Assert.assertThat import static org.mockito.Mockito.when /** - * Created by pldupont on 2016-05-19. + * Created on 2016-05-19. + * @author pldupont */ class AgileClientTest extends AbstractResourceTest { @@ -24,30 +25,63 @@ class AgileClientTest extends AbstractResourceTest { assertThat boards, new IsNot<>(new IsNull()) assertThat boards.size(), new IsEqual(2) - "Assert equals to Board 84"(boards.get(0)) + "Assert equals to Board ${JSONResources.BOARD_ID}"(boards.get(0)) } @Test - void "Given an agileClient, when calling getBoard(84), then receive one Board."() { + void "Given an agileClient, when calling getBoard(boardId), then receive one Board."() { "given an Agile Client"() - when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84")) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/" + JSONResources.BOARD_ID)) .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD)) - Board board = agileClient.getBoard(84); + Board board = agileClient.getBoard(JSONResources.BOARD_ID); assertThat board, new IsNot<>(new IsNull()) - "Assert equals to Board 84"(board) + "Assert equals to Board ${JSONResources.BOARD_ID}"(board) } @Test - void "Given an agileClient, when calling getSprint(37), then receive one Sprint."() { + void "Given an agileClient, when calling getSprint(sprintId), then receive one Sprint."() { "given an Agile Client"() - when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/37")) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/" + JSONResources.SPRINT_ID)) .thenReturn(JSONSerializer.toJSON(JSONResources.SPRINT)) - Sprint sprint = agileClient.getSprint(37); + Sprint sprint = agileClient.getSprint(JSONResources.SPRINT_ID); assertThat sprint, new IsNot<>(new IsNull()) - "Assert equals to Sprint 37"(sprint) + "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprint) + } + + @Test + void "Given an agileClient, when calling getIssue(id), then receive one Issue."() { + "given an Agile Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/" + JSONResources.ISSUE_ID)) + .thenReturn(JSONSerializer.toJSON(JSONResources.ISSUE)) + + Issue issue = agileClient.getIssue(JSONResources.ISSUE_ID); + + "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + } + + @Test + void "Given an agileClient, when calling getIssue(key), then receive one Issue."() { + "given an Agile Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "issue/" + JSONResources.ISSUE_KEY)) + .thenReturn(JSONSerializer.toJSON(JSONResources.ISSUE)) + + Issue issue = agileClient.getIssue(JSONResources.ISSUE_KEY); + + "Assert equals to Issue ${JSONResources.ISSUE_KEY}"(issue) + } + + @Test + void "Given an agileClient, when calling getEpic(id), then receive one Epic."() { + "given an Agile Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "epic/" + JSONResources.EPIC_ID)) + .thenReturn(JSONSerializer.toJSON(JSONResources.EPIC)) + + Epic epic = agileClient.getEpic(JSONResources.EPIC_ID); + + "Assert equals to Epic ${JSONResources.EPIC_ID}"(epic) } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy index 8ed3fa0..4061331 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy @@ -15,7 +15,8 @@ import static org.junit.Assert.assertThat import static org.mockito.Mockito.when /** - * Created by pldupont on 2016-05-19. + * Created on 2016-05-19. + * @author pldupont */ class BoardTest extends AbstractResourceTest { @@ -44,16 +45,16 @@ class BoardTest extends AbstractResourceTest { expectedException.expect(JiraException.class); expectedException.expectMessage("Failed to retrieve a list of Board : /rest/agile/1.0/board"); - List boards = Board.getAll(mockRestClient); + Board.getAll(mockRestClient); } @Test - void "Given a RestClient, when calling getBoard(84), then receive one Board."() { + void "Given a RestClient, when calling getBoard(boardId), then receive one Board."() { RestClient mockRestClient = "given a REST Client"() - when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84")) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/${JSONResources.BOARD_ID}")) .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD)) - Board board = Board.get(mockRestClient, 84); + Board board = Board.get(mockRestClient, JSONResources.BOARD_ID); "Assert equals to Board 84"(board) } @@ -67,24 +68,24 @@ class BoardTest extends AbstractResourceTest { expectedException.expect(JiraException.class); expectedException.expectMessage("Failed to retrieve Board : /rest/agile/1.0/board/666"); - Board board = Board.get(mockRestClient, 666); + Board.get(mockRestClient, 666); } @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/84")) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/${JSONResources.BOARD_ID}")) .thenReturn(JSONSerializer.toJSON(JSONResources.BOARD)) - when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/84/sprint")) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "board/${JSONResources.BOARD_ID}/sprint")) .thenReturn(JSONSerializer.toJSON(JSONResources.LIST_OF_SPRINTS)) - Board board = Board.get(mockRestClient, 84); - "Assert equals to Board 84"(board) + Board board = Board.get(mockRestClient, JSONResources.BOARD_ID); + "Assert equals to Board ${JSONResources.BOARD_ID}"(board) List sprints = board.getSprints(); assertThat sprints, new IsNot<>(new IsNull()) assertThat sprints.size(), new IsEqual(2) - "Assert equals to Sprint 37"(sprints.get(0)) + "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprints.get(0)) } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy new file mode 100644 index 0000000..bae381b --- /dev/null +++ b/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy @@ -0,0 +1,44 @@ +package net.rcarz.jiraclient.agile + +import net.rcarz.jiraclient.JiraException +import net.rcarz.jiraclient.RestClient +import net.rcarz.jiraclient.RestException +import net.sf.json.JSONSerializer +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException + +import static org.mockito.Mockito.when + +/** + * Created on 2016-05-20. + * @author pldupont + */ +class EpicTest extends AbstractResourceTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + void "Given a valid Epic ID, when calling Epic.get(id), then receive one Epic."() { + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "epic/" + JSONResources.EPIC_ID)) + .thenReturn(JSONSerializer.toJSON(JSONResources.EPIC)) + + Epic epic = Epic.get(mockRestClient, JSONResources.EPIC_ID); + + "Assert equals to Epic ${JSONResources.EPIC_ID}"(epic) + } + + @Test + void "Given an invalid epic ID, when calling getEpic(666), then throws an 404 error."() { + RestException unauthorized = new RestException("Do not have access", 404, "Unauthorized") + RestClient mockRestClient = "given a REST Client"() + when(mockRestClient.get(AgileResource.RESOURCE_URI + "epic/666")) + .thenThrow(unauthorized) + expectedException.expect(JiraException.class); + expectedException.expectMessage("Failed to retrieve Epic : /rest/agile/1.0/epic/666"); + + Epic.get(mockRestClient, 666); + } +} diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy index 33ff1f4..67870f2 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy @@ -8,11 +8,11 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException -import static org.mockito.Mockito.when import static org.mockito.Mockito.when /** - * Created by pldupont on 2016-05-20. + * Created on 2016-05-20. + * @author pldupont */ class IssueTest extends AbstractResourceTest { @@ -39,7 +39,7 @@ class IssueTest extends AbstractResourceTest { expectedException.expect(JiraException.class); expectedException.expectMessage("Failed to retrieve Issue : /rest/agile/1.0/issue/666"); - Issue issue = Issue.get(mockRestClient, 666); + Issue.get(mockRestClient, 666); } @Test @@ -62,6 +62,6 @@ class IssueTest extends AbstractResourceTest { expectedException.expect(JiraException.class); expectedException.expectMessage("Failed to retrieve Issue : /rest/agile/1.0/issue/HSP-2"); - Issue issue = Issue.get(mockRestClient, "HSP-2"); + Issue.get(mockRestClient, "HSP-2"); } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy index 3b8c90c..922c60c 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy @@ -3,14 +3,15 @@ package net.rcarz.jiraclient.agile import net.rcarz.jiraclient.Field /** - * Created by pldupont on 2016-05-19. + * Created on 2016-05-19. + * @author pldupont */ interface JSONResources { - String BOARD_SELF = "http://www.example.com/jira/rest/agile/1.0/board/84" + long BOARD_ID = 84L + String BOARD_SELF = "http://www.example.com/jira/rest/agile/1.0/board/${BOARD_ID}" String BOARD_NAME = "scrum board" String BOARD_TYPE = "scrum" - int BOARD_ID = 84 String BOARD = """{ "id": ${BOARD_ID}, "self": "${BOARD_SELF}", @@ -34,11 +35,11 @@ interface JSONResources { ] }""" - int SPRINT_ID = 37 + long SPRINT_ID = 37L String SPRINT_NAME = "sprint 1" - String SPRINT_SELF = "http://www.example.com/jira/rest/agile/1.0/sprint/23" + String SPRINT_SELF = "http://www.example.com/jira/rest/agile/1.0/sprint/${SPRINT_ID}" String SPRINT_STATE = "closed" - int SPRINT_ORIGIN_BOARD_ID = BOARD_ID + long SPRINT_ORIGIN_BOARD_ID = BOARD_ID Date SPRINT_START_DATE = Field.getDateTime("2015-04-11T15:22:00.000+10:00") Date SPRINT_END_DATE = Field.getDateTime("2015-04-20T01:22:00.000+10:00") Date SPRINT_COMPLETE_DATE = Field.getDateTime("2015-04-20T11:04:00.000+10:00") @@ -69,7 +70,23 @@ interface JSONResources { ] }""" - int ISSUE_ID = 10001 + long EPIC_ID = 23 + String EPIC_SELF = "http://www.example.com/jira/rest/agile/1.0/epic/${EPIC_ID}" + String EPIC_NAME = "epic 1" + String EPIC_SUMMARY = "epic 1 summary" + boolean EPIC_DONE = true + String EPIC = """{ + "id": ${EPIC_ID}, + "self": "${EPIC_SELF}", + "name": "${EPIC_NAME}", + "summary": "${EPIC_SUMMARY}", + "color": { + "key": "color_4" + }, + "done": ${EPIC_DONE} +}""" + + 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 = """{ @@ -80,14 +97,14 @@ interface JSONResources { "fields": { "flagged": true, "sprint": { - "id": 37, - "self": "http://www.example.com/jira/rest/agile/1.0/sprint/13", + "id": ${SPRINT_ID}, + "self": "http://www.example.com/jira/rest/agile/1.0/sprint/${SPRINT_ID}", "state": "future", "name": "sprint 2" }, "closedSprints": [ { - "id": 37, + "id": 23, "self": "http://www.example.com/jira/rest/agile/1.0/sprint/23", "state": "closed", "name": "sprint 1", diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy index 8ae4c1f..05ffd32 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy @@ -15,7 +15,8 @@ import static org.junit.Assert.assertThat import static org.mockito.Mockito.when /** - * Created by pldupont on 2016-05-19. + * Created on 2016-05-19. + * @author pldupont */ class SprintTest extends AbstractResourceTest { @@ -32,7 +33,7 @@ class SprintTest extends AbstractResourceTest { assertThat sprints, new IsNot<>(new IsNull()) assertThat sprints.size(), new IsEqual(2) - "Assert equals to Sprint 37"(sprints.get(0)) + "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprints.get(0)) } @Test @@ -44,18 +45,18 @@ class SprintTest extends AbstractResourceTest { expectedException.expect(JiraException.class); expectedException.expectMessage("Failed to retrieve a list of Sprint : /rest/agile/1.0/board/" + JSONResources.SPRINT_ORIGIN_BOARD_ID + "/sprint"); - List sprints = Sprint.getAll(mockRestClient, JSONResources.SPRINT_ORIGIN_BOARD_ID); + Sprint.getAll(mockRestClient, JSONResources.SPRINT_ORIGIN_BOARD_ID); } @Test - void "Given a RestClient, when calling getSprint(84), then receive one Sprint."() { + void "Given a RestClient, when calling getSprint(sprintId), then receive one Sprint."() { RestClient mockRestClient = "given a REST Client"() - when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/37")) + when(mockRestClient.get(AgileResource.RESOURCE_URI + "sprint/${JSONResources.SPRINT_ID}")) .thenReturn(JSONSerializer.toJSON(JSONResources.SPRINT)) - Sprint sprint = Sprint.get(mockRestClient, 37); + Sprint sprint = Sprint.get(mockRestClient, JSONResources.SPRINT_ID); - "Assert equals to Sprint 37"(sprint) + "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprint) } @Test @@ -67,6 +68,6 @@ class SprintTest extends AbstractResourceTest { expectedException.expect(JiraException.class); expectedException.expectMessage("Failed to retrieve Sprint : /rest/agile/1.0/sprint/666"); - Sprint sprint = Sprint.get(mockRestClient, 666); + Sprint.get(mockRestClient, 666); } } From 04f90c00d1232c1585c0d6ecd08ec11426786bb8 Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Wed, 1 Jun 2016 16:27:50 -0400 Subject: [PATCH 10/11] Explode Issue attributes --- README.md | 45 +- .../rcarz/jiraclient/agile/AgileClient.java | 1 + .../rcarz/jiraclient/agile/AgileResource.java | 128 +++-- .../net/rcarz/jiraclient/agile/Board.java | 41 +- .../net/rcarz/jiraclient/agile/Comment.java | 26 +- .../java/net/rcarz/jiraclient/agile/Epic.java | 48 +- .../net/rcarz/jiraclient/agile/Issue.java | 163 ++++++- .../net/rcarz/jiraclient/agile/IssueType.java | 42 ++ .../net/rcarz/jiraclient/agile/Priority.java | 42 ++ .../net/rcarz/jiraclient/agile/Project.java | 26 +- .../rcarz/jiraclient/agile/Resolution.java | 42 ++ .../net/rcarz/jiraclient/agile/Sprint.java | 28 +- .../net/rcarz/jiraclient/agile/Status.java | 42 ++ .../rcarz/jiraclient/agile/TimeTracking.java | 26 +- .../java/net/rcarz/jiraclient/agile/User.java | 42 ++ .../net/rcarz/jiraclient/agile/Worklog.java | 26 +- .../agile/AbstractResourceTest.groovy | 100 ++++ .../rcarz/jiraclient/agile/BoardTest.groovy | 51 +- .../rcarz/jiraclient/agile/EpicTest.groovy | 65 +++ .../rcarz/jiraclient/agile/IssueTest.groovy | 11 + .../jiraclient/agile/JSONResources.groovy | 440 ++++++++++++++---- .../rcarz/jiraclient/agile/SprintTest.groovy | 15 + 22 files changed, 1249 insertions(+), 201 deletions(-) create mode 100644 src/main/java/net/rcarz/jiraclient/agile/IssueType.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Priority.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Resolution.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/Status.java create mode 100644 src/main/java/net/rcarz/jiraclient/agile/User.java 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)) + } } From 7747d35542dd9817f8bdc61bcd3b860e7bb0092a Mon Sep 17 00:00:00 2001 From: Pierre-Luc Dupont Date: Wed, 1 Jun 2016 22:42:47 -0400 Subject: [PATCH 11/11] Completed the AgileClient implementation - Read Only. --- README.md | 3 +- .../rcarz/jiraclient/agile/AgileClient.java | 4 + .../rcarz/jiraclient/agile/AgileResource.java | 8 +- .../net/rcarz/jiraclient/agile/Comment.java | 51 +++++++ .../java/net/rcarz/jiraclient/agile/Epic.java | 31 ++++ .../net/rcarz/jiraclient/agile/IssueType.java | 26 ++++ .../net/rcarz/jiraclient/agile/Project.java | 20 +++ .../rcarz/jiraclient/agile/Resolution.java | 20 +++ .../net/rcarz/jiraclient/agile/Status.java | 20 +++ .../rcarz/jiraclient/agile/TimeTracking.java | 55 +++++++ .../java/net/rcarz/jiraclient/agile/User.java | 42 ++++++ .../net/rcarz/jiraclient/agile/Worklog.java | 68 +++++++++ src/test/groovy/AgileClientDemoTest.groovy | 137 ++++++++++++++++++ .../agile/AbstractResourceTest.groovy | 111 ++++++++++---- .../jiraclient/agile/AgileClientTest.groovy | 12 +- .../jiraclient/agile/AgileResourceTest.groovy | 91 ++++++++++++ .../rcarz/jiraclient/agile/BoardTest.groovy | 12 +- .../rcarz/jiraclient/agile/EpicTest.groovy | 10 +- .../rcarz/jiraclient/agile/IssueTest.groovy | 6 +- .../jiraclient/agile/JSONResources.groovy | 96 ++++++++---- .../rcarz/jiraclient/agile/SprintTest.groovy | 6 +- 21 files changed, 745 insertions(+), 84 deletions(-) create mode 100644 src/test/groovy/AgileClientDemoTest.groovy create mode 100644 src/test/groovy/net/rcarz/jiraclient/agile/AgileResourceTest.groovy diff --git a/README.md b/README.md index dd9aca4..093f382 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,7 @@ public class Example { System.err.println(ex.getCause().getMessage()); } } +} ``` ## Agile API ## @@ -304,7 +305,7 @@ https://docs.atlassian.com/jira-software/REST/cloud/ ### Agile Example ### - +To see more examples, look at [AgileClientDemoTest](test/groovy/AgileClientDemoTest.groovy) ```java import java.util.List; diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java index 0aef07b..b137b9f 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileClient.java @@ -108,5 +108,9 @@ public class AgileClient { public Epic getEpic(long id) throws JiraException { return Epic.get(restclient, id); } + + public RestClient getRestclient() { + return restclient; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java index a0414fd..8700618 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java +++ b/src/main/java/net/rcarz/jiraclient/agile/AgileResource.java @@ -88,7 +88,7 @@ public abstract class AgileResource { Constructor constructor = type.getDeclaredConstructor(RestClient.class, JSONObject.class); result = constructor.newInstance(restclient, r); } catch (Exception e) { - throw new JiraException("Failed to deserialize object array."); + throw new JiraException("Failed to deserialize object.", e); } } @@ -114,7 +114,7 @@ public abstract class AgileResource { JSONObject jo = (JSONObject) ra; if (!jo.containsKey(listName) || !(jo.get(listName) instanceof JSONArray)) { - throw new JiraException(type.getSimpleName() + " result is malformed"); + throw new JiraException("No array found for name '" + listName + "'"); } List results = new ArrayList(); @@ -226,7 +226,7 @@ public abstract class AgileResource { T getSubResource( Class type, JSONObject subJson, String resourceName) throws JiraException { T result = null; - if (subJson.containsKey(resourceName)) { + if (subJson.containsKey(resourceName) && !subJson.get(resourceName).equals("null")) { result = getResource(type, subJson.get(resourceName), getRestclient()); } return result; @@ -274,7 +274,7 @@ public abstract class AgileResource { * @return The value of the attribute. */ public Object getAttribute(String name) { - return (String) attributes.get(name); + return attributes.get(name); } /** diff --git a/src/main/java/net/rcarz/jiraclient/agile/Comment.java b/src/main/java/net/rcarz/jiraclient/agile/Comment.java index 7557fdb..c42b757 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Comment.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Comment.java @@ -19,10 +19,13 @@ 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; + /** * Represents an Agile Comment. * @@ -30,6 +33,12 @@ import net.sf.json.JSONObject; */ public class Comment extends AgileResource { + private User author; + private String body; + private User updateAuthor; + private Date created; + private Date updated; + /** * Creates a new Agile resource. * @@ -39,4 +48,46 @@ public class Comment extends AgileResource { public Comment(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + + this.author = getSubResource(User.class, json, "author"); + this.body = Field.getString(json.get("body")); + this.updateAuthor = getSubResource(User.class, json, "updateAuthor"); + this.created = Field.getDateTime(json.get("created")); + this.updated = Field.getDateTime(json.get("updated")); + } + + @Override + public String toString() { + return String.format("%s{id=%s, body='%s'}", getClass().getSimpleName(), getId(), getBody()); + } + + public User getAuthor() { + return author; + } + + public String getBody() { + return body; + } + + public User getUpdateAuthor() { + return updateAuthor; + } + + public Date getCreated() { + return created; + } + + public Date getUpdated() { + return updated; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Epic.java b/src/main/java/net/rcarz/jiraclient/agile/Epic.java index f0f657c..6531572 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Epic.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Epic.java @@ -19,6 +19,7 @@ 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; @@ -33,6 +34,9 @@ import java.util.List; public class Epic extends AgileResource { private Issue issue; + private String key; + private String summary; + private boolean done; /** * Creates a new Agile resource. @@ -75,4 +79,31 @@ public class Epic extends AgileResource { public List getIssues() throws JiraException { return AgileResource.list(getRestclient(), Issue.class, RESOURCE_URI + "epic/" + getId() + "/issue", "issues"); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + + this.key = Field.getString(json.get("key")); + this.summary = Field.getString(json.get("summary")); + this.done = Field.getBoolean(json.get("done")); + } + + public String getKey() { + return key; + } + + public String getSummary() { + return summary; + } + + public boolean isDone() { + return done; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/IssueType.java b/src/main/java/net/rcarz/jiraclient/agile/IssueType.java index c677f08..47c97e8 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/IssueType.java +++ b/src/main/java/net/rcarz/jiraclient/agile/IssueType.java @@ -19,6 +19,7 @@ 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; @@ -30,6 +31,9 @@ import net.sf.json.JSONObject; */ public class IssueType extends AgileResource { + private String description; + private boolean subTask; + /** * Creates a new Agile resource. * @@ -39,4 +43,26 @@ public class IssueType extends AgileResource { public IssueType(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + + this.description = Field.getString(json.get("description")); + this.subTask = Field.getBoolean(json.get("subtask")); + } + + public String getDescription() { + return description; + } + + public boolean isSubTask() { + return subTask; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Project.java b/src/main/java/net/rcarz/jiraclient/agile/Project.java index a7f673a..499758b 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Project.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Project.java @@ -19,6 +19,7 @@ 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; @@ -30,6 +31,8 @@ import net.sf.json.JSONObject; */ public class Project extends AgileResource { + private String key; + /** * Creates a new Agile resource. * @@ -39,4 +42,21 @@ public class Project extends AgileResource { public Project(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + + this.key = Field.getString(json.get("key")); + } + + public String getKey() { + return key; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Resolution.java b/src/main/java/net/rcarz/jiraclient/agile/Resolution.java index b1c6c86..aa15aa7 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Resolution.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Resolution.java @@ -19,6 +19,7 @@ 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; @@ -30,6 +31,8 @@ import net.sf.json.JSONObject; */ public class Resolution extends AgileResource { + private String description; + /** * Creates a new Agile resource. * @@ -39,4 +42,21 @@ public class Resolution extends AgileResource { public Resolution(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + + this.description = Field.getString(json.get("description")); + } + + public String getDescription() { + return description; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Status.java b/src/main/java/net/rcarz/jiraclient/agile/Status.java index a8aec67..88d802d 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Status.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Status.java @@ -19,6 +19,7 @@ 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; @@ -30,6 +31,8 @@ import net.sf.json.JSONObject; */ public class Status extends AgileResource { + private String description; + /** * Creates a new Agile resource. * @@ -39,4 +42,21 @@ public class Status extends AgileResource { public Status(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + + this.description = Field.getString(json.get("description")); + } + + public String getDescription() { + return description; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java b/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java index 4a7acf4..98f19fd 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java +++ b/src/main/java/net/rcarz/jiraclient/agile/TimeTracking.java @@ -19,6 +19,7 @@ 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; @@ -30,6 +31,13 @@ import net.sf.json.JSONObject; */ public class TimeTracking extends AgileResource { + private String originalEstimate; + private String remainingEstimate; + private String timeSpent; + private long originalEstimateSeconds; + private long remainingEstimateSeconds; + private long timeSpentSeconds; + /** * Creates a new Agile resource. * @@ -39,4 +47,51 @@ public class TimeTracking extends AgileResource { public TimeTracking(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + this.originalEstimate = Field.getString(json.get("originalEstimate")); + this.remainingEstimate = Field.getString(json.get("remainingEstimate")); + this.timeSpent = Field.getString(json.get("timeSpent")); + this.originalEstimateSeconds = Field.getLong(json.get("originalEstimateSeconds")); + this.remainingEstimateSeconds = Field.getLong(json.get("remainingEstimateSeconds")); + this.timeSpentSeconds = Field.getLong(json.get("timeSpentSeconds")); + } + + @Override + public String toString() { + return String.format("%s{original='%s', remaining='%s', timeSpent='%s'}", + getClass().getSimpleName(), getOriginalEstimate(), getRemainingEstimate(), getTimeSpent()); + } + + public String getOriginalEstimate() { + return originalEstimate; + } + + public String getRemainingEstimate() { + return remainingEstimate; + } + + public String getTimeSpent() { + return timeSpent; + } + + public long getOriginalEstimateSeconds() { + return originalEstimateSeconds; + } + + public long getRemainingEstimateSeconds() { + return remainingEstimateSeconds; + } + + public long getTimeSpentSeconds() { + return timeSpentSeconds; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/User.java b/src/main/java/net/rcarz/jiraclient/agile/User.java index 0cebeea..e81a58f 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/User.java +++ b/src/main/java/net/rcarz/jiraclient/agile/User.java @@ -19,6 +19,7 @@ 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; @@ -30,6 +31,11 @@ import net.sf.json.JSONObject; */ public class User extends AgileResource { + private String emailAddress; + private String displayName; + private boolean active; + private String timeZone; + /** * Creates a new Agile resource. * @@ -39,4 +45,40 @@ public class User extends AgileResource { public User(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + this.emailAddress = Field.getString(json.get("emailAddress")); + this.displayName = Field.getString(json.get("displayName")); + this.active = Field.getBoolean(json.get("active")); + this.timeZone = Field.getString(json.get("timeZone")); + } + + @Override + public String toString() { + return String.format("%s{name='%s', Display Name='%s'}", getClass().getSimpleName(), getName(), getDisplayName()); + } + + public String getEmailAddress() { + return emailAddress; + } + + public String getDisplayName() { + return displayName; + } + + public boolean isActive() { + return active; + } + + public String getTimeZone() { + return timeZone; + } } diff --git a/src/main/java/net/rcarz/jiraclient/agile/Worklog.java b/src/main/java/net/rcarz/jiraclient/agile/Worklog.java index 6a8d7f5..c1a2389 100644 --- a/src/main/java/net/rcarz/jiraclient/agile/Worklog.java +++ b/src/main/java/net/rcarz/jiraclient/agile/Worklog.java @@ -19,10 +19,13 @@ 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; + /** * Represents an Agile Worklog. * @@ -30,6 +33,15 @@ import net.sf.json.JSONObject; */ public class Worklog extends AgileResource { + private User author; + private String comment; + private Date created; + private Date updated; + private User updateAuthor; + private Date started; + private String timeSpent; + private long timeSpentSeconds; + /** * Creates a new Agile resource. * @@ -39,4 +51,60 @@ public class Worklog extends AgileResource { public Worklog(RestClient restclient, JSONObject json) throws JiraException { super(restclient, json); } + + /** + * Deserialize the json to extract standard attributes and keep a reference of + * other attributes. + * + * @param json The JSON object to read. + */ + @Override + void deserialize(JSONObject json) throws JiraException { + super.deserialize(json); + this.author = getSubResource(User.class, json, "author"); + this.comment = Field.getString(json.get("comment")); + this.created = Field.getDateTime(json.get("created")); + this.updated = Field.getDateTime(json.get("updated")); + this.updateAuthor = getSubResource(User.class, json, "updateAuthor"); + this.started = Field.getDateTime(json.get("started")); + this.timeSpent = Field.getString(json.get("timeSpent")); + this.timeSpentSeconds = Field.getLong(json.get("timeSpentSeconds")); + } + + @Override + public String toString() { + return String.format("%s{id=%s, comment='%s'}", getClass().getSimpleName(), getId(), getComment()); + } + + public User getAuthor() { + return author; + } + + public String getComment() { + return comment; + } + + public Date getCreated() { + return created; + } + + public Date getUpdated() { + return updated; + } + + public User getUpdateAuthor() { + return updateAuthor; + } + + public Date getStarted() { + return started; + } + + public String getTimeSpent() { + return timeSpent; + } + + public long getTimeSpentSeconds() { + return timeSpentSeconds; + } } diff --git a/src/test/groovy/AgileClientDemoTest.groovy b/src/test/groovy/AgileClientDemoTest.groovy new file mode 100644 index 0000000..52c2d9d --- /dev/null +++ b/src/test/groovy/AgileClientDemoTest.groovy @@ -0,0 +1,137 @@ +import net.rcarz.jiraclient.BasicCredentials +import net.rcarz.jiraclient.JiraClient +import net.rcarz.jiraclient.agile.* +import org.junit.Ignore +import org.junit.Test + +/** + * Demo test, used to show how to use the AgileClient API. + * @author pldupont + */ +class AgileClientDemoTest { + + private static final long BOARD_ID = 507L; + private static final long SPRINT_ID = 1165L; + private static final long EPIC_ID = 62133L; + private static final long ISSUE_ID = 63080L; + private static final String ISSUE_KEY = "TEST-1551"; + + @Test + @Ignore("Demo to use the AgileClient") + public void demoUsingAgileClient() { + // Init Agile client + AgileClient agileClient = new AgileClient(new JiraClient("https://jira.example.com/jira", new BasicCredentials("batman", "pow! pow!"))) + + demoBoard(agileClient) + demoSprint(agileClient) + demoEpic(agileClient) + demoIssue(agileClient) + } + + static void demoSprint(AgileClient agileClient) { + println "********** Sprint demo" + // Retrieve all sprints + List sprints = Sprint.getAll(agileClient.getRestclient(), BOARD_ID) + println sprints + + // Retrieve a specific Sprint + Sprint sprint1 = agileClient.getSprint(SPRINT_ID) + println sprint1 + Sprint sprint2 = Sprint.get(agileClient.getRestclient(), SPRINT_ID) + println sprint2 + println sprint1.toString() == sprint2.toString() + println sprint1.getSelfURL() + + // Retrieve issues associated to the sprint + List issues = sprint1.getIssues() + println issues + } + + static void demoIssue(AgileClient agileClient) { + println "********** Issue demo" + // Retrieve a specific Issue + Issue issue1 = agileClient.getIssue(ISSUE_ID) + println issue1 + Issue issue2 = Issue.get(agileClient.getRestclient(), ISSUE_ID) + println issue2 + println issue1.toString() == issue2.toString() + Issue issue3 = agileClient.getIssue(ISSUE_KEY) + println issue3 + println issue1.toString() == issue3.toString() + println issue1.getSelfURL() + + // Retrieve the issue attribute + println issue1.getProject() + println issue1.getEpic() + println issue1.getSprint() + println issue1.getKey(); + println issue1.isFlagged(); + println issue1.getDescription(); + println issue1.getComments(); + println issue1.getWorklogs(); + println issue1.getTimeTracking(); + println issue1.getIssueType(); + println issue1.getStatus(); + println issue1.getResolution(); + println issue1.getCreated(); + println issue1.getUpdated(); + println issue1.getPriority(); + println issue1.getAssignee(); + println issue1.getCreator(); + println issue1.getReporter(); + println issue1.getEnvironment(); + } + + static void demoEpic(AgileClient agileClient) { + println "********** Epic demo" + // Retrieve a specific Epic + Epic epic1 = agileClient.getEpic(EPIC_ID) + println epic1 + Epic epic2 = Epic.get(agileClient.getRestclient(), EPIC_ID) + println epic2 + println epic1.toString() == epic2.toString() + println epic1.getSelfURL() + + // Retrieve the epic as a normal Issue + Issue issue = epic1.asIssue(true) + println issue + + // pldupont: Doesn't work with my version of JIRA, but the doc says otherwise. +// // Retrieve issues associated to the Epic +// List issues = epic1.getIssues() +// println issues + } + + static void demoBoard(AgileClient agileClient) { + println "********** Board demo" + // Retrieve all board + List boards = agileClient.getBoards() + println boards + + // Retrieve a specific Board + Board board1 = agileClient.getBoard(BOARD_ID) + println board1 + Board board2 = Board.get(agileClient.getRestclient(), BOARD_ID) + println board2 + println board1.toString() == board2.toString() + println board1.getSelfURL() + + // Retrieve sprints associated to the board + List sprints = board1.getSprints() + println sprints + + // Retrieve sprints associated to the board + List epics = board1.getEpics() + println epics + + // Retrieve sprints associated to the board + List backlog = board1.getBacklog() + println backlog + + // pldupont: Doesn't work with my version of JIRA, but the doc says otherwise. +// // Retrieve sprints associated to the board +// List issuesWithoutEpics = board1.getIssuesWithoutEpic() +// println sprints + + } +} diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy index 3691f99..d60ec19 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AbstractResourceTest.groovy @@ -37,7 +37,7 @@ class AbstractResourceTest { return new Issue(mockRestClient, JSONSerializer.toJSON(JSONResources.ISSUE) as JSONObject) } - static void "Assert equals to Board 84"(Board board) { + static void "Assert equals to Board"(Board board) { assertThat board, new IsNot<>(new IsNull()) assertThat board.getId(), new IsEqual(JSONResources.BOARD_ID) assertThat board.getName(), new IsEqual(JSONResources.BOARD_NAME) @@ -49,7 +49,7 @@ class AbstractResourceTest { } - static void "Assert equals to Sprint 37"(Sprint sprint) { + static void "Assert equals to Sprint"(Sprint sprint) { assertThat sprint, new IsNot<>(new IsNull()) assertThat sprint.getId(), new IsEqual(JSONResources.SPRINT_ID) assertThat sprint.getName(), new IsEqual(JSONResources.SPRINT_NAME) @@ -64,28 +64,43 @@ class AbstractResourceTest { JSONResources.SPRINT_ID, JSONResources.SPRINT_NAME)) } - static void "Assert equals to Epic 23"(Epic epic) { + static void "Assert equals to Epic"(Epic epic) { assertThat epic, new IsNot<>(new IsNull()) assertThat epic.getId(), new IsEqual(JSONResources.EPIC_ID) assertThat epic.getName(), new IsEqual(JSONResources.EPIC_NAME) assertThat epic.getSelfURL(), new IsEqual(JSONResources.EPIC_SELF) - + assertThat epic.getKey(), new IsEqual(JSONResources.EPIC_KEY) + assertThat epic.getSummary(), new IsEqual(JSONResources.EPIC_SUMMARY) + assertThat epic.isDone(), new IsEqual(JSONResources.EPIC_DONE) + assertThat epic.toString(), new IsEqual( + String.format("Epic{id=%s, name='%s'}", + JSONResources.EPIC_ID, JSONResources.EPIC_NAME)) } - static void "Assert equals to Project 10000"(Project project) { + static void "Assert equals to Project"(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) - + assertThat project.getKey(), new IsEqual(JSONResources.PROJECT_KEY) + assertThat project.toString(), new IsEqual( + String.format("Project{id=%s, name='%s'}", + JSONResources.PROJECT_ID, JSONResources.PROJECT_NAME)) } - static void "Assert equals to Comment 9999"(Comment comment) { + static void "Assert equals to Comment"(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) - + assertThat comment.getBody(), new IsEqual(JSONResources.ISSUE_COMMENT_BODY) + assertThat comment.getCreated(), new IsEqual(JSONResources.ISSUE_COMMENT_CREATED) + assertThat comment.getUpdated(), new IsEqual(JSONResources.ISSUE_COMMENT_UPDATED) + "Assert equals to User"(comment.getAuthor()) + "Assert equals to User"(comment.getUpdateAuthor()) + assertThat comment.toString(), new IsEqual( + String.format("Comment{id=%s, body='%s'}", + JSONResources.ISSUE_COMMENT_ID, JSONResources.ISSUE_COMMENT_BODY)) } static void "Assert equals to TimeTracking"(TimeTracking timeTracking) { @@ -93,7 +108,17 @@ class AbstractResourceTest { assertThat timeTracking.getId(), new IsEqual(0L) assertThat timeTracking.getName(), new IsNull() assertThat timeTracking.getSelfURL(), new IsNull() - + assertThat timeTracking.getOriginalEstimate(), new IsEqual(JSONResources.ISSUE_TIMETRACKING_ORIGINAL_ESTIMATE) + assertThat timeTracking.getRemainingEstimate(), new IsEqual(JSONResources.ISSUE_TIMETRACKING_REMAINING_ESTIMATE) + assertThat timeTracking.getTimeSpent(), new IsEqual(JSONResources.ISSUE_TIMETRACKING_TIME_SPENT) + assertThat timeTracking.getOriginalEstimateSeconds(), new IsEqual(JSONResources.ISSUE_TIMETRACKING_ORIGINAL_ESTIMATE_SECONDS) + assertThat timeTracking.getRemainingEstimateSeconds(), new IsEqual(JSONResources.ISSUE_TIMETRACKING_REMAINING_ESTIMATE_SECONDS) + assertThat timeTracking.getTimeSpentSeconds(), new IsEqual(JSONResources.ISSUE_TIMETRACKING_TIME_SPENT_SECONDS) + assertThat timeTracking.toString(), new IsEqual( + String.format("TimeTracking{original='%s', remaining='%s', timeSpent='%s'}", + JSONResources.ISSUE_TIMETRACKING_ORIGINAL_ESTIMATE, + JSONResources.ISSUE_TIMETRACKING_REMAINING_ESTIMATE, + JSONResources.ISSUE_TIMETRACKING_TIME_SPENT)) } static void "Assert equals to IssueType"(IssueType issueType) { @@ -101,6 +126,11 @@ class AbstractResourceTest { 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) + assertThat issueType.getDescription(), new IsEqual(JSONResources.ISSUE_TYPE_DESCRIPTION) + assertThat issueType.isSubTask(), new IsEqual(JSONResources.ISSUE_TYPE_SUB_TASK) + assertThat issueType.toString(), new IsEqual( + String.format("IssueType{id=%s, name='%s'}", + JSONResources.ISSUE_TYPE_ID, JSONResources.ISSUE_TYPE_NAME)) } static void "Assert equals to Status"(Status status) { @@ -108,6 +138,10 @@ class AbstractResourceTest { 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) + assertThat status.getDescription(), new IsEqual(JSONResources.ISSUE_STATUS_DESCRIPTION) + assertThat status.toString(), new IsEqual( + String.format("Status{id=%s, name='%s'}", + JSONResources.ISSUE_STATUS_ID, JSONResources.ISSUE_STATUS_NAME)) } static void "Assert equals to Resolution"(Resolution resolution) { @@ -115,6 +149,10 @@ class AbstractResourceTest { 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) + assertThat resolution.getDescription(), new IsEqual(JSONResources.ISSUE_RESOLUTION_DESCRIPTION) + assertThat resolution.toString(), new IsEqual( + String.format("Resolution{id=%s, name='%s'}", + JSONResources.ISSUE_RESOLUTION_ID, JSONResources.ISSUE_RESOLUTION_NAME)) } static void "Assert equals to Priority"(Priority priority) { @@ -122,6 +160,9 @@ class AbstractResourceTest { 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) + assertThat priority.toString(), new IsEqual( + String.format("Priority{id=%s, name='%s'}", + JSONResources.ISSUE_PRIORITY_ID, JSONResources.ISSUE_PRIORITY_NAME)) } static void "Assert equals to User"(User user) { @@ -129,35 +170,54 @@ class AbstractResourceTest { assertThat user.getId(), new IsEqual(0L) assertThat user.getName(), new IsEqual(JSONResources.USER_NAME) assertThat user.getSelfURL(), new IsEqual(JSONResources.USER_SELF) + assertThat user.getEmailAddress(), new IsEqual(JSONResources.USER_EMAIL_ADDRESS) + assertThat user.getDisplayName(), new IsEqual(JSONResources.USER_DISPLAY_NAME) + assertThat user.isActive(), new IsEqual(JSONResources.USER_ACTIVE) + assertThat user.getTimeZone(), new IsEqual(JSONResources.USER_TIME_ZONE) + assertThat user.toString(), new IsEqual( + String.format("User{name='%s', Display Name='%s'}", + JSONResources.USER_NAME, JSONResources.USER_DISPLAY_NAME)) } - static void "Assert equals to Worklog 100028"(Worklog worklog) { + static void "Assert equals to Worklog"(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) + assertThat worklog.getComment(), new IsEqual(JSONResources.ISSUE_WORKLOG_COMMENT) + assertThat worklog.getCreated(), new IsEqual(JSONResources.ISSUE_WORKLOG_CREATED) + assertThat worklog.getUpdated(), new IsEqual(JSONResources.ISSUE_WORKLOG_UPDATED) + assertThat worklog.getStarted(), new IsEqual(JSONResources.ISSUE_WORKLOG_STARTED) + assertThat worklog.getTimeSpent(), new IsEqual(JSONResources.ISSUE_WORKLOG_TIMESPEND) + assertThat worklog.getTimeSpentSeconds(), new IsEqual(JSONResources.ISSUE_WORKLOG_TIMESPEND_SECONDS) + "Assert equals to User"(worklog.getAuthor()) + "Assert equals to User"(worklog.getUpdateAuthor()) + assertThat worklog.toString(), new IsEqual( + String.format("Worklog{id=%s, comment='%s'}", + JSONResources.ISSUE_WORKLOG_ID, JSONResources.ISSUE_WORKLOG_COMMENT)) } - static void "Assert equals to Issue 10001"(Issue issue) { + static void "Assert equals to Issue"(Issue issue) { assertThat issue, new IsNot<>(new IsNull()) + assertThat issue.getAttribute("fields"), new IsNot<>(new IsNull()) assertThat issue.getId(), new IsEqual(JSONResources.ISSUE_ID) - assertThat issue.getName(), new IsNull() + assertThat issue.getName(), new IsEqual(JSONResources.ISSUE_SUMMARY) 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()) + "Assert equals to Sprint"(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()) + "Assert equals to Project"(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 Comment"(issue.getComments().get(0)) + "Assert equals to Epic"(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)) + "Assert equals to Worklog"(issue.getWorklogs().get(0)) assertThat issue.getEnvironment(), new IsEqual(JSONResources.ISSUE_ENVIRONMENT) "Assert equals to IssueType"(issue.getIssueType()) "Assert equals to Status"(issue.getStatus()) @@ -168,20 +228,19 @@ class AbstractResourceTest { "Assert equals to User"(issue.getCreator()) "Assert equals to User"(issue.getReporter()) "Assert equals to Priority"(issue.getPriority()) - - + assertThat issue.toString(), new IsEqual( + String.format("Issue{id=%s, name='%s'}", + JSONResources.ISSUE_ID, JSONResources.ISSUE_SUMMARY)) } - static void "Assert equals to Issue 10010"(Issue issue) { + static void "Assert equals to Issue Blank"(Issue issue) { assertThat issue, new IsNot<>(new IsNull()) + assertThat issue.getAttribute("fields"), 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) - - } - - static void "Assert equals to Issue HSP-1"(Issue issue) { - "Assert equals to Issue 10001"(issue) - + assertThat issue.toString(), new IsEqual( + String.format("Issue{id=%s, name='%s'}", + JSONResources.BLANK_ISSUE1_ID, null)) } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy index 19ecf71..c64db74 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AgileClientTest.groovy @@ -25,7 +25,7 @@ class AgileClientTest extends AbstractResourceTest { assertThat boards, new IsNot<>(new IsNull()) assertThat boards.size(), new IsEqual(2) - "Assert equals to Board ${JSONResources.BOARD_ID}"(boards.get(0)) + "Assert equals to Board"(boards.get(0)) } @Test @@ -37,7 +37,7 @@ class AgileClientTest extends AbstractResourceTest { Board board = agileClient.getBoard(JSONResources.BOARD_ID); assertThat board, new IsNot<>(new IsNull()) - "Assert equals to Board ${JSONResources.BOARD_ID}"(board) + "Assert equals to Board"(board) } @Test @@ -49,7 +49,7 @@ class AgileClientTest extends AbstractResourceTest { Sprint sprint = agileClient.getSprint(JSONResources.SPRINT_ID); assertThat sprint, new IsNot<>(new IsNull()) - "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprint) + "Assert equals to Sprint"(sprint) } @Test @@ -60,7 +60,7 @@ class AgileClientTest extends AbstractResourceTest { Issue issue = agileClient.getIssue(JSONResources.ISSUE_ID); - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + "Assert equals to Issue"(issue) } @Test @@ -71,7 +71,7 @@ class AgileClientTest extends AbstractResourceTest { Issue issue = agileClient.getIssue(JSONResources.ISSUE_KEY); - "Assert equals to Issue ${JSONResources.ISSUE_KEY}"(issue) + "Assert equals to Issue"(issue) } @Test @@ -82,6 +82,6 @@ class AgileClientTest extends AbstractResourceTest { Epic epic = agileClient.getEpic(JSONResources.EPIC_ID); - "Assert equals to Epic ${JSONResources.EPIC_ID}"(epic) + "Assert equals to Epic"(epic) } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/AgileResourceTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/AgileResourceTest.groovy new file mode 100644 index 0000000..88eeb2b --- /dev/null +++ b/src/test/groovy/net/rcarz/jiraclient/agile/AgileResourceTest.groovy @@ -0,0 +1,91 @@ +package net.rcarz.jiraclient.agile + +import net.rcarz.jiraclient.JiraException +import net.sf.json.JSONSerializer +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 + +/** + * Test for edge cases on deserialization. + * @author pldupont + */ +class AgileResourceTest extends AbstractResourceTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + void "given a valid single resource JSON and a valid type, when calling getResource(), then should return an object"() { + def aRESTClient = "given a REST Client"() + def aValidResource = JSONSerializer.toJSON(JSONResources.BOARD) + + def resource = AgileResource.getResource(Board.class, aValidResource, aRESTClient) + + assertThat resource, new IsNot<>(new IsNull()) + } + + @Test + void "given an invalid single resource JSON and a valid type, when calling getResource(), then should throw an exception"() { + def aRESTClient = "given a REST Client"() + def anInvalidResource = JSONResources.BOARD + expectedException.expectMessage("JSON payload is malformed") + expectedException.expect(JiraException.class) + + AgileResource.getResource(Board.class, anInvalidResource, aRESTClient) + } + + @Test + void "given a valid single resource JSON and an invalid type, when calling getResource(), then should throw an exception"() { + def aRESTClient = "given a REST Client"() + def aValidResource = JSONSerializer.toJSON(JSONResources.BOARD) + expectedException.expectMessage("Failed to deserialize object.") + expectedException.expect(JiraException.class) + + AgileResource.getResource(String.class, aValidResource, aRESTClient) + } + + @Test + void "given a valid resource array JSON and a valid type, when calling getResource(), then should return an object"() { + def aRESTClient = "given a REST Client"() + def aValidResource = JSONSerializer.toJSON(JSONResources.LIST_OF_BOARDS) + + def resource = AgileResource.getResourceArray(Board.class, aValidResource, aRESTClient, "values") + + assertThat resource, new IsNot<>(new IsNull()) + } + + @Test + void "given a valid resource array JSON and a valid type but list name invalid, when calling getResource(), then should return an object"() { + def aRESTClient = "given a REST Client"() + def aValidResource = JSONSerializer.toJSON(JSONResources.LIST_OF_BOARDS) + expectedException.expectMessage("No array found for name 'v'") + expectedException.expect(JiraException.class) + + AgileResource.getResourceArray(Board.class, aValidResource, aRESTClient, "v") + } + + @Test + void "given an invalid resource array JSON and a valid type, when calling getResource(), then should throw an exception"() { + def aRESTClient = "given a REST Client"() + def anInvalidResource = JSONResources.LIST_OF_BOARDS + expectedException.expectMessage("JSON payload is malformed") + expectedException.expect(JiraException.class) + + AgileResource.getResourceArray(Board.class, anInvalidResource, aRESTClient, "values") + } + + @Test + void "given a valid resource array JSON and an invalid type, when calling getResource(), then should throw an exception"() { + def aRESTClient = "given a REST Client"() + def aValidResource = JSONSerializer.toJSON(JSONResources.LIST_OF_BOARDS) + expectedException.expectMessage("Failed to deserialize object.") + expectedException.expect(JiraException.class) + + AgileResource.getResourceArray(String.class, aValidResource, aRESTClient, "values") + } +} diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy index edadc19..eaba815 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/BoardTest.groovy @@ -34,7 +34,7 @@ class BoardTest extends AbstractResourceTest { assertThat boards, new IsNot<>(new IsNull()) assertThat boards.size(), new IsEqual(2) - "Assert equals to Board 84"(boards.get(0)) + "Assert equals to Board"(boards.get(0)) } @Test @@ -57,7 +57,7 @@ class BoardTest extends AbstractResourceTest { Board board = Board.get(mockRestClient, JSONResources.BOARD_ID); - "Assert equals to Board 84"(board) + "Assert equals to Board"(board) } @Test @@ -83,7 +83,7 @@ class BoardTest extends AbstractResourceTest { assertThat sprints, new IsNot<>(new IsNull()) assertThat sprints.size(), new IsEqual(2) - "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprints.get(0)) + "Assert equals to Sprint"(sprints.get(0)) } @Test @@ -97,7 +97,7 @@ class BoardTest extends AbstractResourceTest { assertThat epics, new IsNot<>(new IsNull()) assertThat epics.size(), new IsEqual(2) - "Assert equals to Epic ${JSONResources.EPIC_ID}"(epics.get(0)) + "Assert equals to Epic"(epics.get(0)) } @Test @@ -111,7 +111,7 @@ class BoardTest extends AbstractResourceTest { assertThat backlog, new IsNot<>(new IsNull()) assertThat backlog.size(), new IsEqual(4) - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(backlog.get(0)) + "Assert equals to Issue"(backlog.get(0)) } @Test @@ -125,6 +125,6 @@ class BoardTest extends AbstractResourceTest { assertThat issues, new IsNot<>(new IsNull()) assertThat issues.size(), new IsEqual(4) - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issues.get(0)) + "Assert equals to Issue"(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 ae01803..9034615 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/EpicTest.groovy @@ -32,7 +32,7 @@ class EpicTest extends AbstractResourceTest { Epic epic = Epic.get(mockRestClient, JSONResources.EPIC_ID); - "Assert equals to Epic ${JSONResources.EPIC_ID}"(epic) + "Assert equals to Epic"(epic) } @Test @@ -57,7 +57,7 @@ class EpicTest extends AbstractResourceTest { assertThat mockEpic.issue, new IsNull() Issue issue = mockEpic.asIssue(false) - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + "Assert equals to Issue"(issue) assertThat mockEpic.issue, new IsNot<>(new IsNull()) } @@ -71,7 +71,7 @@ class EpicTest extends AbstractResourceTest { assertThat mockEpic.issue, new IsNot<>(new IsNull()) Issue issue = mockEpic.asIssue(false) - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + "Assert equals to Issue"(issue) assertThat mockEpic.issue, new IsNot<>(new IsNull()) assert mockEpic.issue == mockIssue } @@ -88,7 +88,7 @@ class EpicTest extends AbstractResourceTest { assertThat mockEpic.issue, new IsNot<>(new IsNull()) Issue issue = mockEpic.asIssue(true) - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + "Assert equals to Issue"(issue) assertThat mockEpic.issue, new IsNot<>(new IsNull()) assert mockEpic.issue != mockIssue } @@ -104,6 +104,6 @@ class EpicTest extends AbstractResourceTest { assertThat issues, new IsNot<>(new IsNull()) assertThat issues.size(), new IsEqual(4) - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issues.get(0)) + "Assert equals to Issue"(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 16e3bd9..65f232f 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/IssueTest.groovy @@ -27,7 +27,7 @@ class IssueTest extends AbstractResourceTest { Issue issue = Issue.get(mockRestClient, JSONResources.ISSUE_ID); - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issue) + "Assert equals to Issue"(issue) } @Test @@ -50,7 +50,7 @@ class IssueTest extends AbstractResourceTest { Issue issue = Issue.get(mockRestClient, JSONResources.ISSUE_KEY); - "Assert equals to Issue ${JSONResources.ISSUE_KEY}"(issue) + "Assert equals to Issue"(issue) } @Test @@ -73,6 +73,6 @@ class IssueTest extends AbstractResourceTest { Issue issue = Issue.get(mockRestClient, JSONResources.BLANK_ISSUE1_ID); - "Assert equals to Issue ${JSONResources.BLANK_ISSUE1_ID}"(issue) + "Assert equals to Issue Blank"(issue) } } diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy index 9fa59e6..173a6db 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/JSONResources.groovy @@ -40,17 +40,20 @@ interface JSONResources { String SPRINT_SELF = "http://www.example.com/jira/rest/agile/1.0/sprint/${SPRINT_ID}" String SPRINT_STATE = "closed" long SPRINT_ORIGIN_BOARD_ID = BOARD_ID - Date SPRINT_START_DATE = Field.getDateTime("2015-04-11T15:22:00.000+10:00") - Date SPRINT_END_DATE = Field.getDateTime("2015-04-20T01:22:00.000+10:00") - Date SPRINT_COMPLETE_DATE = Field.getDateTime("2015-04-20T11:04:00.000+10:00") + String SPRINT_START_DATE_STR = "2015-04-11T15:22:00.000+10:00" + Date SPRINT_START_DATE = Field.getDateTime(SPRINT_START_DATE_STR) + String SPRINT_END_DATE_STR = "2015-04-20T01:22:00.000+10:00" + Date SPRINT_END_DATE = Field.getDateTime(SPRINT_END_DATE_STR) + String SPRINT_COMPLETE_DATE_STR = "2015-04-20T11:04:00.000+10:00" + Date SPRINT_COMPLETE_DATE = Field.getDateTime(SPRINT_COMPLETE_DATE_STR) String SPRINT = """{ "id": ${SPRINT_ID}, "self": "${SPRINT_SELF}", "state": "${SPRINT_STATE}", "name": "${SPRINT_NAME}", - "startDate": "${SPRINT_START_DATE}", - "endDate": "${SPRINT_END_DATE}", - "completeDate": "${SPRINT_COMPLETE_DATE}", + "startDate": "${SPRINT_START_DATE_STR}", + "endDate": "${SPRINT_END_DATE_STR}", + "completeDate": "${SPRINT_COMPLETE_DATE_STR}", "originBoardId": ${BOARD_ID} }""" @@ -73,12 +76,14 @@ interface JSONResources { long EPIC_ID = 23 String EPIC_SELF = "http://www.example.com/jira/rest/agile/1.0/epic/${EPIC_ID}" String EPIC_NAME = "epic 1" + String EPIC_KEY = "EX" String EPIC_SUMMARY = "epic 1 summary" boolean EPIC_DONE = true String EPIC = """{ "id": ${EPIC_ID}, "self": "${EPIC_SELF}", "name": "${EPIC_NAME}", + "key": "${EPIC_KEY}", "summary": "${EPIC_SUMMARY}", "color": { "key": "color_4" @@ -130,60 +135,86 @@ interface JSONResources { String USER_NAME = "Example" String USER_SELF = "https://www.example.com/rest/api/2/user?username=${USER_NAME}" + String USER_EMAIL_ADDRESS = "pldupont@example.com" + String USER_DISPLAY_NAME = "Pierre-Luc Dupont" + boolean USER_ACTIVE = true + String USER_TIME_ZONE = "America/New_York" + String USER = """{ "self" : "${USER_SELF}", "name" : "${USER_NAME}", "key" : "pldupont", - "emailAddress" : "pldupont@example.com", + "emailAddress" : "${USER_EMAIL_ADDRESS}", "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" + "displayName" : "${USER_DISPLAY_NAME}", + "active" : ${USER_ACTIVE}, + "timeZone" : "${USER_TIME_ZONE}" }""" + String ISSUE_TIMETRACKING_ORIGINAL_ESTIMATE = "10m" + String ISSUE_TIMETRACKING_REMAINING_ESTIMATE = "3m" + String ISSUE_TIMETRACKING_TIME_SPENT = "6m" + long ISSUE_TIMETRACKING_ORIGINAL_ESTIMATE_SECONDS = 600L + long ISSUE_TIMETRACKING_REMAINING_ESTIMATE_SECONDS = 200L + long ISSUE_TIMETRACKING_TIME_SPENT_SECONDS = 400L String ISSUE_TIMETRACKING = """{ - "originalEstimate": "10m", - "remainingEstimate": "3m", - "timeSpent": "6m", - "originalEstimateSeconds": 600, - "remainingEstimateSeconds": 200, - "timeSpentSeconds": 400 + "originalEstimate": "${ISSUE_TIMETRACKING_ORIGINAL_ESTIMATE}", + "remainingEstimate": "${ISSUE_TIMETRACKING_REMAINING_ESTIMATE}", + "timeSpent": "${ISSUE_TIMETRACKING_TIME_SPENT}", + "originalEstimateSeconds": ${ISSUE_TIMETRACKING_ORIGINAL_ESTIMATE_SECONDS}, + "remainingEstimateSeconds": ${ISSUE_TIMETRACKING_REMAINING_ESTIMATE_SECONDS}, + "timeSpentSeconds": ${ISSUE_TIMETRACKING_TIME_SPENT_SECONDS} }""" 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_COMMENT = "I did some work here." + String ISSUE_WORKLOG_CREATED_STR = "2016-03-21T15:25:17.882+0100" + Date ISSUE_WORKLOG_CREATED = Field.getDateTime(ISSUE_WORKLOG_CREATED_STR) + String ISSUE_WORKLOG_UPDATED_STR = "2016-03-21T15:26:17.882+0100" + Date ISSUE_WORKLOG_UPDATED = Field.getDateTime(ISSUE_WORKLOG_UPDATED_STR) + String ISSUE_WORKLOG_STARTED_STR = "2016-03-21T15:26:17.881+0100" + Date ISSUE_WORKLOG_STARTED = Field.getDateTime(ISSUE_WORKLOG_STARTED_STR) + String ISSUE_WORKLOG_TIMESPEND = "3h 20m" + long ISSUE_WORKLOG_TIMESPEND_SECONDS = 12000 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", + "comment": "${ISSUE_WORKLOG_COMMENT}", + "created": "${ISSUE_WORKLOG_CREATED_STR}", + "updated": "${ISSUE_WORKLOG_UPDATED_STR}", "visibility": { "type": "group", "value": "jira-developers" }, - "started": "2016-03-21T15:26:17.881+0100", - "timeSpent": "3h 20m", - "timeSpentSeconds": 12000, + "started": "${ISSUE_WORKLOG_STARTED_STR}", + "timeSpent": "${ISSUE_WORKLOG_TIMESPEND}", + "timeSpentSeconds": ${ISSUE_WORKLOG_TIMESPEND_SECONDS}, "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_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." + String ISSUE_COMMENT_CREATED_STR = "2016-05-11T10:58:01.000-0400" + Date ISSUE_COMMENT_CREATED = Field.getDateTime(ISSUE_COMMENT_CREATED_STR) + String ISSUE_COMMENT_UPDATED_STR = "2016-05-30T14:20:29.000-0400" + Date ISSUE_COMMENT_UPDATED = Field.getDateTime(ISSUE_COMMENT_UPDATED_STR) String ISSUE_COMMENT = """{ "self": "${ISSUE_COMMENT_SELF}", - "id": "9999", + "id": "${ISSUE_COMMENT_ID}", "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.", + "body": "${ISSUE_COMMENT_BODY}", "updateAuthor": ${USER}, - "created": "2016-03-21T15:26:17.875+0100", - "updated": "2016-03-21T15:26:17.878+0100", + "created": "${ISSUE_COMMENT_CREATED_STR}", + "updated": "${ISSUE_COMMENT_UPDATED_STR}", "visibility": { "type": "role", "value": "Administrators" @@ -192,30 +223,34 @@ interface JSONResources { 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_DESCRIPTION = "A problem which impairs or prevents the functions of the product." + boolean ISSUE_TYPE_SUB_TASK = true String ISSUE_TYPE = """{ "self" : "${ISSUE_TYPE_SELF}", "id" : "${ISSUE_TYPE_ID}", - "description" : "A problem which impairs or prevents the functions of the product.", + "description" : "${ISSUE_TYPE_DESCRIPTION}", "iconUrl" : "https://www.example.com/images/icons/issuetypes/bug.png", "name" : "${ISSUE_TYPE_NAME}", - "subtask" : false + "subtask" : ${ISSUE_TYPE_SUB_TASK} }""" 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_DESCRIPTION = "The problem is not a problem" String ISSUE_RESOLUTION = """{ "self" : "${ISSUE_RESOLUTION_SELF}", "id" : "${ISSUE_RESOLUTION_ID}", - "description" : "The problem is not a problem", + "description" : "${ISSUE_RESOLUTION_DESCRIPTION}", "name" : "${ISSUE_RESOLUTION_NAME}" }""" long ISSUE_STATUS_ID = 6L String ISSUE_STATUS_NAME = "Closed" + String ISSUE_STATUS_DESCRIPTION = "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened." 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.", + "description" : "${ISSUE_STATUS_DESCRIPTION}", "iconUrl" : "https://www.example.com/images/icons/statuses/closed.png", "name" : "${ISSUE_STATUS_NAME}", "id" : "${ISSUE_STATUS_ID}", @@ -239,6 +274,7 @@ interface JSONResources { 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_SUMMARY = "Issue summary" boolean ISSUE_FLAGGED = true String ISSUE_DESCRIPTION = "example bug report" String ISSUE_ENVIRONMENT = "PROD" @@ -254,6 +290,7 @@ interface JSONResources { "fields": { "flagged": ${ISSUE_FLAGGED}, "sprint": ${SPRINT}, + "summary": "${ISSUE_SUMMARY}", "closedSprint": { "closedSprints": [ { @@ -298,7 +335,6 @@ interface JSONResources { ${ISSUE_WORKLOG} ] }, - "updated": 1, "timetracking": ${ISSUE_TIMETRACKING}, "environment": "${ISSUE_ENVIRONMENT}", "issuetype" : ${ISSUE_TYPE}, diff --git a/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy index 494f301..330ee22 100644 --- a/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy +++ b/src/test/groovy/net/rcarz/jiraclient/agile/SprintTest.groovy @@ -34,7 +34,7 @@ class SprintTest extends AbstractResourceTest { assertThat sprints, new IsNot<>(new IsNull()) assertThat sprints.size(), new IsEqual(2) - "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprints.get(0)) + "Assert equals to Sprint"(sprints.get(0)) } @Test @@ -57,7 +57,7 @@ class SprintTest extends AbstractResourceTest { Sprint sprint = Sprint.get(mockRestClient, JSONResources.SPRINT_ID); - "Assert equals to Sprint ${JSONResources.SPRINT_ID}"(sprint) + "Assert equals to Sprint"(sprint) } @Test @@ -83,6 +83,6 @@ class SprintTest extends AbstractResourceTest { assertThat issues, new IsNot<>(new IsNull()) assertThat issues.size(), new IsEqual(4) - "Assert equals to Issue ${JSONResources.ISSUE_ID}"(issues.get(0)) + "Assert equals to Issue"(issues.get(0)) } }