Skip to main content
How to create a Confluence page from a Jira post function
Share on socials
A lightbulb
Tiffany Wortham
Tiffany Wortham
17 November 2020
Data center icon
Server icon

How to create a Confluence page from a Jira post function

Want to learn how to create a Confluence page from a Jira workflow post function? Check out this walkthrough and free script.
During a recent webinar, a ScriptRunner user asked us this question:
How do I create a Confluence page from a Jira workflow post function with many multiline text Jira fields which have HTML and XML tags in their content? 
Below you will find guidance on how to achieve this, including the video demo and the Groovy code I used in the demo. Feel free to download it and use it for your own needs.
To illustrate the example, I created a Jira issue which has a custom field “Ideas to Increase Sales” which contains HTML, and a custom field “Store Locations” which contains XML.
A screenshot of a Jira ticket about pizza sales
I want to display HTML and data extracted from the XML in a Confluence page whenever the workflow transition to “Done” occurs. In order to achieve this, I’ll create a Custom Script Post Function on the “Done” workflow transition with the following script.
package examples

import com.atlassian.applinks.api.ApplicationLink
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.Issue
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.sal.api.net.Request
import com.atlassian.sal.api.net.Response
import com.atlassian.sal.api.net.ResponseException
import com.atlassian.sal.api.net.ResponseHandler
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
import org.jsoup.Jsoup

/**
 * Retrieve the primary confluence application link
 * @return confluence app link
 */
def getPrimaryConfluenceLink() {
    def applicationLinkService = ComponentLocator.getComponent(ApplicationLinkService.class)
    final ApplicationLink conflLink = applicationLinkService.getPrimaryApplicationLink(ConfluenceApplicationType.class)
    conflLink
}

// the issue provided to us in the binding
Issue issue = issue

def confluenceLink = getPrimaryConfluenceLink()
assert confluenceLink // must have a working app link set up

def authenticatedRequestFactory = confluenceLink.createImpersonatingAuthenticatedRequestFactory()

// set the page title - this should be unique in the space or page creation will fail
def pageTitle = issue.key + " Sales Improvement Plan"
def htmlCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("customfield_10201")
def xmlCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("customfield_10202")
def xml = Jsoup.parse(issue.getCustomFieldValue(xmlCustomField).toString())
def locations = xml.getElementsByTag("locations").collect {
    it.text()
}.join(" ")
// since my field renders html with the html macro, I need to strip it out before adding my html to the page
def parsedHtmlFieldValue = issue.getCustomFieldValue(htmlCustomField).toString().replaceAll("\\{html}", '')

def pageBody = """<p> ${issue.description} </p>
${parsedHtmlFieldValue}

<p> Locations: ${locations} </p>

<p> Use this page to discuss our sales improvement plan </p>
"""

def params = [
    type : "page",
    title: pageTitle,
    space: [
        key: "SAL" // set the space key - or calculate it from the project or something
    ],
    body : [
        storage: [
            value         : pageBody,
            representation: "storage"
        ],
    ],
]

authenticatedRequestFactory
    .createRequest(Request.MethodType.POST, "rest/api/content")
    .addHeader("Content-Type", "application/json")
    .setRequestBody(new JsonBuilder(params).toString())
    .execute(new ResponseHandler<Response>() {
        @Override
        void handle(Response response) throws ResponseException {
            if (response.statusCode != HttpURLConnection.HTTP_OK) {
                throw new Exception(response.getResponseBodyAsString())
            } else {
                def webUrl = new JsonSlurper().parseText(response.responseBodyAsString)["_links"]["webui"]
            }
        }
    })
Please note that in this example I’m using app links, as this is the most universal way to achieve something like this. However, the more complex your use case is, you may want to consider using ScriptRunner’s remote control feature. Hope that helps!

Step-by-step guide


If you would like to watch a step-by-step video demo of what I described above, check out this video.

Get a 30 day free trial

ScriptRunner for Confluence is an amazingly versatile tool that lets you customise, extend and automate Confluence as much as you need. Explore what you can achieve!