Skip to content

Commit 0dbabcd

Browse files
committed
Initial commit
0 parents  commit 0dbabcd

15 files changed

Lines changed: 1072 additions & 0 deletions

.flake8

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[flake8]
2+
ignore = E203, E266, E501, W503
3+
max-complexity = 18
4+
select = B,C,E,F,W,T4,B9
5+
max-line-length = 88
6+
exclude = .git,*migrations*

.gitignore

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
.DS_Store
2+
3+
4+
# Created by https://www.gitignore.io/api/macos,linux,python,windows
5+
# Edit at https://www.gitignore.io/?templates=macos,linux,python,windows
6+
7+
### Linux ###
8+
*~
9+
10+
# temporary files which can be created if a process still has a handle open of a deleted file
11+
.fuse_hidden*
12+
13+
# KDE directory preferences
14+
.directory
15+
16+
# Linux trash folder which might appear on any partition or disk
17+
.Trash-*
18+
19+
# .nfs files are created when an open file is removed but is still being accessed
20+
.nfs*
21+
22+
### macOS ###
23+
# General
24+
.DS_Store
25+
.AppleDouble
26+
.LSOverride
27+
28+
# Icon must end with two \r
29+
Icon
30+
31+
# Thumbnails
32+
._*
33+
34+
# Files that might appear in the root of a volume
35+
.DocumentRevisions-V100
36+
.fseventsd
37+
.Spotlight-V100
38+
.TemporaryItems
39+
.Trashes
40+
.VolumeIcon.icns
41+
.com.apple.timemachine.donotpresent
42+
43+
# Directories potentially created on remote AFP share
44+
.AppleDB
45+
.AppleDesktop
46+
Network Trash Folder
47+
Temporary Items
48+
.apdisk
49+
50+
### Python ###
51+
# Byte-compiled / optimized / DLL files
52+
__pycache__/
53+
*.py[cod]
54+
*$py.class
55+
56+
# C extensions
57+
*.so
58+
59+
# Distribution / packaging
60+
.Python
61+
build/
62+
develop-eggs/
63+
dist/
64+
downloads/
65+
eggs/
66+
.eggs/
67+
lib/
68+
lib64/
69+
parts/
70+
sdist/
71+
var/
72+
wheels/
73+
pip-wheel-metadata/
74+
share/python-wheels/
75+
*.egg-info/
76+
.installed.cfg
77+
*.egg
78+
MANIFEST
79+
80+
# PyInstaller
81+
# Usually these files are written by a python script from a template
82+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
83+
*.manifest
84+
*.spec
85+
86+
# Installer logs
87+
pip-log.txt
88+
pip-delete-this-directory.txt
89+
90+
# Unit test / coverage reports
91+
htmlcov/
92+
.tox/
93+
.nox/
94+
.coverage
95+
.coverage.*
96+
.cache
97+
nosetests.xml
98+
coverage.xml
99+
*.cover
100+
.hypothesis/
101+
.pytest_cache/
102+
103+
# Translations
104+
*.mo
105+
*.pot
106+
107+
# Django stuff:
108+
*.log
109+
local_settings.py
110+
db.sqlite3
111+
112+
# Flask stuff:
113+
instance/
114+
.webassets-cache
115+
116+
# Scrapy stuff:
117+
.scrapy
118+
119+
# Sphinx documentation
120+
docs/_build/
121+
122+
# PyBuilder
123+
target/
124+
125+
# Jupyter Notebook
126+
.ipynb_checkpoints
127+
128+
# IPython
129+
profile_default/
130+
ipython_config.py
131+
132+
# pyenv
133+
.python-version
134+
135+
# celery beat schedule file
136+
celerybeat-schedule
137+
138+
# SageMath parsed files
139+
*.sage.py
140+
141+
# Environments
142+
.env
143+
.venv
144+
env/
145+
venv/
146+
ENV/
147+
env.bak/
148+
venv.bak/
149+
150+
# Spyder project settings
151+
.spyderproject
152+
.spyproject
153+
154+
# Rope project settings
155+
.ropeproject
156+
157+
# mypy
158+
.mypy_cache/
159+
.dmypy.json
160+
dmypy.json
161+
162+
# Pyre type checker
163+
.pyre/
164+
165+
### Python Patch ###
166+
.venv/
167+
168+
### Windows ###
169+
# Windows thumbnail cache files
170+
Thumbs.db
171+
ehthumbs.db
172+
ehthumbs_vista.db
173+
174+
# Dump file
175+
*.stackdump
176+
177+
# Folder config file
178+
[Dd]esktop.ini
179+
180+
# Recycle Bin used on file shares
181+
$RECYCLE.BIN/
182+
183+
# Windows Installer files
184+
*.cab
185+
*.msi
186+
*.msix
187+
*.msm
188+
*.msp
189+
190+
# Windows shortcuts
191+
*.lnk
192+
193+
# End of https://www.gitignore.io/api/macos,linux,python,windows
194+
195+
196+
.vscode/

