jiraCloud/services/jiraProcessor.js
jmcqueen 449550cb54 Add webhook skip diagnostics for approval processing.
Log why REQUEST/CHANGE webhooks are ignored and warn when no pending approvers are found, making notification failures easier to trace.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-17 09:15:28 -04:00

117 lines
5.1 KiB
JavaScript

import { buildChangeApproval, buildRequestApproval } from './approvalCards.js';
export function createJiraProcessor({ config, requests, jiraService, webexService, log }) {
const { logger, logWarn, logError } = log;
const approvalRoomId = config.rooms.approval;
function handleApprovalNotifications(issueKey, jiraTicket, buildApprovalFn) {
buildApprovalFn(jiraTicket, log)
.then(approvalCard => jiraService.buildApprovers(issueKey).then(approvers => ({ approvalCard, approvers })))
.then(({ approvalCard, approvers }) => {
const cardPayload = {
text: approvalCard.message,
attachments: [{ contentType: 'application/vnd.microsoft.card.adaptive', content: approvalCard.card }],
};
for (const approver of approvers) {
logger('processJiraTicket', `Notifying ${issueKey} --> ${approver}`);
webexService.sendTicketCard(issueKey, { toPersonEmail: approver, ...cardPayload });
}
if (approvers.length > 0) {
webexService.sendTicketCard(issueKey, { roomId: approvalRoomId, ...cardPayload });
} else {
logWarn('processJiraTicket', `${issueKey} no pending approvers found after Jira lookup — no Webex messages sent`);
}
})
.catch(error => logError('processJiraTicket', `Failed approval notifications for ${issueKey}`, error));
}
function processJiraTicket(jiraTicket) {
if (!jiraTicket?.issue?.key) {
logError('processJiraTicket', 'Missing issue key in webhook payload');
return;
}
const issueKey = jiraTicket.issue.key;
const projectKey = jiraTicket.issue.fields?.project?.key;
const requestTypeField = jiraTicket.issue.fields?.customfield_10010;
const requestType = requestTypeField?.requestType?.id != null
? String(requestTypeField.requestType.id)
: undefined;
const transitionId = jiraTicket.transition?.transitionId != null
? String(jiraTicket.transition.transitionId)
: undefined;
const webhookEvent = jiraTicket.webhookEvent || 'unknown';
logger(
'processJiraTicket',
`${issueKey} event=${webhookEvent} project=${projectKey || '?'} requestType=${requestType || '?'} transition=${transitionId || 'none'}`
);
if (projectKey !== 'CHANGE' && projectKey !== 'REQUEST') {
logWarn('processJiraTicket', `${issueKey} skipped: project ${projectKey} is not CHANGE or REQUEST`);
return;
}
if (!requestType) {
logWarn('processJiraTicket', `${issueKey} skipped: missing request type in customfield_10010`);
return;
}
if (!requests[requestType]) {
logWarn(
'processJiraTicket',
`${issueKey} skipped: request type ${requestType} (${requestTypeField.requestType?.name || 'unknown'}) is not configured in requests.json`
);
return;
}
logger('processJiraTicket', `${issueKey} matched request config: ${JSON.stringify(requests[requestType])}`);
if (transitionId && requests[requestType].transitions[transitionId]) {
logger('processJiraTicket', `${issueKey} matched transition ${transitionId} (${requests[requestType].transitions[transitionId].name})`);
if (projectKey == 'CHANGE') {
handleApprovalNotifications(issueKey, jiraTicket, buildChangeApproval);
} else {
handleApprovalNotifications(issueKey, jiraTicket, buildRequestApproval);
}
return;
}
if (!jiraTicket.changelog) {
if (transitionId) {
logWarn(
'processJiraTicket',
`${issueKey} skipped: transition ${transitionId} is not configured for request type ${requestType}`
);
} else {
logWarn('processJiraTicket', `${issueKey} skipped: no transition and no changelog in webhook`);
}
return;
}
const approvalStatuses = ['Pending Approval', 'Emergency Approval', 'Waiting for approval'];
const statusName = jiraTicket.issue.fields?.status?.name;
let approverChange = false;
for (const change of jiraTicket.changelog.items) {
if (change.field != 'Approvers' || !approvalStatuses.includes(statusName)) {
continue;
}
approverChange = true;
if (projectKey == 'CHANGE') {
handleApprovalNotifications(issueKey, jiraTicket, buildChangeApproval);
} else {
handleApprovalNotifications(issueKey, jiraTicket, buildRequestApproval);
}
}
if (!approverChange) {
logWarn(
'processJiraTicket',
`${issueKey} skipped: changelog did not include an Approvers update in an approval status (status=${statusName || '?'})`
);
}
}
return { processJiraTicket };
}