fix: add date filtering to usage/real endpoint and export
This commit is contained in:
254
gitea-integration.js
Normal file
254
gitea-integration.js
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* Gitea Integration for AgentDash
|
||||
* Provides real-time data from Gitea API
|
||||
*/
|
||||
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
class GiteaIntegration {
|
||||
constructor(config = {}) {
|
||||
this.baseUrl = config.baseUrl || 'https://gitea.tophermayor.com';
|
||||
this.token = config.token || process.env.GITEA_TOKEN;
|
||||
this.owner = config.owner || 'TopherMayor';
|
||||
this.cache = new Map();
|
||||
this.cacheTimeout = config.cacheTimeout || 30000; // 30 seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Make authenticated request to Gitea API
|
||||
*/
|
||||
async request(endpoint) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = new URL(endpoint, this.baseUrl);
|
||||
const client = url.protocol === 'https:' ? https : http;
|
||||
|
||||
const options = {
|
||||
hostname: url.hostname,
|
||||
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
||||
path: url.pathname + url.search,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `token ${this.token}`,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
const req = client.request(options, (res) => {
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (e) {
|
||||
reject(new Error(`Failed to parse response: ${e.message}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', reject);
|
||||
req.setTimeout(10000, () => {
|
||||
req.destroy();
|
||||
reject(new Error('Request timeout'));
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached data or fetch fresh
|
||||
*/
|
||||
async getCached(key, fetcher) {
|
||||
const cached = this.cache.get(key);
|
||||
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
const data = await fetcher();
|
||||
this.cache.set(key, { data, timestamp: Date.now() });
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all repositories for the owner
|
||||
*/
|
||||
async getRepos() {
|
||||
return this.getCached('repos', () =>
|
||||
this.request(`/api/v1/user/repos?limit=50`)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository details
|
||||
*/
|
||||
async getRepo(repoName) {
|
||||
return this.getCached(`repo:${repoName}`, () =>
|
||||
this.request(`/api/v1/repos/${this.owner}/${repoName}`)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get open pull requests for a repository
|
||||
*/
|
||||
async getPullRequests(repoName, state = 'open') {
|
||||
return this.getCached(`prs:${repoName}:${state}`, () =>
|
||||
this.request(`/api/v1/repos/${this.owner}/${repoName}/pulls?state=${state}&limit=20`)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get issues for a repository
|
||||
*/
|
||||
async getIssues(repoName, state = 'open') {
|
||||
return this.getCached(`issues:${repoName}:${state}`, () =>
|
||||
this.request(`/api/v1/repos/${this.owner}/${repoName}/issues?state=${state}&limit=20`)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recent commits for a repository
|
||||
*/
|
||||
async getCommits(repoName, branch = 'main', limit = 10) {
|
||||
return this.getCached(`commits:${repoName}:${branch}`, () =>
|
||||
this.request(`/api/v1/repos/${this.owner}/${repoName}/commits?sha=${branch}&limit=${limit}`)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get branches for a repository
|
||||
*/
|
||||
async getBranches(repoName) {
|
||||
return this.getCached(`branches:${repoName}`, () =>
|
||||
this.request(`/api/v1/repos/${this.owner}/${repoName}/branches`)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository activity feed
|
||||
*/
|
||||
async getActivity(repoName) {
|
||||
return this.getCached(`activity:${repoName}`, () =>
|
||||
this.request(`/api/v1/repos/${this.owner}/${repoName}/activities/feeds?limit=20`)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user info
|
||||
*/
|
||||
async getUser() {
|
||||
return this.getCached('user', () =>
|
||||
this.request('/api/v1/user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get organization info (if applicable)
|
||||
*/
|
||||
async getOrgs() {
|
||||
return this.getCached('orgs', () =>
|
||||
this.request('/api/v1/user/orgs')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache
|
||||
*/
|
||||
clearCache() {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get swarm summary - all repos with PRs and issues
|
||||
*/
|
||||
async getSwarmSummary() {
|
||||
const repos = await this.getRepos();
|
||||
const summary = [];
|
||||
|
||||
for (const repo of repos.slice(0, 10)) { // Limit to 10 repos
|
||||
try {
|
||||
const [prs, issues, branches] = await Promise.all([
|
||||
this.getPullRequests(repo.name, 'open').catch(() => []),
|
||||
this.getIssues(repo.name, 'open').catch(() => []),
|
||||
this.getBranches(repo.name).catch(() => [])
|
||||
]);
|
||||
|
||||
summary.push({
|
||||
name: repo.name,
|
||||
full_name: repo.full_name,
|
||||
stars: repo.stars_count || 0,
|
||||
forks: repo.forks_count || 0,
|
||||
open_prs: prs.length,
|
||||
open_issues: issues.length,
|
||||
branches: branches.length,
|
||||
updated_at: repo.updated_at,
|
||||
html_url: repo.html_url
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Error fetching data for ${repo.name}:`, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pending reviews (PRs needing attention)
|
||||
*/
|
||||
async getPendingReviews() {
|
||||
const repos = await this.getRepos();
|
||||
const pending = [];
|
||||
|
||||
for (const repo of repos.slice(0, 10)) {
|
||||
try {
|
||||
const prs = await this.getPullRequests(repo.name, 'open');
|
||||
for (const pr of prs) {
|
||||
pending.push({
|
||||
repo: repo.name,
|
||||
repo_url: repo.html_url,
|
||||
pr_number: pr.number,
|
||||
pr_title: pr.title,
|
||||
pr_url: pr.html_url,
|
||||
author: pr.user?.login,
|
||||
created_at: pr.created_at,
|
||||
mergeable: pr.mergeable,
|
||||
draft: pr.draft,
|
||||
labels: pr.labels || []
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Error fetching PRs for ${repo.name}:`, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recent activity across all repos
|
||||
*/
|
||||
async getRecentActivity() {
|
||||
const repos = await this.getRepos();
|
||||
const activities = [];
|
||||
|
||||
for (const repo of repos.slice(0, 5)) {
|
||||
try {
|
||||
const activity = await this.getActivity(repo.name);
|
||||
for (const act of (activity || []).slice(0, 5)) {
|
||||
activities.push({
|
||||
repo: repo.name,
|
||||
repo_url: repo.html_url,
|
||||
...act
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// Skip repos without activity access
|
||||
}
|
||||
}
|
||||
|
||||
return activities
|
||||
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))
|
||||
.slice(0, 20);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GiteaIntegration;
|
||||
Reference in New Issue
Block a user