After looking into EWM Discovery, how can one create or update a work item using the techniques explained so far? This post will look into the steps that are required to create and update a work item. The techniques explained in the previous posts in this series are important. If necessary, go back to the previous posts to understand the details.
This blog was originally separated into two sections, creating a work item and then updating the work item. The first part mentioned programming and Python, the second used RESTClient to demonstrate the concepts. This was just due to the code I have written so far and due to complexity of the operations. The blog post was recently updated with Python code snippets for work item update and additional content.
Update: The blog post has also been rearranged and updated to separate getting a work item and updating a work item.
Update: The blog post has been rearranged and updated to show the usage of the oslc.properties query parameter for partial get and update.
Update: The blog post has been rearranged and updated to show how to resolve a work item and setting the resolution.
Update: The blog post has been updated with how to get the complete workflow information needed to navigate the workflow states and actions.
Context of the blog post is the series
This is the series of planned posts I intent to publish over time. Most of the examples will be EWM based, but quite a lot of the content applies to more ELM applications. The examples where performed with versions 126.96.36.199 and 7.0.x.
- Using the EWM REST and OSLC APIs
- ELM Authentication
- EWM Discovery
- EWM Work Item OSLC CM API – this post
- EWM OSLC Query API
- EWM REST API to access existing Work Item Queries
- EWM Reportable REST API
I used at least the following links for exploring this mechanism.
- Resource Oriented Work Item API with OSLC_CM 1.0 especially the Updating Work Items section in the Resource Oriented Work Item API with OSLC_CM 1.0
Discover the Creation Factory
To create a work item using the OSLC API requires some information that is provided by the OSLC API and can be discovered. To create a work item first requires a URI/URL of a creation factory providing the capability to create the work item.
EWM supports customizable work item types with customizable attributes of customizable attribute types. Each work item type has its own creation factory URL that needs to be looked up to create a work item of that type.
Work item types have potentially different sets of attributes configured. Each attribute has a type from a number of available attribute types. EWM allows to create custom attribute types. Some of the attribute types are primitive and are easy to handle. As an example the summary of a work item is just a string and it is easy to provide data. Other attribute types are far more complex. Many attributes are enumeration types. Enumerations are a number of available literals with an ID and a display name for each literal. A work item usually has an owner or subscribers. These represent users that are available in the system referenced by a unique URI. Work items can be assigned to a project or team area, which are other attribute types available in a project areas process. Which process area a work item is assigned to is controlled by a Category that maps a user readable string to the process area represented by its URI.
Note, some data that shows up in the work item is not attribute based. As example the collection of reviews and approvals, the attachments and the comments are not attribute type based. Some attributes that show up are only presentations or are calculated and can not be changed. Some of the not attribute based data is provided as pseudo attribute e.g. to be able to export the data.
To create a work item it is necessary to find out which attributes of which types a work item can have and which values the attribute of such a type can have. Attribute types can be single value such as enumerations or strings or they can have multiple values such as enumeration lists or string lists. All this information is required when creating a work item.
The information which work item attributes with what types a work item type can have, can be discovered in OSLC APIs as part of discovering the creation factory. The information is accessible via a resource shape. How the discovery process works in general is described in EWM Discovery.
Reminder, for all requests use the mandatory OSLC header:
To receive RDF encoded data use the Accept header and for sending RDF use the content Type header as shown below:
Accept application/rdf+xml; charset=utf-8 Content Type application/rdf+xml; charset=utf-8
The image below shows the RDF form of a part of the service provider catalog for a project area. Using the namespace
the oslc:CreationFactory entry contains the resourceType(s) and the resourceShape. The first resourceType http://open-services.net/ns/cm#ChangeRequest is used for OSLC integrations. The second resourceType provides the link to the work item type definition. The entry oslc:creation contains the creation factory URI.
To receive JSON encoded data use the Accept header and for sending JSON use the content Type header as shown below.
Accept application/json; charset=utf-8 Content Type application/json; charset=utf-8
The image below shows the JSON format of the creation factory entry for the work item type defect. The data is provided analogue to the RDF format and can also be used to access the data for the creation factories.
Discover Resource Type and Shape
Following the resourceType URI provides the details of the work item type. The image below shows the details for the defect. Getting the resourceType
with the headers introduced above provides more details. The display name is Defect and the work item type ID is defect. The data also contains the URI for the EWM project area that defines the work item type. The image below shows the result of such a GET request.
The Python code block below processes the RDF data and extracts the important data. The important take away are the predicates to select the information to be iterated.
The code operates on some simplifications. The code gets the work item type ID by filtering out the entry that starts with the public URI root. The code assumes that the end segment is equal to the work item type ID. This just saves the call to the resourceType URI which would contain the information. The code gets the creation factory URI and the resource shape URI.
To be able to create a work item, GET the resource shape using its URI and the headers described above. As an example:
The resource shape contains a number of attribute type definitions for the attributes (and link types) the work item type can have. The information contains the name (id) of the type, the title (display name) of the attribute type, the allowed values, the default value, if the attribute is read only etc.
The image below shows one example for the attribute Priority with ID priority, the default attribute literal and the link to the allowed values. The attribute is defined for values in an enumeration. The allowed values URI describes the available values defined in the enumeration.
To get the allowed values for the attribute Priority perform a GET using the shape URI. As always provide the OSLC headers.
The result of the request is shown below.
Note that the allowed values, the priority enumeration literals, do not provide any information about the display name or any other details. To get the display name it is necessary to GET (OSLC headers!) each of the priority literal resource URIs and analyze the results.
To create a work item, the next steps would be to get allowed values for all required attributes and to create a request body containing this information.
At the time of writing, OSLC does not provide a mechanism to get the list of attributes that are required to create a work item due to restrictions in the process. If the target system requires special attributes to be set e.g. in certain states, or expects special values, the work item creation or save will fail. To successfully create or update work items, it is necessary to know such limitations ore provide a configuration capability to adjust for such information.
For the JKE Banking Example that is shipped with EWM, the process requires the following information to create a defect:
To make the example a bit nicer we also want to also set the description of the work item. The summary and the description attributes are easy. This is just a string value. The category is the mapping to a process area. This is not a trivial attribute and it is necessary to get an allowed value. A valid approach is to get all allowed values into an array and to pick one value. If it is desired to find the correct allowed value based on a display value or some other characteristics, iterate all allowed value URIs and get the details.
The code below is the code that creates the payload for the request body needed to create the work item. It looks more complicated than it is, probably because of the RDF library. The code creates an empty graph, a node for the work item and then adds the predicate object configuration that represents the desired information e.g. the text for the summary and the description.
The payloadString serialized in createRDFWorkItem from the graph simply looks like the RDF XML below. It only contains the information about the summary, description and the category
Creating the Work Item
To create the work item, POST to the work item types creation factory URI like shown below:
Provide the required headers to declare OSLC, and the headers to control the content encoding that were already explained. The Content-Type defines the format of the request body. The request body is the payloadString created above.
OSLC-Core-Version 2.0 Accept application/rdf+xml; charset=utf-8 Content-type application/rdf+xml; charset=utf-8
The response status should be a 201. The response headers should contain the location header with the URI of the work item. The URI of the work item is the unique URI of the work item and can be used in subsequent operations to identify the work item. E.g. in GET, or PUT operations to retrieve or modify the work item. The URI is also used in the process of linking work items. The URI can be used in a redirect to open the work item editor in a web UI.
The response headers contain a new important header called ETag. The ETag value describes the state of the work item. Every time the work item is changed it gets a new ETag. When trying to update a work item it is necessary to send the ETag value from the previous GET in a special If-Match header. The server can use this value to evaluate the state of the work item the update is supposed to be applied to based on the current ETag. If the ETag in the request is not the current ETag of the work item state, the request is based on stale data. New changes where done to the work item. The server detects the mismatch and alerts the client that the change can not be executed. The client needs to refresh the work item information, GET the latest state, modify it accordingly and retry to update the work item based on this information.
The response body sent back by the server, contains the data for the new work item. The information is usually much more than the information that went into the creation of the work item. The server creates several special attributes such as the creation date, the creator and similar information. In addition attributes with default values are automatically set and will be returned.
All subsequent operations on the work item should be based on this state, or a never version state that was retrieved by a GET on the work item URI.
The code below shows the creation of the work item and gets the work item URI from the results location header and the etag from the results ETag header.
The same process can be used with the JSON format. The image below shows an example for a work item creation using the JSON encoding with the same attributes used with RDF above.
JSON requires to use the headers shown below instead. The header Content-Type only needs to be set when a request body is sent.
OSLC-Core-Version 2.0 Accept application/json; charset=utf-8 Content-type application/json; charset=utf-8
Get a Work Item
The following sequence is done with the RESTClient extension installed in Firefox. RESTClient is a Firefox extension that runs in the browser. This allows you to log in to the server with the web UI in Firefox and then use the RESTClient without worrying about the authentication because RESTClient reuses the authentication done in the UI. Another Option would be Postman, but that requires to log into the CCM server as explained here. Install RESTClient and Firefox to do these steps yourself.
To get a work item we need the public URI of the work item. The public URI was returned in the Location header when creating the work item. It can also be located e.g. using an OSLC Query. The public URI has this form:
where the number at the end is the work item unique ID for the repository. Note that the URI of the work item is not the URL for the work item editor you get when you copy the address URL from the browser. That URL contains information like the project area name and is not stable.
Open the Web UI of EWM. Open a work item e.g. the one created before. Get the work item URI by copying it out of the Web UI like shown below. You can also use the work item URI from the automation to create the work item.
To get the current state of the work item it is necessary to perform a HTTP GET operation on the public URI. Open a RESTClient and prepare to get a work item. As an example select GET as method and paste the work item URI into the URL address.
Use the OSLC, Accept and Content Type headers as explained above.
Push the Send button to execute the request.
The request should succeed with a status 200. Here the Request and the response headers in RESTClient in Firefox.
Browse the response Headers tab first. Note the ETag header. This is important for a later update.
Update: It is possible to use the oslc.properties query parameter to select which properties (attributes) are of interest in this OSLC request. Note that the oslc.properties require URL encoding to allow to send them in the request URL. The code shown below shows which part of the URI needs to be URL encoded. It is the the comma separated section of property definitions behind the
The oslc.properties can be used in a GET request. In this case it can be used to specify which properties the requestor is interested in. The server does not have to collect and transmit all properties, but only the ones of interest. This saves computing resources and bandwidth.
The image below shows the result of a GET request on a work item URI, providing a oslc.properties selection. Note the response body only returns a limited amount of properties compared to the full GET above.
The image below shows how the requested properties are selected using Python code.
Update a Work Item
To update a work item it is necessary to get the current state of the work item. For this it is necessary to perform a HTTP GET operation on the public URI as shown above. Go back to the result of the previous section or open a RESTClient and prepare to get a work item. For the latter make sure to select GET as method have the work item URI into the URL address.
Make sure to use the OSLC, Accept and Content Type headers as explained above.
Push the Send button to execute the request.
The request should succeed with a status 200.
Browse the response Headers tab first to prepare for updating the work item. Copy the ETag header into a text editor, we need the value of the header later.
Switch over to the Response tab. Search the content for :title to locate the XML containing the work item summary attribute. Mark the response body and copy its content.
Open a new RESTClient window. Paste the response body from the previous GET request into the request body of the new request. Copy the work item URI into the address URL. Change the method to PUT.
Search for the :title in the new request body. Modify the text enclosed in the tag e.g. to An updated summary like below.
<dcterms:title rdf:parseType="Literal">An updated summary</dcterms:title>
Add the OSLC and content headers:
OSLC-Core-Version 2.0 Accept application/json; charset=utf-8 Content-type application/json; charset=utf-8
Now add another header If-Match with the ETag value from the GET method.
See the image below how the request looks like. Perform the send.
The update should succeed with a 200 status and contain a new ETag.
Open the work item in a work item editor. You can do this by pasting the work item URI into the browser address field. If the work item editor is already open the editor should show the work item was changed. Refresh the editor if this is the case. The summary attribute was successfully updated:
Performing a subsequent GET in the initial RESTClient window provides the same information and the new ETag. The ETag will change if the work item is changed again.
Update: change a work item in Python code
The code below retrieves the work item based on its URI.
After getting the work item and the etag, the response body is parsed into a graph that has the required namespaces bound to it. The response has the work item URI as subject in the response, this is retrieved and validated. The work item data is analyzed and some data is pulled out by querying the graph for objects with a specific predicate (e.g. DCTERMS.identifier) and the data is printed.
The code below shows the modification of the summary of the work item.
The new summary is computed based on a timestamp. Then the value of the subject node is set using the code below.
# Set a RDF entry for a node, predicate and object. def setRDFAttribute(self, graph, node, rdfPredicate, rdfObject): graph.set((node, rdfPredicate, rdfObject))
The update header is created, including the If-Match header with the work items ETag from the get operation. The RDF graph is serialized to be sent. Then the PUT operation is performed. The change will have a new ETag, so that is received.
The response body is parsed into an RDF graph again and the information for some of the attributes is again analyzed and printed. The image below shows the console output that is created.
Update: It is possible to use the oslc.properties query parameter to select which properties (attributes) are of interest in this OSLC request.
The oslc.properties can also be used in create and update requests. This can be used for partial updates. Please carefully read this section about updating work items and also check the examples that are provided. Especially for creating and removing links and custom attributes.
For using the oslc.properties query parameter, to limit the amount of properties to a subset, please check the sections oslc.select and oslc.properties in the post EWM OSLC Query API. Syntax and encoding for these query parameters are the same. You have to provide the oslc.properties as a query parameter URL encoded like shown below.
As a summary, the usage of the oslc.properties query parameter allows to
- Limit the properties returned in a GET request to the selected properties. Instead of sending all properties, the server can just respond with the sub set of properties.
- Limit the properties that are considered to be received to the selected properties in PUT and POST requests. This can be used to just have to send a limited amount of attributes, and not all, to achieve a partial update. This can also used to remove properties by including a property in the oslc.properties but not sending data for it.
The link above mentions to use the PATCH method for partial updates a couple of times. I briefly tried to use PATCH to partially update a work item, but I got an “Error 501: Not Implemented”, so I assume PATCH is not available.
Work Item Workflow State change
One important work item attribute is the workflow state also abbreviated with state of the work item (not to be confused with the ETag). When checking the Resource Oriented Work Item API V2 it mentions that the state is read only. It mentions the capability to use an action to perform a state change, but there is no documentation provided that shows how that works. Digging deeper into the Jazz.net forum there are answers that hint on how it could work, but every one of the answers I found was lacking some detail. Here what I was able to come up with to make it work for me.
The work item workflow is defining the states of the workflow and actions that are valid to get from one state to another. States and actions have unique ID’s.
Analyzing the resource shape of the work item type, the state attribute with ID internalState can be located. The attribute has allowed values that can be discovered. The allowed values are the states of the workflow. As an example for one state there is a URI like below:
We are not interested in the state, we need the ID of the action to perform the workflow action. I have not found any simple way to discover the URI to get the workflow actions. There is however a pattern how to access the required information for workflows and actions and other information required to manipulate the workflow state of a work item.
Looking at the path of the URI for the workflow state reveals that the path section after the section workflows is the project area ID. The next path section is states and the section after that describes the workflow ID. The last section is the workflow state ID.
If we remove the workflow state ID section, and perform an GET on the resulting URI e.g.
the resulting response is a list of the workflow states available for the workflow.
Please note, that I experienced issues with the headers to be used here, dependent on the headers used different information was returned in some cases. I would suggest to test using the OSLC headers. If there is a lack of information try to only use the header Accept application/xml (or application/json). The result could contain more information. Please note that in this case the format is not RDF.
If we replace the section states in the URI by actions we get an URI that allows to GET all the workflow actions.
GET https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/actions/com.ibm.team.workitem.defectWorkflow Accept application/xml
Please note, to get the complete workflow information, use only the header Accept application/xml (or application/json). Do not use the Accept application/rdf+xml and do not use the OSLC-Core-Version or any other header. Run the call as shown above.
This way you receive the full workflow table. This contains the information of the workflow action including the resulting state. Given this information it is then possible to extract all workflow information necessary to navigate the workflow. I found this hint in this answer.
To get the information in JSON use only the header application/json.
The image below shows how the complete workflow information looks like, if you get it in the correct way.
Once a desired workflow action ID is selected, it is possible to perform a workflow action. This can be achieved by adding a query parameter ?_action=<actionID>, to the work item URI, where <actionID> is replaced by the ID found as workflow action. The result is shown in the image below. Please note the familiar OSLC and content headers as well as the ETag for the last state of the work item are needed as well.
It is also necessary to send the representation of the work item, otherwise the PUT call will fail. To get an ETag, it is necessary to do a GET, so all the information is already available. By default OSLC expects the complete representation and deletes data that is no longer available in the request.
I have tried to send an “empty” work item representation as hinted in one of the forum questions and the one shown above in the image and below as code worked for me. Note that there is no guarantee that this works with all versions and forever. An attempt to do a partial update using PATCH resulted in an not implemented response. In general see some hints on partial representations in Resource Oriented Work Item API V2.
Important Update about partial update: Please see the Updating Work Items section in the Resource Oriented Work Item API with OSLC_CM 1.0 wiki page and scan through the documentation, especially for partial update. Note the usage of the query parameter oslc_cm.properties. By providing a list of properties that is to be updated it is possible to send only part of the representation containing said properties. The oslc_cm.properties uses the same syntax used by the oslc_cm.select statement. See the post EWM OSLC Query API and check the section about oslc.select for how to create, compose and encode the parameter.
To get the minimal RDF shown here, I cut out all content and stripped it down to the bare minimum. RDF libraries should be able to serialize empty graphs as well and it should be easy enough to find a minimal empty body for JSON.
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> </rdf:RDF>
The URL below successfully updated the work item state without the need to pass additional attributes. The minimal request body above was used with the URL below and the work item state update was successfully performed.
OSLC-Core-Version 2.0 Accept Type application/rdf+xml; charset=utf-8 Content Type application/rdf+xml; charset=utf-8 If-Match "fcd3b360-d152-367d-956e-d1f9f428ced4"
Note that the oslc.properties statement did not work with rdf.nil. But it was possible to omit a value as shown above to clarify that no property value would be included. IT would be possible to specify additional values in oslc.properties that would be sent in the request body. One example is the resolution – see below how that looks like.
Please note, that it is necessary to satisfy all required attributes when performing a workflow action. The new state might require additional values that you might have to provide, in which case you want to definitely use the full information from the resource.
Please also note that I am not seeing errors if the workflow action can not be done or does not exist. The response is 200, regardless of this fact.
Resolve Work Item With Resolution
One example for attributes that might become required with respect to a state change is the resolution attribute
that might be required in certain states when resolving/closing the work item. Following the pattern we discovered the resolutions can be found using the workflow URI and replacing the section states by resolutions. The resulting URI provides the available resolutions.
Please note, that I experienced issues with the headers to be used here, dependent on the headers used different information was returned in cases such as the actions above. I would suggest to test using the OSLC headers. If there is a lack of information try to only use the header Accept application/xml (or application/json). The result could contain more information. Please note that in the latter case the format is not RDF.
Since I had built all the logic to get the action information using XML (minidom) and not RDF in python, I used only Accept application/xml as header to get the resolution information and reused the code written to analyze the actions.
GET https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/resolutions/com.ibm.team.workitem.defectWorkflow Accept application/xml
With the call above it is possible to GET all resolution information like ID’s and names. The image below shows an example. Mind the request header used.
It is then possible to add or set the attribute value like below.
See the response from a GET response to an work item URI, containing the value below as the example.
The example below shows all that is needed to close the work item and set the resolution updated in the same request. In addition to the workflow action as above use the the oslc.properties and define an additional property, the resolution attribute, to be provided.
The request URL contains the workflow action and the request body contains the data for the additional attribute to be set as follows:
<?xml version="1.0" encoding="UTF-8"?> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rtc_cm="http://jazz.net/xmlns/prod/jazz/rtc/cm/1.0/" > <rdf:Description rdf:about="https://elm.example.com:9443/ccm/resource/itemName/com.ibm.team.workitem.WorkItem/241"> <rtc_cm:resolution rdf:resource="https://elm.example.com:9443/ccm/oslc/workflows/_8e5qfFpmEeukW7cqqDjAuA/resolutions/com.ibm.team.workitem.defectWorkflow/com.ibm.team.workitem.defectWorkflow.resolution.r3"/> </rdf:Description> </rdf:RDF>
The request headers, including the If-Match header, have been shown already and show up in the image below which shows all the important data in RESTClient:
This is a complete example of a state change while changing the resolution attribute in addition. This can be expanded on to set more properties using oslc.properties.
I found numerous questions around this in the Jazz forum, but there was still some considerable amount of work to be done, to get the state change working.
The page Resource Oriented Work Item API V2 also describes other interesting concepts like query mechanisms and representations. Some of them will be presented in subsequent upcoming posts. Something I have not yet explored are the draft work items. Intriguing. Maybe I find time to look at it.
I am fully aware that I am quite late to the party, but despite trying, I was unable to find examples for the whole process that were consistent and simple enough, covered most of the ground or worked for me. There was quite some research that needed to be done to get all the concepts covered. All the information in the blog series I am currently writing has been collected to help customers as well as IBM internal resources with the ELM APIs.
So, as always I hope that the content of this blog (series) is of interest to users out there and helps to save some time achieving their goals.
Where do we get the node id that was mentioned in the post request to create a workitem.
The data in the POST request does not have an ID. The ID is created during the POST and the URI for the new work item is returned. You then GET the new URI to get the work item data.
The ID of the BNODE is created by the framework that I use in Python.