ghapi 2.0.1__tar.gz → 2.0.2__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.
- {ghapi-2.0.1/ghapi.egg-info → ghapi-2.0.2}/PKG-INFO +1 -1
- ghapi-2.0.2/ghapi/__init__.py +1 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/actions.py +7 -10
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/auth.py +4 -6
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/core.py +12 -15
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/event.py +5 -6
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/gh_spec.py +43 -6
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/graphql.py +1 -4
- {ghapi-2.0.1 → ghapi-2.0.2/ghapi.egg-info}/PKG-INFO +1 -1
- ghapi-2.0.1/ghapi/__init__.py +0 -1
- {ghapi-2.0.1 → ghapi-2.0.2}/CONTRIBUTING.md +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/LICENSE +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/MANIFEST.in +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/README.md +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/_modidx.py +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/all.py +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/build_lib.py +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/cli.py +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/page.py +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/py.typed +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/skill.py +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi/templates.py +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi.egg-info/SOURCES.txt +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi.egg-info/dependency_links.txt +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi.egg-info/entry_points.txt +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi.egg-info/requires.txt +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/ghapi.egg-info/top_level.txt +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/pyproject.toml +0 -0
- {ghapi-2.0.1 → ghapi-2.0.2}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.0.2"
|
|
@@ -18,7 +18,6 @@ from .templates import *
|
|
|
18
18
|
|
|
19
19
|
import textwrap
|
|
20
20
|
from contextlib import contextmanager
|
|
21
|
-
from enum import Enum
|
|
22
21
|
|
|
23
22
|
# %% ../nbs/01_actions.ipynb #fb69ba90
|
|
24
23
|
# So we can run this outside of GitHub actions too, read from file if needed
|
|
@@ -26,8 +25,7 @@ for a,b in (('CONTEXT_GITHUB',context_example), ('CONTEXT_NEEDS',needs_example),
|
|
|
26
25
|
if a not in os.environ: os.environ[a] = b
|
|
27
26
|
|
|
28
27
|
contexts = 'github', 'env', 'job', 'steps', 'runner', 'secrets', 'strategy', 'matrix', 'needs'
|
|
29
|
-
for context in contexts:
|
|
30
|
-
globals()[f'context_{context}'] = dict2obj(loads(os.getenv(f"CONTEXT_{context.upper()}", "{}")))
|
|
28
|
+
for context in contexts: globals()[f'context_{context}'] = dict2obj(loads(os.getenv(f"CONTEXT_{context.upper()}", "{}")))
|
|
31
29
|
|
|
32
30
|
# %% ../nbs/01_actions.ipynb #393990e1
|
|
33
31
|
_all_ = ['context_github', 'context_env', 'context_job', 'context_steps', 'context_runner', 'context_secrets', 'context_strategy', 'context_matrix', 'context_needs']
|
|
@@ -41,7 +39,7 @@ def user_repo():
|
|
|
41
39
|
return env_github.repository.split('/')
|
|
42
40
|
|
|
43
41
|
# %% ../nbs/01_actions.ipynb #deb389d7
|
|
44
|
-
Event = str_enum('Event',
|
|
42
|
+
Event = str_enum('Event', # chkstyle: ignore-node
|
|
45
43
|
'page_build','content_reference','repository_import','create','workflow_run','delete','organization','sponsorship',
|
|
46
44
|
'project_column','push','context','milestone','project_card','project','package','pull_request','repository_dispatch',
|
|
47
45
|
'team_add','workflow_dispatch','member','meta','code_scanning_alert','public','needs','check_run','security_advisory',
|
|
@@ -54,8 +52,7 @@ Event = str_enum('Event',
|
|
|
54
52
|
def _create_file(path:Path, fname:str, contents):
|
|
55
53
|
if contents and not (path/fname).exists(): (path/fname).write_text(contents)
|
|
56
54
|
|
|
57
|
-
def _replace(s:str, find, repl, i:int=0, suf:str=''):
|
|
58
|
-
return s.replace(find, textwrap.indent(repl, ' '*i)+suf)
|
|
55
|
+
def _replace(s:str, find, repl, i:int=0, suf:str=''): return s.replace(find, textwrap.indent(repl, ' '*i)+suf)
|
|
59
56
|
|
|
60
57
|
# %% ../nbs/01_actions.ipynb #26eb64e5
|
|
61
58
|
def create_workflow_files(fname:str, workflow:str, build_script:str, prebuild:bool=False):
|
|
@@ -75,9 +72,9 @@ def fill_workflow_templates(name:str, event, run, context, script, opersys='ubun
|
|
|
75
72
|
c = wf_tmpl
|
|
76
73
|
if event=='workflow_dispatch:': event=''
|
|
77
74
|
needs = ' needs: [prebuild]' if prebuild else ''
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
repls = (('NAME',name,0), ('EVENT',event,2), ('RUN',run,8), ('CONTEXTS',context,8),
|
|
76
|
+
('OPERSYS',f'[{opersys}]',0), ('NEEDS',needs,0), ('PREBUILD',pre_tmpl if prebuild else '',2))
|
|
77
|
+
for find,repl,i in repls: c = _replace(c, f'${find}', str(repl), i)
|
|
81
78
|
create_workflow_files(name, c, script, prebuild=prebuild)
|
|
82
79
|
|
|
83
80
|
# %% ../nbs/01_actions.ipynb #bc2f80a5
|
|
@@ -93,7 +90,7 @@ def_pipinst = 'pip install -Uq ghapi'
|
|
|
93
90
|
def create_workflow(name:str, event:Event, contexts:list=None, opersys='ubuntu', prebuild=False):
|
|
94
91
|
"Function to create a simple Ubuntu workflow that calls a Python `ghapi` script"
|
|
95
92
|
script = "from fastcore.all import *\nfrom ghapi import *"
|
|
96
|
-
fill_workflow_templates(name, f'{event}:', def_pipinst, env_contexts(contexts),
|
|
93
|
+
fill_workflow_templates(name, f'{event}:', def_pipinst, env_contexts(contexts), # chkstyle: ignore-node
|
|
97
94
|
script=script, opersys=opersys, prebuild=prebuild)
|
|
98
95
|
|
|
99
96
|
# %% ../nbs/01_actions.ipynb #e8482286
|
|
@@ -12,10 +12,10 @@ from fastcore.all import *
|
|
|
12
12
|
from .core import *
|
|
13
13
|
|
|
14
14
|
import webbrowser,time
|
|
15
|
-
from urllib.parse import parse_qs
|
|
15
|
+
from urllib.parse import parse_qs
|
|
16
16
|
|
|
17
17
|
# %% ../nbs/02_auth.ipynb #46620407
|
|
18
|
-
_scopes =(
|
|
18
|
+
_scopes =( # chkstyle: ignore-node
|
|
19
19
|
'repo','repo:status','repo_deployment','public_repo','repo:invite','security_events','admin:repo_hook','write:repo_hook',
|
|
20
20
|
'read:repo_hook','admin:org','write:org','read:org','admin:public_key','write:public_key','read:public_key','admin:org_hook',
|
|
21
21
|
'gist','notifications','user','read:user','user:email','user:follow','delete_repo','write:discussion','read:discussion',
|
|
@@ -61,10 +61,8 @@ def open_browser(self:GhDeviceAuth):
|
|
|
61
61
|
@patch
|
|
62
62
|
def auth(self:GhDeviceAuth)->str:
|
|
63
63
|
"Return token if authentication complete, or `None` otherwise"
|
|
64
|
-
resp = parse_qs(urlread(
|
|
65
|
-
'
|
|
66
|
-
client_id=self.client_id, device_code=self.device_code,
|
|
67
|
-
grant_type='urn:ietf:params:oauth:grant-type:device_code'))
|
|
64
|
+
resp = parse_qs(urlread('https://github.com/login/oauth/access_token',
|
|
65
|
+
client_id=self.client_id, device_code=self.device_code, grant_type='urn:ietf:params:oauth:grant-type:device_code'))
|
|
68
66
|
err = nested_idx(resp, 'error', 0)
|
|
69
67
|
if err == 'authorization_pending': return None
|
|
70
68
|
if err: raise Exception(resp['error_description'][0])
|
|
@@ -11,7 +11,7 @@ __all__ = ['GH_HOST', 'pspec', 'img_md_pat', 'EMPTY_TREE_SHA', 'GhTransport', 'G
|
|
|
11
11
|
# %% ../nbs/00_core.ipynb #5b5cba7b
|
|
12
12
|
from fastcore.all import *
|
|
13
13
|
from fastspec.spec import SpecParser
|
|
14
|
-
from fastspec.oapi import OpenAPIClient, OpFunc, SyncOpFunc, _build_groups
|
|
14
|
+
from fastspec.oapi import OpenAPIClient, OpFunc, SyncOpFunc, _build_groups, UNSET
|
|
15
15
|
from fastspec.transport import AsyncTransport, SyncTransport
|
|
16
16
|
from .gh_spec import spec
|
|
17
17
|
from fastspec.errors import APIError
|
|
@@ -19,8 +19,7 @@ from fastspec.errors import APIError
|
|
|
19
19
|
import mimetypes,base64
|
|
20
20
|
from collections import Counter
|
|
21
21
|
from urllib.parse import quote
|
|
22
|
-
from datetime import datetime
|
|
23
|
-
from time import sleep
|
|
22
|
+
from datetime import datetime
|
|
24
23
|
import os, shutil, tempfile, subprocess, fnmatch, html
|
|
25
24
|
|
|
26
25
|
# %% ../nbs/00_core.ipynb #ed04302a
|
|
@@ -60,8 +59,7 @@ class GhTransport(AsyncTransport):
|
|
|
60
59
|
self.recv_hdrs = resp.headers
|
|
61
60
|
if 'X-RateLimit-Remaining' in resp.headers:
|
|
62
61
|
newlim = resp.headers['X-RateLimit-Remaining']
|
|
63
|
-
if self.limit_cb is not None and newlim != self.limit_rem:
|
|
64
|
-
self.limit_cb(int(newlim), int(resp.headers['X-RateLimit-Limit']))
|
|
62
|
+
if self.limit_cb is not None and newlim != self.limit_rem: self.limit_cb(int(newlim), int(resp.headers['X-RateLimit-Limit']))
|
|
65
63
|
self.limit_rem = newlim
|
|
66
64
|
if raw: return resp
|
|
67
65
|
res = self._decode(resp)
|
|
@@ -90,7 +88,7 @@ def print_summary(method, url, kwargs):
|
|
|
90
88
|
# %% ../nbs/00_core.ipynb #83e8a9ce
|
|
91
89
|
class GhApi(OpenAPIClient):
|
|
92
90
|
"GitHub API client. Endpoint groups (`issues`, `pulls`, ...) are generated per-instance from GitHub's OpenAPI metadata, so the class shows only convenience methods -- inspect a live instance, e.g. `doc(GhApi())`, to see the full API."
|
|
93
|
-
def __init__(self, owner=None, repo=None, token=None, jwt_token=None, debug=None, limit_cb=None, gh_host=None,
|
|
91
|
+
def __init__(self, owner=None, repo=None, token=None, jwt_token=None, debug=None, limit_cb=None, gh_host=None, # chkstyle: ignore-node
|
|
94
92
|
authenticate=True, timeout=60.0, sync=False, **kwargs):
|
|
95
93
|
self.headers = { 'Accept': 'application/vnd.github.v3+json' }
|
|
96
94
|
if authenticate:
|
|
@@ -215,11 +213,11 @@ async def upload_file(self:GhApi, rel, fn):
|
|
|
215
213
|
# %% ../nbs/00_core.ipynb #3cad71a4
|
|
216
214
|
@patch
|
|
217
215
|
async def create_release(self:GhApi, tag_name, branch='master', name=None, body='',
|
|
218
|
-
|
|
216
|
+
draft=False, prerelease=False, files=None, make_latest=UNSET):
|
|
219
217
|
"Wrapper for `GhApi.repos.create_release` which also uploads `files`"
|
|
220
218
|
if name is None: name = 'v'+tag_name
|
|
221
219
|
rel = await self.repos.create_release(tag_name, target_commitish=branch, name=name, body=body,
|
|
222
|
-
|
|
220
|
+
draft=draft, prerelease=prerelease, make_latest=make_latest)
|
|
223
221
|
for file in listify(files): await self.upload_file(rel, file)
|
|
224
222
|
return rel
|
|
225
223
|
|
|
@@ -299,8 +297,7 @@ async def create_file(self:GhApi, path, message, committer, author, content=None
|
|
|
299
297
|
async def delete_file(self:GhApi, path, message, committer, author, sha=None, branch=None):
|
|
300
298
|
if not branch: branch = (await self.repos.get())['default_branch']
|
|
301
299
|
if sha is None: sha = (await self.list_files())[path].sha
|
|
302
|
-
return await self.repos.delete_file(path, message=message, sha=sha,
|
|
303
|
-
branch=branch, committer=committer, author=author)
|
|
300
|
+
return await self.repos.delete_file(path, message=message, sha=sha, branch=branch, committer=committer, author=author)
|
|
304
301
|
|
|
305
302
|
# %% ../nbs/00_core.ipynb #93f6b559
|
|
306
303
|
@patch
|
|
@@ -346,7 +343,7 @@ async def get_repo_contents(self:GhApi, owner, repo, branch='main',
|
|
|
346
343
|
n_workers=16, # Max concurrent downloads
|
|
347
344
|
**kwargs
|
|
348
345
|
):
|
|
349
|
-
repo_files = await self.get_repo_files(owner, repo, **kwargs)
|
|
346
|
+
repo_files = await self.get_repo_files(owner, repo, branch, **kwargs)
|
|
350
347
|
paths = repo_files.attrgot("path")
|
|
351
348
|
return L(await parallel_async(self.get_file_content, paths, owner=owner, repo=repo, branch=branch, n_workers=n_workers))
|
|
352
349
|
|
|
@@ -379,7 +376,7 @@ async def read_issue(self:GhApi, issue_number:int):
|
|
|
379
376
|
try: pr = await self.pulls.get(issue_number)
|
|
380
377
|
except APIError: pr = None
|
|
381
378
|
iss = await self.issues.get(issue_number)
|
|
382
|
-
res = dict(title=iss.title, body=iss.body or '', is_pr=pr is not None,
|
|
379
|
+
res = dict(title=iss.title, body=iss.body or '', is_pr=pr is not None, # chkstyle: ignore-node
|
|
383
380
|
comments=await self.issues.list_comments(issue_number))
|
|
384
381
|
if pr is not None:
|
|
385
382
|
res['diff'] = await self.pulls.get(issue_number, _headers={'Accept': 'application/vnd.github.v3.diff'})
|
|
@@ -395,7 +392,7 @@ async def read_issue(self:GhApi, issue_number:int):
|
|
|
395
392
|
def _filter_diff(diff, folder='', skip_files=('_modidx.py',)):
|
|
396
393
|
"Filter unified diff to only include files under `folder`, skipping `skip_files`"
|
|
397
394
|
sections = re.split(r'(?=^diff --git )', diff, flags=re.MULTILINE)
|
|
398
|
-
return ''.join(s for s in sections
|
|
395
|
+
return ''.join(s for s in sections # chkstyle: ignore-node
|
|
399
396
|
if s.startswith(f'diff --git a/{folder}')
|
|
400
397
|
and not any(f'/{f} ' in s.split('\n')[0] for f in skip_files))
|
|
401
398
|
|
|
@@ -460,7 +457,7 @@ def _parse_tmpl(name, txt):
|
|
|
460
457
|
if not name.endswith(('.yml','.yaml')): return dict2obj(dict(name=name, raw=txt))
|
|
461
458
|
import yaml
|
|
462
459
|
d = yaml.safe_load(txt)
|
|
463
|
-
secs = [dict(label=b['attributes']['label'], type=b['type'],
|
|
460
|
+
secs = [dict(label=b['attributes']['label'], type=b['type'], # chkstyle: ignore-node
|
|
464
461
|
required=bool(nested_idx(b, 'validations', 'required')),
|
|
465
462
|
options=[o['label'] if isinstance(o, dict) else o for o in b['attributes'].get('options', [])])
|
|
466
463
|
for b in d.get('body', []) if b['type']!='markdown']
|
|
@@ -475,7 +472,7 @@ async def issue_template(self:GhApi):
|
|
|
475
472
|
except APIError as e:
|
|
476
473
|
if e.status_code != 404: raise
|
|
477
474
|
continue
|
|
478
|
-
return L([_parse_tmpl(f.name, base64.b64decode((await self.repos.get_content(path=f.path, **kw)).content).decode())
|
|
475
|
+
return L([_parse_tmpl(f.name, base64.b64decode((await self.repos.get_content(path=f.path, **kw)).content).decode()) # chkstyle: ignore-node
|
|
479
476
|
for f in fs if f.name.endswith(('.md','.yml','.yaml')) and f.name != 'config.yml'])
|
|
480
477
|
return L()
|
|
481
478
|
|
|
@@ -129,7 +129,7 @@ def full_type(self:GhEvent):
|
|
|
129
129
|
_all_ = ['PageBuildEvent', 'ContentReferenceEvent', 'RepositoryImportEvent', 'CreateEvent', 'WorkflowRunEvent', 'DeleteEvent', 'OrganizationEvent', 'SponsorshipEvent', 'ProjectColumnEvent', 'PushEvent', 'ContextEvent', 'MilestoneEvent', 'ProjectCardEvent', 'ProjectEvent', 'PackageEvent', 'PullRequestEvent', 'RepositoryDispatchEvent', 'TeamAddEvent', 'WorkflowDispatchEvent', 'MemberEvent', 'MetaEvent', 'CodeScanningAlertEvent', 'PublicEvent', 'NeedsEvent', 'CheckRunEvent', 'SecurityAdvisoryEvent', 'PullRequestReviewCommentEvent', 'OrgBlockEvent', 'CommitCommentEvent', 'WatchEvent', 'MarketplacePurchaseEvent', 'StarEvent', 'InstallationRepositoriesEvent', 'CheckSuiteEvent', 'GithubAppAuthorizationEvent', 'TeamEvent', 'StatusEvent', 'RepositoryVulnerabilityAlertEvent', 'PullRequestReviewEvent', 'LabelEvent', 'InstallationEvent', 'ReleaseEvent', 'IssuesEvent', 'RepositoryEvent', 'GollumEvent', 'MembershipEvent', 'DeploymentEvent', 'DeployKeyEvent', 'IssueCommentEvent', 'PingEvent', 'DeploymentStatusEvent', 'ForkEvent', 'ScheduleEvent']
|
|
130
130
|
|
|
131
131
|
# %% ../nbs/04_event.ipynb #83be1955
|
|
132
|
-
evt_emojis = dict(
|
|
132
|
+
evt_emojis = dict( # chkstyle: ignore-node
|
|
133
133
|
PushEvent= '⭐',
|
|
134
134
|
CreateEvent= '🏭',
|
|
135
135
|
IssueCommentEvent_created= '💬',
|
|
@@ -157,7 +157,7 @@ def _ref_detl(pay): return pay.ref_type + _ref(pay)
|
|
|
157
157
|
|
|
158
158
|
def _action(self):
|
|
159
159
|
pay = self.payload
|
|
160
|
-
det = (f'issue #{pay.issue.number} on' if isinstance(self,IssuesEvent) else
|
|
160
|
+
det = (f'issue #{pay.issue.number} on' if isinstance(self,IssuesEvent) else # chkstyle: ignore-node
|
|
161
161
|
f'PR #{pay.number} on' if isinstance(self,PullRequestEvent) else
|
|
162
162
|
f'member {pay.member.login} in' if isinstance(self,MemberEvent) else
|
|
163
163
|
f'review comment on PR #{pay.pull_request.number} in' if isinstance(self,PullRequestReviewCommentEvent) else
|
|
@@ -173,7 +173,7 @@ def description(self:GhEvent):
|
|
|
173
173
|
"Description of event"
|
|
174
174
|
act,pay,cls,repo = self.actor,self.payload,type(self),self.repo
|
|
175
175
|
res = _action(self)
|
|
176
|
-
return res if res else (
|
|
176
|
+
return res if res else ( # chkstyle: ignore-node
|
|
177
177
|
f'deleted {_ref_detl(pay)} in' if isinstance(self,DeleteEvent) else
|
|
178
178
|
f'created {_ref_detl(pay)} in' if isinstance(self,CreateEvent) else
|
|
179
179
|
f'pushed {len(pay.commits)} commits{_ref(pay," to")} in' if isinstance(self,PushEvent) else
|
|
@@ -184,17 +184,16 @@ def description(self:GhEvent):
|
|
|
184
184
|
remove_suffix(self.type, "Event")
|
|
185
185
|
)
|
|
186
186
|
|
|
187
|
-
#export
|
|
188
187
|
@patch(as_prop=True)
|
|
189
188
|
def emoji(self:GhEvent):
|
|
190
189
|
"Emoji for event from `evt_emojis`"
|
|
191
190
|
return evt_emojis.get(self.full_type, '❌')
|
|
192
191
|
|
|
193
192
|
# %% ../nbs/04_event.ipynb #daad2a54
|
|
194
|
-
described_evts = (PushEvent,CreateEvent,IssueCommentEvent,WatchEvent,PullRequestEvent,PullRequestReviewEvent,PullRequestReviewCommentEvent,
|
|
193
|
+
described_evts = (PushEvent,CreateEvent,IssueCommentEvent,WatchEvent,PullRequestEvent,PullRequestReviewEvent,PullRequestReviewCommentEvent, # chkstyle: ignore-node
|
|
195
194
|
DeleteEvent,ForkEvent,IssuesEvent,ReleaseEvent,MemberEvent,CommitCommentEvent,GollumEvent,PublicEvent)
|
|
196
195
|
|
|
197
|
-
_text_keys = dict(
|
|
196
|
+
_text_keys = dict( # chkstyle: ignore-node
|
|
198
197
|
CreateEvent = "description",
|
|
199
198
|
PullRequestEvent = "pull_request.title",
|
|
200
199
|
PullRequestReviewCommentEvent = "comment.body",
|
|
@@ -6495,7 +6495,7 @@ spec = {'base_url': 'https://api.github.com',
|
|
|
6495
6495
|
'verb': 'GET',
|
|
6496
6496
|
'summary': 'List secret scanning alerts for an organization',
|
|
6497
6497
|
'route_params': ['org'],
|
|
6498
|
-
'query_params': ['state', 'secret_type', 'exclude_secret_types', 'exclude_providers', 'providers', 'resolution', 'assignee', 'sort', 'direction', 'page', 'per_page', 'before', 'after', 'validity', 'is_publicly_leaked', 'is_multi_repo', 'hide_secret', 'is_bypassed'],
|
|
6498
|
+
'query_params': ['state', 'secret_type', 'exclude_secret_types', 'exclude_providers', 'providers', 'resolution', 'assignee', 'sort', 'direction', 'page', 'per_page', 'before', 'after', 'validity', 'is_publicly_leaked', 'is_multi_repo', 'hide_secret', 'is_bypassed', 'included_metadata', 'owner_email_hash'],
|
|
6499
6499
|
'required_params': ['org'],
|
|
6500
6500
|
'param_types': {'org': 'str',
|
|
6501
6501
|
'state': 'str',
|
|
@@ -6515,7 +6515,9 @@ spec = {'base_url': 'https://api.github.com',
|
|
|
6515
6515
|
'is_publicly_leaked': 'bool',
|
|
6516
6516
|
'is_multi_repo': 'bool',
|
|
6517
6517
|
'hide_secret': 'bool',
|
|
6518
|
-
'is_bypassed': 'bool'
|
|
6518
|
+
'is_bypassed': 'bool',
|
|
6519
|
+
'included_metadata': 'str',
|
|
6520
|
+
'owner_email_hash': 'str'},
|
|
6519
6521
|
'param_defaults': {'sort': 'created', 'direction': 'desc', 'page': 1, 'per_page': 30, 'is_publicly_leaked': False, 'is_multi_repo': False, 'hide_secret': False},
|
|
6520
6522
|
'param_docs': {'org': 'The organization name. The name is not case sensitive.',
|
|
6521
6523
|
'state': 'Set to `open` or `resolved` to only list secret scanning alerts in a specific state.',
|
|
@@ -6538,7 +6540,11 @@ spec = {'base_url': 'https://api.github.com',
|
|
|
6538
6540
|
'is_multi_repo': 'A boolean value representing whether or not to filter alerts by the multi-repo tag being present.',
|
|
6539
6541
|
'hide_secret': 'A boolean value representing whether or not to hide literal secrets in the results.',
|
|
6540
6542
|
'is_bypassed': 'A boolean value (`true` or `false`) indicating whether to filter alerts by their push protection bypass status. When set to `true`, only alerts that were created because a push protection rule was bypassed will be returned. When set to `false`, only alerts that were not caused by a push protection bypass will be '
|
|
6541
|
-
'returned.'
|
|
6543
|
+
'returned.',
|
|
6544
|
+
'included_metadata': 'A comma-separated list of metadata fields to filter alerts by. Only alerts that have all of the specified metadata fields attached will be returned. Possible values are: `owner-email`, `owner-id`, `owner-name`, `secret-id`, `secret-name`, `secret-issued-date`, `secret-expiration-date`, `organization-name`, '
|
|
6545
|
+
'`organization-id`, `last-used-date`, and `has-organization-access`.',
|
|
6546
|
+
'owner_email_hash': 'Filters alerts to only those whose attached `owner_email` metadata field matches the provided value. The value must be the lowercase hex-encoded SHA-256 hash of the email address to match (for example, the SHA-256 of `user@example.com`). Only alerts that have an `owner_email` metadata value whose SHA-256 hash '
|
|
6547
|
+
'equals this parameter are returned.'},
|
|
6542
6548
|
'docs_url': 'https://docs.github.com/rest/secret-scanning/secret-scanning#list-secret-scanning-alerts-for-an-organization'},
|
|
6543
6549
|
{'group': 'secret_scanning',
|
|
6544
6550
|
'name': 'list_org_pattern_configs',
|
|
@@ -11396,6 +11402,31 @@ spec = {'base_url': 'https://api.github.com',
|
|
|
11396
11402
|
'param_types': {'owner': 'str', 'repo': 'str', 'users': 'list'},
|
|
11397
11403
|
'param_docs': {'owner': 'The account owner of the repository. The name is not case sensitive.', 'repo': 'The name of the repository without the `.git` extension. The name is not case sensitive.', 'users': 'A list of user logins to add or remove from the bypass list.'},
|
|
11398
11404
|
'docs_url': 'https://docs.github.com/rest/interactions/repos#remove-users-from-the-pull-request-creation-cap-bypass-list-for-a-repository'},
|
|
11405
|
+
{'group': 'interactions',
|
|
11406
|
+
'name': 'get_pull_request_creation_cap_for_repo',
|
|
11407
|
+
'path': '/repos/{owner}/{repo}/interaction-limits/pulls/creation-cap',
|
|
11408
|
+
'verb': 'GET',
|
|
11409
|
+
'summary': 'Get pull request creation cap for a repository',
|
|
11410
|
+
'route_params': ['owner', 'repo'],
|
|
11411
|
+
'required_params': ['owner', 'repo'],
|
|
11412
|
+
'param_types': {'owner': 'str', 'repo': 'str'},
|
|
11413
|
+
'param_docs': {'owner': 'The account owner of the repository. The name is not case sensitive.', 'repo': 'The name of the repository without the `.git` extension. The name is not case sensitive.'},
|
|
11414
|
+
'docs_url': 'https://docs.github.com/rest/interactions/repos#get-pull-request-creation-cap-for-a-repository'},
|
|
11415
|
+
{'group': 'interactions',
|
|
11416
|
+
'name': 'update_pull_request_creation_cap_for_repo',
|
|
11417
|
+
'path': '/repos/{owner}/{repo}/interaction-limits/pulls/creation-cap',
|
|
11418
|
+
'verb': 'PATCH',
|
|
11419
|
+
'summary': 'Update pull request creation cap for a repository',
|
|
11420
|
+
'route_params': ['owner', 'repo'],
|
|
11421
|
+
'body_params': ['enabled', 'max_open_pull_requests'],
|
|
11422
|
+
'request_content_type': 'application/json',
|
|
11423
|
+
'required_params': ['enabled', 'owner', 'repo'],
|
|
11424
|
+
'param_types': {'owner': 'str', 'repo': 'str', 'enabled': 'bool', 'max_open_pull_requests': 'int'},
|
|
11425
|
+
'param_docs': {'owner': 'The account owner of the repository. The name is not case sensitive.',
|
|
11426
|
+
'repo': 'The name of the repository without the `.git` extension. The name is not case sensitive.',
|
|
11427
|
+
'enabled': 'Whether the pull request creation cap is enabled',
|
|
11428
|
+
'max_open_pull_requests': 'The maximum number of open pull requests a user can have at one time'},
|
|
11429
|
+
'docs_url': 'https://docs.github.com/rest/interactions/repos#update-pull-request-creation-cap-for-a-repository'},
|
|
11399
11430
|
{'group': 'repos',
|
|
11400
11431
|
'name': 'list_invitations',
|
|
11401
11432
|
'path': '/repos/{owner}/{repo}/invitations',
|
|
@@ -13469,7 +13500,7 @@ spec = {'base_url': 'https://api.github.com',
|
|
|
13469
13500
|
'verb': 'GET',
|
|
13470
13501
|
'summary': 'List secret scanning alerts for a repository',
|
|
13471
13502
|
'route_params': ['owner', 'repo'],
|
|
13472
|
-
'query_params': ['state', 'secret_type', 'exclude_secret_types', 'exclude_providers', 'providers', 'resolution', 'assignee', 'sort', 'direction', 'page', 'per_page', 'before', 'after', 'validity', 'is_publicly_leaked', 'is_multi_repo', 'hide_secret', 'is_bypassed'],
|
|
13503
|
+
'query_params': ['state', 'secret_type', 'exclude_secret_types', 'exclude_providers', 'providers', 'resolution', 'assignee', 'sort', 'direction', 'page', 'per_page', 'before', 'after', 'validity', 'is_publicly_leaked', 'is_multi_repo', 'hide_secret', 'is_bypassed', 'included_metadata', 'owner_email_hash'],
|
|
13473
13504
|
'required_params': ['owner', 'repo'],
|
|
13474
13505
|
'param_types': {'owner': 'str',
|
|
13475
13506
|
'repo': 'str',
|
|
@@ -13490,7 +13521,9 @@ spec = {'base_url': 'https://api.github.com',
|
|
|
13490
13521
|
'is_publicly_leaked': 'bool',
|
|
13491
13522
|
'is_multi_repo': 'bool',
|
|
13492
13523
|
'hide_secret': 'bool',
|
|
13493
|
-
'is_bypassed': 'bool'
|
|
13524
|
+
'is_bypassed': 'bool',
|
|
13525
|
+
'included_metadata': 'str',
|
|
13526
|
+
'owner_email_hash': 'str'},
|
|
13494
13527
|
'param_defaults': {'sort': 'created', 'direction': 'desc', 'page': 1, 'per_page': 30, 'is_publicly_leaked': False, 'is_multi_repo': False, 'hide_secret': False},
|
|
13495
13528
|
'param_docs': {'owner': 'The account owner of the repository. The name is not case sensitive.',
|
|
13496
13529
|
'repo': 'The name of the repository without the `.git` extension. The name is not case sensitive.',
|
|
@@ -13514,7 +13547,11 @@ spec = {'base_url': 'https://api.github.com',
|
|
|
13514
13547
|
'is_multi_repo': 'A boolean value representing whether or not to filter alerts by the multi-repo tag being present.',
|
|
13515
13548
|
'hide_secret': 'A boolean value representing whether or not to hide literal secrets in the results.',
|
|
13516
13549
|
'is_bypassed': 'A boolean value (`true` or `false`) indicating whether to filter alerts by their push protection bypass status. When set to `true`, only alerts that were created because a push protection rule was bypassed will be returned. When set to `false`, only alerts that were not caused by a push protection bypass will be '
|
|
13517
|
-
'returned.'
|
|
13550
|
+
'returned.',
|
|
13551
|
+
'included_metadata': 'A comma-separated list of metadata fields to filter alerts by. Only alerts that have all of the specified metadata fields attached will be returned. Possible values are: `owner-email`, `owner-id`, `owner-name`, `secret-id`, `secret-name`, `secret-issued-date`, `secret-expiration-date`, `organization-name`, '
|
|
13552
|
+
'`organization-id`, `last-used-date`, and `has-organization-access`.',
|
|
13553
|
+
'owner_email_hash': 'Filters alerts to only those whose attached `owner_email` metadata field matches the provided value. The value must be the lowercase hex-encoded SHA-256 hash of the email address to match (for example, the SHA-256 of `user@example.com`). Only alerts that have an `owner_email` metadata value whose SHA-256 hash '
|
|
13554
|
+
'equals this parameter are returned.'},
|
|
13518
13555
|
'docs_url': 'https://docs.github.com/rest/secret-scanning/secret-scanning#list-secret-scanning-alerts-for-a-repository'},
|
|
13519
13556
|
{'group': 'secret_scanning',
|
|
13520
13557
|
'name': 'get_alert',
|
|
@@ -24,10 +24,7 @@ class GhGql:
|
|
|
24
24
|
"Lazy-load the GraphQL client and schema"
|
|
25
25
|
if self._client is None:
|
|
26
26
|
if not self.token: raise ValueError("GITHUB_TOKEN not set")
|
|
27
|
-
transport = RequestsHTTPTransport(
|
|
28
|
-
url='https://api.github.com/graphql',
|
|
29
|
-
headers={'Authorization': f'bearer {self.token}'}
|
|
30
|
-
)
|
|
27
|
+
transport = RequestsHTTPTransport(url='https://api.github.com/graphql', headers={'Authorization': f'bearer {self.token}'})
|
|
31
28
|
self._client = Client(transport=transport, fetch_schema_from_transport=True)
|
|
32
29
|
self._client.execute(gql('{ __typename }')) # Trigger schema fetch
|
|
33
30
|
return self._client
|
ghapi-2.0.1/ghapi/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.0.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|