Convert a GitHub URL to a downloadable zip URL if possible. Args: url: GitHub URL (can be git, https, or already a zip URL) Returns: Tuple of (converted_url, needs_manual_install): - converted_url: Zip URL if conversion succeeded, None otherwise - needs
(url: str)
| 10 | |
| 11 | |
| 12 | def convert_github_url_to_zip(url: str) -> tuple[Optional[str], bool]: |
| 13 | """ |
| 14 | Convert a GitHub URL to a downloadable zip URL if possible. |
| 15 | |
| 16 | Args: |
| 17 | url: GitHub URL (can be git, https, or already a zip URL) |
| 18 | |
| 19 | Returns: |
| 20 | Tuple of (converted_url, needs_manual_install): |
| 21 | - converted_url: Zip URL if conversion succeeded, None otherwise |
| 22 | - needs_manual_install: True if URL requires manual git installation |
| 23 | |
| 24 | Examples: |
| 25 | >>> convert_github_url_to_zip("https://github.com/user/repo.git") |
| 26 | (None, True) # Cannot convert without version info |
| 27 | |
| 28 | >>> convert_github_url_to_zip("https://github.com/user/repo/archive/refs/tags/v1.0.0.zip") |
| 29 | ("https://github.com/user/repo/archive/refs/tags/v1.0.0.zip", False) # Already zip |
| 30 | |
| 31 | >>> convert_github_url_to_zip("https://github.com/user/repo.git#v1.0.0") |
| 32 | ("https://github.com/user/repo/archive/refs/tags/v1.0.0.zip", False) # Converted |
| 33 | """ |
| 34 | if not url: |
| 35 | return None, False |
| 36 | |
| 37 | # Already a zip URL - return as-is |
| 38 | if url.endswith(".zip") or ".zip?" in url: |
| 39 | return url, False |
| 40 | |
| 41 | # Parse the URL |
| 42 | parsed = urlparse(url) |
| 43 | |
| 44 | # Only handle GitHub URLs |
| 45 | if parsed.netloc not in ("github.com", "www.github.com"): |
| 46 | return None, False |
| 47 | |
| 48 | # Extract repository path and ref/tag info |
| 49 | # Pattern: https://github.com/owner/repo.git#ref |
| 50 | # Pattern: https://github.com/owner/repo.git |
| 51 | # Pattern: https://github.com/owner/repo (without .git) |
| 52 | |
| 53 | path = parsed.path.rstrip("/") |
| 54 | fragment = parsed.fragment # The part after # |
| 55 | |
| 56 | # Remove .git suffix if present |
| 57 | if path.endswith(".git"): |
| 58 | path = path[:-4] |
| 59 | |
| 60 | # Split path into components |
| 61 | path_parts = [p for p in path.split("/") if p] |
| 62 | if len(path_parts) < 2: |
| 63 | # Not a valid owner/repo path |
| 64 | return None, False |
| 65 | |
| 66 | owner = path_parts[0] |
| 67 | repo = path_parts[1] |
| 68 | |
| 69 | # Check if there's a ref/tag in the fragment or path |
no outgoing calls
no test coverage detected