Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Here is the out of box issue tracking systems. To configure, select Jira and click the Edit button. Issue Tracking System screen allows you to view the details on our of box Jira. FlexDeploy comes up with Java Implementation to integrate with Jira, you are not allowed to change implementation class and change or add new  properties. You can create additional Issue Tracking System as necessary using the Create button.


Image Added

You can provide global customizations update description and ticket patter for the Jira integration here, or override the settings at the environment, project, or environment/project level. The customizations available are as follows. Other fields are not editable.

Check this box if you want to globally update any tickets associated to FlexDeploy builds. Can be overridden at the environment,

Field Name

Required

Description

Id

Yes

System generated identifier (read-only).

Name

Yes

Name of the issue tracking system.

Description

No

Description of the issue tracking system.

Ticket Number Pattern

Yes

Pattern of the issues within the issue tracking system, used to associate FlexDeploy builds with particular issue(s). If not specified here, the pattern will need to be defined on each project which associates to your issue tracking system. For Jira, the pattern of tickets is the Jira project Key, followed by a dash (e.g. "MYPROJ-"). All tickets created for this project are prefixed by this key, making it the pattern.

Update Tickets on Build

No

Java ImplementationYesImplementation class for Jira written in Java


You can provide global customizations for the Jira integration here, or override the settings at the project, or environment/project level. The customizations available are as follows.

...

Build Update Comment Pattern

...

No

...

Default Configuration

FlexDeploy can configure default rules which will apply at the project level.

Image Added


You can provide global customizations for the Jira integration here, or override the settings at the project, or environment/project level. The customizations available are as follows.

Field Name

Required

Description

Update Ticket Status Tickets on Build

No

Applicable only if Update Tickets on Build is checked. Check this box if you want to globally update the status of any tickets associated to FlexDeploy builds. Can be overridden at the environment, project, or environment/project level.

To (Build )Update Comment Pattern

No

Applicable only if Update Ticket Status Tickets on Build is checked. Any associated ticket will be updated to this status whenever the build completes successfully. The value of this property is a groovy script which evaluates to the comment you wish to update associated tickets with when a build completes successfully. Groovy variables available to the script are provided in the (x=) dropdown to the right. Can be overridden at the environment, project, or environment/project level.

Update Ticket Status on Build

No

Applicable only if Update Tickets on DeployBuild is checked. Check this box if you want to globally update the status of any tickets associated to FlexDeploy deploymentsbuilds. Can be overridden at the environment, project, or environment/project level.Deploy Update Comment Pattern

To (Build)

No

Applicable only if Update Tickets Ticket Status on DeployBuild is checked. The value of this property is a groovy script which evaluates to the comment you wish to update associated tickets with when a deployment completes successfully. Groovy variables available to the script are provided in the (x=) dropdown to the rightAny associated ticket will be updated to this status whenever the build completes successfully. Can be overridden at the environment, project, or environment/project level.

Update Ticket Status Tickets on Deploy


Applicable only if Update Tickets on Deploy is checked. Check this box if you want to globally update the status of any tickets associated to FlexDeploy builds when they are deployeddeployments. Can be overridden at the environment, project, or environment/project level.

To (Deploy )Update Comment Pattern


Applicable only if Update Ticket Status Tickets on Deploy is checked. Any associated ticket will be updated to this status whenever the deployment completes successfullyThe value of this property is a groovy script which evaluates to the comment you wish to update associated tickets with when a deployment completes successfully. Groovy variables available to the script are provided in the (x=) dropdown to the right. Can be overridden at the environment, project, or environment/project level.

Issue Tracking System properties provide the definition of configuration parameters that are required to integrate with that system. Values for these properties will be provided when Issue Tracking System Instances associated with the system (e.g. Jira) are configured in the FlexDeploy topology. See Topology for more information.

...

Lastly, as mentioned above, FlexDeploy can configure global environment rules which will apply to all projects in the application unless overridden at the project level.

Image Removed

...

