Update JIRA subtask Fix Version when parent issue Fix Version updated - jira

When an issue is created, the Fix Version field is set to a particular value (say 2.0). Then subtasks are created, and they inherit this value. So far so good. But if later, the issue's Fix Version value is modified (to say 1.0), the subtasks still keep the 2.0 fix version value.
Is there a plugin or technique I can use to keep these fields in sync?
Note: This has been requested as a JIRA feature, but Atlassian doesn't seem to want to do it.
https://jira.atlassian.com/browse/JRA-9016

I know its rather an old question. But here is my code I recently deployed. This is an event listener for issueUpdated event deployed on Script Listener from ScriptRunner plugin. A lot of the code is from Jamie Echlin's examples. It still needs to be tweaked for when a Fix Version field on the Parent is made "empty", it's sub tasks also need to be empty.
package com.custom.listeners
import org.apache.log4j.Category
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.event.issue.AbstractIssueEventListener
import com.atlassian.jira.event.issue.IssueEvent
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.project.version.Version
import com.opensymphony.workflow.InvalidInputException
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import java.util.ArrayList
import java.util.Collection
class FixVersionPBI_To_SBI_1 extends AbstractIssueEventListener
{
Category log = Category.getInstance(FixVersionPBI_To_SBI_1.class)
#Override
void issueUpdated(IssueEvent event)
{
try
{
Issue fix_Issue = event.getIssue()
if (fix_Issue.issueTypeObject.name == "Parent issue type" )
{
List changeItems = event.getChangeLog().getRelated("ChildChangeItem")
if( fix_Issue.fixVersions?.name && changeItems.any {it.get('field')=='Fix Version'} )
{
Collection<Version> fixVersions = new ArrayList<Version>();
fixVersions = fix_Issue.getFixVersions()
Collection subTasks = fix_Issue.getSubTasks();
SubTaskManager subTaskManager = ComponentManager.getInstance().getSubTaskManager();
if (subTaskManager.subTasksEnabled && !subTasks.empty)
{
IssueManager issueManager = ComponentManager.getInstance().getIssueManager()
Collection _subTasks = fix_Issue.getSubTaskObjects()
_subTasks.each
{
it.setFixVersions(fixVersions)
issueManager.updateIssue(event.getUser(), it, EventDispatchOption.ISSUE_UPDATED, false)
}
}
}
}
}
catch (ex)
{
log.debug "Event: ${event.getEventTypeId()} fired for ${event.issue} and caught by FixVersionPBI_To_SBI_1"
log.debug (ex.getMessage())
}
}
}

For Jira 6.4
Your subtasks fixversion fields will be update automatically.
Install ScriptRunner plugin.
OPEN your-jira.host/secure/admin/ViewCustomFields.jspa
ADD the new custom field with (Advanced>Scripted field)
OPEN /plugins/servlet/scriptrunner/builtin?section=script_fields and find new field there.
ADD this script, test it and save.
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.config.SubTaskManager;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.event.type.EventDispatchOption;
def result = "";
def subTasks = issue.getSubTaskObjects()
Collection fixVersions = issue.getFixVersions();
if (!fixVersions.empty) {
SubTaskManager subTaskManager = ComponentAccessor.getSubTaskManager();
if(subTaskManager.subTasksEnabled && !subTasks.empty) {
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser();
subTasks.each {
if (it.statusObject.name != "Closed") {
it.setFixVersions(fixVersions);
IssueManager issueManager = ComponentAccessor.getIssueManager()
result += it.getKey() + " ";
issueManager.updateIssue(user, it, EventDispatchOption.ISSUE_UPDATED, false);
}
}
if (count > 0) {
result += " versions updated";
}
}
}
return result;

To do it manually, you could do query such as "parent=TEST-123" and then a bulk edit. To do it automatically you would need to have a custom listener (e.g. Script Runner) to detect the Issue Updated event and only do something if the change was an issue update. Updating the subtask Fix Versions will also require that the subtasks are reindexed or your searches will not work as expected.
I don't know of a plugin to do this.

