0Pricing
AI Agents · درس

عرض المشكلات وإدارتها

جلب المشكلات وإنشاؤها وإضافة الوسوم إليها وإغلاقها برمجيًا

عرض المشكلات وإدارتها درس مجاني في AI Agents على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Agents، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Agents 4 دروس في المجموع.

الحصول على المشكلات من مستودع

استخدموا repo.get_issues() لسرد المشكلات. ويُرجع افتراضيًا المشكلات المفتوحة؛ مرّروا state='closed' أو state='all' للحصول على الحالات الأخرى. والنتيجة هي PaginatedList — كرّروا عليها لمعالجة كل مشكلة.

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')

# Open issues (default)
open_issues = repo.get_issues(state='open')
print(f'Open issues: {open_issues.totalCount}')

# Process first 20
for issue in open_issues[:20]:
    print(f'#{issue.number}: {issue.title}')
    print(f'  Labels: {[l.name for l in issue.labels]}')
    print(f'  Assignee: {issue.assignee.login if issue.assignee else None}')
    print(f'  Created: {issue.created_at.date()}')

تصفية المشكلات

يدعم get_issues() عدة معاملات للتصفية: state وlabels وassignee وmilestone وsince وsort. ادمجوها للحصول على المشكلات التي يحتاج وكيلكم إلى معالجتها بدقة.

import datetime
from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')

# Issues with the 'bug' label, sorted by newest
bug_issues = repo.get_issues(
    state='open',
    labels=['bug'],
    sort='created',
    direction='desc'
)

# Issues updated in the last 7 days
cutoff = datetime.datetime.now() - datetime.timedelta(days=7)
recent_issues = repo.get_issues(
    state='open',
    since=cutoff
)

# Issues assigned to a specific user
my_issues = repo.get_issues(
    state='open',
    assignee='username'
)

print(f'Bug issues: {bug_issues.totalCount}')
print(f'Recent issues: {recent_issues.totalCount}')

الوصول إلى خصائص المشكلة

يحتوي كل كائن من نوع Issue على خصائص غنية: الرقم والعنوان والنص الأساسي والتسميات والمكلّفون والمرحلة والحالة وعدد التعليقات والطوابع الزمنية. يمكنكم الوصول إليها كسمات في Python. والنص الأساسي هو نص Markdown خام.

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
issue = repo.get_issue(42)  # get by number

print(f'Number: #{issue.number}')
print(f'Title: {issue.title}')
print(f'State: {issue.state}')        # 'open' or 'closed'
print(f'Author: {issue.user.login}')
print(f'Body length: {len(issue.body or "")}')
print(f'Labels: {[l.name for l in issue.labels]}')
print(f'Assignees: {[a.login for a in issue.assignees]}')
print(f'Milestone: {issue.milestone.title if issue.milestone else None}')
print(f'Comments: {issue.comments}')
print(f'Reactions: {issue.get_reactions().totalCount}')
print(f'URL: {issue.html_url}')

إنشاء مشكلات جديدة

استخدموا repo.create_issue() لإنشاء مشكلة جديدة برمجيًا. والحقل الوحيد المطلوب هو title. أضيفوا body (بتنسيق Markdown) وlabels (يجب أن تكون موجودة مسبقًا) وassignees (أسماء مستخدمي GitHub) وmilestone (كائن المرحلة).

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')

# Create a bug report
bug_body = (
    '## Bug Report\n\n'
    '**Observed:** Login fails with 500 error\n'
    '**Expected:** Successful login\n'
    '**Steps to reproduce:**\n'
    '1. Navigate to /login\n'
    '2. Enter valid credentials\n'
    '3. Click Submit\n\n'
    '**Environment:** Production, v2.3.1'
)

issue = repo.create_issue(
    title='Login endpoint returns 500 for valid credentials',
    body=bug_body,
    labels=['bug', 'priority:high'],
    assignees=['alice'],       # must be repo collaborators
)

print(f'Created issue #{issue.number}: {issue.html_url}')

تحرير المشكلات وتحديثها

استخدموا issue.edit() لتحديث أي خاصية في مشكلة موجودة. يمكنكم تغيير العنوان أو النص الأساسي أو الحالة أو التسميات أو المكلّفين أو المرحلة في استدعاء واحد. مرّروا الحقول التي تريدون تغييرها فقط — وتبقى الحقول الأخرى محفوظة.

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
issue = repo.get_issue(42)

# Update title and add new labels
issue.edit(
    title='[URGENT] Login endpoint returns 500',
    labels=['bug', 'priority:critical', 'needs-hotfix']
)

# Close the issue
issue.edit(state='closed')
print(f'Issue #{issue.number} closed')

# Reopen it
issue.edit(state='open')