Update Ticket Status on Deploy


Applicable only if Update Tickets on Deploy is checked. Check this box if you want to globally update the status of any tickets associated to FlexDeploy builds when they are deployed. Can be overridden at the environment, project, or environment/project level.

To (Deploy)


Applicable only if Update Ticket Status on Deploy is checked. Any associated ticket will be updated to this status whenever the deployment completes successfully. Can be overridden at the environment, project, or environment/project level.

Environment Configuration

FlexDeploy can configure global environment rules which will apply to all projects in the application unless overridden at the project level.

Image Added

The selected ticket status for the Auto-approve Tasks on Status field, is for any External Approval Task that gets created for the Development environment. The task is automatically approved when the associated ticket, in the Issue Tracking System, reaches or exceeds the desired status. For more information on the setup of the External Approvals and configuring Issue Tracking System at the Project level, refer to the Issue Tracking System section of the Projects page.

Properties

Issue Tracking System properties provide the definition of configuration parameters that are required to integrate with that system. Values for these properties will be provided when Issue Tracking System Instances associated with the system (e.g. Jira) are configured in the FlexDeploy topology. See Topology for more information.

Image Added

Status

Issue Tracking System statuses identify the statuses within your Jira system, and allows FlexDeploy to update your issues to those values at build or deployment time. You will add the statuses from the Jira workflow(s) associated to your Jira project(s). Click the Image AddedandImage Addedbuttons to add or remove statuses from the list. 


Image Added

To identify the statuses to add, from within your Jira system, view the workflow(s) associated to your Jira project(s). Switching to the Text view of the workflow editor/viewer you can identify the workflow statuses and transition ids.

Image Added

Image Added
 
It is critical that the ids entered match the transition ids within your Jira workflows, otherwise, FlexDeploy will be unable provide the desired updates.


Click the Save button to apply any updates. 

Build Request

Tickets can also be manually associated to an Issue Tracking System on the Build Request Form for each project.

...

Here we are creating custom issue tracking system with the properties, you can add more as necessary.

Image RemovedImage Added

API Implementation

...

Code Block
languagejava
themeEmacs
titleExample class RedmineServiceIntegration.java
linenumberstrue
collapsetrue
package mycompany.extension.redmine.impl;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;

import java.io.Serializable;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.core.Response;

import flexagon.fd.model.integration.its.api.IssueTrackingSystem;
import flexagon.fd.model.integration.its.api.Ticket;
import flexagon.fd.model.integration.util.ApiException;

