```python-traceback
Traceback (most recent call last):
File ".local/bin/github-backup", line 6, in <module>
sys.exit(main())
~~~~^^
File ".local/share/pipx/venvs/github-backup/lib/python3.14/site-packages/github_backup/cli.py", line 83, in main
backup_repositories(args, output_directory, repositories)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".local/share/pipx/venvs/github-backup/lib/python3.14/site-packages/github_backup/github_backup.py", line 1845, in backup_repositories
backup_pulls(args, repo_cwd, repository, repos_template)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".local/share/pipx/venvs/github-backup/lib/python3.14/site-packages/github_backup/github_backup.py", line 2019, in backup_pulls
pulls[number]["commit_data"] = retrieve_data(args, template)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File ".local/share/pipx/venvs/github-backup/lib/python3.14/site-packages/github_backup/github_backup.py", line 766, in retrieve_data
return list(fetch_all())
File ".local/share/pipx/venvs/github-backup/lib/python3.14/site-packages/github_backup/github_backup.py", line 717, in fetch_all
response = json.loads(http_response.read().decode("utf-8"))
~~~~~~~~~~~~~~~~~~^^
File "/usr/lib/python3.14/http/client.py", line 500, in read
s = self._safe_read(self.length)
File "/usr/lib/python3.14/http/client.py", line 648, in _safe_read
data = self.fp.read(cursize)
File "/usr/lib/python3.14/socket.py", line 725, in readinto
return self._sock.recv_into(b)
~~~~~~~~~~~~~~~~~~~~^^^
File "/usr/lib/python3.14/ssl.py", line 1304, in recv_into
return self.read(nbytes, buffer)
~~~~~~~~~^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/ssl.py", line 1138, in read
return self._sslobj.read(len, buffer)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
ConnectionResetError: [Errno 104] Connection reset by peer
```
Empty repositories have None for pushed_at/updated_at, causing a
TypeError when compared to the last_update string. Use .get() with
truthiness check to skip None timestamps in incremental tracking.
The DMCA handling added in PR #454 had a bug: make_request_with_retry()
raises HTTPError before retrieve_data() could check the status code via
getcode(), making the case 451 handler dead code. This also affected
HTTP 403 TOS violations (e.g. jumoog/MagiskOnWSA).
Fix by catching HTTPError in retrieve_data() and converting 451 and
blocked 403 responses (identified by "block" key in response body) to
RepositoryUnavailableError. Non-block 403s (permissions, scopes) still
propagate as HTTPError. Also handle RepositoryUnavailableError in
retrieve_repositories() for the --repository case.
Rewrote tests to mock urlopen (not make_request_with_retry) to exercise
the real code path that was previously untested.
Closes#487
The repository dictionary uses lowercase "private" key. Use .get() with
the correct case to match the pattern used elsewhere in the codebase.
The bug only affects --all users since --security-advisories short-circuits
before the key access.
Fine-grained personal access tokens cannot download attachments from
private repositories directly due to a GitHub platform limitation.
This adds a workaround for image attachments (/assets/ URLs) using
GitHub's Markdown API to convert URLs to JWT-signed URLs that can be
downloaded without authentication.
Changes:
- Add get_jwt_signed_url_via_markdown_api() function
- Detect fine-grained token + private repo + /assets/ URL upfront
- Use JWT workaround for those cases, mark success with jwt_workaround flag
- Skip download with skipped_at when workaround fails
- Add startup warning when using --attachments with fine-grained tokens
- Document limitation in README (file attachments still fail)
- Add 6 unit tests for JWT workaround logic
### What
1. configureable retry count
2. additional logging
### Why
1. pass retry count as a command line arg; default 5
2. show details when api requests fail
### Testing before merge
compiles cleanly
### Validation after merge
compile and test
### Issue addressed by this PR
https://github.com/stellar/ops/issues/2039
Allow users to skip starred repositories exceeding a size threshold
when using --all-starred. Size is specified in MB and checked against
the GitHub API's repository size field.
- Only affects starred repos; user's own repos always included
- Logs each skipped repo with name and size
Closes#108
Refactors error handling to retry all 5xx errors (not just 502), network errors (URLError, socket.error, IncompleteRead), and JSON parse errors with exponential backoff and jitter. Respects retry-after and rate limit headers per GitHub API requirements. Consolidates retry logic into make_request_with_retry() wrapper and adds clear logging for retry attempts and failures. Removes dead code from 2016 (errors list, _request_http_error, _request_url_error) that was intentionally disabled in commit 1e5a9048 to fix#29.
Fixes#140, #110, #138