# Assign to a user
from github import NamedUser
issue.edit(assignees=['bob', 'carol'])

# Update the body
issue.edit(body=issue.body + '\n\n**Update:** Hotfix deployed to production.')

إدارة التسميات

تُستخدم التسميات لتنظيم المشكلات. احصلوا على جميع تسميات المستودع باستخدام repo.get_labels()، وأنشئوا تسميات جديدة باستخدام repo.create_label()، وأضيفوا التسميات إلى مشكلة أو أزيلوها منها باستخدام issue.add_to_labels() وissue.remove_from_labels().

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')

# List all labels
for label in repo.get_labels():
    print(f'{label.name}: #{label.color}')

# Create a new label if it doesn't exist
existing_names = {l.name for l in repo.get_labels()}
if 'agent-reviewed' not in existing_names:
    repo.create_label(
        name='agent-reviewed',
        color='0075ca',       # hex without #
        description='Reviewed by AI agent'
    )
    print('Created label: agent-reviewed')

# Add a label to an issue
issue = repo.get_issue(42)
issue.add_to_labels('agent-reviewed')

# Remove a label
issue.remove_from_labels('needs-triage')

قراءة تعليقات المشكلات

استخدموا issue.get_comments() لاسترداد جميع التعليقات على مشكلة. يحتوي كل تعليق على مؤلف (user.login) ونص وتواريخ. كرّروا عليها بالترتيب لمتابعة سجل المحادثة.

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
issue = repo.get_issue(42)

# Get all comments
comments = list(issue.get_comments())
print(f'Comments on #{issue.number}: {len(comments)}')

for comment in comments:
    print(f'\n{comment.user.login} ({comment.created_at.date()}):')
    print(comment.body[:200])

# Get only recent comments
for comment in issue.get_comments(since=cutoff):
    print(f'Recent: {comment.user.login}: {comment.body[:100]}')

إضافة تعليقات إلى المشكلات

استخدموا issue.create_comment(body) لنشر تعليق. يدعم النص الأساسي Markdown. ينبغي أن توضّح تعليقات الوكيل أنها آلية — أدرجوا عنوانًا مثل "🤖 Automated analysis" لتوضيح ذلك.

from github import Github
import os
import datetime

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')
issue = repo.get_issue(42)

# Add an agent comment with clear attribution
agent_comment = (
    '**Automated Analysis** (via code-review agent)\n\n'
    '---\n'
    f'**Issue classified as:** Critical Bug\n'
    f'**Suggested priority:** P0\n'
    f'**Suggested assignee:** @backend-team\n\n'
    '**Analysis:**\n'
    'The login 500 error matches pattern #12 in our known issues database.\n'
    'Likely cause: database connection pool exhaustion during peak traffic.\n\n'
    '**Suggested fix:** Increase pool size in `db_config.py` or add circuit breaker.\n\n'
    f'_Generated at {datetime.datetime.now().strftime("%Y-%m-%d %H:%M UTC")}_'
)

comment = issue.create_comment(agent_comment)
print(f'Comment added: {comment.html_url}')

وكيل فرز جماعي للمشكلات

يعالج وكيل الفرز المشكلات الجديدة تلقائيًا: يقرأ العنوان والنص الأساسي، ويصنّفهما باستخدام LLM، ويضيف التسميات المناسبة، ويسند المشكلة إلى الفريق الصحيح، وينشر تعليقًا أوليًا. ويوفر ذلك على المهندسين ساعات من العمل اليدوي في فرز المشكلات.

import anthropic
import json
import os
from github import Github

g = Github(token=os.environ['GITHUB_TOKEN'])
client = anthropic.Anthropic(api_key=os.environ['ANTHROPIC_API_KEY'])

def triage_issue(repo, issue):
    prompt = (
        'Classify this GitHub issue. Return JSON only:\n'
        '{"type": "bug|feature|question|docs", '
        '"priority": "critical|high|medium|low", '
        '"team": "backend|frontend|infra|ml", '
        '"summary": "one sentence"}\n\n'
        f'Title: {issue.title}\n'
        f'Body: {(issue.body or "")[:1000]}'
    )
    response = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=200,
        messages=[{'role': 'user', 'content': prompt}]
    )
    try:
        return json.loads(response.content[0].text)
    except json.JSONDecodeError:
        return {'type': 'question', 'priority': 'medium', 'team': 'backend', 'summary': 'Needs manual review'}

تطبيق نتائج الفرز على المشكلات

طبّقوا تصنيف الفرز الذي أنشأه LLM على المشكلة: عيّنوا التسميات بناءً على النوع والأولوية، وأسندوا المشكلة إلى قائد الفريق المناسب، وانشروا تعليقًا عن الفرز. تتبّعوا المشكلات التي خضعت للفرز باستخدام تسمية مخصصة لتجنب معالجتها مرة أخرى.

