github-backup 0.65.0__tar.gz → 0.65.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.
Files changed (41) hide show
  1. {github_backup-0.65.0 → github_backup-0.65.1}/CHANGES.rst +25 -1
  2. {github_backup-0.65.0/github_backup.egg-info → github_backup-0.65.1}/PKG-INFO +1 -1
  3. github_backup-0.65.1/github_backup/__init__.py +1 -0
  4. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup/github_backup.py +26 -16
  5. {github_backup-0.65.0 → github_backup-0.65.1/github_backup.egg-info}/PKG-INFO +1 -1
  6. {github_backup-0.65.0 → github_backup-0.65.1}/release-requirements.txt +1 -1
  7. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_issue_timeline.py +31 -6
  8. github_backup-0.65.0/github_backup/__init__.py +0 -1
  9. {github_backup-0.65.0 → github_backup-0.65.1}/LICENSE.txt +0 -0
  10. {github_backup-0.65.0 → github_backup-0.65.1}/MANIFEST.in +0 -0
  11. {github_backup-0.65.0 → github_backup-0.65.1}/README +0 -0
  12. {github_backup-0.65.0 → github_backup-0.65.1}/README.rst +0 -0
  13. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup/__main__.py +0 -0
  14. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup/cli.py +0 -0
  15. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup/graphql_queries.py +0 -0
  16. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup.egg-info/SOURCES.txt +0 -0
  17. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup.egg-info/dependency_links.txt +0 -0
  18. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup.egg-info/entry_points.txt +0 -0
  19. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup.egg-info/top_level.txt +0 -0
  20. {github_backup-0.65.0 → github_backup-0.65.1}/github_backup.egg-info/zip-safe +0 -0
  21. {github_backup-0.65.0 → github_backup-0.65.1}/requirements.txt +0 -0
  22. {github_backup-0.65.0 → github_backup-0.65.1}/setup.cfg +0 -0
  23. {github_backup-0.65.0 → github_backup-0.65.1}/setup.py +0 -0
  24. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_all_starred.py +0 -0
  25. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_attachments.py +0 -0
  26. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_auth.py +0 -0
  27. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_case_sensitivity.py +0 -0
  28. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_disabled_issues_pulls.py +0 -0
  29. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_discussions.py +0 -0
  30. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_gists.py +0 -0
  31. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_http_451.py +0 -0
  32. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_incremental_per_repository.py +0 -0
  33. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_json_dump_if_changed.py +0 -0
  34. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_logging_subprocess.py +0 -0
  35. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_pagination.py +0 -0
  36. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_pull_incremental_pagination.py +0 -0
  37. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_pull_reviews.py +0 -0
  38. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_releases.py +0 -0
  39. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_retrieve_data.py +0 -0
  40. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_skip_assets_on.py +0 -0
  41. {github_backup-0.65.0 → github_backup-0.65.1}/tests/test_starred_skip_size_over.py +0 -0
@@ -1,9 +1,33 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- 0.65.0 (2026-07-27)
4
+ 0.65.1 (2026-08-01)
5
5
  -------------------
6
6
  ------------------------