Related

Install Snyk in Jenkins "Global Tool Configuration" using groovy

I'm trying to add a Snyk installation to Jenkins using groovy. The plugin is installed and I can see the installation option in Global Tool Configuration:
The problem is the Descriptor is not available until I manually add the installer and click Save. If I don't do this task manually, which I want to prevent, it causes my code to fail with the following error message "Cannot invoke method setInstallations() on null object"
My code:
import hudson.model.*
import jenkins.model.*
import hudson.tools.*
import hudson.tasks.*
import io.snyk.jenkins.tools.SnykInstaller
import io.snyk.jenkins.tools.SnykInstallation
def snyk_name = "Snyk"
def snyk_home = ""
def snyk_installer = new SnykInstaller("", "latest", 24)
def snyk_properties = new InstallSourceProperty([snyk_installer])
def instance = Jenkins.getInstance()
println("[init.groovy.d] START Configuring Snyk Installation...")
// Get the GlobalConfiguration descriptor of Snyk plugin.
def snyk_conf = instance.getDescriptor("io.snyk.jenkins.SnykStepBuilder.SnykStepBuilderDescriptor")
def snyk_inst = new SnykInstallation(
snyk_name,
snyk_home,
[snyk_properties]
)
// Only add the new Snyk setting if it does not exist - do not overwrite existing config
def snyk_installations = snyk_conf.getInstallations()
def snyk_inst_exists = false
snyk_installations.each {
installation = (SnykInstallation) it
if (snyk_inst.getName() == installation.getName()) {
snyk_inst_exists = true
println("Found existing installation: " + installation.getName())
}
}
if (!snyk_inst_exists) {
snyk_installations += snyk_inst
snyk_conf.setInstallations((SnykInstallation[]) snyk_installations)
snyk_conf.save()
}
// Save the state
instance.save()
println("[init.groovy.d] END")
Is there any way to do what I want programmatically?
After testing your groovy on my local Jenkins (v 2.263.1) I came up with the below which then worked for me:
import hudson.model.*
import jenkins.model.*
import hudson.tools.*
import hudson.tasks.*
import io.snyk.jenkins.tools.*
def instance = Jenkins.getInstance()
def snyk_name = "SnykLatest"
def snyk_home = ""
def snyk_installer = new SnykInstaller("", "latest", 24L, null)
def snyk_properties = new InstallSourceProperty([snyk_installer])
println("[init.groovy.d] START Configuring Snyk Installation...")
// Get the GlobalConfiguration descriptor of Snyk plugin.
def snyk_conf = instance.getDescriptor("io.snyk.jenkins.tools.SnykInstallation")
def snyk_inst = new SnykInstallation(
snyk_name,
snyk_home,
[snyk_properties]
)
// Only add the new Snyk setting if it does not exist - do not overwrite existing config
def snyk_installations = snyk_conf.getInstallations()
def snyk_inst_exists = false
snyk_installations.each {
installation = (SnykInstallation) it
if (snyk_inst.getName() == installation.getName()) {
snyk_inst_exists = true
println("Found existing installation: " + installation.getName())
}
}
if (!snyk_inst_exists) {
snyk_installations += snyk_inst
snyk_conf.setInstallations((SnykInstallation[]) snyk_installations)
snyk_conf.save()
}
// Save the state
instance.save()
println("[init.groovy.d] END")
In basic Terms the SnykInstaller was expecting 4 values not 3. Groovy also took the 3rd value as an Integer when it was expecting a Long Value.
References:
https://javadoc.jenkins.io/plugin/snyk-security-scanner/io/snyk/jenkins/tools/SnykInstaller.html
https://github.com/jenkinsci/snyk-security-scanner-plugin/blob/master/src/main/java/io/snyk/jenkins/tools/SnykInstaller.java
https://github.com/jenkinsci/snyk-security-scanner-plugin/blob/master/src/main/java/io/snyk/jenkins/tools/PlatformItem.java

