Skip to content

Commit 34fa7a7

Browse files
committed
Listen forge app installation event (not uninstallation)
1 parent 096ac25 commit 34fa7a7

File tree

2 files changed

+79
-35
lines changed

2 files changed

+79
-35
lines changed

manifest.yml

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
modules:
22
# Trigger is used to invoke a function when a Jira issue event is fired.
33
# https://developer.atlassian.com/platform/forge/manifest-reference/modules/trigger/
4-
# trigger:
5-
# - key: issue-trigger
6-
# function: webhook
7-
# # https://developer.atlassian.com/platform/forge/events-reference/jira/#issue-events
8-
# events:
9-
# - avi:jira:created:issue
10-
# - avi:jira:updated:issue
11-
# filter:
12-
# ignoreSelf: true # Prevents infinite loops by ignoring self-generated events
13-
# # expression: event.issue.fields.issuetype.name == 'Bug' # Optional: example filter for bug issues only
14-
# onError: IGNORE_AND_LOG # Will invoke function and log errors
4+
trigger:
5+
- key: installation-trigger
6+
function: webhook
7+
events:
8+
# https://developer.atlassian.com/platform/forge/events-reference/life-cycle/
9+
- avi:forge:installed:app # Doesn't include un-installation
10+
- avi:forge:upgraded:app
1511

1612
# The jira module provides functionality for Jira products.
1713
jira:issuePanel:
@@ -27,20 +23,25 @@ modules:
2723
function:
2824
- key: resolver
2925
handler: index.handler
30-
# - key: webhook
31-
# handler: webhook.handler
26+
- key: webhook
27+
handler: webhook.handler
3228

29+
# https://developer.atlassian.com/platform/forge/manifest-reference/resources/#resources
3330
resources:
3431
- key: main
3532
path: src/frontend/index.jsx
33+
34+
# https://developer.atlassian.com/platform/forge/manifest-reference/#app
3635
app:
37-
runtime:
38-
name: nodejs20.x # Has to be 'sandbox', 'nodejs18.x', 'nodejs20.x'
3936
id: ari:cloud:ecosystem::app/f434bcc5-834f-45e5-ba1d-62e2ee8952cd
37+
runtime:
38+
name: nodejs20.x # https://developer.atlassian.com/platform/forge/manifest-reference/#runtime
39+
# licensing:
40+
# enabled: true # https://developer.atlassian.com/platform/marketplace/listing-forge-apps/#enabling-licensing-for-your-app
4041

41-
# Environment variables are not supported in the manifest.yml file.
42-
# https://developer.atlassian.com/platform/forge/manifest-reference/permissions/
43-
# It takes a few hours to 1 day to update here: https://developer.atlassian.com/console/myapps/f434bcc5-834f-45e5-ba1d-62e2ee8952cd/manage/permissions
42+
# Environment variables are not supported in "permissions" section.
43+
# https://developer.atlassian.com/platform/forge/manifest-reference/permissions/
44+
# It takes a few hours to 1 day to update here: https://developer.atlassian.com/console/myapps/f434bcc5-834f-45e5-ba1d-62e2ee8952cd/manage/permissions
4445
permissions:
4546
scopes:
4647
- storage:app

src/webhook.js

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,66 @@
1-
// Handle only webhook events
1+
import forge, { route } from "@forge/api";
2+
23
export const handler = async (event, context) => {
3-
console.log("Event: ", event);
4-
console.log("Context: ", context);
5-
const { changelog } = event;
6-
console.log("Changelog: ", changelog);
4+
// https://developer.atlassian.com/platform/forge/events-reference/life-cycle/
5+
console.log("Installation event payload:", event);
6+
console.log("Context:", context);
77

8-
if (event.type === "avi:jira:created:issue") {
9-
return handleIssueCreated(event);
10-
}
8+
if (event.eventType === "avi:forge:installed:app") {
9+
console.log("App was installed!");
1110

12-
if (event.type === "avi:jira:updated:issue") {
13-
return handleIssueUpdated(event);
14-
}
15-
};
11+
// Extract cloudId and contextToken
12+
const cloudId = event.context.cloudId;
13+
const contextToken = event.contextToken;
1614

17-
const handleIssueCreated = async (event) => {
18-
console.log("Issue created");
19-
};
15+
try {
16+
let startAt = 0;
17+
const maxResults = 50; // Number of results per page
18+
let allProjects = [];
19+
let isLastPage = false;
20+
21+
while (!isLastPage) {
22+
// https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-projects/#api-rest-api-3-project-search-get
23+
const url = route`/rest/api/3/project/search?startAt=${startAt}&maxResults=${maxResults}`;
24+
const response = await forge
25+
.asApp()
26+
.requestJira(url, { headers: { Accept: "application/json" } });
27+
28+
// Add status code checking and response logging
29+
if (!response.ok) {
30+
console.error("API request failed:", {
31+
status: response.status,
32+
statusText: response.statusText,
33+
body: await response.text(),
34+
});
35+
throw new Error(`API request failed with status ${response.status}`);
36+
}
37+
38+
const result = await response.json();
39+
// console.log("Raw API response:", JSON.stringify(result, null, 2));
40+
const { values, total, isLast } = result;
41+
42+
allProjects = [...allProjects, ...values];
43+
isLastPage = isLast;
44+
startAt += maxResults;
45+
46+
console.log(`Fetched ${values.length} projects. Total: ${total}. Page complete: ${isLast}`);
47+
}
48+
49+
console.log(
50+
"All projects found:",
51+
allProjects.map((p) => ({
52+
id: p.id,
53+
key: p.key,
54+
name: p.name,
55+
}))
56+
);
57+
} catch (error) {
58+
console.error("Error fetching projects:", error);
59+
}
60+
} else if (event.eventType === "avi:forge:upgraded:app") {
61+
console.log("App was upgraded!");
62+
// Handle upgrade logic here
63+
}
2064

21-
const handleIssueUpdated = async (event) => {
22-
console.log("Issue updated");
65+
return { status: 200, body: "Installation event processed" };
2366
};

0 commit comments

Comments
 (0)