Adding OSLC Links
Adding OSLC Links can be done via Scriptrunner. For unidirectional links (or links discovered by a remote tool like DNG) these can be done with the addition of a Jira Remote Link. The structure of those links are found in Understanding OSLC Connect for Jira Link Storage . For backlinks that are used on CM to CM artifacts or in repositories not using link discovery, this can be done via creating links on the remote resource.
The example script below demonstrates both of these scenarios. In this script we are using a workitem key stored in the description of a Jira issue to create a local link to a Polarion artifact and creating the backlink on the Polarion artifact.
Our initial state is without any links, but a simple workitem key in the description.
![image-20240403-181756.png](../../__attachments/3047030795/image-20240403-181756.png?inst-v=994e91ac-a2ec-48d8-883e-5926c5eddff7)
After executing the script, locally the Jira Remote Link is created (and takes on the OSLC dynamics)
![image-20240403-182018.png](../../__attachments/3047030795/image-20240403-182018.png?inst-v=994e91ac-a2ec-48d8-883e-5926c5eddff7)
And the backlink has been created in Polarion.
![image-20240403-182115.png](../../__attachments/3047030795/image-20240403-182115.png?inst-v=994e91ac-a2ec-48d8-883e-5926c5eddff7)
The following script is a sample for you to explore and build your own automation.
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.sodius.oslc.core.process.model.LinkType
import com.sodius.oslc.core.process.links.model.DirectedLink;
import com.sodius.oslc.core.process.links.requests.AddLink;
import org.eclipse.lyo.oslc4j.core.model.Link;
import com.sodius.oslc.client.OslcClient;
import com.sodius.oslc.client.OslcClients;
import org.apache.http.auth.UsernamePasswordCredentials;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.link.RemoteIssueLinkManager;
import com.atlassian.jira.issue.link.RemoteIssueLink;
import com.atlassian.jira.issue.link.RemoteIssueLinkBuilder;
@WithPlugin("com.sodius.oslc.app.jira")
// Test mode disables the creation but runs all the checks
boolean testMode = true;
boolean jazz = false;
// Get the Jira base URL
def jiraRootUrl = ComponentAccessor.getApplicationProperties().getString('jira.baseurl')
def targetBaseUrl = "https://polar-21r1-brest.sodius.cloud/polarion/oslc"
// Set the local username to be logged as the action performing the work
def userName = "patricia"
// Set the remote user name and password
def remoteUserName = "admin"
def remoteUserPassword = "admin"
def oslcConnectApp = "com.sodius.oslc.app.jira"
def oslcConnectName = "Collaboration Link"
// Metrics counters
int createdLinks = 0;
int issueCount = 0;
log.info("Starting Sodius Link Creation")
// This is an example of converting a description field key to a remote link.
// The target in this example uses Polarion for simplcity of the URL formulation of the OSLC target
// User customization can take place for more complex storage, URL composition and the like
// The structure of this example is to ease understanding
// Get the local Jira user
def user = ComponentAccessor.getUserManager().getUserByName(userName)
// Get the remote Client (assuming all links are to the same respository) - note jazz/IBM have different client connections
def userCredentials = new UsernamePasswordCredentials(remoteUserName, remoteUserPassword);
def OslcClient client;
if (jazz) {
client = OslcClients.jazzForm( userCredentials ).create();
} else {
client = OslcClients.basic( userCredentials ).create();
}
// Iterate through a Project and create local and remote links. (The JQL determines the scope)
Issues.search('project = POL21R1 AND issuekey = POL21R1-1').findAll { issue ->
issueCount++;
// Fixed project key for the example
def projectKey = "drivepilot";
// Use the description field to get the id of the object to link to (assumes only one artifact per description)
def workItemKey = issue.description
// Construct Polarion and Jira URLs
String targetURL = "$targetBaseUrl/services/projects/$projectKey/workitems/$workItemKey"
String jiraURL = "$jiraRootUrl/rest/oslc/1.0/cm/issue/$issue.key"
log.info("Source of Link -> " + jiraURL);
log.info("Target of Link -> " + targetURL);
if (!testMode) {
// Build and create link in remote tool (Polarion)
DirectedLink directedLink = new DirectedLink()
directedLink.setPropertyDefinition(LinkType.IMPLEMENTED_BY.getPropertyDefinition()); // This link type could be algorithmically determined or fixed
directedLink.setSource( URI.create(targetURL) )
directedLink.setTarget(new Link(URI.create(jiraURL), issue.key))
def addLinkResponse = new AddLink(client, directedLink).call()
log.info("Created Link in Remote Repository");
createdLinks++;
// Build and create the local (Jira Remote Link) link in Jira
def remoteIssueLinkManager = ComponentAccessor.getComponent(RemoteIssueLinkManager.class)
def relationshipType = "implements requirement"; // This is the inverse relationship of the remote link and a textual description
// Check if the link already exists before creating it
def exists = remoteIssueLinkManager.getRemoteIssueLinksForIssue(issue).any { existingLink ->
existingLink.url == targetURL &&
existingLink.applicationType == oslcConnectApp &&
existingLink.relationship == relationshipType
}
if (!exists) {
def remoteLink = new RemoteIssueLinkBuilder()
.url(targetURL)
.title("$workItemKey") // This is the name shown before authenticating to the remote object
.issueId(issue.id)
.relationship(relationshipType)
.applicationType(oslcConnectApp)
.applicationName(oslcConnectName)
.build()
remoteIssueLinkManager.createRemoteIssueLink(remoteLink, user)
log.info("Created Link in Local Repository");
}
} else {
log.info("Operating in test mode. No link creation")
}
log.info("Reviewed " + issueCount + " issues and created " + createdLinks + " links.")
}