public class RedmineServiceIntegration
  extends IssueTrackingSystem
{
  public RedmineServiceIntegration()
  {
    super();
  }

  @Override
  public void checkConnection()
    throws ApiException
  {
    String methodName = "checkConnection";
    System.out.println(methodName + " getting version for project to check connection");
    ClientResponse clientResponse = getWebResource("/projects/1/versions.json").get(ClientResponse.class);
    System.out.println(methodName + String.format(" Successfully invoked test connection URL %s", clientResponse));
    int statusCode = clientResponse.getStatusInfo().getStatusCode();
    if (statusCode == 401)
    {
      throw new ApiException("Invalid credentials.", "");
    }
    if (!(clientResponse.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL))
    {
      throw new ApiException(clientResponse.getEntity(String.class), clientResponse.getStatusInfo().getReasonPhrase());
    }
    System.out.println(methodName + " Test connection response code looks valid, check content of response");
    System.out.println(methodName + " Validated that JSON data was received from test connction URL invocation.");
  }

  private StringBuilder getRedmineURLBuilder()
  {
    StringBuilder urlBuilder = new StringBuilder((String) getProperties().get("REDMINE_URL"));
    return urlBuilder;
  }

  private String getRedmineURL()
  {
    return getRedmineURLBuilder().toString();
  }

  private String getUserName()
  {
    return (String) getProperties().get("REDMINE_USER_NMAE");
  }

  private String getPassword()
  {
    return (String) getProperties().get("REDMINE_PASSWORD");
  }

  @Override
  public void populateTicket(Ticket pTicket)
    throws ApiException
  {
    // TODO Implement this method
  }

  @Override
  public String getTicketURL(Ticket pTicket)
    throws ApiException
  {
    // TODO Implement this method
    return null;
  }

  @Override
  public void addCommentToTicket(Ticket pTicket, String pString)
    throws ApiException
  {
    // TODO Implement this method
  }

  @Override
  public void changeTicketStatusTo(Ticket pTicket, String pString)
    throws ApiException
  {
    // TODO Implement this method
  }

  @Override
  public String getTicketStatus(Ticket pTicket)
    throws ApiException
  {
    // TODO Implement this method
    return null;
  }

  private Client getRestClient()
  {
    Client restClient = Client.create();
    restClient.addFilter(new HTTPBasicAuthFilter(getUserName(), getPassword()));
    restClient.setReadTimeout(20000);
    restClient.setConnectTimeout(10000);
    return restClient;
  }

  public WebResource getWebResource(String resource)
    throws ApiException
  {
    String methodName = "getWebResource";

    if (resource != null && !resource.isEmpty() && !resource.startsWith("/"))
    {
      resource += "/" + resource;
    }
    WebResource webResource = null;
    try
    {
      webResource = getRestClient().resource(getRedmineURL()).path(resource);
    }
    catch (Exception e)
    {
      throw new ApiException(e.getMessage(), e.getMessage());
    }

    return webResource;
  }
}

...

Code Block
languagegroovy
themeEmacs
titleExample groovy RedmineIssueTrackingSystem.groovy
linenumberstruecollapsetrue
import flexagon.fd.model.integration.its.api.Ticket;
import flexagon.fd.model.integration.util.ApiException; 
class RedmineIssueTrackingSystem
{
  def checkConnection()
  {
	String methodName = "checkConnection()";
    try
    { 
      fdrestutils.testConnection(REDMINE_URL, "/projects/1/versions.json", REDMINE_USER_NMAE, REDMINE_PASSWORD)
    }
    catch (Exception e)
    {
      log.logInfo(methodName, " Failed in Test connection" + e.getMessage() + " " + e)
      throw new ApiException("Connection failed. " + e.getMessage());
    }
  }
  
  String getTicketStatus(Ticket ticket)
  {
    String methodName = "getTicketStatus()";
    String message = " ticket# ${ticket.toString()}"
    log.logInfo(methodName, message);
    String resourcePath = REDMINE_TICKET_URL_PATTERN.replaceAll("\\{REDMINE_ISSUE\\}", ticket.getNumber())
    javax.json.JsonObject jsonObj = fdrestutils.getRequest(REDMINE_URL, resourcePath, REDMINE_USER_NMAE, REDMINE_PASSWORD);
    if(jsonObj != null)
    {
      javax.json.JsonObject issue = jsonObj.getJsonObject("issue")
      if(issue!=null)
      {
        javax.json.JsonObject status = issue.getJsonObject("status")
        if(status !=null)
        {
          return status.getString("name")
        }       
      }
    }
	return null;
  }

   
  String getTicketURL(Ticket ticket)
  {
    String methodName = "getTicketURL()";
    String message = "ticket# ${ticket.toString()}"
    log.logInfo(methodName, message);
    String resourcePath = REDMINE_TICKET_URL_PATTERN.replaceAll("\\{REDMINE_ISSUE\\}", ticket.getNumber())
	message = "Redmine ticket URL is # ${REDMINE_URL}, resourcePath=${resourcePath}"
    log.logInfo(methodName, message)
	return REDMINE_URL + resourcePath;
  }
  
