github-backup 0.66.0__tar.gz → 0.66.1__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_backup-0.66.0 → github_backup-0.66.1}/CHANGES.rst +30 -1
- {github_backup-0.66.0/github_backup.egg-info → github_backup-0.66.1}/PKG-INFO +3 -5
- {github_backup-0.66.0 → github_backup-0.66.1}/README +2 -4
- {github_backup-0.66.0 → github_backup-0.66.1}/README.rst +2 -4
- github_backup-0.66.1/github_backup/__init__.py +1 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup/github_backup.py +15 -1
- {github_backup-0.66.0 → github_backup-0.66.1/github_backup.egg-info}/PKG-INFO +3 -5
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup.egg-info/SOURCES.txt +1 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/release-requirements.txt +1 -1
- github_backup-0.66.1/tests/test_hooks.py +96 -0
- github_backup-0.66.0/github_backup/__init__.py +0 -1
- {github_backup-0.66.0 → github_backup-0.66.1}/LICENSE.txt +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/MANIFEST.in +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup/__main__.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup/cli.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup/graphql_queries.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup.egg-info/dependency_links.txt +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup.egg-info/entry_points.txt +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup.egg-info/top_level.txt +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/github_backup.egg-info/zip-safe +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/requirements.txt +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/setup.cfg +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/setup.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_all_starred.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_app_repositories.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_attachments.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_auth.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_case_sensitivity.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_disabled_issues_pulls.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_discussions.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_gists.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_http_451.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_incremental_per_repository.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_issue_timeline.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_json_dump_if_changed.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_logging_subprocess.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_pagination.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_pull_incremental_pagination.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_pull_reviews.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_releases.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_retrieve_data.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_skip_assets_on.py +0 -0
- {github_backup-0.66.0 → github_backup-0.66.1}/tests/test_starred_skip_size_over.py +0 -0
|
@@ -1,9 +1,38 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
-
0.66.
|
|
4
|
+
0.66.1 (2026-11-03)
|
|
5
5
|
-------------------
|
|
6
6
|
------------------------
|
|
7
|
+
- Skip hooks for repositories without admin access instead of logging a
|
|
8
|
+
404 error (#532) [Rodos]
|
|
9
|
+
|
|
10
|
+
Reading hooks needs admin access, and GitHub returns 404 without it. When the
|
|
11
|
+
repository listing says the token isn't an admin, skip hooks without making the
|
|
12
|
+
request. The 404 skip message now names the repository and the permission it
|
|
13
|
+
needs, and the README note about hooks blocking starred backups is updated.
|
|
14
|
+
- Chore(deps): bump pytest. [dependabot[bot]]
|
|
15
|
+
|
|
16
|
+
Bumps the python-packages group with 1 update: [pytest](https://github.com/pytest-dev/pytest).
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
Updates `pytest` from 9.1.1 to 9.2.0
|
|
20
|
+
- [Release notes](https://github.com/pytest-dev/pytest/releases)
|
|
21
|
+
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
|
|
22
|
+
- [Commits](https://github.com/pytest-dev/pytest/compare/9.1.1...9.2.0)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
updated-dependencies:
|
|
26
|
+
- dependency-name: pytest
|
|
27
|
+
dependency-version: 9.2.0
|
|
28
|
+
dependency-type: direct:production
|
|
29
|
+
update-type: version-update:semver-minor
|
|
30
|
+
dependency-group: python-packages
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
0.66.0 (2026-10-28)
|
|
35
|
+
-------------------
|
|
7
36
|
- List a user's private repositories when authenticated as a GitHub App.
|
|
8
37
|
[AC Capehart, Claude Opus 5.5]
|
|
9
38
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-backup
|
|
3
|
-
Version: 0.66.
|
|
3
|
+
Version: 0.66.1
|
|
4
4
|
Summary: backup a github user or organization
|
|
5
5
|
Home-page: http://github.com/josegonzalez/python-github-backup
|
|
6
6
|
Author: Jose Diaz-Gonzalez
|
|
@@ -437,11 +437,9 @@ If the incremental argument is used, per-resource checkpoints are only advanced
|
|
|
437
437
|
|
|
438
438
|
It's therefore recommended to only use the incremental argument if the output/result is being actively monitored, or complimented with periodic full non-incremental runs, to avoid unexpected missing data in a regular backup runs.
|
|
439
439
|
|
|
440
|
-
**
|
|
440
|
+
**Hooks need admin access**
|
|
441
441
|
|
|
442
|
-
Since the ``--all`` argument includes ``--hooks``,
|
|
443
|
-
|
|
444
|
-
This is due to needing the correct permission for ``--hooks`` on public repos.
|
|
442
|
+
Reading a repository's hooks requires admin access to it, and fine-grained tokens also need the Webhooks read permission. Since the ``--all`` argument includes ``--hooks``, repositories you don't administer, such as starred repositories with ``--all-starred``, are skipped for hooks and the rest of the backup continues.
|
|
445
443
|
|
|
446
444
|
|
|
447
445
|
"bare" is actually "mirror"
|
|
@@ -407,11 +407,9 @@ If the incremental argument is used, per-resource checkpoints are only advanced
|
|
|
407
407
|
|
|
408
408
|
It's therefore recommended to only use the incremental argument if the output/result is being actively monitored, or complimented with periodic full non-incremental runs, to avoid unexpected missing data in a regular backup runs.
|
|
409
409
|
|
|
410
|
-
**
|
|
410
|
+
**Hooks need admin access**
|
|
411
411
|
|
|
412
|
-
Since the ``--all`` argument includes ``--hooks``,
|
|
413
|
-
|
|
414
|
-
This is due to needing the correct permission for ``--hooks`` on public repos.
|
|
412
|
+
Reading a repository's hooks requires admin access to it, and fine-grained tokens also need the Webhooks read permission. Since the ``--all`` argument includes ``--hooks``, repositories you don't administer, such as starred repositories with ``--all-starred``, are skipped for hooks and the rest of the backup continues.
|
|
415
413
|
|
|
416
414
|
|
|
417
415
|
"bare" is actually "mirror"
|
|
@@ -407,11 +407,9 @@ If the incremental argument is used, per-resource checkpoints are only advanced
|
|
|
407
407
|
|
|
408
408
|
It's therefore recommended to only use the incremental argument if the output/result is being actively monitored, or complimented with periodic full non-incremental runs, to avoid unexpected missing data in a regular backup runs.
|
|
409
409
|
|
|
410
|
-
**
|
|
410
|
+
**Hooks need admin access**
|
|
411
411
|
|
|
412
|
-
Since the ``--all`` argument includes ``--hooks``,
|
|
413
|
-
|
|
414
|
-
This is due to needing the correct permission for ``--hooks`` on public repos.
|
|
412
|
+
Reading a repository's hooks requires admin access to it, and fine-grained tokens also need the Webhooks read permission. Since the ``--all`` argument includes ``--hooks``, repositories you don't administer, such as starred repositories with ``--all-starred``, are skipped for hooks and the rest of the backup continues.
|
|
415
413
|
|
|
416
414
|
|
|
417
415
|
"bare" is actually "mirror"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.66.1"
|
|
@@ -3155,6 +3155,15 @@ def backup_hooks(args, repo_cwd, repository, repos_template):
|
|
|
3155
3155
|
if not auth:
|
|
3156
3156
|
logger.info("Skipping hooks since no authentication provided")
|
|
3157
3157
|
return
|
|
3158
|
+
# Reading hooks needs admin access, and GitHub returns 404 without it.
|
|
3159
|
+
# Skip the request when the repository listing says we aren't an admin.
|
|
3160
|
+
if repository.get("permissions", {}).get("admin") is False:
|
|
3161
|
+
logger.info(
|
|
3162
|
+
"Skipping hooks for {0} since admin access is required".format(
|
|
3163
|
+
repository["full_name"]
|
|
3164
|
+
)
|
|
3165
|
+
)
|
|
3166
|
+
return
|
|
3158
3167
|
hook_cwd = os.path.join(repo_cwd, "hooks")
|
|
3159
3168
|
output_file = "{0}/hooks.json".format(hook_cwd)
|
|
3160
3169
|
template = "{0}/{1}/hooks".format(repos_template, repository["full_name"])
|
|
@@ -3162,7 +3171,12 @@ def backup_hooks(args, repo_cwd, repository, repos_template):
|
|
|
3162
3171
|
_backup_data(args, "hooks", template, output_file, hook_cwd)
|
|
3163
3172
|
except HTTPError as e:
|
|
3164
3173
|
if e.code == 404:
|
|
3165
|
-
logger.info(
|
|
3174
|
+
logger.info(
|
|
3175
|
+
"Unable to read hooks for {0}, skipping (requires admin access, "
|
|
3176
|
+
"or Webhooks read permission for fine-grained tokens)".format(
|
|
3177
|
+
repository["full_name"]
|
|
3178
|
+
)
|
|
3179
|
+
)
|
|
3166
3180
|
else:
|
|
3167
3181
|
raise e
|
|
3168
3182
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-backup
|
|
3
|
-
Version: 0.66.
|
|
3
|
+
Version: 0.66.1
|
|
4
4
|
Summary: backup a github user or organization
|
|
5
5
|
Home-page: http://github.com/josegonzalez/python-github-backup
|
|
6
6
|
Author: Jose Diaz-Gonzalez
|
|
@@ -437,11 +437,9 @@ If the incremental argument is used, per-resource checkpoints are only advanced
|
|
|
437
437
|
|
|
438
438
|
It's therefore recommended to only use the incremental argument if the output/result is being actively monitored, or complimented with periodic full non-incremental runs, to avoid unexpected missing data in a regular backup runs.
|
|
439
439
|
|
|
440
|
-
**
|
|
440
|
+
**Hooks need admin access**
|
|
441
441
|
|
|
442
|
-
Since the ``--all`` argument includes ``--hooks``,
|
|
443
|
-
|
|
444
|
-
This is due to needing the correct permission for ``--hooks`` on public repos.
|
|
442
|
+
Reading a repository's hooks requires admin access to it, and fine-grained tokens also need the Webhooks read permission. Since the ``--all`` argument includes ``--hooks``, repositories you don't administer, such as starred repositories with ``--all-starred``, are skipped for hooks and the rest of the backup continues.
|
|
445
443
|
|
|
446
444
|
|
|
447
445
|
"bare" is actually "mirror"
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Tests for hooks backup permissions (GitHub issue #532).
|
|
2
|
+
|
|
3
|
+
Reading ``/repos/{owner}/{repo}/hooks`` needs admin access to the repository.
|
|
4
|
+
Without it GitHub responds with HTTP 404 rather than 403, which used to log an
|
|
5
|
+
API error for every repository the user doesn't administer.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from urllib.error import HTTPError
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from github_backup import github_backup
|
|
14
|
+
|
|
15
|
+
REPOS_TEMPLATE = "https://api.github.com/repos"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def hook_args(create_args):
|
|
20
|
+
return create_args(include_hooks=True, token_classic="ghp_token")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _repository(**fields):
|
|
24
|
+
return {"full_name": "owner/repo", **fields}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_hooks_skipped_without_request_when_not_admin(
|
|
28
|
+
hook_args, tmp_path, monkeypatch, caplog
|
|
29
|
+
):
|
|
30
|
+
def fail_retrieve_data(*args, **kwargs):
|
|
31
|
+
raise AssertionError("hooks should not be requested without admin access")
|
|
32
|
+
|
|
33
|
+
monkeypatch.setattr(github_backup, "retrieve_data", fail_retrieve_data)
|
|
34
|
+
|
|
35
|
+
with caplog.at_level(logging.INFO, logger=github_backup.logger.name):
|
|
36
|
+
github_backup.backup_hooks(
|
|
37
|
+
hook_args,
|
|
38
|
+
tmp_path,
|
|
39
|
+
_repository(permissions={"admin": False, "push": True, "pull": True}),
|
|
40
|
+
REPOS_TEMPLATE,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
assert "Skipping hooks for owner/repo since admin access is required" in caplog.text
|
|
44
|
+
assert not (tmp_path / "hooks").exists()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.mark.parametrize(
|
|
48
|
+
"repository",
|
|
49
|
+
[
|
|
50
|
+
_repository(permissions={"admin": True, "push": True, "pull": True}),
|
|
51
|
+
_repository(),
|
|
52
|
+
],
|
|
53
|
+
ids=["admin", "no-permissions-field"],
|
|
54
|
+
)
|
|
55
|
+
def test_hooks_requested_when_admin_or_permissions_unknown(
|
|
56
|
+
hook_args, tmp_path, monkeypatch, repository
|
|
57
|
+
):
|
|
58
|
+
requested = []
|
|
59
|
+
|
|
60
|
+
def fake_retrieve_data(passed_args, template, *args, **kwargs):
|
|
61
|
+
requested.append(template)
|
|
62
|
+
return [{"id": 1, "name": "web"}]
|
|
63
|
+
|
|
64
|
+
monkeypatch.setattr(github_backup, "retrieve_data", fake_retrieve_data)
|
|
65
|
+
|
|
66
|
+
github_backup.backup_hooks(hook_args, tmp_path, repository, REPOS_TEMPLATE)
|
|
67
|
+
|
|
68
|
+
assert requested == ["https://api.github.com/repos/owner/repo/hooks"]
|
|
69
|
+
assert (tmp_path / "hooks" / "hooks.json").exists()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_hooks_404_is_skipped_with_reason(hook_args, tmp_path, monkeypatch, caplog):
|
|
73
|
+
def fake_retrieve_data(passed_args, template, *args, **kwargs):
|
|
74
|
+
raise HTTPError(template, 404, "Not Found", hdrs=None, fp=None)
|
|
75
|
+
|
|
76
|
+
monkeypatch.setattr(github_backup, "retrieve_data", fake_retrieve_data)
|
|
77
|
+
|
|
78
|
+
with caplog.at_level(logging.INFO, logger=github_backup.logger.name):
|
|
79
|
+
github_backup.backup_hooks(
|
|
80
|
+
hook_args,
|
|
81
|
+
tmp_path,
|
|
82
|
+
_repository(permissions={"admin": True}),
|
|
83
|
+
REPOS_TEMPLATE,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
assert "Unable to read hooks for owner/repo, skipping" in caplog.text
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_hooks_non_404_error_propagates(hook_args, tmp_path, monkeypatch):
|
|
90
|
+
def fake_retrieve_data(passed_args, template, *args, **kwargs):
|
|
91
|
+
raise HTTPError(template, 500, "Server Error", hdrs=None, fp=None)
|
|
92
|
+
|
|
93
|
+
monkeypatch.setattr(github_backup, "retrieve_data", fake_retrieve_data)
|
|
94
|
+
|
|
95
|
+
with pytest.raises(HTTPError):
|
|
96
|
+
github_backup.backup_hooks(hook_args, tmp_path, _repository(), REPOS_TEMPLATE)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.66.0"
|
|
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
|
|
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
|