I've installed ScriptRunner, where do I place my script? Do I have to create a plugin to use ScriptRunner?
I want ti use ScriptRunner to populate a custome field with a checkbox list of Confluence pages. If I need to crate a plugin do do this, why would I need ScriptRunner.
Also, is there a graphical IDE editor, not commad line, for creating JIRA/Confluence plugins?
Can I develop plugins for JIRA/Confluece in C#?
So, I'm a bit late to the party on this, but I think ScriptRunner can totally do something for your use case (that is, display or modify a checkbox custom field that lists a bunch of Confluence spaces). No need to write another plugin.
It sounds like your core goal is that when someone's editing an issue, you want them to be able to select a few different Confluence spaces. Is that right?
If so, there are a few ways you might approach the problem, but Scripted Fields aren't one of them--as Nic pointed out, those are just calculated fields, not custom fields that a user might modify through the UI.
I think the easiest way would be to make a classic checkbox field, and then use ScriptRunner to keep the options in sync with Confluence. Doing that would require a few parts:
I'll follow up with some more detailed code in a bit.
We're sorry it's been so hard for you to get started. To say a word about the docs, believe me, as a member of the ScriptRunner dev team, we're acutely aware of the need to make the docs more approachable. We're working with the Learning and Development team here at Adaptavist to improve them, as well as developing training to make it easier for people to get started with ScriptRunner.
I noticed you were having some trouble finding where to contact support. I haven't been able to find a support ticket from you, but if you can get back to me with your issue key, I can look it up and we can talk privately there if need be.
Thank you so much for the responce Jonny. This is very close to what I'm looking to do. The idea is to display a list of Confluence pages from a particular space/parent. Each item in the lisy would have a checkbox the user can select. JIRA would need to store the selected items, perferably page id, within JIRA. The text of each checkbox would be a link to the Confluence page.
Coding in JIRA/Confluence is new to me with Java. I'm a web developer that uses C# (MVC) so I'm familer with object oriented programming, html, javascript. I'm still getting use to Velocity and Groovy.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
No problem, Eric! So, here's a quick script I hacked together that you can run from the script console to get all the pages from a Confluence Space and add them as options to an existing Custom Field called "Confluence Pages". You'll want to modify some of the code to match your Confluence space's key and the name of your custom checkbox field.
import com.atlassian.applinks.api.ApplicationLinkResponseHandler import com.atlassian.applinks.api.ApplicationLinkService import com.atlassian.applinks.api.application.confluence.ConfluenceApplicationType import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.context.GlobalIssueContext import com.atlassian.sal.api.component.ComponentLocator import com.atlassian.sal.api.net.Response import com.atlassian.sal.api.net.ResponseException import groovy.json.JsonSlurper import static com.atlassian.sal.api.net.Request.MethodType.GET //Get the field and its options def customFieldManager = ComponentAccessor.customFieldManager def optionsManager = ComponentAccessor.optionsManager def confluencePagesField = customFieldManager.getCustomFieldObjectByName("Confluence Pages") def fieldConfigSchemeManager = ComponentAccessor.fieldConfigSchemeManager def globalIssueContext = GlobalIssueContext.getInstance() def configScheme = fieldConfigSchemeManager.getConfigSchemesForField(confluencePagesField)[0] def fieldConfig = configScheme?.oneAndOnlyConfig ?: fieldConfigSchemeManager.getRelevantConfig(globalIssueContext, confluencePagesField) def existingOptions = optionsManager.getOptions(fieldConfig) def appLinkService = ComponentLocator.getComponent(ApplicationLinkService) def appLink = appLinkService.getPrimaryApplicationLink(ConfluenceApplicationType) def applicationLinkRequestFactory = appLink.createAuthenticatedRequestFactory() def spaceKey = "ASDF" def request = applicationLinkRequestFactory.createRequest(GET, "/rest/api/content?spaceKey=$spaceKey") def handler = new ApplicationLinkResponseHandler<Map>() { @Override Map credentialsRequired(Response response) throws ResponseException { return null } @Override Map handle(Response response) throws ResponseException { assert response.statusCode == 200 new JsonSlurper().parseText(response.getResponseBodyAsString()) as Map } } def pagesFromConfluence = request.execute(handler)["results"] pagesFromConfluence.eachWithIndex{ pageInformation, int index -> def relativePageLink = pageInformation["_links"]["webui"] def pageIdAttribute = $/data-page-id="${pageInformation['id']}"/$ def linkToPage = $/<a href="${appLink.displayUrl}${relativePageLink}" $pageIdAttribute" >${pageInformation['title']}</a>/$ def option = existingOptions?.find { it.value.contains(pageIdAttribute)} if (!option){ optionsManager.createOption(fieldConfig, null, index + 1, linkToPage) } }
A few important notes:
To run this code as a scheduled service, you'd need to edit it a bit to set the authenticated user first.
import com.atlassian.applinks.api.ApplicationLinkResponseHandler import com.atlassian.applinks.api.ApplicationLinkService import com.atlassian.applinks.api.application.confluence.ConfluenceApplicationType import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.context.GlobalIssueContext import com.atlassian.sal.api.component.ComponentLocator import com.atlassian.sal.api.net.Response import com.atlassian.sal.api.net.ResponseException import groovy.json.JsonSlurper import static com.atlassian.sal.api.net.Request.MethodType.GET def jiraAuthenticationContext = ComponentAccessor.getJiraAuthenticationContext() def originalUser = jiraAuthenticationContext.getLoggedInUser() def userManager = ComponentAccessor.getUserManager() def adminUser = userManager.getUserByName("serviceAccount") assert adminUser // make sure an admin user called "deployer" exists in all instances try { jiraAuthenticationContext.setLoggedInUser(adminUser) // make REST requests here //Get the field and its options def customFieldManager = ComponentAccessor.customFieldManager def optionsManager = ComponentAccessor.optionsManager def confluencePagesField = customFieldManager.getCustomFieldObjectByName("Confluence Pages") def fieldConfigSchemeManager = ComponentAccessor.fieldConfigSchemeManager def globalIssueContext = GlobalIssueContext.getInstance() def configScheme = fieldConfigSchemeManager.getConfigSchemesForField(confluencePagesField)[0] def fieldConfig = configScheme?.oneAndOnlyConfig ?: fieldConfigSchemeManager.getRelevantConfig(globalIssueContext, confluencePagesField) def existingOptions = optionsManager.getOptions(fieldConfig) def appLinkService = ComponentLocator.getComponent(ApplicationLinkService) def appLink = appLinkService.getPrimaryApplicationLink(ConfluenceApplicationType) def applicationLinkRequestFactory = appLink.createAuthenticatedRequestFactory() def spaceKey = "ASDF" def request = applicationLinkRequestFactory.createRequest(GET, "/rest/api/content?spaceKey=$spaceKey") def handler = new ApplicationLinkResponseHandler<Map>() { @Override Map credentialsRequired(Response response) throws ResponseException { return null } @Override Map handle(Response response) throws ResponseException { assert response.statusCode == 200 new JsonSlurper().parseText(response.getResponseBodyAsString()) as Map } } def pagesFromConfluence = request.execute(handler)["results"] pagesFromConfluence.eachWithIndex { pageInformation, int index -> def relativePageLink = pageInformation["_links"]["webui"] def pageIdAttribute = $/data-page-id="${pageInformation['id']}"/$ def linkToPage = $/<a href="${appLink.displayUrl}${relativePageLink}" $pageIdAttribute" >${pageInformation['title']}</a>/$ def option = existingOptions?.find { it.value.contains(pageIdAttribute) } if (!option) { optionsManager.createOption(fieldConfig, null, index + 1, linkToPage) } } } finally { jiraAuthenticationContext.setLoggedInUser(originalUser) }
Again, change the username from serviceAccount to match a cross-product admin's username.
If you need further help with it, let us know. Coming from C#, I suspect you'll find Groovy relatively straightforward to learn, especially if you're used to coding with the Linq library; a lot of Groovy's collectors and iterator methods are analagous to those in Linq (though more intuitive IMHO). Warning: you may find that Groovy spoils you a bit. ;)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks - if there s an award for customer support, you just earned it.
Out of curiosity - what code editor do you use?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You're welcome! So glad we could help.
As to code editor, I use IntelliJ IDEA. We have some guidance on setting up a development environment using IDEA's community edition if you're interested. https://scriptrunner.adaptavist.com/latest/jira/DevEnvironment.html
Full disclosure: we are also hard at work at improving the code editing experience in the browser, but using an IDE with good Groovy support is currently the best way for a power user to start churning out scripts quickly, and will be for the near future.
Happy scripting, and don't hesitate to hit us up on here with a new question when you have one. Tagging your question with the formal (and rather unwieldy) tag of com.onresolve.jira.groovy.groovyrunner is a good way to make sure we see it.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Cool - I installed IntelliJ last week, just need to get it configured.
I did run into one compile issue. I chnaged the name of the space key and the name of my SR custome field to match mine. One thing I'm not sure of, how does this know I want checkboxes and a list of them? I'm not seeing any For loops to iterate over the pages and create chechboxes.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
So, the static type checker is not everything we wish it was. It's not perfectly aware of all of Groovy's dynamic abilities, so it thinks I'm passing bad data to a method when I'm not. You can ignore that error.
As for the loop, that's right there in this bit:
pagesFromConfluence.eachWithIndex { pageInformation, int index -> //...loop code here }
That's using the eachWithIndex method signature to loop. I only used the withIndex version because I needed an index for where the option should be put in the list. You can look at http://mrhaki.blogspot.com/2009/09/groovy-goodness-looping-in-different.html and some other resources for guidance on looping with Groovy. Of course, traditional Java for loops work just fine as well if you prefer that syntax.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
thx - I like the eachWithIndex. It's similar to the foreach in C#.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Jonny - what would I put in the Custom Template section?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Eric - are you still trying to make a Scripted Field? Remember, the script I wrote is meant to be run as a service that operates on a plain old JIRA Custom Field (a checkbox field, specifically). Putting that code I wrote into Script Field wouldn't work for what you're after. Remember, Script Fields are calculated fields that a user cannot edit. I think their use case is different from what you're trying to do.
If you're writing a Script Field for some other case, I'd suggest you take a look at the docs to start. https://scriptrunner.adaptavist.com/latest/jira/scripted-fields.html
You'll only need a custom template if one of the built-in templates (Free text field, HTML, Date Time, etc.) doesn't work for your script. If none the built-in templates work to render the data returned by your script field, then you can write a velocity template as described in the docs on custom templates.
Again, I don't think you need a Script Field for this use case. If you're trying to do something else, I'd suggest starting a new question thread so this doesn't get too confusing.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Eric -
As Jonny seems to be helping you through the issue, please would you consider modifying your review? https://marketplace.atlassian.com/plugins/com.onresolve.jira.groovy.groovyrunner/cloud/reviews
Regards, Jamie
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Maybe I missed something when I read through all the answers, but I don't think I actually saw an answer to the question "Where do I place a ScriptRunner script?". I have been using in-line scripts for behaviors, scripted fields, post-functions, etc. However, I have to do a lot of copy-paste that can be resolved by using files. Unfortunately, I don't know what file path to put for referencing files.
By default, JIRA will try to install itself on C:/Program Files/Atlassian. Is this where ScriptRunner will begin searching for scripts? Should I be creating directories under the "Atlassian" folder called "behaviors", "post-functions", etc. under the "Atlassian" directory to organize my scripts?
The title of this question seems to match what I'm asking.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I usually stick them in <jira home>/scripts, and then have a directory structure that represents a convenient storage pattern (usually directories for behaviours, conditions, post-functions and so-on, but sometimes we do it by project or specific block of work).
I tend to put them under source control as well, so I don't lose them.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi all,
For those who are struggling to find the folder to place your scripts, I found this link from another post that helped me:
https://scriptrunner.adaptavist.com/5.3.6/jira/#_script_roots
According to that documentation, a directory called "scripts" was created under your JIRA home directory.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I'm working in JIRA. I'm trying to create a user control that will display a checkbox list of Confluence pages that the user can select.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Ran into my first script issue. The inlline script does not recognize the line "import com.atlassian.confluence.spaces.SpaceManager" (without quote of cource).
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Could you clarify where you're working here? You appear to be trying to import Confluence libraries, but you talk about scripted fields, which are a JIRA thing. Which application are you in?
By the way, I see your point about the docs for Script Runner, it's something I will pick up with my boss next week. They're utterly dreadful. The content is there, but it's in totally the wrong structure. I can't justify that the scripted field page is even vaguely useful given that it says "A scripted field does X, now lets ramble about caching for the 1% of people who need to talk about it, and not mention how to start configuring or writing scripts for them"
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Ok, you can't import Confluence libraries into JIRA - they're part of Confluence.
A scripted field won't do this either. They are read-only data, so there's no "checkbox a user can select from"
I suspect what you need here is a full add-on, as your code will need to work out what links to display and put them on-screen for selection, and then write any selections somewhere into the issue when the user commits the change. SR could sort of do the first two, but you need a full custom field to do the third.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I finally found part of the answer. I found it in all places this link from Arsenal Dataplane. This is the type of information that should be include in the Script Runner documentation. A page with screenshot and maybe an exapmle would be nice.
*************************************************
Writing a Script for the Scripted Field
To define the functionality of the newly added Scripted Field:
Navigate to Toolgear » Add-ons and select Script Fields on the left-hand navigation menu
Scroll down to find your field, click the edit link, and write the script for your field
*************************************************
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
When I view the custom field based on scriptrunner, there isn't any place to enter a script. The only choice I have from the gear menu are Configure and Edit and neither of those have places to enter a script. When I look at the scriptrunner documentation, it doesn't have any description or visual to guide a new person like myself.
I'm trying to write a custom field that will get all the Coinfluence pages for a given space/parent and then create a multislect checkbox list where the user can select multiple Confluence pages.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Scriptrunner is mostly used to avoid having to write add-ons.
Scripts can live in two places, either inside JIRA itself, in the places where you use scriptrunner, or in files on the file system (or a mix). When you define where a script is used, you'll see the options - most of the scripting screens have three fields "Script description, script file location OR actual script"
Try going to edit a workflow, adding a "post function" and select the "write your own script" option, you'll see what I mean there.
That's also the answer for your "populate custom field" - you'll be able to write a script in there that can put the data into your custom field.
There is no GUI for ScriptRunner itself. The in-line script box has a basic error checker, but that's it. The reason is that it doesn't need one. You should use your favourite fully featured IDE for editing scripts. No need to re-invent the wheel. See https://scriptrunner.adaptavist.com/4.3.4/jira/DevEnvironment.html
Finally, although you could write add-ons in C#, it would be a right pain. The Atlassian applications are written in Java and variants, so it's a lot easier to write in Java, rather than have to implement a whole new framework. (Although if your code is external, like parts of Connect add-ons or things that talk to JIRA over REST, then it's fine, of course, because you're not inside the service and using its frameworks)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.