Jira Cloud app: Hello World!

In this article we will develop a Jira Cloud app using atlassian-connect-spring-boot.

To follow this tutorial you would need maven, ngrok and IntelliJ Idea installed on your PC.

You can see the source code of this app here.

Create project with atlassian-connect-spring-boot

First we will create our project with atlassian-connect-spring-boot. To do it you need to execute the following command in your terminal:

mvn archetype:generate -DarchetypeGroupId=com.atlassian.connect -DarchetypeArtifactId=atlassian-connect-spring-boot-archetype

First, you will be asked to provide groupid, artifactid, version and package. I answered this way:

Define value for property 'groupId': ru.matveev.alexey.atlassian.cloud.tutorial
Define value for property 'artifactId': hello-world
Define value for property 'version' 1.0-SNAPSHOT: : 
Define value for property 'package' ru.matveev.alexey.atlassian.cloud.tutorial: : 

Then confirm your input with the Y input:

Confirm properties configuration:
groupId: ru.matveev.alexey.atlassian.cloud.tutorial
artifactId: hello-world
version: 1.0-SNAPSHOT
package: ru.matveev.alexey.atlassian.cloud.tutorial
 Y: : Y

A new folder called hello-world will be created. Move to this folder with:

cd hello-world

Add a new page to your app

The entry point for Jira Cloud app is src/main/resources/atlassian-connect.json. This file is read by Jira Cloud when you install your app to a Jira Cloud instance.

Right now the contents of this file is the following:

{
  "key": "${addon.key}",
  "baseUrl": "${addon.base-url}",
  "name": "Hello World",
  "authentication": {
    "type": "jwt"
  },
  "lifecycle": {
    "installed": "/installed",
    "uninstalled": "/uninstalled"
  },
  "scopes": ["READ"]
}

Nothing much is going on there. We will add a new page to our app so that we could call this page from our Jira Cloud instance and get the “Hello World” message.

First let’s add the following part to our atlassian-connect.json:

"modules": {
    "generalPages": [
      {
        "key": "helloworld-page-jira",
        "location": "system.top.navigation.bar",
        "name": {
          "value": "Hello World"
        },
        "url": "/helloworld"
      }
    ]
  }

These lines will add a menu to the system.top.navigation.bar menu with the “Hello World” label. Upon clicking on the “Hello World” label the /helloworld method will be called from our app. This helloworld method should return an html template with the “Hello World” message.

Add helloworld method

Create file src/main/java/ru/matveev/alexey/atlassian/cloud/tutorial/controller/HelloWorldController.java with the following text:

package ru.matveev.alexey.atlassian.cloud.tutorial.controller;

import com.atlassian.connect.spring.IgnoreJwt;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;


@Controller
public class HelloWorldController {

        @GetMapping("/helloworld")
        @IgnoreJwt
        public String helloworld() {
            return "helloworld";
        }
}

Here we create a controller with the helloworld method which returns the helloworld view. This method has @IgnoreJwt annotation, which means that if we want to call this method, then the JWT token will not be checked (Atlassian uses JWT auth for Cloud apps. You can read more here). We need to ingnore the JWT token to test our app on our localhost. Later we will comment this annotation.

Create helloworld view

We will call our view with thymeleaf. That is why you need to add dependency into the pom.xml file:

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Here is the complete pom.xml file so far:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
    </parent>

    <groupId>ru.matveev.alexey.atlassian.cloud.tutorial</groupId>
    <artifactId>hello-world</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <atlassian-connect-spring-boot.version>2.1.1</atlassian-connect-spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atlassian.connect</groupId>
            <artifactId>atlassian-connect-spring-boot-starter</artifactId>
            <version>${atlassian-connect-spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>com.atlassian.connect</groupId>
            <artifactId>atlassian-connect-spring-boot-jpa-starter</artifactId>
            <version>${atlassian-connect-spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <build>
        <defaultGoal>spring-boot:run</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>versions-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>display-spring-boot-dependency-updates</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>display-parent-updates</goal>
                            <goal>display-property-updates</goal>
                        </goals>
                        <configuration>
                            <includeProperties>atlassian-connect-spring-boot.version</includeProperties>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>default</id>
            <activation>
                <property>
                    <name>!spring.profiles.active</name>
                </property>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>org.hsqldb</groupId>
                    <artifactId>hsqldb</artifactId>
                    <scope>runtime</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-devtools</artifactId>
                    <optional>true</optional>
                </dependency>
            </dependencies>
        </profile>
    </profiles>
</project>

And now you can create the src/main/resources/templates/helloworld.html file with the following contents:

<!DOCTYPE html>
<html lang="en">
<body>
<section id="content" class="ac-content">
    <h1>Hello World</h1>
</section>
</body>
</html><!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="https://unpkg.com/@atlaskit/css-reset@2.0.0/dist/bundle.css" media="all">
    <script src="https://connect-cdn.atl-paas.net/all.js" async></script>
</head>
<body>
<section id="content" class="ac-content">
    <h1>Hello World</h1>
</section>
</body>
</html>

Run our application on localhost

Now we can run our application on localhost. I run my application from IntelliJ Idea like this:

After the program started we can call it with localhost:8080 in our browser. If everything works you should see the contents of atlassian-connect.json file:

Now we can try our helloworld endpoint with localhost:8080/helloworld. You should see the Hello World message:

Run in Jira Cloud

Comment @IgnoreJWT in our helloworld controller.

Create a Jira Cloud dev instance. You can find instructions here.

I do not have a static ip that is why I need ngrok to provide a tunnel to my pc so that I could connect to my app running on my localhost from internet. Our application runs on port 8080. That is why we need to launch ngrok with the following command:

./ngrok http 8080

Copy the https link to your application (your link will be different form mine):

Now insert this link into src/main/resources/application.yml file for the base-url parameter:

spring.jpa.hibernate.ddl-auto: none
spring.datasource.url: jdbc:hsqldb:file:addon-db # Use a file-based backing store for HSQL

addon:
  key: hello-world
  base-url: https://f42659855a77.ngrok.io

logging.level.com.atlassian.connect.spring: DEBUG

Now run our application as before.

Connect your app to your Jira Cloud

Open your Jira Cloud dev instance, go to Manage Apps and click the Settings button:

You will have the following screen:

Check the Enable development mode checkbox and click the Apply button.

Then push the Upload App button and enter your https path from ngrok:

Click the Upload button. After your app has been installed, you will see a confirmation screen:

Now choose Apps -> Hello World:

And you should see the Hello World message:

Congratulations! Your app is working.

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Leave a Reply

%d bloggers like this:

Spelling error report

The following text will be sent to our editors: