Stabilize logging, correlation IDs, service-account Jira auth, and direct approver reminder DMs while splitting the monolith into focused modules with Compose-based deployment. Co-authored-by: Cursor <cursoragent@cursor.com>
91 lines
3.4 KiB
JavaScript
91 lines
3.4 KiB
JavaScript
import dotenv from 'dotenv';
|
|
import fs from 'fs';
|
|
|
|
dotenv.config();
|
|
|
|
function envOrConfig(envKey, configValue) {
|
|
const envValue = process.env[envKey];
|
|
if (envValue !== undefined && envValue !== '') {
|
|
return envValue;
|
|
}
|
|
return configValue;
|
|
}
|
|
|
|
function resolveJiraHost(fileConfig) {
|
|
const cloudId = envOrConfig('JIRA_CLOUD_ID', fileConfig.jiraCloud?.cloudId)?.trim();
|
|
let baseUrl = envOrConfig('JIRA_BASE_URL', fileConfig.jiraCloud?.host || 'https://aeo.atlassian.net')?.trim();
|
|
|
|
if (cloudId) {
|
|
return `https://api.atlassian.com/ex/jira/${cloudId}`;
|
|
}
|
|
|
|
return baseUrl.replace(/\/$/, '');
|
|
}
|
|
|
|
export function loadConfig() {
|
|
const fileConfig = JSON.parse(fs.readFileSync('./config/config.json'));
|
|
|
|
const config = {
|
|
...fileConfig,
|
|
logLevel: envOrConfig('LOG_LEVEL', fileConfig.logLevel),
|
|
server: {
|
|
...fileConfig.server,
|
|
port: envOrConfig('PORT', fileConfig.server?.port),
|
|
name: envOrConfig('SERVER_NAME', fileConfig.server?.name),
|
|
},
|
|
webex: {
|
|
...fileConfig.webex,
|
|
token: envOrConfig('WEBEX_TOKEN', fileConfig.webex?.token),
|
|
room: {
|
|
...fileConfig.webex?.room,
|
|
id: envOrConfig('WEBEX_ROOM_ID', fileConfig.webex?.room?.id),
|
|
},
|
|
},
|
|
jiraNotifier: {
|
|
...fileConfig.jiraNotifier,
|
|
token: envOrConfig('JIRA_NOTIFIER_TOKEN', fileConfig.jiraNotifier?.token),
|
|
},
|
|
jiraCloud: {
|
|
...fileConfig.jiraCloud,
|
|
cloudId: envOrConfig('JIRA_CLOUD_ID', fileConfig.jiraCloud?.cloudId) || null,
|
|
host: resolveJiraHost(fileConfig),
|
|
siteUrl: (envOrConfig('JIRA_BASE_URL', fileConfig.jiraCloud?.host || 'https://aeo.atlassian.net') || '').replace(/\/$/, ''),
|
|
authType: (envOrConfig('JIRA_AUTH_TYPE', fileConfig.jiraCloud?.authType) || 'basic').toLowerCase(),
|
|
email: envOrConfig('JIRA_EMAIL', fileConfig.jiraCloud?.email),
|
|
token: envOrConfig('JIRA_API_TOKEN', fileConfig.jiraCloud?.token),
|
|
},
|
|
rooms: {
|
|
approval: envOrConfig(
|
|
'APPROVAL_ROOM_ID',
|
|
fileConfig.rooms?.approval || 'Y2lzY29zcGFyazovL3VzL1JPT00vZWQ4ZWY3OTAtMGE5NC0xMWVjLWExZDUtM2I5ZWNlNWFlNDI5'
|
|
),
|
|
support: envOrConfig(
|
|
'SUPPORT_ROOM_ID',
|
|
fileConfig.rooms?.support || 'Y2lzY29zcGFyazovL3VzL1JPT00vZWY4MmExNjAtNzYzNS0xMWU4LWFlYWMtNjNjMGMyMTExYTVm'
|
|
),
|
|
},
|
|
};
|
|
|
|
return config;
|
|
}
|
|
|
|
export function loadRequests() {
|
|
return JSON.parse(fs.readFileSync('./config/requests.json'));
|
|
}
|
|
|
|
export function getMissingSecrets(config) {
|
|
const missing = [];
|
|
if (!config.jiraCloud?.email) missing.push('JIRA_EMAIL');
|
|
if (!config.jiraCloud?.token) missing.push('JIRA_API_TOKEN');
|
|
if (!config.webex?.token) missing.push('WEBEX_TOKEN');
|
|
if (!config.jiraNotifier?.token) missing.push('JIRA_NOTIFIER_TOKEN');
|
|
return missing;
|
|
}
|
|
|
|
export function describeJiraIdentity(config) {
|
|
const email = config.jiraCloud?.email || '(not set)';
|
|
const host = config.jiraCloud?.host || '(not set)';
|
|
const authType = config.jiraCloud?.authType || 'basic';
|
|
const viaCloudId = config.jiraCloud?.cloudId ? `cloudId=${config.jiraCloud.cloudId}` : 'site URL';
|
|
return `${email} (${authType}, ${viaCloudId}) → ${host}`;
|
|
}
|