Import/Post CSV files into ServiceNow

We have a requirement for a CSV file to be pushed to the instance, imported and an incident created. I have created the import table and transformation map, and I've successfully tested them manually.
However, when I've attempted to use the instructions from ServiceNow documents site Post CSV files to Import Set nothing happens. The screen goes blank after I get prompted for login credentials.
When I check the system logs and import logs all I see is the error "java.lang.NullPointerException".
My url is basically the following one: https://.service-now.com/sys_import.do?sysparm_import_set_tablename=&sysparm_transform_after_load=true&uploadfile=
Is there something I'm missing?
I do the same thing but have it come in via an email to the my SN instance and process it using an inbound action.
var type = {};
type.schedule = 'u_imp_tmpl_u_term_phr_empl_mvs_ids'; //Display name for scheduled import -- eb9f2dae6f46a60051281ecbbb3ee4a5
type.table = 'u_imp_tmpl_u_term_phr_empl_mvs_ids'; //Import table name
gs.log('0. Process File Start');
if(type.schedule != '' && type.table != '') {
gs.log('1. Setting up data source');
current.name = type.schedule + ' ' + gs.nowDateTime(); //append date time to name of data source for audit
current.import_set_table_name = type.table;
current.import_set_table_label = "";
current.type= "File";
current.format = "CSV"; //"Excel CSV (tab)";
current.header_row = 1;
current.file_retrieval_method = "Attachment";
var myNewDataSource = current.insert();
gs.log('2. Data source inserted with sys_id - ' + myNewDataSource);
//point the scheduled import record to the new data source
var gr = new GlideRecord ('scheduled_import_set');
gr.addQuery('name', type.schedule);
gr.query();
if (gr.next()) {
gs.log('3. Found Scheduled Import definition');
gr.data_source = myNewDataSource;
gr.update();
gs.log('4. Scheduled Import definition updated to point to data source just added');
//Packages.com.snc.automation.TriggerSynchronizer.executeNow(gr);
//Execute a scheduled script job
SncTriggerSynchronizer.executeNow(gr);
} else {
// add error conditions to email somebody that this has occurred
gs.log('5. ERROR - Unable to locate scheduled import definition. Please contact your system administrator');
}
gs.log('6. Inbound email processing complete');
//gs.eventQueue("ep_server_processed",current);
event.state="stop_processing";
} else {
gs.log('7. Inbound email processing skipped');
}

Is there a way to automatically change epic state to done when all the linked stories and tasks are complete

