Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 19 additions & 18 deletions manifest.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
modules:
# Trigger is used to invoke a function when a Jira issue event is fired.
# https://developer.atlassian.com/platform/forge/manifest-reference/modules/trigger/
# trigger:
# - key: issue-trigger
# function: webhook
# # https://developer.atlassian.com/platform/forge/events-reference/jira/#issue-events
# events:
# - avi:jira:created:issue
# - avi:jira:updated:issue
# filter:
# ignoreSelf: true # Prevents infinite loops by ignoring self-generated events
# # expression: event.issue.fields.issuetype.name == 'Bug' # Optional: example filter for bug issues only
# onError: IGNORE_AND_LOG # Will invoke function and log errors
trigger:
- key: installation-trigger
function: webhook
events:
# https://developer.atlassian.com/platform/forge/events-reference/life-cycle/
- avi:forge:installed:app # Doesn't include un-installation
- avi:forge:upgraded:app

# The jira module provides functionality for Jira products.
jira:issuePanel:
Expand All @@ -27,20 +23,25 @@ modules:
function:
- key: resolver
handler: index.handler
# - key: webhook
# handler: webhook.handler
- key: webhook
handler: webhook.handler

# https://developer.atlassian.com/platform/forge/manifest-reference/resources/#resources
resources:
- key: main
path: src/frontend/index.jsx

# https://developer.atlassian.com/platform/forge/manifest-reference/#app
app:
runtime:
name: nodejs20.x # Has to be 'sandbox', 'nodejs18.x', 'nodejs20.x'
id: ari:cloud:ecosystem::app/f434bcc5-834f-45e5-ba1d-62e2ee8952cd
runtime:
name: nodejs20.x # https://developer.atlassian.com/platform/forge/manifest-reference/#runtime
# licensing:
# enabled: true # https://developer.atlassian.com/platform/marketplace/listing-forge-apps/#enabling-licensing-for-your-app

# Environment variables are not supported in the manifest.yml file.
# https://developer.atlassian.com/platform/forge/manifest-reference/permissions/
# It takes a few hours to 1 day to update here: https://developer.atlassian.com/console/myapps/f434bcc5-834f-45e5-ba1d-62e2ee8952cd/manage/permissions
# Environment variables are not supported in "permissions" section.
# https://developer.atlassian.com/platform/forge/manifest-reference/permissions/
# It takes a few hours to 1 day to update here: https://developer.atlassian.com/console/myapps/f434bcc5-834f-45e5-ba1d-62e2ee8952cd/manage/permissions
permissions:
scopes:
- storage:app
Expand Down
77 changes: 60 additions & 17 deletions src/webhook.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,66 @@
// Handle only webhook events
import forge, { route } from "@forge/api";

export const handler = async (event, context) => {
console.log("Event: ", event);
console.log("Context: ", context);
const { changelog } = event;
console.log("Changelog: ", changelog);
// https://developer.atlassian.com/platform/forge/events-reference/life-cycle/
console.log("Installation event payload:", event);
console.log("Context:", context);

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

if (event.type === "avi:jira:updated:issue") {
return handleIssueUpdated(event);
}
};
// Extract cloudId and contextToken
const cloudId = event.context.cloudId;
const contextToken = event.contextToken;

const handleIssueCreated = async (event) => {
console.log("Issue created");
};
try {
let startAt = 0;
const maxResults = 50; // Number of results per page
let allProjects = [];
let isLastPage = false;

while (!isLastPage) {
// https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-projects/#api-rest-api-3-project-search-get
const url = route`/rest/api/3/project/search?startAt=${startAt}&maxResults=${maxResults}`;
const response = await forge
.asApp()
.requestJira(url, { headers: { Accept: "application/json" } });

// Add status code checking and response logging
if (!response.ok) {
console.error("API request failed:", {
status: response.status,
statusText: response.statusText,
body: await response.text(),
});
throw new Error(`API request failed with status ${response.status}`);
}

const result = await response.json();
// console.log("Raw API response:", JSON.stringify(result, null, 2));
const { values, total, isLast } = result;

allProjects = [...allProjects, ...values];
isLastPage = isLast;
startAt += maxResults;

console.log(`Fetched ${values.length} projects. Total: ${total}. Page complete: ${isLast}`);
}

console.log(
"All projects found:",
allProjects.map((p) => ({
id: p.id,
key: p.key,
name: p.name,
}))
);
} catch (error) {
console.error("Error fetching projects:", error);
}
} else if (event.eventType === "avi:forge:upgraded:app") {
console.log("App was upgraded!");
// Handle upgrade logic here
}

const handleIssueUpdated = async (event) => {
console.log("Issue updated");
return { status: 200, body: "Installation event processed" };
};
Loading