init:taskbot 1.1.0
This commit is contained in:
56
src/config/env.js
Normal file
56
src/config/env.js
Normal file
@@ -0,0 +1,56 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const config = {
|
||||
app: {
|
||||
port: process.env.PORT || 3000,
|
||||
dbPath: process.env.DB_FILE_PATH || './sync.sqlite',
|
||||
rate : process.env.RATE_LIMIT_WINDOW || 10000,
|
||||
maxRequests: process.env.MAX_REQUESTS_PER_WINDOW || 20,
|
||||
debugMode: process.env.DEBUG_MODE === 'true',
|
||||
logRetentionDays: process.env.LOG_RETENTION_DAYS || 30
|
||||
},
|
||||
gitea: {
|
||||
baseUrl: process.env.GITEA_BASE_URL,
|
||||
token: process.env.GITEA_TOKEN,
|
||||
secret: process.env.GITEA_WEBHOOK_SECRET,
|
||||
botId: parseInt(process.env.GITEA_BOT_ID || '0'),
|
||||
botName: process.env.GITEA_BOT_NAME
|
||||
},
|
||||
jira: {
|
||||
baseUrl: process.env.JIRA_BASE_URL,
|
||||
botId: process.env.JIRA_BOT_ID || '',
|
||||
botName: process.env.JIRA_BOT_NAME
|
||||
}
|
||||
};
|
||||
|
||||
const requiredVars = [
|
||||
{ key: 'GITEA_BASE_URL', value: config.gitea.baseUrl },
|
||||
{ key: 'GITEA_TOKEN', value: config.gitea.token },
|
||||
{ key: 'GITEA_WEBHOOK_SECRET', value: config.gitea.secret },
|
||||
{ key: 'JIRA_BASE_URL', value: config.jira.baseUrl }
|
||||
];
|
||||
|
||||
const missingVars = requiredVars.filter(v => !v.value).map(v => v.key);
|
||||
if (missingVars.length > 0) {
|
||||
console.error(`[ERROR] Missing required environment variables: ${missingVars.join(', ')}`);
|
||||
console.error('[ERROR] Please configure these in your .env file');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (process.env.JIRA_PAT) {
|
||||
//个人访问令牌鉴权
|
||||
config.jira.authHeader = {
|
||||
'Authorization': `Bearer ${process.env.JIRA_PAT}`
|
||||
};
|
||||
} else if (process.env.JIRA_USERNAME && process.env.JIRA_PASSWORD) {
|
||||
//账号密码鉴权
|
||||
const authString = Buffer.from(`${process.env.JIRA_USERNAME}:${process.env.JIRA_PASSWORD}`).toString('base64');
|
||||
config.jira.authHeader = {
|
||||
'Authorization': `Basic ${authString}`
|
||||
};
|
||||
} else {
|
||||
console.error("[ERROR] Missing JIRA authentication: Please configure JIRA_PAT or JIRA_USERNAME/PASSWORD");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
144
src/config/mappings.js
Normal file
144
src/config/mappings.js
Normal file
@@ -0,0 +1,144 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 读取配置文件路径
|
||||
const configPath = path.join(__dirname, '../../mappings.json');
|
||||
|
||||
let mappingsConfig = null;
|
||||
|
||||
/**
|
||||
* 加载映射配置文件
|
||||
* @returns {Object} 配置对象
|
||||
*/
|
||||
function loadMappings() {
|
||||
if (mappingsConfig) {
|
||||
return mappingsConfig;
|
||||
}
|
||||
|
||||
try {
|
||||
const configContent = fs.readFileSync(configPath, 'utf8');
|
||||
mappingsConfig = JSON.parse(configContent);
|
||||
|
||||
// 处理环境变量替换
|
||||
processEnvVariables(mappingsConfig);
|
||||
|
||||
return mappingsConfig;
|
||||
} catch (error) {
|
||||
throw new Error(`无法加载映射配置文件 ${configPath}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归处理配置中的环境变量
|
||||
* @param {Object} obj 配置对象
|
||||
*/
|
||||
function processEnvVariables(obj) {
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] === 'string' && obj[key].startsWith('${') && obj[key].endsWith('}')) {
|
||||
const envVar = obj[key].slice(2, -1);
|
||||
obj[key] = process.env[envVar] || obj[key];
|
||||
} else if (typeof obj[key] === 'object' && obj[key] !== null) {
|
||||
processEnvVariables(obj[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有仓库配置
|
||||
* @returns {Object} 仓库配置对象
|
||||
*/
|
||||
const repositories = new Proxy({}, {
|
||||
get(target, prop) {
|
||||
const config = loadMappings();
|
||||
return config.repositories[prop];
|
||||
},
|
||||
ownKeys() {
|
||||
const config = loadMappings();
|
||||
return Object.keys(config.repositories);
|
||||
},
|
||||
getOwnPropertyDescriptor(target, prop) {
|
||||
const config = loadMappings();
|
||||
if (prop in config.repositories) {
|
||||
return {
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取默认映射配置
|
||||
* @returns {Object} 默认映射配置
|
||||
*/
|
||||
const defaultMappings = new Proxy({}, {
|
||||
get(target, prop) {
|
||||
const config = loadMappings();
|
||||
return config.defaultMappings[prop];
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取仓库配置
|
||||
* @param {string} repoFullName 仓库完整名称 (owner/repo)
|
||||
* @returns {Object|null} 仓库配置对象,如果不存在返回 null
|
||||
*/
|
||||
function getRepoConfig(repoFullName) {
|
||||
const config = loadMappings();
|
||||
const repoConfig = config.repositories[repoFullName];
|
||||
|
||||
if (!repoConfig) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
jira: repoConfig.jira,
|
||||
priorities: repoConfig.priorities || config.defaultMappings.priorities,
|
||||
types: repoConfig.types || config.defaultMappings.types,
|
||||
sprints: repoConfig.sprints || config.defaultMappings.sprints,
|
||||
transitions: repoConfig.transitions || config.defaultMappings.transitions
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有已配置的仓库列表
|
||||
* @returns {string[]} 仓库名称数组
|
||||
*/
|
||||
function getConfiguredRepos() {
|
||||
const config = loadMappings();
|
||||
return Object.keys(config.repositories);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Jira项目Key反查对应的Gitea仓库
|
||||
* 返回第一个匹配的仓库配置(如果一个Jira项目对应多个Gitea仓库,只返回第一个)
|
||||
* @param {string} jiraProjectKey Jira项目Key
|
||||
* @returns {Object|null} 包含仓库Key和配置的对象,如果不存在返回 null
|
||||
*/
|
||||
function getRepoByJiraProject(jiraProjectKey) {
|
||||
const config = loadMappings();
|
||||
|
||||
for (const [repoKey, repoConfig] of Object.entries(config.repositories)) {
|
||||
if (repoConfig.jira && repoConfig.jira.projectKey === jiraProjectKey) {
|
||||
return {
|
||||
repoKey,
|
||||
config: {
|
||||
jira: repoConfig.jira,
|
||||
priorities: repoConfig.priorities || config.defaultMappings.priorities,
|
||||
types: repoConfig.types || config.defaultMappings.types,
|
||||
sprints: repoConfig.sprints || config.defaultMappings.sprints,
|
||||
transitions: repoConfig.transitions || config.defaultMappings.transitions
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
repositories,
|
||||
defaultMappings,
|
||||
getRepoConfig,
|
||||
getConfiguredRepos,
|
||||
getRepoByJiraProject
|
||||
};
|
||||
Reference in New Issue
Block a user