7
+ - Fix timeline not being properly incremental. [Duncan Ogilvie]
8
+ - Chore(deps): bump twine from 6.2.0 to 7.0.0 in the python-packages
9
+ group. [dependabot[bot]]
10
+
11
+ Bumps the python-packages group with 1 update: [twine](https://github.com/pypa/twine).
12
+
13
+
14
+ Updates `twine` from 6.2.0 to 7.0.0
15
+ - [Release notes](https://github.com/pypa/twine/releases)
16
+ - [Changelog](https://github.com/pypa/twine/blob/main/docs/changelog.rst)
17
+ - [Commits](https://github.com/pypa/twine/compare/6.2.0...7.0.0)
18
+
19
+ ---
20
+ updated-dependencies:
21
+ - dependency-name: twine
22
+ dependency-version: 7.0.0
23
+ dependency-type: direct:production
24
+ update-type: version-update:semver-major
25
+ dependency-group: python-packages
26
+ ...
27
+
28
+
29
+ 0.65.0 (2026-07-27)
30
+ -------------------
7
31
  - Refresh issue timelines when cross-references change (#168) [Rodos]
8
32
 
9
33
  Cross-references do not change an issue's updated_at, so an incremental
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-backup
3
- Version: 0.65.0
3
+ Version: 0.65.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
@@ -0,0 +1 @@
1
+ __version__ = "0.65.1"
@@ -2757,19 +2757,24 @@ def backup_issues(args, repo_cwd, repository, repos_template):
2757
2757
  stale_timelines = find_stale_timeline_issues(
2758
2758
  args, issue_cwd, repository, include_pulls=not should_include_pulls
2759
2759
  )
2760
- for number in sorted(stale_timelines - set(issues)):
2761
- try:
2762
- issues[number] = retrieve_data(
2763
- args, "{0}/{1}".format(_issue_template, number), paginated=False
2764
- )[0]
2765
- except (HTTPError, RepositoryUnavailableError, IndexError) as e:
2766
- # Deleted or transferred between the sweep and this fetch. The
2767
- # refresh is opportunistic, so skip rather than fail the run.
2768
- logger.warning(
2769
- "Unable to refresh cross-references for issue {0}: {1}".format(
2770
- number, e
2771
- )
2772
- )
2760
+
2761
+ # Issues selected only by the cross-reference sweep have not otherwise
2762
+ # changed. Reuse their complete stored payload and refresh only timeline_data.
2763
+ # Fetching the issue, comments, events and attachments again turns the first
2764
+ # --issue-timeline run into a near-full backup and can discard optional data
2765
+ # when the corresponding flags are absent.
2766
+ timeline_only_issues = stale_timelines - set(issues)
2767
+ for number in sorted(timeline_only_issues):
2768
+ existing = read_json_file_if_exists(
2769
+ "{0}/{1}.json".format(issue_cwd, number)
2770
+ )
2771
+ if existing is None:
2772
+ logger.warning(
2773
+ "Unable to refresh cross-references for issue {0}: "
2774
+ "stored issue data is unreadable".format(number)
2775
+ )
2776
+ continue
2777
+ issues[number] = existing
2773
2778
 
2774
2779
  if issues_skipped:
2775
2780
  issues_skipped_message = " (skipped {0} pull requests)".format(issues_skipped)
@@ -2784,6 +2789,7 @@ def backup_issues(args, repo_cwd, repository, repos_template):
2784
2789
  timeline_template = _issue_template + "/{0}/timeline"
2785
2790
  for number, issue in list(issues.items()):
2786
2791
  issue_file = "{0}/{1}.json".format(issue_cwd, number)
2792
+ timeline_only_refresh = number in timeline_only_issues
2787
2793
  if (
2788
2794
  args.incremental_by_files
2789
2795
  and os.path.isfile(issue_file)
@@ -2799,10 +2805,14 @@ def backup_issues(args, repo_cwd, repository, repos_template):
2799
2805
  )
2800
2806
  continue
2801
2807
 
2802
- if args.include_issue_comments or args.include_everything:
2808
+ if not timeline_only_refresh and (
2809
+ args.include_issue_comments or args.include_everything
2810
+ ):
2803
2811
  template = comments_template.format(number)
2804
2812
  issues[number]["comment_data"] = retrieve_data(args, template)
2805
- if args.include_issue_events or args.include_everything:
2813
+ if not timeline_only_refresh and (
2814
+ args.include_issue_events or args.include_everything
2815
+ ):
2806
2816
  template = events_template.format(number)
2807
2817
  issues[number]["event_data"] = retrieve_data(args, template)
2808
2818
  if include_timeline:
@@ -2815,7 +2825,7 @@ def backup_issues(args, repo_cwd, repository, repos_template):
2815
2825
  for item in retrieve_data(args, template)
2816
2826
  if item.get("event") != "commented"
2817
2827
  ]
2818
- if args.include_attachments:
2828
+ if args.include_attachments and not timeline_only_refresh:
2819
2829
  download_attachments(
2820
2830
  args, issue_cwd, issues[number], number, repository, item_type="issue"
2821
2831
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-backup
3
- Version: 0.65.0
3
+ Version: 0.65.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
@@ -7,7 +7,7 @@ flake8==7.3.0
7
7
  pytest==9.1.1
8
8
 
9
9
  # Release & Publishing
10
- twine==6.2.0
10
+ twine==7.0.0
11
11
  gitchangelog==3.0.4
12
12
  setuptools==83.0.0
13
13
 
@@ -274,12 +274,24 @@ def test_graphql_failure_warns_and_continues(
274
274
  def test_stale_issue_backed_up_though_since_excludes_it(
275
275
  create_args, tmp_path, monkeypatch
276
276
  ):
277
- """The whole point: an issue since cannot see is still refreshed."""
278
- _stored(tmp_path, 7, [])
277
+ """A sweep-only issue refreshes just its timeline and preserves its data."""
278
+ issue_cwd = tmp_path / "issues"
279
+ issue_cwd.mkdir()
280
+ stored = _issue(
281
+ 7,
282
+ body="stored body",
283
+ comment_data=[{"id": 1, "body": "stored comment"}],
284
+ event_data=[{"id": 2, "event": "referenced"}],
285
+ timeline_data=[],
286
+ )
287
+ (issue_cwd / "7.json").write_text(json.dumps(stored))
279
288
  args = _sweep_args(
280
289
  create_args,
281
290
  include_issues=True,
291
+ include_issue_comments=True,
292
+ include_issue_events=True,
282
293
  include_issue_timeline=True,
294
+ include_attachments=True,
283
295
  since="2026-07-01T00:00:00Z",
284
296
  )
285
297
  timeline = [_xref("2026-07-20T00:00:00Z")]
@@ -287,22 +299,35 @@ def test_stale_issue_backed_up_though_since_excludes_it(
287
299
  monkeypatch.setattr(
288
300
  github_backup,
289
301
  "retrieve_data",
290
- _fake_retrieve(
291
- {"/issues": [], "/issues/7": [_issue(7)], "/7/timeline": timeline}, calls
292
- ),
302
+ _fake_retrieve({"/issues": [], "/7/timeline": timeline}, calls),
293
303
  )
294
304
  monkeypatch.setattr(
295
305
  github_backup,
296
306
  "retrieve_graphql_data",
297
307
  _graphql_state({7: (1, "2026-07-20T00:00:00Z")}),
298
308
  )
309
+ attachment_calls = []
310
+ monkeypatch.setattr(
311
+ github_backup,
312
+ "download_attachments",
313
+ lambda *args, **kwargs: attachment_calls.append((args, kwargs)),
314
+ )
299
315
 
300
316
  github_backup.backup_issues(
301
317
  args, str(tmp_path), {"full_name": "owner/repo"}, "https://api.github.com/repos"
302
318
  )
303
319
 
304
- saved = json.loads((tmp_path / "issues" / "7.json").read_text())
320
+ saved = json.loads((issue_cwd / "7.json").read_text())
305
321
  assert saved["timeline_data"] == timeline
322
+ assert saved["body"] == "stored body"
323
+ assert saved["comment_data"] == stored["comment_data"]
324
+ assert saved["event_data"] == stored["event_data"]
325
+ assert calls == [
326
+ "https://api.github.com/repos/owner/repo/issues",
327
+ "https://api.github.com/repos/owner/repo/issues",
328
+ "https://api.github.com/repos/owner/repo/issues/7/timeline",
329
+ ]
330
+ assert attachment_calls == []
306
331
 
307
332
 
308
333
  def test_sweep_follows_pagination_cursors(create_args, tmp_path, monkeypatch):
@@ -1 +0,0 @@
1
- __version__ = "0.65.0"
File without changes
File without changes
File without changes