ความคิดเห็นตรวจสอบ PR อัตโนมัติ
อ่านส่วนต่างของ PR และโพสต์ความคิดเห็นตรวจสอบแบบแทรกบรรทัดผ่าน API
ความคิดเห็นตรวจสอบ PR อัตโนมัติ เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
การตรวจสอบ PR แบบอัตโนมัติคืออะไร
เอเจนต์ตรวจสอบ PR แบบอัตโนมัติจะอ่านไฟล์ที่เปลี่ยนแปลง วิเคราะห์ส่วนต่าง และโพสต์ความคิดเห็นตรวจสอบแบบเจาะจง เช่นเดียวกับผู้ตรวจสอบที่เป็นมนุษย์ แต่เร็วกว่าและสม่ำเสมอกว่า กรณีใช้งาน ได้แก่ การตรวจสอบความปลอดภัย การบังคับใช้รูปแบบ การตรวจหาข้อบกพร่องทั่วไป การตรวจสอบความครอบคลุมของการทดสอบ หรือการสรุปว่า PR ทำอะไร
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
# Get a specific pull request by number
pr = repo.get_pull(42)
print(f'PR #{pr.number}: {pr.title}')
print(f'Author: {pr.user.login}')
print(f'Base branch: {pr.base.ref} <- Head: {pr.head.ref}')
print(f'State: {pr.state}')
print(f'Changed files: {pr.changed_files}')
print(f'Additions: +{pr.additions}')
print(f'Deletions: -{pr.deletions}')การแสดงรายการ PR ที่เปิดอยู่
ใช้ repo.get_pulls() เพื่อแสดงรายการ PR กรองตามสถานะ (open closed) สาขาฐาน หรือลำดับการเรียง สำหรับบอตตรวจสอบ โดยทั่วไปคุณจะประมวลผล PR ที่มีสถานะ open และยังไม่ได้รับการตรวจสอบ
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
# All open PRs targeting main
open_prs = repo.get_pulls(
state='open',
base='main',
sort='created',
direction='desc'
)
for pr in open_prs:
# Check if agent has already reviewed it
reviews = list(pr.get_reviews())
agent_reviewed = any(
r.user.login == 'my-agent-bot[bot]'
for r in reviews
)
if not agent_reviewed:
print(f'Needs review: PR #{pr.number} - {pr.title}')การรับไฟล์ที่เปลี่ยนแปลง
pr.get_files() ส่งคืนรายการออบเจ็กต์ File โดยแต่ละรายการแทนไฟล์ที่เปลี่ยนแปลงใน PR คุณสมบัติสำคัญ ได้แก่ filename status (added/modified/removed) additions deletions และ patch (ข้อความส่วนต่างแบบรวม)
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
pr = repo.get_pull(42)
changed_files = list(pr.get_files())
print(f'Changed files: {len(changed_files)}')
for file in changed_files:
print(f'\n{file.status.upper()}: {file.filename}')
print(f' +{file.additions} -{file.deletions}')
# The patch is the unified diff
if file.patch:
print(f' Patch preview: {file.patch[:200]}')
# Filter to only Python files
python_files = [
f for f in changed_files
if f.filename.endswith('.py') and f.status != 'removed'
]การอ่านแพตช์ไฟล์ (ส่วนต่าง)
file.patch เป็นสตริงส่วนต่างแบบรวม บรรทัดที่ขึ้นต้นด้วย + คือบรรทัดที่เพิ่มเข้ามา ส่วนบรรทัดที่ขึ้นต้นด้วย - คือบรรทัดที่ถูกนำออก ส่วนหัว @@ แสดงหมายเลขบรรทัดที่ส่วนย่อยเริ่มต้น นำข้อมูลนี้ไปวิเคราะห์เพื่อระบุตำแหน่งที่มีปัญหาในโค้ดใหม่ได้อย่างแม่นยำ
def parse_patch_hunks(patch):
if not patch:
return []
hunks = []
current_hunk = None
new_line_num = 0
for line in patch.split('\n'):
if line.startswith('@@'):
# Parse: @@ -old_start,old_count +new_start,new_count @@
import re
match = re.search(r'\+([0-9]+)', line)
if match:
new_line_num = int(match.group(1))
current_hunk = {'header': line, 'lines': [], 'start_line': new_line_num}
hunks.append(current_hunk)
elif current_hunk is not None:
if line.startswith('+'):
current_hunk['lines'].append({'type': 'add', 'content': line[1:], 'line': new_line_num})
new_line_num += 1
elif line.startswith('-'):
current_hunk['lines'].append({'type': 'remove', 'content': line[1:], 'line': None})
else:
new_line_num += 1
return hunks
# --- demo ---
patch = (
'@@ -10,3 +10,4 @@\n'
' def add(a, b):\n'
'- return a - b\n'
'+ return a + b\n'
'+ # fixed subtraction bug\n'
)
for hunk in parse_patch_hunks(patch):
print(hunk['header'])
for line in hunk['lines']:
print(' ', line)
การรับคอมมิตของ PR
pr.get_commits() ส่งคืนคอมมิตใน PR แต่ละคอมมิตมีข้อความ ผู้เขียน และรายการไฟล์ที่เปลี่ยนแปลง การวิเคราะห์ข้อความคอมมิตช่วยให้บอตตรวจสอบสรุปได้ว่า PR ทำอะไร และตรวจสอบแนวปฏิบัติที่ดีในการคอมมิต
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
pr = repo.get_pull(42)
commits = list(pr.get_commits())
print(f'Commits in PR: {len(commits)}')
for commit in commits:
print(f'\nCommit: {commit.sha[:8]}')
print(f'Author: {commit.commit.author.name}')
print(f'Message: {commit.commit.message[:80]}')
print(f'Changes: +{commit.stats.additions} -{commit.stats.deletions}')
# Check commit message quality
poor_messages = [
c for c in commits
if len(c.commit.message.split()[0] if c.commit.message else '') < 3
or c.commit.message.lower().startswith(('wip', 'fix', 'test'))
]
if poor_messages:
print(f'{len(poor_messages)} commits have poor message quality')การโพสต์รีวิว PR
ใช้ pr.create_review() เพื่อส่งรีวิวอย่างเป็นทางการ พารามิเตอร์ event ควบคุมประเภทรีวิว ได้แก่ 'APPROVE' 'REQUEST_CHANGES' หรือ 'COMMENT' รีวิวสามารถมีเนื้อหาทั่วไปและรายการความคิดเห็นแทรกในบรรทัดของบรรทัดที่ระบุได้
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
pr = repo.get_pull(42)
# Submit a review with a general comment (no inline comments)
pr.create_review(
body=(
'**Automated Code Review**\n\n'
'I analyzed this PR and found the following:\n'
'- No security issues detected\n'
'- Style conforms to project guidelines\n'
'- Test coverage looks adequate\n\n'
'_This review was generated automatically._'
),
event='COMMENT' # 'APPROVE', 'REQUEST_CHANGES', or 'COMMENT'
)การโพสต์ความคิดเห็นรีวิวแทรกในบรรทัด
ความคิดเห็นแทรกในบรรทัดจะแสดงโดยตรงบนบรรทัดที่ระบุในส่วนต่าง ความคิดเห็นแต่ละรายการระบุ path (เส้นทางไฟล์) line (หมายเลขบรรทัดในไฟล์ใหม่) และ body ส่งรายการความคิดเห็นไปยัง pr.create_review(comments=[...])
from github import Github
import os
g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
pr = repo.get_pull(42)
# Build inline comments from analysis results
inline_comments = [
{
'path': 'src/auth.py',
'line': 47,
'body': (
':warning: **Security Issue:** Using `md5` for password hashing.\n'
'Use `bcrypt` or `argon2` instead.\n'
'Example: `import bcrypt; bcrypt.hashpw(password.encode(), bcrypt.gensalt())`'
)
},
{
'path': 'src/utils.py',
'line': 23,
'body': (
':bulb: Consider using `pathlib.Path` instead of `os.path.join` '
'for better cross-platform compatibility.'
)
}
]
pr.create_review(
body='Security and style review complete. See inline comments.',
event='REQUEST_CHANGES',
comments=inline_comments
)
print(f'Review submitted with {len(inline_comments)} inline comments')การวิเคราะห์โค้ดด้วย LLM
ป้อนส่วนต่างของไฟล์ให้ LLM พร้อมคำสั่งสำหรับตรวจสอบความปลอดภัย/คุณภาพ ขอการตอบกลับ JSON แบบมีโครงสร้างที่แสดงรายการปัญหา พร้อมเส้นทางไฟล์ หมายเลขบรรทัด ระดับความรุนแรง และคำอธิบาย ใช้ข้อมูลนี้สร้างรายการความคิดเห็นแทรกในบรรทัด
import anthropic
import json
import os
client = anthropic.Anthropic(api_key=os.environ['ANTHROPIC_API_KEY'])
def analyze_file_with_llm(filename, patch):
prompt = (
f'Review this Python code diff for issues.\n'
f'File: {filename}\n\n'
f'Return JSON array: [{{"line": N, "severity": "error|warning|info", '
f'"message": "..."}}]\n'
f'Focus on: security vulnerabilities, bugs, and anti-patterns.\n'
f'Diff:\n{patch[:3000]}'
)
response = client.messages.create(
model='claude-opus-4-5',
max_tokens=1000,
messages=[{'role': 'user', 'content': prompt}]
)
try:
issues = json.loads(response.content[0].text)
return [
{'path': filename, 'line': i.get('line', 1),
'body': f'[{i.get("severity", "info").upper()}] {i.get("message", "")}'}
for i in issues if isinstance(i, dict)
]
except json.JSONDecodeError:
return []ลำดับการทำงานของเอเจนต์ตรวจสอบ PR แบบครบถ้วน
เชื่อมทุกส่วนเข้าด้วยกันเป็นลำดับการตรวจสอบ PR ที่สมบูรณ์: ดึงไฟล์ กรองเฉพาะไฟล์ที่ตรวจสอบได้ วิเคราะห์แต่ละไฟล์ด้วย LLM รวบรวมความคิดเห็น และส่งรีวิวด้วยการเรียก API เพียงครั้งเดียว จำกัดไว้ที่ไฟล์ที่เปลี่ยนแปลง 10 ไฟล์แรกเพื่อควบคุมค่าใช้จ่ายของ LLM
def run_pr_review(g, repo_name, pr_number):
repo = g.get_repo(repo_name)
pr = repo.get_pull(pr_number)
print(f'Reviewing PR #{pr_number}: {pr.title}')
# Get changed files (limit to 10)
files = [
f for f in list(pr.get_files())[:10]
if f.filename.endswith(('.py', '.js', '.ts'))
and f.patch
]
all_comments = []
for file in files:
print(f' Analyzing: {file.filename}')
comments = analyze_file_with_llm(file.filename, file.patch)
all_comments.extend(comments)
# Determine review event based on findings
critical = [c for c in all_comments if '[ERROR]' in c['body']]
event = 'REQUEST_CHANGES' if critical else 'COMMENT'
summary = (
f'Analyzed {len(files)} files. '
f'Found {len(all_comments)} issues '
f'({len(critical)} critical).'
)
pr.create_review(body=summary, event=event, comments=all_comments[:25])
print(f'Review submitted: {event} with {len(all_comments)} comments')การตรวจสอบรีวิวของเอเจนต์ที่มีอยู่
ก่อนโพสต์รีวิว ให้ตรวจสอบว่าบอตเอเจนต์ของคุณได้รีวิว PR นี้ในสถานะปัจจุบันแล้วหรือไม่ ป้องกันรีวิวซ้ำโดยตรวจสอบรายการรีวิวที่มีอยู่เพื่อค้นหาชื่อผู้ใช้ของบอต
def should_review_pr(pr, bot_username):
reviews = list(pr.get_reviews())
# Check if bot already reviewed this PR
bot_reviews = [
r for r in reviews
if r.user and r.user.login == bot_username
]
if not bot_reviews:
return True # No previous review, proceed
# Check if new commits were pushed since last review
last_review_time = max(r.submitted_at for r in bot_reviews)
commits = list(pr.get_commits())
latest_commit_time = commits[-1].commit.author.date if commits else None
if latest_commit_time and latest_commit_time > last_review_time:
print(f'New commits since last review, re-reviewing...')
return True
print(f'PR #{pr.number} already reviewed by {bot_username}')
return False
# --- demo: minimal stand-ins for PyGithub-style PR/review/commit objects ---
import datetime
from types import SimpleNamespace
class _FakeCommit:
def __init__(self, date):
self.commit = SimpleNamespace(author=SimpleNamespace(date=date))
class _FakeReview:
def __init__(self, login, submitted_at):
self.user = SimpleNamespace(login=login)
self.submitted_at = submitted_at
class _FakePR:
def __init__(self, number, reviews, commits):
self.number = number
self._reviews = reviews
self._commits = commits
def get_reviews(self):
return self._reviews
def get_commits(self):
return self._commits
pr_never_reviewed = _FakePR(101, [], [_FakeCommit(datetime.datetime(2026, 8, 1))])
print('PR #101 needs review:', should_review_pr(pr_never_reviewed, 'coddy-bot'))
review_time = datetime.datetime(2026, 8, 1, 10, 0)
pr_up_to_date = _FakePR(102, [_FakeReview('coddy-bot', review_time)],
[_FakeCommit(review_time - datetime.timedelta(hours=1))])
print('PR #102 needs review:', should_review_pr(pr_up_to_date, 'coddy-bot'))
รูปแบบการสแกนความปลอดภัยในการรีวิว PR
รูปแบบการรีวิวอัตโนมัติที่ใช้กันทั่วไปคือการสแกนบรรทัดที่เพิ่มเข้ามาเพื่อค้นหารูปแบบการเขียนโค้ดที่ไม่ปลอดภัย เช่น ข้อมูลลับที่ฝังไว้ตายตัว การใช้ฟังก์ชันที่เลิกใช้แล้ว การต่อสตริง SQL หรือการเรียก eval() ตรวจสอบแต่ละบรรทัดที่เพิ่มเข้ามาเทียบกับชุดรูปแบบ แล้วทำเครื่องหมายสิ่งที่พบเป็นความคิดเห็นในบรรทัด
import re
SECURITY_PATTERNS = [
(r'eval\s*\(', 'Dangerous eval() call — code injection risk'),
(r'os\.system\s*\(', 'os.system() is unsafe; use subprocess with a list'),
(r'pickle\.loads?\s*\(', 'pickle.load is unsafe with untrusted data'),
(r'execute\(.*%\s*', 'Possible SQL injection — use parameterized queries'),
(r'md5\s*\(|hashlib\.md5', 'MD5 is cryptographically broken for passwords; use bcrypt'),
]
def scan_patch_for_security(filename, patch):
if not patch:
return []
comments = []
new_line = 0
for line in patch.split('\n'):
if line.startswith('@@'):
import re as _re
m = _re.search(r'\+([0-9]+)', line)
if m:
new_line = int(m.group(1))
elif line.startswith('+') and not line.startswith('+++'):
content = line[1:]
for pattern, message in SECURITY_PATTERNS:
if re.search(pattern, content):
comments.append({'path': filename, 'line': new_line,
'body': f':rotating_light: **Security:** {message}'})
new_line += 1
elif not line.startswith('-'):
new_line += 1
return comments
# --- demo ---
patch = (
'@@ -1,2 +1,3 @@\n'
' def run(cmd):\n'
'+ os.system(cmd)\n'
'+ hashlib.md5(cmd.encode())\n'
)
for c in scan_patch_for_security('run.py', patch):
print(c)
ตรวจสอบอย่างรวดเร็ว: เหตุการณ์ในการรีวิว
ทดสอบความเข้าใจเกี่ยวกับตัวเลือกการรีวิว PR
สรุปการรีวิว PR อัตโนมัติ
ตอนนี้เอเจนต์ของคุณสามารถรีวิวคำขอรวมโค้ดด้วยโปรแกรมได้แล้ว:
- repo.get_pull(number) — รับอ็อบเจ็กต์ PR พร้อมข้อมูลเมตา
- pr.get_files() — แสดงรายการไฟล์ที่เปลี่ยนแปลง พร้อม
filename,patch,additions - pr.get_commits() — ตรวจสอบข้อความและสถิติของการคอมมิต
- pr.create_review(body, event, comments) — ส่งรีวิวพร้อมความคิดเห็นในบรรทัดที่เลือกใส่ได้
- รูปแบบความคิดเห็นในบรรทัด:
{'path': filename, 'line': N, 'body': markdown} - ใช้
'COMMENT'สำหรับข้อสังเกต และ'REQUEST_CHANGES'สำหรับปัญหาที่ต้องแก้ไขก่อน - ตรวจสอบรีวิวที่มีอยู่ก่อนรีวิวซ้ำ เพื่อหลีกเลี่ยงรายการซ้ำ
- จำกัดการวิเคราะห์ไว้ที่ 10 ไฟล์และความคิดเห็นในบรรทัด 25 รายการ เพื่อให้อยู่ภายในขีดจำกัดของ API
เรียนรู้ AI Agents ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 60
- บทเรียน
- 239
คำถามที่พบบ่อย
บทเรียน “ความคิดเห็นตรวจสอบ PR อัตโนมัติ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ความคิดเห็นตรวจสอบ PR อัตโนมัติ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ความคิดเห็นตรวจสอบ PR อัตโนมัติ”
อ่านส่วนต่างของ PR และโพสต์ความคิดเห็นตรวจสอบแบบแทรกบรรทัดผ่าน API คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “ความคิดเห็นตรวจสอบ PR อัตโนมัติ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม
ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ภาพรวม GitHub REST API
- การแสดงรายการและจัดการประเด็น
- ความคิดเห็นตรวจสอบ PR อัตโนมัติ
- ประวัติการคอมมิตและการวิเคราะห์ส่วนต่าง