0
# Issues and Pull Requests
1
2
Complete issue and pull request lifecycle management including creation, editing, commenting, labeling, milestone assignment, and review processes.
3
4
## Capabilities
5
6
### Issue Management
7
8
Create, edit, and manage GitHub issues with full support for labels, assignees, milestones, and comments.
9
10
```python { .api }
11
class Repository:
12
def get_issues(
13
self,
14
milestone: Union[Milestone, str] = None,
15
state: str = None,
16
assignee: Union[NamedUser, str] = None,
17
mentioned: NamedUser = None,
18
labels: list = None,
19
sort: str = None,
20
direction: str = None,
21
since: datetime = None
22
):
23
"""
24
Get repository issues.
25
26
Args:
27
milestone (Union[Milestone, str], optional): Filter by milestone ("*", "none", or milestone)
28
state (str, optional): Issue state ("open", "closed", "all")
29
assignee (Union[NamedUser, str], optional): Filter by assignee ("*", "none", or username)
30
mentioned (NamedUser, optional): Filter by mentioned user
31
labels (list, optional): List of label names
32
sort (str, optional): Sort by ("created", "updated", "comments")
33
direction (str, optional): Sort direction ("asc", "desc")
34
since (datetime, optional): Only issues updated after this date
35
36
Returns:
37
PaginatedList[Issue]: List of issues
38
"""
39
40
def get_issue(self, number: int):
41
"""
42
Get a specific issue by number.
43
44
Args:
45
number (int): Issue number
46
47
Returns:
48
Issue: Issue object
49
"""
50
51
def create_issue(
52
self,
53
title: str,
54
body: str = None,
55
assignee: str = None,
56
milestone: Milestone = None,
57
labels: list = None,
58
assignees: list = None
59
):
60
"""
61
Create a new issue.
62
63
Args:
64
title (str): Issue title
65
body (str, optional): Issue body text
66
assignee (str, optional): Username of assignee (deprecated, use assignees)
67
milestone (Milestone, optional): Milestone to assign
68
labels (list, optional): List of label names or Label objects
69
assignees (list, optional): List of usernames to assign
70
71
Returns:
72
Issue: Created issue
73
"""
74
75
class Issue:
76
# Issue properties
77
@property
78
def number(self) -> int: ...
79
@property
80
def title(self) -> str: ...
81
@property
82
def body(self) -> str: ...
83
@property
84
def state(self) -> str: ... # "open" or "closed"
85
@property
86
def user(self) -> NamedUser: ...
87
@property
88
def assignee(self) -> NamedUser: ...
89
@property
90
def assignees(self) -> list: ...
91
@property
92
def milestone(self) -> Milestone: ...
93
@property
94
def labels(self) -> list: ...
95
@property
96
def comments(self) -> int: ...
97
@property
98
def created_at(self) -> datetime: ...
99
@property
100
def updated_at(self) -> datetime: ...
101
@property
102
def closed_at(self) -> datetime: ...
103
@property
104
def closed_by(self) -> NamedUser: ...
105
@property
106
def html_url(self) -> str: ...
107
@property
108
def pull_request(self) -> IssuePullRequest: ... # Present if issue is a PR
109
110
def edit(
111
self,
112
title: str = None,
113
body: str = None,
114
assignee: str = None,
115
state: str = None,
116
milestone: Milestone = None,
117
labels: list = None,
118
assignees: list = None
119
):
120
"""
121
Edit issue properties.
122
123
Args:
124
title (str, optional): New title
125
body (str, optional): New body text
126
assignee (str, optional): Username of assignee (deprecated)
127
state (str, optional): New state ("open", "closed")
128
milestone (Milestone, optional): Milestone to assign
129
labels (list, optional): List of labels
130
assignees (list, optional): List of assignee usernames
131
"""
132
133
def create_comment(self, body: str):
134
"""
135
Create a comment on the issue.
136
137
Args:
138
body (str): Comment body text
139
140
Returns:
141
IssueComment: Created comment
142
"""
143
144
def get_comments(self, since: datetime = None):
145
"""
146
Get issue comments.
147
148
Args:
149
since (datetime, optional): Only comments updated after this date
150
151
Returns:
152
PaginatedList[IssueComment]: List of comments
153
"""
154
155
def add_to_labels(self, *labels):
156
"""
157
Add labels to the issue.
158
159
Args:
160
*labels: Label names or Label objects to add
161
"""
162
163
def remove_from_labels(self, *labels):
164
"""
165
Remove labels from the issue.
166
167
Args:
168
*labels: Label names or Label objects to remove
169
"""
170
171
def set_labels(self, *labels):
172
"""
173
Replace all labels on the issue.
174
175
Args:
176
*labels: Label names or Label objects
177
"""
178
179
def add_to_assignees(self, *assignees):
180
"""
181
Add assignees to the issue.
182
183
Args:
184
*assignees: Usernames or NamedUser objects to assign
185
"""
186
187
def remove_from_assignees(self, *assignees):
188
"""
189
Remove assignees from the issue.
190
191
Args:
192
*assignees: Usernames or NamedUser objects to unassign
193
"""
194
195
def get_events(self):
196
"""
197
Get issue events (labeled, assigned, closed, etc.).
198
199
Returns:
200
PaginatedList[IssueEvent]: List of events
201
"""
202
203
def get_timeline(self):
204
"""
205
Get issue timeline (comments and events combined).
206
207
Returns:
208
PaginatedList[TimelineEvent]: List of timeline events
209
"""
210
211
def lock(self, lock_reason: str = None):
212
"""
213
Lock the issue.
214
215
Args:
216
lock_reason (str, optional): Lock reason ("off-topic", "too heated", "resolved", "spam")
217
"""
218
219
def unlock(self):
220
"""Unlock the issue."""
221
```
222
223
### Issue Comments
224
225
Manage comments on issues and pull requests.
226
227
```python { .api }
228
class IssueComment:
229
@property
230
def id(self) -> int: ...
231
@property
232
def body(self) -> str: ...
233
@property
234
def user(self) -> NamedUser: ...
235
@property
236
def created_at(self) -> datetime: ...
237
@property
238
def updated_at(self) -> datetime: ...
239
@property
240
def html_url(self) -> str: ...
241
242
def edit(self, body: str):
243
"""
244
Edit comment body.
245
246
Args:
247
body (str): New comment body
248
"""
249
250
def delete(self):
251
"""Delete the comment."""
252
253
def get_reactions(self):
254
"""
255
Get comment reactions.
256
257
Returns:
258
PaginatedList[Reaction]: List of reactions
259
"""
260
261
def create_reaction(self, reaction_type: str):
262
"""
263
Add reaction to comment.
264
265
Args:
266
reaction_type (str): Reaction type ("+1", "-1", "laugh", "confused", "heart", "hooray", "rocket", "eyes")
267
268
Returns:
269
Reaction: Created reaction
270
"""
271
```
272
273
### Pull Request Management
274
275
Complete pull request lifecycle including creation, review, merging, and file management.
276
277
```python { .api }
278
class Repository:
279
def get_pulls(
280
self,
281
state: str = None,
282
head: str = None,
283
base: str = None,
284
sort: str = None,
285
direction: str = None
286
):
287
"""
288
Get repository pull requests.
289
290
Args:
291
state (str, optional): PR state ("open", "closed", "all")
292
head (str, optional): Filter by head branch (format: "user:ref-name")
293
base (str, optional): Filter by base branch
294
sort (str, optional): Sort by ("created", "updated", "popularity")
295
direction (str, optional): Sort direction ("asc", "desc")
296
297
Returns:
298
PaginatedList[PullRequest]: List of pull requests
299
"""
300
301
def get_pull(self, number: int):
302
"""
303
Get a specific pull request by number.
304
305
Args:
306
number (int): Pull request number
307
308
Returns:
309
PullRequest: Pull request object
310
"""
311
312
def create_pull(
313
self,
314
title: str,
315
body: str = None,
316
head: str = None,
317
base: str = None,
318
maintainer_can_modify: bool = None,
319
draft: bool = None
320
):
321
"""
322
Create a new pull request.
323
324
Args:
325
title (str): Pull request title
326
body (str, optional): Pull request body text
327
head (str): Branch containing changes (format: "user:ref-name" or "ref-name")
328
base (str): Branch to merge into
329
maintainer_can_modify (bool, optional): Allow maintainers to modify PR
330
draft (bool, optional): Create as draft PR
331
332
Returns:
333
PullRequest: Created pull request
334
"""
335
336
class PullRequest:
337
# Pull request properties (inherits from Issue)
338
@property
339
def number(self) -> int: ...
340
@property
341
def title(self) -> str: ...
342
@property
343
def body(self) -> str: ...
344
@property
345
def state(self) -> str: ... # "open" or "closed"
346
@property
347
def user(self) -> NamedUser: ...
348
@property
349
def head(self) -> PullRequestPart: ...
350
@property
351
def base(self) -> PullRequestPart: ...
352
@property
353
def merged(self) -> bool: ...
354
@property
355
def merged_at(self) -> datetime: ...
356
@property
357
def merged_by(self) -> NamedUser: ...
358
@property
359
def mergeable(self) -> bool: ...
360
@property
361
def mergeable_state(self) -> str: ...
362
@property
363
def merge_commit_sha(self) -> str: ...
364
@property
365
def additions(self) -> int: ...
366
@property
367
def deletions(self) -> int: ...
368
@property
369
def changed_files(self) -> int: ...
370
@property
371
def commits(self) -> int: ...
372
@property
373
def review_comments(self) -> int: ...
374
@property
375
def maintainer_can_modify(self) -> bool: ...
376
@property
377
def draft(self) -> bool: ...
378
@property
379
def rebaseable(self) -> bool: ...
380
381
def edit(
382
self,
383
title: str = None,
384
body: str = None,
385
state: str = None,
386
base: str = None,
387
maintainer_can_modify: bool = None
388
):
389
"""
390
Edit pull request properties.
391
392
Args:
393
title (str, optional): New title
394
body (str, optional): New body text
395
state (str, optional): New state ("open", "closed")
396
base (str, optional): New base branch
397
maintainer_can_modify (bool, optional): Allow maintainer modifications
398
"""
399
400
def merge(
401
self,
402
commit_message: str = None,
403
commit_title: str = None,
404
merge_method: str = None,
405
sha: str = None
406
):
407
"""
408
Merge the pull request.
409
410
Args:
411
commit_message (str, optional): Merge commit message
412
commit_title (str, optional): Merge commit title
413
merge_method (str, optional): Merge method ("merge", "squash", "rebase")
414
sha (str, optional): SHA of head commit to verify
415
416
Returns:
417
PullRequestMergeStatus: Merge result
418
"""
419
420
def is_merged(self):
421
"""
422
Check if pull request is merged.
423
424
Returns:
425
bool: True if merged
426
"""
427
428
def get_commits(self):
429
"""
430
Get pull request commits.
431
432
Returns:
433
PaginatedList[Commit]: List of commits
434
"""
435
436
def get_files(self):
437
"""
438
Get files changed in the pull request.
439
440
Returns:
441
PaginatedList[File]: List of changed files
442
"""
443
444
def create_review(
445
self,
446
body: str = None,
447
event: str = None,
448
comments: list = None
449
):
450
"""
451
Create a pull request review.
452
453
Args:
454
body (str, optional): Review body text
455
event (str, optional): Review event ("APPROVE", "REQUEST_CHANGES", "COMMENT")
456
comments (list, optional): List of review comments
457
458
Returns:
459
PullRequestReview: Created review
460
"""
461
462
def get_reviews(self):
463
"""
464
Get pull request reviews.
465
466
Returns:
467
PaginatedList[PullRequestReview]: List of reviews
468
"""
469
470
def get_review_comments(self, since: datetime = None):
471
"""
472
Get pull request review comments.
473
474
Args:
475
since (datetime, optional): Only comments updated after this date
476
477
Returns:
478
PaginatedList[PullRequestComment]: List of review comments
479
"""
480
481
def create_review_comment(
482
self,
483
body: str,
484
commit_id: str,
485
path: str,
486
position: int
487
):
488
"""
489
Create a review comment on a specific line.
490
491
Args:
492
body (str): Comment body
493
commit_id (str): SHA of commit to comment on
494
path (str): File path
495
position (int): Line position in diff
496
497
Returns:
498
PullRequestComment: Created review comment
499
"""
500
```
501
502
### Pull Request Reviews
503
504
Manage pull request reviews and review comments.
505
506
```python { .api }
507
class PullRequestReview:
508
@property
509
def id(self) -> int: ...
510
@property
511
def body(self) -> str: ...
512
@property
513
def user(self) -> NamedUser: ...
514
@property
515
def state(self) -> str: ... # "PENDING", "APPROVED", "CHANGES_REQUESTED", "COMMENTED", "DISMISSED"
516
@property
517
def commit_id(self) -> str: ...
518
@property
519
def submitted_at(self) -> datetime: ...
520
@property
521
def html_url(self) -> str: ...
522
523
def edit(self, body: str):
524
"""
525
Edit review body.
526
527
Args:
528
body (str): New review body
529
"""
530
531
def dismiss(self, message: str):
532
"""
533
Dismiss the review.
534
535
Args:
536
message (str): Dismissal message
537
"""
538
539
def submit(self, body: str, event: str):
540
"""
541
Submit pending review.
542
543
Args:
544
body (str): Review body
545
event (str): Review event ("APPROVE", "REQUEST_CHANGES", "COMMENT")
546
"""
547
548
class PullRequestComment:
549
@property
550
def id(self) -> int: ...
551
@property
552
def body(self) -> str: ...
553
@property
554
def user(self) -> NamedUser: ...
555
@property
556
def path(self) -> str: ...
557
@property
558
def position(self) -> int: ...
559
@property
560
def original_position(self) -> int: ...
561
@property
562
def commit_id(self) -> str: ...
563
@property
564
def original_commit_id(self) -> str: ...
565
@property
566
def diff_hunk(self) -> str: ...
567
@property
568
def created_at(self) -> datetime: ...
569
@property
570
def updated_at(self) -> datetime: ...
571
@property
572
def html_url(self) -> str: ...
573
574
def edit(self, body: str):
575
"""
576
Edit review comment body.
577
578
Args:
579
body (str): New comment body
580
"""
581
582
def delete(self):
583
"""Delete the review comment."""
584
585
def get_reactions(self):
586
"""
587
Get comment reactions.
588
589
Returns:
590
PaginatedList[Reaction]: List of reactions
591
"""
592
593
def create_reaction(self, reaction_type: str):
594
"""
595
Add reaction to comment.
596
597
Args:
598
reaction_type (str): Reaction type
599
600
Returns:
601
Reaction: Created reaction
602
"""
603
```
604
605
### Labels and Milestones
606
607
Manage repository labels and milestones for issue organization.
608
609
```python { .api }
610
class Repository:
611
def get_labels(self):
612
"""
613
Get repository labels.
614
615
Returns:
616
PaginatedList[Label]: List of labels
617
"""
618
619
def get_label(self, name: str):
620
"""
621
Get a specific label.
622
623
Args:
624
name (str): Label name
625
626
Returns:
627
Label: Label object
628
"""
629
630
def create_label(self, name: str, color: str, description: str = None):
631
"""
632
Create a new label.
633
634
Args:
635
name (str): Label name
636
color (str): Label color (hex code without #)
637
description (str, optional): Label description
638
639
Returns:
640
Label: Created label
641
"""
642
643
def get_milestones(self, state: str = None, sort: str = None, direction: str = None):
644
"""
645
Get repository milestones.
646
647
Args:
648
state (str, optional): Milestone state ("open", "closed", "all")
649
sort (str, optional): Sort by ("due_on", "completeness")
650
direction (str, optional): Sort direction ("asc", "desc")
651
652
Returns:
653
PaginatedList[Milestone]: List of milestones
654
"""
655
656
def get_milestone(self, number: int):
657
"""
658
Get a specific milestone.
659
660
Args:
661
number (int): Milestone number
662
663
Returns:
664
Milestone: Milestone object
665
"""
666
667
def create_milestone(
668
self,
669
title: str,
670
state: str = None,
671
description: str = None,
672
due_on: datetime = None
673
):
674
"""
675
Create a new milestone.
676
677
Args:
678
title (str): Milestone title
679
state (str, optional): Milestone state ("open", "closed")
680
description (str, optional): Milestone description
681
due_on (datetime, optional): Due date
682
683
Returns:
684
Milestone: Created milestone
685
"""
686
687
class Label:
688
@property
689
def name(self) -> str: ...
690
@property
691
def color(self) -> str: ...
692
@property
693
def description(self) -> str: ...
694
@property
695
def url(self) -> str: ...
696
697
def edit(self, name: str = None, color: str = None, description: str = None):
698
"""
699
Edit label properties.
700
701
Args:
702
name (str, optional): New name
703
color (str, optional): New color
704
description (str, optional): New description
705
"""
706
707
def delete(self):
708
"""Delete the label."""
709
710
class Milestone:
711
@property
712
def number(self) -> int: ...
713
@property
714
def title(self) -> str: ...
715
@property
716
def description(self) -> str: ...
717
@property
718
def state(self) -> str: ...
719
@property
720
def open_issues(self) -> int: ...
721
@property
722
def closed_issues(self) -> int: ...
723
@property
724
def created_at(self) -> datetime: ...
725
@property
726
def updated_at(self) -> datetime: ...
727
@property
728
def due_on(self) -> datetime: ...
729
@property
730
def creator(self) -> NamedUser: ...
731
732
def edit(
733
self,
734
title: str = None,
735
state: str = None,
736
description: str = None,
737
due_on: datetime = None
738
):
739
"""
740
Edit milestone properties.
741
742
Args:
743
title (str, optional): New title
744
state (str, optional): New state
745
description (str, optional): New description
746
due_on (datetime, optional): New due date
747
"""
748
749
def delete(self):
750
"""Delete the milestone."""
751
752
def get_labels(self):
753
"""
754
Get labels for issues in this milestone.
755
756
Returns:
757
PaginatedList[Label]: List of labels
758
"""
759
```
760
761
## Usage Examples
762
763
### Issue Management
764
765
```python
766
from github import Github, Auth
767
768
g = Github(auth=Auth.Token("your_token"))
769
repo = g.get_repo("owner/repository")
770
771
# Create an issue
772
issue = repo.create_issue(
773
title="Bug: Application crashes on startup",
774
body="The application crashes when starting with the following error...",
775
labels=["bug", "high-priority"],
776
assignees=["developer1", "developer2"]
777
)
778
print(f"Created issue #{issue.number}")
779
780
# Add comment to issue
781
comment = issue.create_comment("I can reproduce this issue on Windows 10.")
782
print(f"Added comment: {comment.body}")
783
784
# Update issue
785
issue.edit(
786
state="closed",
787
body="Fixed in commit abc123"
788
)
789
790
# List repository issues
791
for issue in repo.get_issues(state='open', labels=['bug']):
792
print(f"Bug #{issue.number}: {issue.title}")
793
```
794
795
### Pull Request Management
796
797
```python
798
# Create pull request
799
pr = repo.create_pull(
800
title="Fix application crash on startup",
801
body="This PR fixes the crash by handling the null pointer exception.",
802
head="fix-startup-crash", # Source branch
803
base="main" # Target branch
804
)
805
print(f"Created PR #{pr.number}")
806
807
# Review pull request
808
review = pr.create_review(
809
body="Great fix! Just a couple of minor suggestions.",
810
event="APPROVE"
811
)
812
813
# Add review comment on specific line
814
review_comment = pr.create_review_comment(
815
body="Consider adding error handling here.",
816
commit_id=pr.head.sha,
817
path="src/main.py",
818
position=42
819
)
820
821
# Merge pull request
822
merge_result = pr.merge(
823
commit_message="Fix application crash on startup",
824
merge_method="squash"
825
)
826
print(f"Merged: {merge_result.merged}")
827
```
828
829
### Labels and Milestones
830
831
```python
832
# Create labels
833
bug_label = repo.create_label(
834
name="bug",
835
color="d73a4a",
836
description="Something isn't working"
837
)
838
839
# Create milestone
840
milestone = repo.create_milestone(
841
title="Version 2.0",
842
description="Features and fixes for version 2.0 release",
843
due_on=datetime(2024, 12, 31)
844
)
845
846
# Create issue with label and milestone
847
issue = repo.create_issue(
848
title="Implement new feature",
849
labels=[bug_label],
850
milestone=milestone
851
)
852
```