  def populateTicket(Ticket ticket)
  {
    String methodName = "populateTicket()";
	String message = "Populate ticket# ${ticket.toString()}"
    log.logInfo(methodName, message)
    String resourcePath = REDMINE_TICKET_URL_PATTERN.replaceAll("\\{REDMINE_ISSUE\\}", ticket.getNumber())
    javax.json.JsonObject jsonObj = fdrestutils.getRequest(REDMINE_URL, resourcePath, REDMINE_USER_NMAE, REDMINE_PASSWORD);
    if(jsonObj != null)
    {
      javax.json.JsonObject issue = jsonObj.getJsonObject("issue")
      if(issue!=null)
      {
        ticket.setDescription(issue.getString("description"))
        javax.json.JsonObject tracker = issue.getJsonObject("tracker")
        if(tracker !=null)
        {
          ticket.setType(tracker.getString("name"))
        }       
      }
    }
  }
  
  def addCommentToTicket(Ticket ticket, String pComment)
  {
	String methodName = "addCommentToTicket()";   
    try
    { 
	  String message = " Adding comment to ${ticket.toString()} , comment=${pComment}"
      log.logInfo(methodName, message)
      def builder = new groovy.json.JsonBuilder()
      def root = builder.issue {
              notes "${pComment}"
       }
      String payload = builder.toString();
      String resourcePath = REDMINE_TICKET_REST_PATTERN.replaceAll("\\{REDMINE_ISSUE\\}", ticket.getNumber())
      fdrestutils.putRequest(REDMINE_URL, REDMINE_USER_NMAE, REDMINE_PASSWORD, resourcePath, payload);
    }
    catch (Exception e)
    {
      log.logInfo( methodName, " Failed while  adding comment to the issue - " + e.getMessage() + " " + e)
      throw new ApiException("Connection failed. " + e.getMessage());
    }
  }
  
  def changeTicketStatusTo(Ticket ticket, String pStatus)
  {
    String methodName = "changeTicketStatusTo()";
	String message = " Adding comment to ${ticket.toString()} , status=${pStatus}"
    log.logInfo(methodName, message)
	def builder = new groovy.json.JsonBuilder()
	def root = builder.issue {
		notes "Status updated to ${pStatus}"
		status_id "${pStatus}"
	}
	String payload = builder.toString();
	String resourcePath = REDMINE_TICKET_REST_PATTERN.replaceAll("\\{REDMINE_ISSUE\\}", ticket.getNumber())
	fdrestutils.putRequest(REDMINE_URL, REDMINE_USER_NMAE, REDMINE_PASSWORD, resourcePath, payload);
  }
  
   
   def parseTicketNumberFromChangeLogs(String pProjectName, List<String> pChangeLogMessages, List<String> pTicketPatternList)
  {
	String methodName = "parseTicketNumberFromChangeLogs()";
	Set<String> ticketNumberList = HashSet<String>();
	String message = " Input ProjectName= ${pProjectName}, ChangeLogMessages=${pChangeLogMessages} , TicketPatternList=${pTicketPatternList}"
    log.logInfo(methodName, message)	
    if("Gradle".equals(pProjectName)) {
      String[] patterns = ["ZZZ-"];
      pTicketPatternList = Arrays.asList(patterns);
      message = "override pattern for Gradle TicketPatternList=${pTicketPatternList}"
      log.logInfo(methodName, message)
    }
    Collection<String> parsedTicketNumbers = flexagon.fd.model.integration.its.util.ChangeLogParser.getParser().parse(pChangeLogMessages, pTicketPatternList);
	message = "parsedTicketNumbers=${parsedTicketNumbers}"
    log.logInfo(methodName, message)
		
    if(parsedTicketNumbers != null && !parsedTicketNumbers.isEmpty() && pTicketPatternList != null && !pTicketPatternList.isEmpty())
    {
      parsedTicketNumbers.each{ parsedTicket ->
        pTicketPatternList.each{ pattern ->
			if(parsedTicket.startsWith(pattern))
			{
				String ticketNumber = parsedTicket.substring(pattern.length(),parsedTicket.length())
				ticketNumberList.add(ticketNumber)
			}
		}
      }
    }
	return ticketNumberList;
  }

}

...