github-overlord 0.3.2__tar.gz → 0.4.0__tar.gz
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.
- {github_overlord-0.3.2 → github_overlord-0.4.0}/PKG-INFO +6 -1
- {github_overlord-0.3.2 → github_overlord-0.4.0}/README.md +5 -1
- {github_overlord-0.3.2 → github_overlord-0.4.0}/github_overlord/__init__.py +77 -17
- {github_overlord-0.3.2 → github_overlord-0.4.0}/github_overlord/utils.py +1 -1
- {github_overlord-0.3.2 → github_overlord-0.4.0}/pyproject.toml +2 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: github-overlord
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Automatically merge Dependabot PRs in public repositories
|
|
5
5
|
Home-page: https://github.com/iloveitaly/github-overlord
|
|
6
6
|
Keywords: github,dependabot,automation
|
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
13
13
|
Requires-Dist: apscheduler (>=3.10.4,<4.0.0)
|
|
14
14
|
Requires-Dist: click (>=8.1.7,<9.0.0)
|
|
15
15
|
Requires-Dist: funcy-pipe (>=0.11.0,<0.12.0)
|
|
16
|
+
Requires-Dist: openai (>=1.33.0,<2.0.0)
|
|
16
17
|
Requires-Dist: pygithub (>=2.3.0,<3.0.0)
|
|
17
18
|
Requires-Dist: python-decouple-typed (>=3.11.0,<4.0.0)
|
|
18
19
|
Requires-Dist: structlog (>=24.2.0,<25.0.0)
|
|
@@ -47,3 +48,7 @@ Options:
|
|
|
47
48
|
```
|
|
48
49
|
|
|
49
50
|
### Docker Cron
|
|
51
|
+
|
|
52
|
+
There's a docker container you can use to run this on a cron. [Fits nicely into a orange pi.](https://mikebian.co/pi-hole-tailscale-and-docker-on-an-orange-pi/)
|
|
53
|
+
|
|
54
|
+
Check out [docker-compose.yml](./docker-compose.yml) for an example, or `git pull ghcr.io/iloveitaly/github-overlord:latest`.
|
|
@@ -26,4 +26,8 @@ Options:
|
|
|
26
26
|
--help Show this message and exit.
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
### Docker Cron
|
|
29
|
+
### Docker Cron
|
|
30
|
+
|
|
31
|
+
There's a docker container you can use to run this on a cron. [Fits nicely into a orange pi.](https://mikebian.co/pi-hole-tailscale-and-docker-on-an-orange-pi/)
|
|
32
|
+
|
|
33
|
+
Check out [docker-compose.yml](./docker-compose.yml) for an example, or `git pull ghcr.io/iloveitaly/github-overlord:latest`.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
3
|
import time
|
|
4
|
+
from types import NoneType
|
|
4
5
|
|
|
5
6
|
import click
|
|
6
7
|
import funcy_pipe as fp
|
|
@@ -42,13 +43,39 @@ def resolve_async_status(object, key):
|
|
|
42
43
|
return
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
def handle_stale_dependabot_pr(pr: PullRequest) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Handle a dependabot PR that has been open for at least 30 days and has conflicts
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
assert not pr.mergeable
|
|
52
|
+
assert pr.mergeable_state == "dirty"
|
|
53
|
+
|
|
54
|
+
if pr.body is None:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
if "Automatic rebases have been disabled on this pull request" in pr.body:
|
|
58
|
+
log.info(
|
|
59
|
+
"PR has disabled automatic rebases, manually commenting", url=pr.html_url
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
pr.create_issue_comment("@dependabot rebase")
|
|
63
|
+
|
|
64
|
+
|
|
45
65
|
def is_eligible_for_merge(pr: PullRequest):
|
|
46
66
|
resolve_async_status(pr, "mergeable")
|
|
47
67
|
|
|
68
|
+
if pr.state == "closed":
|
|
69
|
+
log.debug("PR is closed", url=pr.html_url)
|
|
70
|
+
return
|
|
71
|
+
|
|
48
72
|
if not pr.mergeable:
|
|
73
|
+
log.debug("PR is not mergeable", url=pr.html_url)
|
|
74
|
+
handle_stale_dependabot_pr(pr)
|
|
49
75
|
return False
|
|
50
76
|
|
|
51
77
|
if pr.user.login != "dependabot[bot]":
|
|
78
|
+
log.debug("PR is not from dependabot", url=pr.html_url)
|
|
52
79
|
return False
|
|
53
80
|
|
|
54
81
|
last_commit = pr.get_commits().reversed[0]
|
|
@@ -57,43 +84,51 @@ def is_eligible_for_merge(pr: PullRequest):
|
|
|
57
84
|
|
|
58
85
|
# status is different than CI runs!
|
|
59
86
|
if len(combined_status.statuses) > 0 and status != "success":
|
|
87
|
+
log.debug("PR has failed status", url=pr.html_url, status=status)
|
|
60
88
|
return False
|
|
61
89
|
|
|
62
90
|
# checks are the CI runs
|
|
63
91
|
all_checks_successful = (
|
|
64
|
-
last_commit.get_check_runs()
|
|
92
|
+
last_commit.get_check_runs()
|
|
93
|
+
| fp.pluck_attr("conclusion")
|
|
94
|
+
| fp.all({"success", "skipped"})
|
|
65
95
|
)
|
|
66
96
|
|
|
67
97
|
if not all_checks_successful:
|
|
98
|
+
log.debug("PR has failed checks", url=pr.html_url)
|
|
68
99
|
return False
|
|
69
100
|
|
|
70
101
|
return True
|
|
71
102
|
|
|
72
103
|
|
|
73
104
|
def process_repo(repo, dry_run):
|
|
74
|
-
log.
|
|
105
|
+
with log.context(repo=repo.full_name):
|
|
106
|
+
log.debug("checking repository")
|
|
75
107
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
108
|
+
if repo.fork:
|
|
109
|
+
log.debug("skipping forked repo")
|
|
110
|
+
return
|
|
79
111
|
|
|
80
|
-
|
|
112
|
+
pulls = repo.get_pulls(state="open")
|
|
81
113
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
114
|
+
if pulls.totalCount == 0 or pulls == NoneType:
|
|
115
|
+
log.debug("no open prs, skipping")
|
|
116
|
+
return
|
|
85
117
|
|
|
86
|
-
|
|
118
|
+
merged_pr_count = 0
|
|
87
119
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
120
|
+
for pr in pulls:
|
|
121
|
+
if is_eligible_for_merge(pr):
|
|
122
|
+
merge_pr(pr, dry_run)
|
|
91
123
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
124
|
+
merged_pr_count += 1
|
|
125
|
+
else:
|
|
126
|
+
log.debug("skipping PR", url=pr.html_url)
|
|
95
127
|
|
|
96
|
-
|
|
128
|
+
if merged_pr_count == 0:
|
|
129
|
+
log.debug("no PRs were merged")
|
|
130
|
+
else:
|
|
131
|
+
log.info("merged prs", count=merged_pr_count)
|
|
97
132
|
|
|
98
133
|
|
|
99
134
|
def main(token, dry_run, repo):
|
|
@@ -145,9 +180,34 @@ def dependabot(token, dry_run, repo):
|
|
|
145
180
|
|
|
146
181
|
|
|
147
182
|
def pr_bumper():
|
|
183
|
+
"""
|
|
184
|
+
Look at PRs which you have written:
|
|
185
|
+
|
|
186
|
+
1. There are bots out there which will close the PR if there are is no activity, even if there is no activity from
|
|
187
|
+
the maintainer. This will keep the PR open by adding a comment.
|
|
188
|
+
2. PRs that are not merged, been open for at least 30 days, with no comments from the maintainer.
|
|
189
|
+
"""
|
|
190
|
+
|
|
148
191
|
pass
|
|
149
192
|
|
|
150
193
|
|
|
194
|
+
"""
|
|
195
|
+
token = token or os.getenv('GITHUB_TOKEN')
|
|
196
|
+
if not token:
|
|
197
|
+
raise ValueError("GitHub token must be provided either as an option or via the GITHUB_TOKEN environment variable")
|
|
198
|
+
|
|
199
|
+
g = Github(token)
|
|
200
|
+
user = g.get_user()
|
|
201
|
+
notifications = user.get_notifications()
|
|
202
|
+
|
|
203
|
+
for notification in notifications:
|
|
204
|
+
print(f"Notification: {notification.subject['title']}, Reason: {notification.reason}")
|
|
205
|
+
if not read_only:
|
|
206
|
+
notification.mark_as_read()
|
|
207
|
+
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
|
|
151
211
|
cli.add_command(dependabot)
|
|
152
212
|
|
|
153
213
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "github-overlord"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Automatically merge Dependabot PRs in public repositories"
|
|
5
5
|
authors = ["Michael Bianco <mike@mikebian.co>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -15,6 +15,7 @@ python-decouple-typed = "^3.11.0"
|
|
|
15
15
|
funcy-pipe = "^0.11.0"
|
|
16
16
|
structlog = "^24.2.0"
|
|
17
17
|
apscheduler = "^3.10.4"
|
|
18
|
+
openai = "^1.33.0"
|
|
18
19
|
|
|
19
20
|
[tool.poetry.scripts]
|
|
20
21
|
github-overlord = "github_overlord:cli"
|