Introduction
We are finishing up a release cycle at work. We have switched from Clearcase to Mercurial, and from a home grown bug tracking system to JIRA. We just released our latest software release on Monday, and its time to clean up the repo and JIRA.Here is the situation. We chose for this release iteration to use a JIRA issue per branch approach. This worked for our situation where we had a number of new users to Mercurial, and JIRA. We could easily manage any issues with the build, or user mistakes. We will re-think the approach now that our team are up to speed on Mercurial.
We also implemented a server side Mercurial trigger that checked if the JIRA issue was assigned to the committer (person pushing to "master" repo). If not, they would not be able to push to the server. That way we could make sure that there were issues associated with check-ins.
So far, I think we did a good job since we yanked the rug from under the staff. QA finished their process and marked all of the JIRA issues closed. However, they don't have permissions to modify Mercurial to close the branches. That makes sense because they should be testing and not writing code. Now it is time to pay the piper.
We needed a mechanism to read the JIRA issues, look for the closed issues, assign them to a primary committer on JIRA with permissions on Mercurial, close the branch, and push to update the issue with a JIRA comment from the Mercurial check-in trigger. Got that?
Lets try that again...
- Read the JIRA issues and find all CLOSED issues.
- Read all of the Mercurial branches that are not closed. Remember the branches have the same name as the JIRA issue.
- Assign the JIRA issue to a primary committer.
- Switch to the branch and update
- Close branch and commit
- Push to "Master" server. This will not work unless the issue is assigned to primary committer since it has a commit trigger.
- The commit will update JIRA with the closed branch commit comments.
Are you still with me?
The code we wrote to do most of the work is proprietary. However, one aspect of it is worth sharing with the community. How do you assign a JIRA ticket to another user using the JIRA REST interface. The code below demonstrates how to do that.
Code
IssueAssignmentClient.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | package com.bluelotussoftware.jira; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; import com.sun.jersey.api.json.JSONConfiguration; import java.text.MessageFormat; import javax.ws.rs.core.MediaType; /** * USAGE: * <pre> * IssueAssignmentClient client = new IssueAssignmentClient(); * Object response = client.XXX(...); * // do whatever with response * client.close(); * </pre> * * @author John Yeary * @version 1.0 */ public class IssueAssignmentClient { private WebResource webResource; private final Client client; public IssueAssignmentClient(String issueIdOrKey) { ClientConfig config = new DefaultClientConfig(); config.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); client = Client.create(config); String resourcePath = MessageFormat.format( "api/2/issue/{0}/assignee" , new Object[]{issueIdOrKey}); webResource = client.resource(BASE_URI).path(resourcePath); } public void setResourcePath(String issueIdOrKey) { String resourcePath = MessageFormat.format( "api/2/issue/{0}/assignee" , new Object[]{issueIdOrKey}); webResource = client.resource(BASE_URI).path(resourcePath); } /** * @param responseType Class representing the response * @param requestEntity request data@return response object (instance of * responseType class) */ public <T> T assign(Object requestEntity, Class<T> responseType) throws UniformInterfaceException { return webResource.type(MediaType.APPLICATION_JSON).put(responseType, requestEntity); } public void close() { client.destroy(); } public void setUsernamePassword(String username, String password) { client.addFilter( new HTTPBasicAuthFilter(username, password)); } } |
App.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | package com.bluelotussoftware.jira; import com.sun.jersey.api.client.ClientResponse; /** * Example Application * * @author John Yeary * @version 1.0 */ public class App { public static void main(String[] args) { if (args.length < 4 ) { System.out.println( "Usage\n\t\t com.bluelotussoftware.jira.App username password issueOrKey assignee" ); } String username = args[ 0 ]; String password = args[ 1 ]; String issueOrKey = args[ 2 ]; String assignee = args[ 3 ]; IssueAssignmentClient iac = new IssueAssignmentClient(issueOrKey); iac.setUsernamePassword(username, password); class Assignee { private String name; public Assignee(String name) { this .name = name; } public String getName() { return name; } public void setName(String name) { this .name = name; } } ClientResponse cr = iac.assign( new Assignee(assignee), ClientResponse. class ); int status = cr.getStatus(); switch (status) { case 204 : { System.out.println( "Success. The JIRA was assigned to user." ); break ; } case 400 : { System.out.println( "The user representation had errors." ); break ; } case 401 : { System.out.println( "The calling user does not have permissions to assign the issue." ); break ; } case 404 : { System.out.println( "The user, or issue does not exist." ); break ; } default : { System.out.println( "Unknown Status Code: " + status); break ; } } iac.close(); } } |
0 comments :
Post a Comment