TEAM_ASSIGNEES = {
    'backend': 'alice',
    'frontend': 'bob',
    'infra': 'carol',
    'ml': 'dave'
}

def apply_triage(repo, issue, classification):
    issue_type = classification.get('type', 'question')
    priority = classification.get('priority', 'medium')
    team = classification.get('team', 'backend')
    summary = classification.get('summary', '')

    # Apply labels
    labels_to_add = [f'type:{issue_type}', f'priority:{priority}', 'agent-triaged']
    issue.edit(labels=labels_to_add)

    # Assign to team lead
    assignee = TEAM_ASSIGNEES.get(team, 'alice')
    issue.edit(assignees=[assignee])

    # Post triage comment
    comment = (
        f'**Automated Triage**\n\n'
        f'Type: `{issue_type}` | Priority: `{priority}` | Team: `{team}`\n'
        f'Summary: {summary}\n\n'
        f'Assigned to @{assignee} for follow-up.'
    )
    issue.create_comment(comment)
    print(f'Triaged #{issue.number}: {issue_type}/{priority} -> {assignee}')

# --- demo: minimal stand-in for a GitHub Issue object ---
class _FakeIssue:
    number = 501
    def edit(self, **kwargs):
        print(f'[github] issue.edit({kwargs})')
    def create_comment(self, body):
        print(f'[github] comment posted:\n{body}')

classification = {'type': 'bug', 'priority': 'high', 'team': 'backend',
                   'summary': 'Login fails with 500 when email has a plus sign'}
apply_triage('coddy-agents', _FakeIssue(), classification)

إغلاق المشكلات القديمة تلقائيًا

تُعد إدارة المشكلات القديمة من عمليات الأتمتة الشائعة: العثور على المشكلات المفتوحة التي لم تشهد نشاطًا منذ N يومًا، ونشر تعليق تحذيري، وإغلاقها إذا لم يصل رد خلال فترة سماح. استخدموا issue.updated_at للتحقق من النشاط وissue.edit(state='closed') للإغلاق.

import datetime
from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')

STALE_DAYS = 90
GRACE_DAYS = 14

now = datetime.datetime.utcnow()
stale_cutoff = now - datetime.timedelta(days=STALE_DAYS)

for issue in repo.get_issues(state='open'):
    last_updated = issue.updated_at.replace(tzinfo=None)
    if last_updated > stale_cutoff:
        continue

    # Check if stale warning already posted
    comments = list(issue.get_comments())
    stale_warned = any('stale' in c.body.lower() for c in comments)

    if not stale_warned:
        issue.create_comment(
            'This issue has been inactive for 90 days. '
            'It will be closed in 14 days unless there is activity.'
        )
        issue.add_to_labels('stale')
        print(f'Stale warning: #{issue.number}')

تحقق سريع: issue.edit() مقابل create_issue()

اختبروا مدى فهمكم لإدارة مشكلات GitHub.

خلاصة إدارة المشكلات

يمكن لوكيلكم الآن إدارة مشكلات GitHub من البداية إلى النهاية:

  • repo.get_issues(state, labels, assignee, since) — تصفية المشكلات وسردها
  • repo.get_issue(number) — الحصول على مشكلة محددة حسب الرقم
  • repo.create_issue(title, body, labels, assignees) — فتح مشكلة جديدة
  • issue.edit(state, title, labels, assignees) — تحديث أي حقل
  • issue.create_comment(body) — إضافة تعليق بتنسيق Markdown
  • repo.create_label() / issue.add_to_labels() — إدارة التسميات
  • احرصوا دائمًا على توضيح أن تعليقات الوكيل آلية لتمييزها عن نشاط المستخدمين
  • استخدموا تسميات 'agent-triaged' لمنع إعادة المعالجة

الأسئلة الشائعة

هل درس «عرض المشكلات وإدارتها» مجاني؟

نعم — نص درس «عرض المشكلات وإدارتها» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Agents، انتقل إلى CoddyKit PRO. تتضمن دورة AI Agents 4 دروس في المجموع.

ماذا ستتعلم في «عرض المشكلات وإدارتها»؟

جلب المشكلات وإنشاؤها وإضافة الوسوم إليها وإغلاقها برمجيًا تتمرن على AI Agents مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Agents؟

لا تُشترط خبرة سابقة. AI Agents على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «عرض المشكلات وإدارتها»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Agents هذا؟

نعم. كل درس في AI Agents يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. نظرة عامة على GitHub REST API
  2. عرض المشكلات وإدارتها
  3. تعليقات المراجعة الآلية لـ PR
  4. تحليل سجل الالتزامات والفروق
← العودة إلى AI Agents