Listowanie i zarządzanie zgłoszeniami
Programowe pobieranie, tworzenie, etykietowanie i zamykanie zgłoszeń.
Listowanie i zarządzanie zgłoszeniami to bezpłatna lekcja AI Agents na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Agents, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Agents zawiera 4 lekcji w sumie.
Pobieranie zgłoszeń z repozytorium
Za pomocą repo.get_issues() można wyświetlić listę zgłoszeń. Domyślnie metoda zwraca otwarte zgłoszenia; aby pobrać zgłoszenia o innym stanie, należy przekazać state='closed' lub state='all'. Wynikiem jest obiekt PaginatedList — należy go iterować, aby przetworzyć każde zgłoszenie.
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()}')Filtrowanie zgłoszeń
Metoda get_issues() obsługuje kilka parametrów filtrowania: state, labels, assignee, milestone, since i sort. Można je łączyć, aby pobrać dokładnie te zgłoszenia, które agent ma przetworzyć.
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}')Dostęp do właściwości zgłoszenia
Każdy obiekt Issue ma rozbudowane właściwości: numer, tytuł, treść, etykiety, osoby przypisane, kamień milowy, stan, liczbę komentarzy i znaczniki czasu. Dostęp do nich uzyskuje się jako do atrybutów Pythona. Treść ma postać surowego tekstu 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}')Tworzenie nowych zgłoszeń
Za pomocą repo.create_issue() można programowo utworzyć nowe zgłoszenie. Jedynym wymaganym polem jest title. Można także dodać body (Markdown), labels (etykiety muszą już istnieć), assignees (nazwy użytkowników GitHuba) oraz milestone (obiekt kamienia milowego).
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}')Edycja (aktualizowanie) zgłoszeń
Za pomocą issue.edit() można zaktualizować dowolną właściwość istniejącego zgłoszenia. W jednym wywołaniu można zmienić tytuł, treść, stan, etykiety, osoby przypisane lub kamień milowy. Należy przekazać tylko pola, które mają zostać zmienione — pozostałe zostaną zachowane.
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.')Zarządzanie etykietami
Etykiety służą do porządkowania zgłoszeń. Wszystkie etykiety repozytorium można pobrać za pomocą repo.get_labels(), nowe utworzyć za pomocą repo.create_label(), a etykiety zgłoszenia dodawać i usuwać za pomocą issue.add_to_labels() oraz 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')Odczytywanie komentarzy do zgłoszeń
Za pomocą issue.get_comments() można pobrać wszystkie komentarze do zgłoszenia. Każdy komentarz zawiera autora (user.login), treść oraz znaczniki czasu. Należy iterować po komentarzach w kolejności, aby zobaczyć historię rozmowy.
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]}')Dodawanie komentarzy do zgłoszeń
Za pomocą issue.create_comment(body) można opublikować komentarz. Treść obsługuje Markdown. Komentarze agenta powinny jasno wskazywać, że są automatyczne — warto dodać nagłówek „🤖 Automated analysis”, aby określić ich charakter.
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}')Agent do masowej kategoryzacji zgłoszeń
Agent do kategoryzacji automatycznie przetwarza nowe zgłoszenia: odczytuje tytuł i treść, klasyfikuje je za pomocą LLM, dodaje odpowiednie etykiety, przypisuje je właściwemu zespołowi i publikuje pierwszy komentarz. Pozwala to zaoszczędzić inżynierom wiele godzin ręcznej pracy związanej z kategoryzacją.
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'}Zastosowanie wyników kategoryzacji do zgłoszeń
Wynik klasyfikacji LLM należy zastosować do zgłoszenia: ustawić etykiety na podstawie typu i priorytetu, przypisać zgłoszenie odpowiedniemu liderowi zespołu oraz opublikować komentarz z wynikiem kategoryzacji. Aby uniknąć ponownego przetwarzania, należy śledzić, które zgłoszenia zostały już skategoryzowane, korzystając z niestandardowej etykiety.
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)
Automatyczne zamykanie nieaktywnych zgłoszeń
Zarządzanie nieaktywnymi zgłoszeniami jest częstym zadaniem automatyzacji: należy znaleźć otwarte zgłoszenia bez aktywności przez N dni, opublikować komentarz ostrzegawczy i zamknąć je, jeśli w okresie karencji nie pojawi się odpowiedź. Do sprawdzania aktywności należy użyć issue.updated_at, a do zamykania zgłoszeń 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}')Szybki test: issue.edit() a create_issue()
Proszę sprawdzić swoją wiedzę na temat zarządzania zgłoszeniami GitHuba.
Podsumowanie: zarządzanie zgłoszeniami
Agent może już zarządzać zgłoszeniami GitHuba od początku do końca:
- repo.get_issues(state, labels, assignee, since) — filtrowanie i wyświetlanie zgłoszeń
- repo.get_issue(number) — pobieranie konkretnego zgłoszenia według numeru
- repo.create_issue(title, body, labels, assignees) — otwieranie nowego zgłoszenia
- issue.edit(state, title, labels, assignees) — aktualizowanie dowolnego pola
- issue.create_comment(body) — dodawanie komentarza w formacie Markdown
- repo.create_label() / issue.add_to_labels() — zarządzanie etykietami
- Komentarze agenta należy zawsze wyraźnie oznaczać, aby odróżnić je od aktywności użytkowników
- Należy używać etykiet
'agent-triaged', aby zapobiec ponownemu przetwarzaniu
Często zadawane pytania
Czy lekcja „Listowanie i zarządzanie zgłoszeniami” jest bezpłatna?
Tak — pełny tekst „Listowanie i zarządzanie zgłoszeniami” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Agents, przejdź na CoddyKit PRO. Kurs AI Agents zawiera 4 lekcji w sumie.
Co nauczysz się w „Listowanie i zarządzanie zgłoszeniami”?
Programowe pobieranie, tworzenie, etykietowanie i zamykanie zgłoszeń. Ćwiczysz AI Agents z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Agents?
Nie wymagamy żadnego doświadczenia. AI Agents w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Listowanie i zarządzanie zgłoszeniami”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Agents?
Tak. Każda lekcja AI Agents zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Przegląd GitHub REST API
- Listowanie i zarządzanie zgłoszeniami
- Automatyczne komentarze w przeglądach PR
- Historia commitów i analiza diffów