Skip to main content
How to create a Confluence page from a Jira post function
Share on socials
A lightbulb
Tiffany Wortham
Tiffany Wortham
17th November, 2020
Confluence
Jira
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.
1package examples
2
3import com.atlassian.applinks.api.ApplicationLink
4import com.atlassian.applinks.api.ApplicationLinkService
5import com.atlassian.applinks.api.application.confluence.ConfluenceApplicationType
6import com.atlassian.jira.component.ComponentAccessor
7import com.atlassian.jira.issue.Issue
8import com.atlassian.sal.api.component.ComponentLocator
9import com.atlassian.sal.api.net.Request
10import com.atlassian.sal.api.net.Response
11import com.atlassian.sal.api.net.ResponseException
12import com.atlassian.sal.api.net.ResponseHandler
13import groovy.json.JsonBuilder
14import groovy.json.JsonSlurper
15import org.jsoup.Jsoup
16
17/**
18 * Retrieve the primary confluence application link
19 * @return confluence app link
20 */
21def getPrimaryConfluenceLink() {
22    def applicationLinkService = ComponentLocator.getComponent(ApplicationLinkService.class)
23    final ApplicationLink conflLink = applicationLinkService.getPrimaryApplicationLink(ConfluenceApplicationType.class)
24    conflLink
25}
26
27// the issue provided to us in the binding
28Issue issue = issue
29
30def confluenceLink = getPrimaryConfluenceLink()
31assert confluenceLink // must have a working app link set up
32
33def authenticatedRequestFactory = confluenceLink.createImpersonatingAuthenticatedRequestFactory()
34
35// set the page title - this should be unique in the space or page creation will fail
36def pageTitle = issue.key + " Sales Improvement Plan"
37def htmlCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("customfield_10201")
38def xmlCustomField = ComponentAccessor.getCustomFieldManager().getCustomFieldObject("customfield_10202")
39def xml = Jsoup.parse(issue.getCustomFieldValue(xmlCustomField).toString())
40def locations = xml.getElementsByTag("locations").collect {
41    it.text()
42}.join(" ")
43// since my field renders html with the html macro, I need to strip it out before adding my html to the page
44def parsedHtmlFieldValue = issue.getCustomFieldValue(htmlCustomField).toString().replaceAll("\\{html}", '')
45
46def pageBody = """<p> ${issue.description} </p>
47${parsedHtmlFieldValue}
48
49<p> Locations: ${locations} </p>
50
51<p> Use this page to discuss our sales improvement plan </p>
52"""
53
54def params = [
55    type : "page",
56    title: pageTitle,
57    space: [
58        key: "SAL" // set the space key - or calculate it from the project or something
59    ],
60    body : [
61        storage: [
62            value         : pageBody,
63            representation: "storage"
64        ],
65    ],
66]
67
68authenticatedRequestFactory
69    .createRequest(Request.MethodType.POST, "rest/api/content")
70    .addHeader("Content-Type", "application/json")
71    .setRequestBody(new JsonBuilder(params).toString())
72    .execute(new ResponseHandler<Response>() {
73        @Override
74        void handle(Response response) throws ResponseException {
75            if (response.statusCode != HttpURLConnection.HTTP_OK) {
76                throw new Exception(response.getResponseBodyAsString())
77            } else {
78                def webUrl = new JsonSlurper().parseText(response.responseBodyAsString)["_links"]["webui"]
79            }
80        }
81    })
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!