Skip to main content
Skip table of contents

Reviewing OSLC Links

There are situations where you may want to review links and look for different conditions. You can use Scriptrunner to rapidly review your OSLC links and tell details about link types, URLs, Count, etc.

The goal of the following script was to identify links to IBM ELM that were using the Base Artifact (rather than the module-bound artifact) and report these items. It shows what you can do by simply reviewing the URL pattern. For example, with Polarion links, you can filter out the Project identifiers in the URL to find improper project linking. All it takes is some review of the URLs and some simple text matching.

In this example, you can see

  • Filtering out remote links by OSLC Connect application

  • Filtering out links based on the URL root (ELM) so no other Friend links are involved

  • Filtering out by link type

  • Finding the requirement id root

  • And providing a simple summary

From this script, a typical output would look like:

image-20240905-192307.png

With the details in the log

image-20240905-192409.png

This script is accessible and adaptable to needs.

CODE
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.link.RemoteIssueLinkManager;
import com.atlassian.jira.issue.link.RemoteIssueLink;
import org.apache.log4j.Logger;
import org.apache.log4j.Level;

def log = Logger.getLogger("com.onresolve.scriptrunner.runner.ScriptRunnerImpl")

def rootUrl = ComponentAccessor.getApplicationProperties().getString('jira.baseurl')

// Set the log level.  
// Test mode disables the creation but runs all the checks
log.setLevel(Level.WARN);

// Set the local username to be logged as the action performing the work
def userName = "bob"

// Metrics counters
int linkCount = 0;
int issueCount = 0;
int linksToReview = 0;

log.info("Starting Sodius Link RM Module Checker")

// The purpose of this script is to identify links to Module Bound or Base Requirements
// Users can customize this to detect when users have link to the non-preferred versions of the artifacts
// This implementation use the id of the RM artifact to detect the variant to save the time of retreiving the artifact 
// from DOORS next and checking the relationships.  This is less formal but is consistent to the goal and significantly faster
//
// The short cut string check is that Module Bound requirements are prefixed with BI and Base Artifacts are prefixed with TX 


// Get the local Jira user
def user = ComponentAccessor.getUserManager().getUserByName(userName)

// Set the ELM root to filter out the target
def elmRoot = "portland-elm.sodius.cloud"



// Search parameter can be set to '' to get all issues from all projects or add 'AND issuekey = JPG-3' to filter on a specific issue
Issues.search('project = AMRPORTLAND').findAll { issue ->

	log.info "Looking at issue " + issue.getKey()
	issueCount++;
	def remoteIssueLinkManager = ComponentAccessor.getComponent(RemoteIssueLinkManager.class)

	log.info("Reviewing " + issue.getKey() )

	// Iterate over links (OSLC Links are stored as Remote Links tied to tha Application Type com.sodius.oslc.app.jira)
	for (RemoteIssueLink existingLink in remoteIssueLinkManager.getRemoteIssueLinksForIssue( issue ) ) {
		// Need to check for the application owner to get all of the OSLC Links
		//  It is assumed that backlinks exist and must be deleted.  If using GC, just set removebacklinks to false
		if ( existingLink.getApplicationType() == "com.sodius.oslc.app.jira" ) {
			// found a OSLC link, we should review
			linkCount++
			if ( isRMLinkType( existingLink.getRelationship() ) ) {
				// We have an RM link type, so check the URL
				if ( existingLink.getUrl().contains(elmRoot) ) {
					log.debug("Found a DNG Link")
					String dngId = existingLink.getUrl().split('/').last() 
					String linkDetails = existingLink.getRelationship() + " with Title " + existingLink.getTitle() + " (" + existingLink.getUrl() + ")"
					if ( dngId.startsWith("BI") ) {
						log.info( issue.getKey() + " Found Module Bound Requirement Link. Please check " + linkDetails)
					} else {
					linksToReview++;	
					if ( dngId.startsWith("TX") ) {
						log.warn( issue.getKey() + " Found Base Requirement Link. Please check " + linkDetails)
					} else {
						log.warn("Unknown RM link type for " + linkDetails)
					}
					}
				}

			}

		}
	}

}

"Reviewed  " + issueCount + " issues" + " with " + linkCount + " links and must review " + linksToReview + " links in log."


def boolean isRMLinkType(String relationship) {
	switch (relationship) {
		case "implements requirement":
			return true
		case "tracks requirement":
			return true
		case "affects requirement":
			return true
		default:
			return false
	}
}

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.