UNPKG

review-copilot

Version:

ReviewCopilot - AI-powered code review assistant with customizable prompts

107 lines (106 loc) 4.18 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GithubProvider = void 0; const rest_1 = require("@octokit/rest"); const chalk_1 = __importDefault(require("chalk")); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); class GithubProvider { constructor() { // Cache for PR commits to avoid redundant API calls, with expiration this.cachedCommits = null; this.CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes } async getPRInfo() { const token = process.env.GITHUB_TOKEN; if (!token) { throw new Error('Missing GITHUB_TOKEN'); } const eventPath = process.env.GITHUB_EVENT_PATH; // Validate eventPath is absolute for security if (!eventPath || !path_1.default.isAbsolute(eventPath)) { throw new Error('Invalid event path'); } // Securely read and parse the event payload const event = JSON.parse(fs_1.default.readFileSync(eventPath, 'utf8')); const pull_number = event.pull_request?.number; if (!pull_number) { throw new Error('Missing PR number in event payload'); } const [owner, repo] = (process.env.GITHUB_REPOSITORY || '').split('/'); return { owner, repo, pull_number }; } getOctokit() { const token = process.env.GITHUB_TOKEN; if (!token) { throw new Error('Missing GITHUB_TOKEN'); } return new rest_1.Octokit({ auth: token }); } // Helper to fetch and cache PR commits with expiration async getCommits() { if (!this.cachedCommits || Date.now() - this.cachedCommits.timestamp > this.CACHE_TTL_MS) { const prInfo = await this.getPRInfo(); if (!prInfo) throw new Error('Failed to get PR info'); const octokit = this.getOctokit(); const response = await octokit.pulls.listCommits({ ...prInfo, }); this.cachedCommits = { data: response.data, timestamp: Date.now() }; } return this.cachedCommits.data; } async getCurrentBranchName() { const headRef = process.env.GITHUB_HEAD_REF; if (headRef) { return headRef; } return ''; } async getPullRequestCommits() { const commits = await this.getCommits(); // For commit message review, we only need basic commit info without files const reviewInfos = commits.map((commit) => ({ hash: commit.sha, date: commit.commit.author?.date || '', message: commit.commit.message, author: commit.commit.author?.name || '', files: [], })); return reviewInfos; } async getPullRequestFiles() { try { const prInfo = await this.getPRInfo(); if (!prInfo) throw new Error('Failed to get PR info'); const octokit = this.getOctokit(); // Get PR details const { data: pullRequest } = await octokit.pulls.get(prInfo); // Get all file changes in the PR const { data: files } = await octokit.pulls.listFiles(prInfo); // For code review, we only need the final state of changes const reviewInfo = { hash: pullRequest.head.sha, date: pullRequest.updated_at, message: pullRequest.title, author: pullRequest.user?.login || '', files: files.map((file) => ({ filename: file.filename, changes: file.patch || '', })), }; return reviewInfo; } catch (error) { console.error(chalk_1.default.red('Error getting PR changes for code review:'), error); throw new Error('Failed to fetch GitHub PR changes for code review'); } } } exports.GithubProvider = GithubProvider;