.pre-commit-config.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v3.2.0
4+
hooks:
5+
- id: trailing-whitespace
6+
- id: end-of-file-fixer
7+
- id: check-yaml
8+
- id: check-added-large-files
9+
- id: check-ast
10+
11+
- repo: https://github.com/asottile/pyupgrade
12+
rev: master
13+
hooks:
14+
- id: pyupgrade
15+
16+
- repo: local
17+
hooks:
18+
- id: mypy
19+
name: run mypy
20+
language: system
21+
entry: bash -c 'poetry run mypy "${@/backend\//./}"' --
22+
types: [python]
23+
files: ^backend/
24+
25+
- id: flake8
26+
name: run flake8
27+
language: system
28+
entry: bash -c 'poetry run flake8 "${@/backend\//./}"' --
29+
types: [python]
30+
31+
- id: isort
32+
name: run isort
33+
language: system
34+
entry: bash -c 'poetry run isort "${@/backend\//./}"' --
35+
types: [python]
36+
37+
- id: black
38+
name: run black
39+
language: system
40+
entry: bash -c 'poetry run black "${@/backend\//./}"' --
41+
types: [python]

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(The MIT License)
2+
3+
Copyright (c) Patrick Arminio
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
run:
2+
GITHUB_TOKEN=demo poetry run python main.py --reload

app/__init__.py

Whitespace-only changes.

app/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import os
2+
3+
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]

app/github.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import typing
2+
3+
import httpx
4+
5+
from .config import GITHUB_TOKEN
6+
from .release import ReleaseInfo
7+
8+
SIGNATURE = "<!-- action-check: release-file -->"
9+
API_BASE = "https://api.github.com"
10+
11+
12+
def is_release_check_comment(comment: dict) -> bool:
13+
return (
14+
comment["user"]["login"] in ["github-actions[bot]", "botberry"]
15+
and SIGNATURE in comment["body"]
16+
)
17+
18+
19+
def get_comments_link(pr_number: int) -> str:
20+
url = f"/repos/strawberry-graphql/strawberry/issues/{pr_number}/comments"
21+
22+
return API_BASE + url
23+
24+
25+
def get_labels_link(pr_number: int) -> str:
26+
url = f"/repos/strawberry-graphql/strawberry/issues/{pr_number}/labels"
27+
28+
return API_BASE + url
29+
30+
31+
def get_comments(pr_number: int) -> typing.List[dict]:
32+
comments_link = get_comments_link(pr_number)
33+
34+
response = httpx.get(comments_link)
35+
36+
return response.json()
37+
38+
39+
def get_labels(pr_number) -> typing.List[dict]:
40+
labels_link = get_labels_link(pr_number)
41+
42+
response = httpx.get(labels_link)
43+
44+
return response.json()
45+
46+
47+
def add_or_edit_comment(pr_number: int, comment: str):
48+
current_comments = get_comments(pr_number)
49+
50+
previous_comment = next(
51+
(comment for comment in current_comments if is_release_check_comment(comment)),
52+
None,
53+
)
54+
55+
method = httpx.patch if previous_comment else httpx.post
56+
url = previous_comment["url"] if previous_comment else get_comments_link(pr_number)
57+
58+
response = method(
59+
url,
60+
headers={"Authorization": f"token {GITHUB_TOKEN}"},
61+
json={"body": comment + SIGNATURE},
62+
)
63+
64+
response.raise_for_status()
65+
66+
67+
def update_labels(pr_number: int, release_info: typing.Optional[ReleaseInfo]):
68+
labels_to_add = {"bot:has-release-file"}
69+
labels_to_remove: typing.Set[str] = set()
70+
71+
new_release_label = None
72+
73+
if release_info is None or release_info.change_type is None:
74+
labels_to_remove = labels_to_add
75+
labels_to_add = set()
76+
else:
77+
new_release_label = f"bot:release-type-{release_info.change_type.value}"
78+
labels_to_add.add(new_release_label)
79+
80+
labels_url = get_labels_link(pr_number)
81+
current_labels = get_labels(pr_number)
82+
83+
current_labels_url_by_name = {
84+
label["name"]: label["url"] for label in current_labels
85+
}
86+
87+
current_labels = set(current_labels_url_by_name.keys())
88+
89+
release_labels_to_remove = [
90+
label
91+
for label in current_labels
92+
if label.startswith("bot:release-type-") and label != new_release_label
93+
]
94+
labels_to_remove.update(release_labels_to_remove)
95+
96+
if not current_labels.issuperset(labels_to_add):
97+
response = httpx.post(
98+
labels_url,
99+
headers={"Authorization": f"token {GITHUB_TOKEN}"},
100+
json={"labels": list(labels_to_add)},
101+
)
102+
103+
response.raise_for_status()
104+
105+
if current_labels.issuperset(labels_to_remove):
106+
for label in labels_to_remove:
107+
response = httpx.delete(
108+
current_labels_url_by_name[label],
109+
headers={"Authorization": f"token {GITHUB_TOKEN}"},
110+
)
111+
112+
response.raise_for_status()

0 commit comments

Comments
 (0)