diff --git a/src/github/api/queries/gitea.ts b/src/github/api/queries/gitea.ts index ef5345a..15a844b 100644 --- a/src/github/api/queries/gitea.ts +++ b/src/github/api/queries/gitea.ts @@ -17,6 +17,17 @@ type RestReviewComment = Awaited< ReturnType >["data"][number]; +// Gitea REST API extensions - fields present in Gitea responses but not in Octokit types +type GiteaReview = RestReview & { + created_at?: string; +}; + +type GiteaUser = { + login: string; + name: string | null; + full_name?: string; +}; + /** * Fetch complete Pull Request data including commits, files, comments, and reviews */ @@ -68,8 +79,9 @@ export async function fetchPullRequest( // Fetch review comments for each review using Gitea API // Gitea endpoint: GET /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments + const reviews = prReviews.data as GiteaReview[]; const reviewsWithComments = await Promise.all( - prReviews.data.map(async (review: RestReview) => { + reviews.map(async (review) => { try { // Use Gitea-specific endpoint to get comments for each review const response = await octokit.request( @@ -85,18 +97,17 @@ export async function fetchPullRequest( return { ...review, - comments: response.data, + comments: response.data as RestReviewComment[], }; } catch (error) { // If fetching comments fails, return review with empty comments - // @ts-expect-error - console is available at runtime console.warn( `Failed to fetch comments for review ${review.id}:`, error, ); return { ...review, - comments: [], + comments: [] as RestReviewComment[], }; } }), @@ -121,6 +132,11 @@ export async function fetchPullRequest( additions: prData.data.additions || 0, deletions: prData.data.deletions || 0, state: prData.data.state.toUpperCase(), // "open" -> "OPEN" + labels: { + nodes: (prData.data.labels || []).map((label: { name?: string }) => ({ + name: label.name || "", + })), + }, commits: { totalCount: prCommits.data.length, nodes: prCommits.data.map((commit: RestCommit) => ({ @@ -145,7 +161,7 @@ export async function fetchPullRequest( comments: { nodes: prComments.data.map((comment: RestComment) => ({ id: `comment_${comment.id}`, - databaseId: comment.id, + databaseId: String(comment.id), body: comment.body || "", author: { login: comment.user?.login || "", @@ -157,36 +173,34 @@ export async function fetchPullRequest( })), }, reviews: { - nodes: reviewsWithComments.map( - (review: RestReview & { comments: RestReviewComment[] }) => ({ - id: `review_${review.id}`, - databaseId: review.id, - author: { - login: review.user?.login || "", - }, - body: review.body || "", - state: review.state.toUpperCase(), // "APPROVED", "CHANGES_REQUESTED", etc. - submittedAt: review.submitted_at || review.created_at || "", - updatedAt: review.submitted_at || review.created_at || "", - lastEditedAt: review.submitted_at || review.created_at || "", - comments: { - nodes: review.comments.map((comment: RestReviewComment) => ({ - id: `review_comment_${comment.id}`, - databaseId: comment.id, - body: comment.body || "", - path: comment.path, - line: comment.line || comment.original_line || null, - author: { - login: comment.user?.login || "", - }, - createdAt: comment.created_at, - updatedAt: comment.updated_at, - lastEditedAt: comment.updated_at, - isMinimized: false, - })), - }, - }), - ), + nodes: reviewsWithComments.map((review) => ({ + id: `review_${review.id}`, + databaseId: String(review.id), + author: { + login: review.user?.login || "", + }, + body: review.body || "", + state: review.state.toUpperCase(), // "APPROVED", "CHANGES_REQUESTED", etc. + submittedAt: review.submitted_at || review.created_at || "", + updatedAt: review.submitted_at || review.created_at || "", + lastEditedAt: review.submitted_at || review.created_at || "", + comments: { + nodes: review.comments.map((comment: RestReviewComment) => ({ + id: `review_comment_${comment.id}`, + databaseId: String(comment.id), + body: comment.body || "", + path: comment.path, + line: comment.line ?? comment.original_line ?? null, + author: { + login: comment.user?.login || "", + }, + createdAt: comment.created_at, + updatedAt: comment.updated_at, + lastEditedAt: comment.updated_at, + isMinimized: false, + })), + }, + })), }, }, }, @@ -230,10 +244,17 @@ export async function fetchIssue( updatedAt: issueData.data.updated_at, lastEditedAt: issueData.data.updated_at, state: issueData.data.state.toUpperCase(), + labels: { + nodes: (issueData.data.labels || []).map( + (label: string | { name?: string }) => ({ + name: typeof label === "string" ? label : label.name || "", + }), + ), + }, comments: { nodes: issueComments.data.map((comment: RestComment) => ({ id: `comment_${comment.id}`, - databaseId: comment.id, + databaseId: String(comment.id), body: comment.body || "", author: { login: comment.user?.login || "", @@ -258,14 +279,13 @@ export async function fetchUser(octokit: Octokit, login: string) { username: login, }); + const user = userData.data as unknown as GiteaUser; return { user: { - name: userData.data.name || userData.data.full_name || null, + name: user.name || user.full_name || null, }, }; } catch (error) { - // Note: console is available at runtime in Node.js environment - // @ts-expect-error - console is not in lib but available at runtime console.warn(`Failed to fetch user ${login}:`, error); return { user: { diff --git a/src/github/data/fetcher.ts b/src/github/data/fetcher.ts index a924e0e..d2637b7 100644 --- a/src/github/data/fetcher.ts +++ b/src/github/data/fetcher.ts @@ -308,6 +308,10 @@ export async function fetchGitHubData({ throw new Error(`Failed to fetch ${isPR ? "PR" : "issue"} data`); } + if (!contextData) { + throw new Error(`Failed to fetch ${isPR ? "PR" : "issue"} data`); + } + // Compute SHAs for changed files let changedFilesWithSHA: GitHubFileWithSHA[] = []; if (isPR && changedFiles.length > 0) {