I am new to JIRA and Kanban. I was expecting that when I create an epic and link some stories and tasks to it. The status of the epic will automatically change (e.g. to done) when all the stories and tasks linked to it are done. But it seems this is not the case. I can move the epic from the Backlog to the Done column even when its linked tasks and stories are still in the backlog. Is there a way to make JIRA prevent that from happening?
I have been working on something similar. My intention was to set assigne of all linked issues of another one to a specific user when the status changes to a specific state.
I did this with a postfunction of the workflow of type: "Set Field Value to constant or Groovy expression"
In your situation I would do the following:
go to "Close" transition, and click configure.
select postfunctions, and add the type i told you.
mark the chekbox that says execute only if condition is true
set your condition. Probably something like issue.epic=your epic.
Then you add your script, where you recover alll the issues linked to the epic, and check their status.
Create your logic so that if everithing is as it should be, you just change the status, using MutableIssue object.
remember that a field is going to be modified by this script, and i guess you cant choose status as field to be set. If this happens, choose summary, and store the current value, and use it to end your script, and set the summary value, whtih the same you had.
Publish your workflow.
Excuse me if it is not clear, but is difficult to explain. Let me know if you need somenthing else.
PD: If you just want to do this at some specific moment and not for every epics automatically, just add Script Runner plugin, and run your script in the console. Much easier.
Regards
Maybe it helps you:
I used jira with system language set to "Russian" (and i'm not good in groovy), that's why script below contains language dependencies (you should edit code if you use differ from my jira system language! At least change )
Use Scrip Runner plugin
Create "Custom listener" and paste code (code is not so good as can be but it's working):
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.link.IssueLinkManager;
import com.atlassian.jira.issue.link.IssueLink;
import com.atlassian.jira.issue.ModifiedValue;
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder;
import com.atlassian.jira.issue.customfields.option.Options;
import com.atlassian.jira.issue.customfields.option.Option;
import com.atlassian.jira.issue.fields.config.FieldConfig;
import com.atlassian.jira.issue.customfields.manager.OptionsManager;
import com.atlassian.jira.ComponentManager;
ComponentManager componentManager = ComponentManager.getInstance();
def groupMan = ComponentAccessor.getGroupManager()
def authCon = ComponentAccessor.getJiraAuthenticationContext()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def changeHolder = new DefaultIssueChangeHolder();
IssueManager issueManager = ComponentAccessor.getIssueManager();
OptionsManager optionsManager = componentManager.getComponentInstanceOfType(OptionsManager.class);
IssueLinkManager issueLinkManager = ComponentAccessor.getIssueLinkManager()
def curUser = authCon.getUser()
def issue = event.issue
def epicLinkCf = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Epic Link'}
if(!epicLinkCf) {log.warn "No Epic Link field"; return}
log.warn "Existing Epic Link: ${epicLinkCf.getValue(issue)}"
String epicIssue = epicLinkCf.getValue(issue)
Issue epic = issueManager.getIssueObject(epicIssue) // epicKey is passed into your script
// Check if Epic link is exist
if(!epic)
return true
def newEpicState = "Сделано"
log.warn "Epic: " + epic
List<IssueLink> allOutIssueLink = issueLinkManager.getOutwardLinks(epic.getId());
for (Iterator<IssueLink> outIterator = allOutIssueLink.iterator(); outIterator.hasNext();) {
IssueLink issueLink = (IssueLink) outIterator.next();
log.warn "child link type: " + issueLink.getIssueLinkType().getName()
// Check status of all issues from epic
if (issueLink.getIssueLinkType().getName() == "Epic-Story Link") {
Issue chIssue = issueLink.getDestinationObject();
log.warn "child state: " + chIssue.getStatusObject().getName()
if(chIssue.getStatusObject().getName() == "В процессе") {
newEpicState = "В процессе"
} else if (chIssue.getStatusObject().getName() != "Закрыто" && newEpicState != "В процессе") {
newEpicState = "Сделать"
}
}
}
def epicStatusCf = customFieldManager.getCustomFieldObjects(epic).find {it.name == 'Epic Status'}
log.warn "Current epic status: " + epicStatusCf.getValue(epic)
FieldConfig epicStatusFieldConfig = epicStatusCf.getRelevantConfig(epic);
String oldStatus = epicStatusCf.getValue(epic)
log.warn "New epic status: " + newEpicState
// Set new status if it necessary
if (oldStatus != newEpicState) {
Options epicStatusOptions = optionsManager.getOptions(epicStatusFieldConfig);
Option epicStatusDoneOption = epicStatusOptions.getOptionForValue(newEpicState, null);
epicStatusCf.updateValue(null, epic, new ModifiedValue(epic.getCustomFieldValue(epicStatusCf),epicStatusDoneOption),changeHolder)
log.warn "Epic status is updated!"
}
If you're using Scriptrunner then you should be good to use the scriptrunner code. Please check this code from scriptrunner:
// Add the next line as a condition to the script listener, so it gets executed only for epic issues, the line must be written uncommented:
// issue.isEpic
// Check if the resolution has been changed
def resolutionChange = changelog.items.find {
(it as Map).field == 'resolution'
} as Map
logger.info("The resolution change of issue '${issue.key}': ${resolutionChange}.")
if (!resolutionChange) {
logger.info("The resolution didn't change.")
return
}
// Compute the 'Epic Status' value to set based on the resolution value
def newEpicStatusValue = (resolutionChange.toString == 'Done') ? 'Done' : 'To Do'
// Get the 'Epic Status' field ID
final epicStatusField = get("/rest/api/2/field")
.asObject(List)
.body
.find {
(it as Map).name == 'Epic Status'
} as Map
def epicStatusFieldId = epicStatusField.id
logger.info("Updating Epic Status field (${epicStatusFieldId}) to '${newEpicStatusValue}'.")
// Update the 'Epic Status' field value
put("/rest/api/2/issue/${issue.key}")
.queryString("overrideScreenSecurity", Boolean.TRUE)
.header("Content-Type", "application/json")
.body([
fields: [
(epicStatusFieldId): [value: newEpicStatusValue]
]
])
.asString()
You can automate this code your post-function or automation in jira. Please find the further details in this link.

Curious call of merge inside un-true if case

If sample is not null the line with merge(..) is called while the other 5 lines in the if are not. Why the ****? I'm jumping out the window soon...
class SampleService {
def markError(def job, def prop) {
def sample = job.getSamples().find { sample ->
sample.getProp() == prop }
if (sample == null) {
log.debug("i can see this only when sample == null")
println "i can see this only when sample == null"
def newSample = new Sample(prop: prob)
newSample.setJob(job)
newSample.merge(flush: true, failOnError: true)
}
}
}
I did already:
grails clean & grails compile.
deleted target folder and bin folder.
restarted app several times.
checked with intellij and eclipse.
I was missguided by the debuggers: The line has not been executed but highlighted. I don't know why it has been highlighted.
Hope this prevents anyone else from going crazy! :)

Grails - How Do I Show Version And Build Date/Time In My Application

I'd like to know if there is a way to display the version and build date at the top of my Grails application.
Edit: I should have said I'm looking for the Date/Time the app was built.
In your main template, or wherever.
<p style="float:right">Server version: <%=ApplicationHolder.application.metadata['app.version']%></p>
You can use <g:if env="..."> to limit by environments if you wish.
Build date is trickier, and probably doesn't mean anything. Do you never build twice on the same day? Same hour? I'm sticking the svn revision in my application version before the build to identify builds, as such:
_Events.groovy
eventWarStart = { type ->
addSvnRevisionToAppVersion()
}
private def addSvnRevisionToAppVersion() {
try {
DAVRepositoryFactory.setup();
SVNRepositoryFactoryImpl.setup();
FSRepositoryFactory.setup();
SVNClientManager clientManager = SVNClientManager.newInstance();
SVNWCClient wcClient = clientManager.getWCClient();
File baseFile = new File(basedir);
SVNInfo svninfo = wcClient.doInfo(baseFile, SVNRevision.WORKING);
def svnRevision = svninfo.getRevision().number;
String oldVersion = metadata.'app.version'
String newVersion
if (oldVersion.matches(/.*\.r\d+/)) {
newVersion = oldVersion.replaceAll(/\.r\d+/, ".r${svnRevision}");
}
else {
newVersion = oldVersion + ".r${svnRevision}".toString()
}
metadata.'app.version' = newVersion
metadata.persist()
}
catch (SVNException ex) {
println "**************** SVN exception **************"
println ex.getMessage();
}
}
Note that instead of appending svn revision, you could just append new Date() to get the build date.
i havent tried it my self but there is something like
grails set-version 20110101-3
def version = grailsApplication.metadata['app.version']
for more info refer to documentation
Any one looking for the solution for grails 3. It can be done by configuring the buildProperties task
buildProperties {
inputs.property("info.app.build.date", new Date().format('yyyy-MM-dd HH:mm:ss'))
}
<g:meta name="info.app.build.date"/>
See Adding build date and other custom info to war

Resources