pygitpub 0.0.64__tar.gz → 0.0.65__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.
- {pygitpub-0.0.64 → pygitpub-0.0.65}/PKG-INFO +2 -2
- {pygitpub-0.0.64 → pygitpub-0.0.65}/README.md +1 -1
- {pygitpub-0.0.64 → pygitpub-0.0.65}/pyproject.toml +1 -2
- {pygitpub-0.0.64 → pygitpub-0.0.65}/src/pygitpub/configs.py +1 -4
- {pygitpub-0.0.64 → pygitpub-0.0.65}/src/pygitpub/main.py +45 -35
- {pygitpub-0.0.64 → pygitpub-0.0.65}/src/pygitpub/static.py +1 -1
- {pygitpub-0.0.64 → pygitpub-0.0.65}/src/pygitpub/utils/misc.py +0 -17
- {pygitpub-0.0.64 → pygitpub-0.0.65}/.gitignore +0 -0
- {pygitpub-0.0.64 → pygitpub-0.0.65}/LICENSE +0 -0
- {pygitpub-0.0.64 → pygitpub-0.0.65}/src/pygitpub/__init__.py +0 -0
- {pygitpub-0.0.64 → pygitpub-0.0.65}/src/pygitpub/utils/__init__.py +0 -0
- {pygitpub-0.0.64 → pygitpub-0.0.65}/src/pygitpub/utils/lua.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pygitpub
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.65
|
|
4
4
|
Summary: Pygitpub will help you work with github
|
|
5
5
|
Project-URL: Homepage, https://github.com/veltzer/pygitpub
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/veltzer/pygitpub/issues
|
|
@@ -41,7 +41,7 @@ project website: https://veltzer.github.io/pygitpub
|
|
|
41
41
|
|
|
42
42
|
author: Mark Veltzer
|
|
43
43
|
|
|
44
|
-
version: 0.0.
|
|
44
|
+
version: 0.0.65
|
|
45
45
|
|
|
46
46
|
## github
|
|
47
47
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pygitpub"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.65"
|
|
8
8
|
requires-python = ">=3.14"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Mark Veltzer", email = "mark.veltzer@gmail.com" }
|
|
@@ -90,7 +90,6 @@ preset = "legacy"
|
|
|
90
90
|
python-version = "3.14"
|
|
91
91
|
search-path = [
|
|
92
92
|
"src",
|
|
93
|
-
"scripts",
|
|
94
93
|
".",
|
|
95
94
|
]
|
|
96
95
|
# Third-party libraries without type information.
|
|
@@ -14,11 +14,8 @@ AFFILIATIONS = [
|
|
|
14
14
|
|
|
15
15
|
class ConfigGithub(Config):
|
|
16
16
|
"""
|
|
17
|
-
|
|
17
|
+
Parameters for your github account
|
|
18
18
|
"""
|
|
19
|
-
username = ParamCreator.create_str(
|
|
20
|
-
help_string="What is your github username?",
|
|
21
|
-
)
|
|
22
19
|
apikey = ParamCreator.create_str(
|
|
23
20
|
help_string="What is the name of your apikey (see pyapikey)?",
|
|
24
21
|
)
|
|
@@ -44,9 +44,13 @@ def get_affiliation() -> str:
|
|
|
44
44
|
return ",".join(values)
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
def
|
|
47
|
+
def get_github(**kwargs: Any) -> github.Github:
|
|
48
48
|
apikey = pyapikey.get_key(ConfigGithub.apikey)
|
|
49
|
-
|
|
49
|
+
return github.Github(auth=github.Auth.Token(apikey), **kwargs)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def yield_repos():
|
|
53
|
+
g = get_github()
|
|
50
54
|
# github filters by affiliation server side, so repos we are not interested
|
|
51
55
|
# in (org repos, by default) are never fetched in the first place
|
|
52
56
|
affiliation = get_affiliation()
|
|
@@ -95,7 +99,8 @@ def fix_metadata() -> None:
|
|
|
95
99
|
print(f"in {folder}...")
|
|
96
100
|
print(f"description_short is [{description_short}]")
|
|
97
101
|
print(f"repo.description is [{repo.description}]")
|
|
98
|
-
|
|
102
|
+
if not ConfigAlgo.dryrun:
|
|
103
|
+
repo.edit(description=description_short)
|
|
99
104
|
if "KEYWORDS" not in project:
|
|
100
105
|
print(f"{folder} no keywords")
|
|
101
106
|
continue
|
|
@@ -104,32 +109,36 @@ def fix_metadata() -> None:
|
|
|
104
109
|
print(f"in {folder}...")
|
|
105
110
|
print(f"keywords is [{keywords}]")
|
|
106
111
|
print(f"repo.get_topics() is [{repo.get_topics()}]")
|
|
107
|
-
|
|
112
|
+
if not ConfigAlgo.dryrun:
|
|
113
|
+
repo.replace_topics(keywords)
|
|
108
114
|
|
|
109
115
|
|
|
110
116
|
@register_endpoint(
|
|
111
117
|
description="Set the correct website for the project on all repos where it is not correct",
|
|
112
118
|
configs=[
|
|
113
119
|
ConfigGithub,
|
|
120
|
+
ConfigOutput,
|
|
114
121
|
ConfigAlgo,
|
|
115
122
|
],
|
|
116
123
|
)
|
|
117
124
|
def homepage_fix() -> None:
|
|
118
125
|
for repo in yield_repos():
|
|
126
|
+
owner = repo.owner.login
|
|
127
|
+
# the user site repo is served at the root of the site, usually under
|
|
128
|
+
# a custom domain, so the pattern below does not apply to it
|
|
129
|
+
if repo.name.lower() == f"{owner.lower()}.github.io":
|
|
130
|
+
if ConfigOutput.verbose:
|
|
131
|
+
print(f"skipping [{repo.name}] because it is the user site")
|
|
132
|
+
continue
|
|
119
133
|
if repo.has_pages:
|
|
120
|
-
right_homepage = f"https://{
|
|
121
|
-
if repo.homepage != right_homepage:
|
|
122
|
-
print(f"{repo.name} is wrong!")
|
|
123
|
-
print(f"homepage: {repo.homepage}")
|
|
124
|
-
print(f"right_homepage: {right_homepage}")
|
|
125
|
-
print(f"patching [{repo.name}]...")
|
|
126
|
-
repo.edit(repo.name, homepage=right_homepage)
|
|
134
|
+
right_homepage = f"https://{owner}.github.io/{repo.name}/"
|
|
127
135
|
else:
|
|
128
|
-
right_homepage = f"https://github.com/{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
right_homepage = f"https://github.com/{owner}/{repo.name}/"
|
|
137
|
+
if repo.homepage != right_homepage:
|
|
138
|
+
print(f"{repo.name} is wrong!")
|
|
139
|
+
print(f"homepage: {repo.homepage}")
|
|
140
|
+
print(f"right_homepage: {right_homepage}")
|
|
141
|
+
if not ConfigAlgo.dryrun:
|
|
133
142
|
print(f"patching [{repo.name}]...")
|
|
134
143
|
repo.edit(repo.name, homepage=right_homepage)
|
|
135
144
|
|
|
@@ -198,20 +207,23 @@ def repos_list() -> None:
|
|
|
198
207
|
],
|
|
199
208
|
)
|
|
200
209
|
def cleanup() -> None:
|
|
201
|
-
# pylint: disable=too-many-branches,too-many-statements
|
|
202
210
|
for repo in yield_repos():
|
|
203
211
|
# 1. Cleanup workflow runs
|
|
204
212
|
for workflow in repo.get_workflows():
|
|
205
213
|
existing = 0
|
|
206
214
|
for run in workflow.get_runs():
|
|
207
215
|
if ConfigOutput.verbose:
|
|
208
|
-
print(f"inspecting [workflow run] {repo.name} {workflow.name} {run.conclusion}")
|
|
216
|
+
print(f"inspecting [workflow run] {repo.name} {workflow.name} {run.status} {run.conclusion}")
|
|
217
|
+
# github refuses to delete a run that is queued or still
|
|
218
|
+
# running, so leave those alone and don't count them
|
|
219
|
+
if run.status != "completed":
|
|
220
|
+
continue
|
|
209
221
|
delete_it = False
|
|
210
|
-
# if its a pages build delete it
|
|
211
|
-
if workflow.name == "pages-build-deployment"
|
|
222
|
+
# if its a pages build delete it
|
|
223
|
+
if workflow.name == "pages-build-deployment":
|
|
212
224
|
delete_it = True
|
|
213
|
-
# if its not on the
|
|
214
|
-
if run.head_branch !=
|
|
225
|
+
# if its not on the default branch, delete it
|
|
226
|
+
if run.head_branch != repo.default_branch:
|
|
215
227
|
delete_it = True
|
|
216
228
|
# if its not a paged build and it failed then delete it
|
|
217
229
|
if workflow.name != "pages-build-deployment" and run.conclusion in (
|
|
@@ -222,6 +234,8 @@ def cleanup() -> None:
|
|
|
222
234
|
delete_it = True
|
|
223
235
|
if delete_it:
|
|
224
236
|
print(f"deleting [workflow run] {repo.name} {workflow.name} {run.head_branch} {run.conclusion} {run.url}")
|
|
237
|
+
if ConfigAlgo.dryrun:
|
|
238
|
+
continue
|
|
225
239
|
try:
|
|
226
240
|
run.delete()
|
|
227
241
|
except github.GithubException as e:
|
|
@@ -245,12 +259,13 @@ def cleanup() -> None:
|
|
|
245
259
|
|
|
246
260
|
if delete_it:
|
|
247
261
|
print(f"deleting [deployment] {repo.name} {deployment.id}")
|
|
262
|
+
if ConfigAlgo.dryrun:
|
|
263
|
+
continue
|
|
248
264
|
try:
|
|
249
265
|
deployment.create_status("inactive")
|
|
250
266
|
except github.GithubException as e:
|
|
251
267
|
print(f"Failed to deactivate deployment: {e}")
|
|
252
268
|
try:
|
|
253
|
-
# pylint: disable=protected-access
|
|
254
269
|
status, _, _ = deployment._requester.requestJson("DELETE", deployment.url)
|
|
255
270
|
if status != 204:
|
|
256
271
|
print(f"Failed to delete deployment: HTTP {status}")
|
|
@@ -262,6 +277,8 @@ def cleanup() -> None:
|
|
|
262
277
|
for release in repo.get_releases():
|
|
263
278
|
if existing_releases >= 4:
|
|
264
279
|
print(f"deleting [release] {repo.name} {release.title}")
|
|
280
|
+
if ConfigAlgo.dryrun:
|
|
281
|
+
continue
|
|
265
282
|
try:
|
|
266
283
|
release.delete_release()
|
|
267
284
|
except github.GithubException as e:
|
|
@@ -295,8 +312,8 @@ def runs_show_running() -> None:
|
|
|
295
312
|
for repo in yield_repos():
|
|
296
313
|
for workflow in repo.get_workflows():
|
|
297
314
|
for run in workflow.get_runs():
|
|
298
|
-
if run.
|
|
299
|
-
print(f"{repo.name}: {workflow.name} {run.
|
|
315
|
+
if run.status in ("in_progress", "queued"):
|
|
316
|
+
print(f"{repo.name}: {workflow.name} {run.status}")
|
|
300
317
|
|
|
301
318
|
|
|
302
319
|
# repos per GraphQL query; measured fastest at around 10
|
|
@@ -344,11 +361,9 @@ def graphql_show_runs(bad_state: Callable[[str], bool], bad_conclusion: Callable
|
|
|
344
361
|
Only the head commit of the default branch is looked at, so a failed run
|
|
345
362
|
on another branch, or a scheduled run on an older commit, does not show.
|
|
346
363
|
"""
|
|
347
|
-
apikey = pyapikey.get_key(ConfigGithub.apikey)
|
|
348
364
|
# the default client sleeps a second between POSTs, and every GraphQL
|
|
349
365
|
# query is a POST, which would serialize the parallel queries
|
|
350
|
-
g =
|
|
351
|
-
login_or_token=apikey,
|
|
366
|
+
g = get_github(
|
|
352
367
|
pool_size=GRAPHQL_WORKERS,
|
|
353
368
|
seconds_between_requests=None,
|
|
354
369
|
seconds_between_writes=None,
|
|
@@ -464,7 +479,6 @@ def pull_all() -> None:
|
|
|
464
479
|
[
|
|
465
480
|
"git",
|
|
466
481
|
"pull",
|
|
467
|
-
# "--tags",
|
|
468
482
|
],
|
|
469
483
|
cwd=folder,
|
|
470
484
|
)
|
|
@@ -484,7 +498,7 @@ def pull_all() -> None:
|
|
|
484
498
|
|
|
485
499
|
|
|
486
500
|
@register_endpoint(
|
|
487
|
-
description="
|
|
501
|
+
description="Clone all projects from github",
|
|
488
502
|
configs=[
|
|
489
503
|
ConfigGithub,
|
|
490
504
|
ConfigAlgo,
|
|
@@ -497,12 +511,9 @@ def clone_all() -> None:
|
|
|
497
511
|
project = repo.name
|
|
498
512
|
folder = get_repo_folder(repo)
|
|
499
513
|
all_repo_folders.add(folder)
|
|
500
|
-
# print(f"considering [{project}] from [{repo.ssh_url}]...")
|
|
501
514
|
if os.path.isfile(folder):
|
|
502
|
-
# print(f"skipping [{folder}] as it is not to be cloned...")
|
|
503
515
|
continue
|
|
504
516
|
if os.path.isdir(folder):
|
|
505
|
-
# print(f"skipping [{folder}] as it is already cloned...")
|
|
506
517
|
continue
|
|
507
518
|
if ConfigAlgo.dryrun:
|
|
508
519
|
continue
|
|
@@ -516,7 +527,6 @@ def clone_all() -> None:
|
|
|
516
527
|
],
|
|
517
528
|
cwd=base_dir,
|
|
518
529
|
stdout=subprocess.DEVNULL,
|
|
519
|
-
stderr=subprocess.DEVNULL,
|
|
520
530
|
)
|
|
521
531
|
if ConfigAlgo.show_extra:
|
|
522
532
|
disk_repos = get_all_git_repos(base_dir)
|
|
@@ -540,7 +550,7 @@ def workflows_run() -> None:
|
|
|
540
550
|
for workflow in repo.get_workflows():
|
|
541
551
|
print(f"{repo.name}: {workflow.name}...", end="")
|
|
542
552
|
sys.stdout.flush()
|
|
543
|
-
ret = workflow.create_dispatch(ref=
|
|
553
|
+
ret = workflow.create_dispatch(ref=repo.default_branch)
|
|
544
554
|
print(f"{ret}")
|
|
545
555
|
|
|
546
556
|
|
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
""" misc.py """
|
|
2
2
|
|
|
3
3
|
import glob
|
|
4
|
-
import logging
|
|
5
|
-
import os
|
|
6
4
|
import os.path
|
|
7
5
|
|
|
8
|
-
from pygitpub import LOGGER_NAME
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def get_logger():
|
|
12
|
-
return logging.getLogger(LOGGER_NAME)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def get_number_of_files(folder: str) -> int:
|
|
16
|
-
count = 0
|
|
17
|
-
for _root, _directories, files in os.walk(folder):
|
|
18
|
-
count += len(files)
|
|
19
|
-
return count
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
6
|
|
|
24
7
|
def get_all_git_repos(base_dir: str) -> set[str]:
|
|
25
8
|
""" we use */.git under base_dir with recursive=False (which is the default)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|