Course menuForge Kitchen

Level 1 · Lesson 7

Hang the bell

Run code when a dish ticket is created, with nobody looking at a card, and read what it did in the kitchen log.

About 20 min4 steps

Behind, or starting here? Download the code as it should be before this lesson.

So far the app only works when someone opens a card. Some work should happen by itself: when a new dish ticket goes up, the kitchen should check the supplier has the recipe. Jira can tell your app about events like that.

A product trigger

Someone creates a work item.

In the kitchen: A new dish ticket goes up.

Atlassian’s own products · House systems

Jira work items Dish tickets

A Jira issue. In this course each work item names one dish, such as “Pad thai”.

A ticket on the board for one dish.

Select any box in the diagram to see what it is.

Step 1: Write what happens when it rings

Runs in the Atlassian cloud · Back of house

Product trigger · the bell

A trigger module runs a function when something happens in the product, such as avi:jira:created:issue when a work item is created. The function gets an event with the details instead of a click, and nobody sees its answer. It is a separate function from the resolver, with its own key and handler.

In the kitchen A bell that rings in back of house whenever a new dish ticket goes up.

Atlassian docs: Product events (opens in a new tab)

Create src/bell.js. It reuses the supplier module, and writes what it finds to the log, because there is no card to show it on:

New filesrc/bell.js

A new file: look up the new ticket’s dish and write it to the log.

Added: import { findDish } from './supplier/apiNinjas';
Added:
Added: // Runs when a work item is created (avi:jira:created:issue).
Added: // No one is looking at a card here, so the result goes to the log.
Added: export async function run(event) {
Added: const { key, fields } = event.issue;
Added: const summary = fields?.summary ?? '';
Added: console.log(`Bell: ${key} "${summary}" went up.`);
Added: try {
Added: const dish = await findDish(summary, process.env.API_NINJAS_KEY);
Added: console.log(dish ? `Bell: the supplier has a recipe for ${dish.title}.` : `Bell: no recipe for "${summary}".`);
Added: } catch (error) {
Added: console.error('Bell: supplier lookup failed:', error.message);
Added: }
Added: }

Why: Product trigger · forge logs

The event carries the new work item, including its key and summary, so the function does not need to ask Jira for them.

Stuck? I changed code in src/

Step 2: Hang the bell on the licence

Jira sends avi:jira:created:issue to your trigger’s function. Nobody is looking at a card.The bell rings in back of house. Nobody is at the card.

Add two things to the manifest: the trigger, which says which event to listen for and which function to run, and the function itself, which points at the run export in src/bell.js:

Editmanifest.yml
  • A trigger that fires when a work item is created.
  • The function it runs.
render: native
title: Recipe card
icon: https://developer.atlassian.com/platform/forge/images/icons/issue-panel-icon.svg
Added: trigger:
Added: - key: new-ticket-bell
Added: function: bell
Added: events:
Added: - avi:jira:created:issue
function:
- key: resolver
handler: index.handler
Added: - key: bell
Added: handler: bell.run
resources:
- key: main
path: src/frontend/index.jsx

Why: Product trigger · Function

The scope from lesson 6, read:jira-work, also covers receiving work item events, so this needs no new permission.

Stuck? I changed manifest.yml

Step 3: Deploy the bell

A new module with no new permissions is a minor version: deploy, and the site picks it up by itself.

RunTerminal
forge deploy

Stuck? The tunnel is running while I deploy or upgrade · Deploy stops after a permission change

Step 4: Ring it, and read the kitchen log

Lives on your laptop · Home kitchen

forge logs · the kitchen log

forge logs shows what your functions wrote with console.log and console.error, and errors Forge caught, for the development environment by default. Lines can take a minute to arrive. With forge tunnel running, the same lines print in the tunnel’s terminal instead, as they happen.

In the kitchen The log where every station writes what it did and what went wrong.

Atlassian docs: Forge CLI reference (opens in a new tab)

The function looks the dish up and writes the result to the logs.The cook checks with the supplier and writes the answer in the kitchen log.

Create a dish ticket in the Kitchen space, such as Green curry. Wait a minute, then read the log:

RunTerminal
forge logs --since 15m
You should seeExampleYour keys, dishes and timestamps will differ.
$ forge logs --since 15m
INFO  Bell: KIT-4 "Green curry" went up.
INFO  Bell: the supplier has a recipe for Green Curry.

Stuck? I changed code in src/

Compare with yours: download the code after this lesson.

What you built

One app, in one folder: a recipe card on every dish ticket that reads the ticket as the person looking at it, buys the recipe from an outside supplier with a key nobody can see, and a bell that checks every new ticket by itself. Level 2 opens a back kitchen in the same app.

Check what you know

Eight questions on Level 1. Each answer explains itself.

  1. Question 1 of 8

    Where does src/resolvers/index.js run?

  2. Question 2 of 8

    The card calls invoke('getDish'). What has to exist for that to work?

  3. Question 3 of 8

    Where does the API Ninjas key live?

  4. Question 4 of 8

    You added api.api-ninjas.com to the manifest and ran forge deploy. It stops. What now?

  5. Question 5 of 8

    With forge tunnel running, you change the manifest. When does Jira see the change?

  6. Question 6 of 8

    How does getDish know which work item the card is on?

  7. Question 7 of 8

    readSummary calls api.asUser().requestJira(…). Which scope does the app need?

  8. Question 8 of 8

    Who sees what the bell’s function returns?

Type at least two letters.