Last updatedAug 17, 2019

Getting started

This 5 min app tutorial shows you a preview of the Atlassian Connect for Bitbucket Cloud framework with a running app showing several of the functions and available extension points.

Bitbucket Cloud apps need to be hosted somewhere that is reachable by Bitbucket. So we use ngrok to proxy a port on your local machine to the public Internet and connect with your app.

Install prerequisites

Before you get building make sure you have the following tools installed:

Okay, now you've got what you need, let's get going.

Create a simple web application to stand in as an app

Now, you're ready to build an example app.

  1. Run the following command:

    1
    $ atlas-connect new a-quick-addon -t bitbucket

    This will create a subdirectory named a-quick-addon.

  2. Switch to the a-quick-addon directory.

  3. Download all the dependencies for this app by running the command npm install.
  4. Open a new shell and run the following command: ngrok http 3000. This will expose a local port on your machine to the Internet which the app can use to communicate with Bitbucket. Leave this running in your shell. You'll see output similar to this: ngrok
  5. Copy the https forwarding address from the response, highlighted in blue in the preceding example.
  6. Open a new shell (in addition to the one running ngrok) and start the node process with the following command (Replace the URL https://2c57c047.ngrok.com/ with the https:// address you copied from ngrok).

    1
    $ AC_LOCAL_BASE_URL=https://2c57c047.ngrok.com/ npm run start
  7. Then create the app by going to https://bitbucket.org/account/apps and inputting your ngrok URL to the "Create an app" form.

  8. Once your app is created, navigate to https://bitbucket.org/account/addon-management and install the app into your account so you can test it, by clicking "Install add-on from URL" and then inputting the same URL as in step 7.

You should be able to browse to a Bitbucket Cloud repository you own and see the example extension points registered by your app.

Updating the app

Whenever you make changes to the descriptor and you would like to have existing installations receive this update, head back to https://bitbucket.org/account/apps and find the application you created. By clicking "Update", Bitbucket will fetch the latest version of your descriptor and then apply it to all the installations of your app.

If your descriptor update contains an increase in the amount of scopes the app requests, an email will be sent to account owners for accounts where your app is installed, and they will need to manually approve the update, and until they do this they will still see the previous version of your app descriptor.

Anatomy of the example app

The app descriptor is a JSON file that describes the app modules and end-points implemented by your app. It sits in the root of your app project at atlassian-connect.json and is served at your app's base URL.

The descriptor included in the example app subscribes to all repository events via webhooks and registers a webPanel, webItem, and repoPage.

Routes

There are three routes for the app defined in routes/index.js:

  • / simply forwards to /atlassian-connect.json, and serves the descriptor.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    app.get('/', function (req, res) {
        res.format({
            // If the request content-type is text-html, it will decide which to serve up
            'text/html': function () {
                res.redirect('/atlassian-connect.json');
            },
            // This logic is here to make sure that the `atlassian-connect.json` is always
            // served up when requested by the host
            'application/json': function () {
                res.redirect('/atlassian-connect.json');
            }
        });
    });
  • /connect-example makes a JWT authenticated call to the Bitbucket Cloud API and renders a simple view that is used as the target for the webPanel and repoPage modules

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
        app.get('/connect-example', addon.authenticate(), function (req, res) {
    
        // the call to addon.authenticate() above verifies the JWT token provided by Bitbucket
        // in the iframe URL
    
        var httpClient = addon.httpClient(req);
    
        httpClient.get('/api/1.0/user/', function (err, resp, data) {
            data = JSON.parse(data);
            res.render('connect-example', {
                title: 'Atlassian Connect',
                displayName: data.user.display_name,
                repoPath: req.query.repoPath
            });
        });
    });
  • /webhook accepts and authenticates webhooks issued by Bitbucket Cloud and dumps them to the console (if you start updating your repositories while the app is running you should start seeing webhook output in your shell)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        app.post('/webhook', addon.authenticate(), function (req, res) {
    
            // log the webhook payload
            console.log(util.inspect(req.body, {
                colors:true,
                depth:null
            }));
            res.send(204);
    
        });
    
        // Add any additional route handlers you need for views or REST resources here...
    };

Views

The views and public directories contain the templates and static resources used to render the content of the webPanel and repoPage iframes.

The most interesting part is /public/js/addon.js, which uses AP.request() to make an authenticated cross-domain ajax call to the Bitbucket Cloud REST API and AP.cookie() to work around third-party cookie restrictions by setting a cookie on the host domain.

atlassian-connect-express

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Bitbucket Connect also supports a client side library - AP (for "Atlassian Plugins") - that
// allows you to interact with the host application. For example, you can make authenticated
// requests to the Bitbucket Cloud REST API ...

AP.require('request', function(request) {
    request({
        url: '/api/1.0/user/',
        success: function(data) {
            data = JSON.parse(data);
            $('#displayName')
                .text(data.user.display_name)
                .next('.loading').hide();
        }
    });
});

// ... and set cookies (browser security policies often prevent this from being done in iframes).

var COOKIE_NAME = 'example-visits';

AP.require('cookie', function(cookie) {
    cookie.read(COOKIE_NAME, function(visits) {
        visits = (visits ? parseInt(visits) : 0) + 1;
        cookie.save(COOKIE_NAME, visits, 30);
        $('#pageVisits')
            .text(visits)
            .next('.loading').hide();
    });
});

The atlassian-connect-express node package is providing the JWT authentication for both incoming requests, in the form of webhooks and iframes, and outbound requests to the Bitbucket Cloud REST API.

It is also providing app registration, installation handshake, persistence, and other bits and pieces that make up the app.