edsger 0.4.8 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -9,29 +9,76 @@ import { logInfo, logError } from '../../utils/logger.js';
|
|
|
9
9
|
import { parsePullRequestUrl, fetchPRReviews, } from '../code-refine/context-fetcher.js';
|
|
10
10
|
import { getFeature } from '../../api/features/get-feature.js';
|
|
11
11
|
/**
|
|
12
|
-
* Fetch
|
|
12
|
+
* Fetch complete file content from a specific ref (branch/commit)
|
|
13
|
+
*/
|
|
14
|
+
async function fetchFileContent(octokit, owner, repo, ref, path, verbose) {
|
|
15
|
+
try {
|
|
16
|
+
const { data } = await octokit.repos.getContent({
|
|
17
|
+
owner,
|
|
18
|
+
repo,
|
|
19
|
+
ref,
|
|
20
|
+
path,
|
|
21
|
+
});
|
|
22
|
+
// Handle file content (not directory)
|
|
23
|
+
if ('content' in data && !Array.isArray(data)) {
|
|
24
|
+
// Content is base64 encoded
|
|
25
|
+
return Buffer.from(data.content, 'base64').toString('utf-8');
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (verbose) {
|
|
31
|
+
logError(`Failed to fetch content for ${path} at ref ${ref}: ${error}`);
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fetch PR file changes (diff information and full content)
|
|
13
38
|
*/
|
|
14
39
|
async function fetchPRFileChanges(octokit, owner, repo, prNumber, verbose) {
|
|
15
40
|
try {
|
|
16
41
|
if (verbose) {
|
|
17
|
-
logInfo('📂 Fetching PR file changes...');
|
|
42
|
+
logInfo('📂 Fetching PR file changes and content...');
|
|
18
43
|
}
|
|
44
|
+
// Get PR details to get the head ref
|
|
45
|
+
const { data: pr } = await octokit.pulls.get({
|
|
46
|
+
owner,
|
|
47
|
+
repo,
|
|
48
|
+
pull_number: prNumber,
|
|
49
|
+
});
|
|
50
|
+
const headRef = pr.head.sha;
|
|
51
|
+
// Get list of changed files
|
|
19
52
|
const { data: files } = await octokit.pulls.listFiles({
|
|
20
53
|
owner,
|
|
21
54
|
repo,
|
|
22
55
|
pull_number: prNumber,
|
|
23
56
|
per_page: 100,
|
|
24
57
|
});
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
58
|
+
if (verbose) {
|
|
59
|
+
logInfo(`✅ Found ${files.length} changed files`);
|
|
60
|
+
logInfo(`📥 Fetching full content for changed files from ${headRef.substring(0, 7)}...`);
|
|
61
|
+
}
|
|
62
|
+
// Fetch full content for each file in parallel
|
|
63
|
+
const fileChanges = await Promise.all(files.map(async (file) => {
|
|
64
|
+
let fullContent;
|
|
65
|
+
// Only fetch content for files that were not deleted
|
|
66
|
+
if (file.status !== 'removed') {
|
|
67
|
+
fullContent = await fetchFileContent(octokit, owner, repo, headRef, file.filename, verbose);
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
filename: file.filename,
|
|
71
|
+
status: file.status,
|
|
72
|
+
additions: file.additions,
|
|
73
|
+
deletions: file.deletions,
|
|
74
|
+
changes: file.changes,
|
|
75
|
+
patch: file.patch,
|
|
76
|
+
fullContent,
|
|
77
|
+
};
|
|
32
78
|
}));
|
|
33
79
|
if (verbose) {
|
|
34
|
-
|
|
80
|
+
const filesWithContent = fileChanges.filter((f) => f.fullContent).length;
|
|
81
|
+
logInfo(`✅ Retrieved full content for ${filesWithContent}/${fileChanges.length} files`);
|
|
35
82
|
}
|
|
36
83
|
return fileChanges;
|
|
37
84
|
}
|
|
@@ -221,6 +268,35 @@ function createThreadAnalysisPrompt(thread, fileChange, firstComment) {
|
|
|
221
268
|
const allComments = thread.comments.nodes
|
|
222
269
|
.map((c, idx) => `Comment ${idx + 1} by @${c.author.login}:\n${c.body}`)
|
|
223
270
|
.join('\n\n');
|
|
271
|
+
// Build the code context section
|
|
272
|
+
let codeContext = '';
|
|
273
|
+
// Include diff (what changed)
|
|
274
|
+
if (fileChange.patch) {
|
|
275
|
+
codeContext += `**Code Changes (Diff):**
|
|
276
|
+
\`\`\`diff
|
|
277
|
+
${fileChange.patch}
|
|
278
|
+
\`\`\`
|
|
279
|
+
|
|
280
|
+
`;
|
|
281
|
+
}
|
|
282
|
+
// Include full file content for better context
|
|
283
|
+
if (fileChange.fullContent) {
|
|
284
|
+
// Truncate very large files to avoid context limits
|
|
285
|
+
const maxLength = 10000;
|
|
286
|
+
const content = fileChange.fullContent.length > maxLength
|
|
287
|
+
? fileChange.fullContent.substring(0, maxLength) +
|
|
288
|
+
'\n\n... (file truncated, showing first 10000 characters)'
|
|
289
|
+
: fileChange.fullContent;
|
|
290
|
+
codeContext += `**Complete File Content (After Changes):**
|
|
291
|
+
\`\`\`
|
|
292
|
+
${content}
|
|
293
|
+
\`\`\`
|
|
294
|
+
|
|
295
|
+
`;
|
|
296
|
+
}
|
|
297
|
+
if (!codeContext) {
|
|
298
|
+
codeContext = '(No code information available)\n\n';
|
|
299
|
+
}
|
|
224
300
|
return `You are analyzing whether a code review comment has been addressed by subsequent code changes.
|
|
225
301
|
|
|
226
302
|
**Review Thread Information:**
|
|
@@ -231,18 +307,24 @@ function createThreadAnalysisPrompt(thread, fileChange, firstComment) {
|
|
|
231
307
|
**Review Comments:**
|
|
232
308
|
${allComments}
|
|
233
309
|
|
|
234
|
-
|
|
235
|
-
\`\`\`diff
|
|
236
|
-
${fileChange.patch || '(No patch available)'}
|
|
237
|
-
\`\`\`
|
|
310
|
+
${codeContext}
|
|
238
311
|
|
|
239
312
|
**Your Task:**
|
|
240
|
-
Analyze whether the code changes adequately address the feedback in the review comments.
|
|
313
|
+
Analyze whether the code changes adequately address the feedback in the review comments. You have access to:
|
|
314
|
+
1. **The diff** showing what was changed
|
|
315
|
+
2. **The complete file content** after changes for full context
|
|
316
|
+
|
|
317
|
+
Consider:
|
|
241
318
|
1. Does the feedback request a specific code change?
|
|
242
319
|
2. Have those changes (or equivalent changes) been made?
|
|
243
|
-
3. If the feedback points to a specific line,
|
|
320
|
+
3. If the feedback points to a specific line, use the full file content to understand the broader context
|
|
321
|
+
4. Check if related areas of code were modified to address the concern
|
|
322
|
+
5. Use the complete file to verify the fix is properly integrated
|
|
244
323
|
|
|
245
|
-
**Important:**
|
|
324
|
+
**Important:**
|
|
325
|
+
- The comment may point to a specific line, but the fix might be in nearby code
|
|
326
|
+
- Focus on whether the **underlying issue** was addressed, not just whether that exact line was modified
|
|
327
|
+
- Use the full file content to understand the complete context and verify the implementation
|
|
246
328
|
|
|
247
329
|
Return your analysis in this JSON format:
|
|
248
330
|
\`\`\`json
|
|
@@ -253,9 +335,10 @@ Return your analysis in this JSON format:
|
|
|
253
335
|
\`\`\`
|
|
254
336
|
|
|
255
337
|
Example responses:
|
|
256
|
-
- If a comment says "add null check" and the
|
|
257
|
-
- If a comment suggests a refactor but no relevant changes are visible: {"isAddressed": false, "reason": "No refactoring changes visible in diff"}
|
|
338
|
+
- If a comment says "add null check" and the code shows a null check was added: {"isAddressed": true, "reason": "Null check added in the updated code"}
|
|
339
|
+
- If a comment suggests a refactor but no relevant changes are visible: {"isAddressed": false, "reason": "No refactoring changes visible in diff or file content"}
|
|
258
340
|
- If code was modified in related areas addressing the concern: {"isAddressed": true, "reason": "Related code modified to address the concern"}
|
|
341
|
+
- If the full context shows the issue is resolved differently: {"isAddressed": true, "reason": "Issue resolved through alternative implementation visible in full file"}
|
|
259
342
|
`;
|
|
260
343
|
}
|
|
261
344
|
/**
|