GitHub's API accepts usernames in any case but returns canonical case.
The case-sensitive comparison in filter_repositories() filtered out all
repositories when user-provided case didn't match GitHub's canonical case.
Changed to case-insensitive comparison.
Fixes#198
This change reduces unnecessary writes when backing up metadata that changes
infrequently. The implementation compares existing file content before writing
and skips the write if the content is identical, preserving file timestamps.
Key changes:
- Added json_dump_if_changed() helper that compares content before writing
- Uses atomic writes (temp file + rename) for all metadata files
- NOT applied to issues/pulls (they use incremental_by_files logic)
- Made log messages consistent and past tense ("Saved" instead of "Saving")
- Added informative logging showing skip counts
Fixes#133
The previous implementation incorrectly assumed empty get_ca_certs()
meant broken SSL, causing false failures in GitHub Codespaces and other
directory-based cert systems where certificates exist but aren't pre-loaded.
It would then attempt to import certifi as a workaround, but certifi wasn't
listed in requirements.txt, causing the fallback to fail with ImportError
even though the system certificates would have worked fine.
This commit replaces the naive check with a layered fallback approach that
checks multiple certificate sources. First it checks for pre-loaded system
certs (file-based systems). Then it verifies system cert paths exist
(directory-based systems like Ubuntu/Debian/Codespaces). Finally it attempts
to use certifi as an optional fallback only if needed.
This approach eliminates hard dependencies (certifi is now optional), works
in GitHub Codespaces without any setup, and fails gracefully with clear hints
for resolution when SSL is actually broken rather than failing with
ModuleNotFoundError.
Fixes#444
Fixes bug where attachments were downloaded multiple times with
incremented filenames (file.mov, file_1.mov, file_2.mov) when
running backups without --skip-existing flag.
I should not have used the --skip-existing flag for attachments,
it did not do what I thought it did.
The correct approach is to always use the manifest to guide what
has already been downloaded and what now needs to be done.
Adds new --attachments flag that downloads user-uploaded files from
issue and PR bodies and comments. Key features:
- Determines attachment URLs
- Tracks downloads in manifest.json with metadata
- Supports --skip-existing to avoid re-downloading
- Handles filename collisions with counter suffix
- Smart retry logic for transient vs permanent failures
- Uses Content-Disposition for correct file extensions
Previously, using -R flag would show zero issues/PRs for repositories
not owned by the primary user due to incorrect pagination parameters
being added to single repository API calls.
- Remove pagination parameters for single repository requests
- Support owner/repo format in -R flag (e.g., -R owner/repo-name)
- Skip filtering when specific repository is requested
- Fix URL construction for requests without query parameters
This enables backing up any repository, not just those owned by the
primary user specified in -u flag.
Some users are relying solely on the certifi package to provide their CA certs, as requests does this by default.
This patch detects this situation and emits a clear warning as well as importing certifi to work around the situation..
Fixes#162 .
When downloading assets using a fine grained token you will get a "can't
concat str to bytes" error. This is due to the fine grained token being
concatenated onto bytes in the line:
`request.add_header("Authorization", "Basic ".encode("ascii") + auth)`
This is better handled in the function `_construct_request` so I changed
the lines that construct the request in `download_file` to use the
function `_construct_request` and updated the function signature to
reflect that.