Parse GitHub URL into (owner, repo, branch). Supports: - https://github.com/owner/repo - https://github.com/owner/repo.git - https://github.com/owner/repo/tree/branch - github:owner/repo - github:owner/repo@branch - owner/repo (assumes GitHub)
(url: str)
| 636 | |
| 637 | |
| 638 | def parse_github_url(url: str) -> Tuple[str, str, Optional[str]]: |
| 639 | """Parse GitHub URL into (owner, repo, branch). |
| 640 | |
| 641 | Supports: |
| 642 | - https://github.com/owner/repo |
| 643 | - https://github.com/owner/repo.git |
| 644 | - https://github.com/owner/repo/tree/branch |
| 645 | - github:owner/repo |
| 646 | - github:owner/repo@branch |
| 647 | - owner/repo (assumes GitHub) |
| 648 | """ |
| 649 | url = url.strip() |
| 650 | branch = None |
| 651 | |
| 652 | # Handle github: shorthand |
| 653 | if url.startswith("github:"): |
| 654 | url = url[7:] # Remove "github:" |
| 655 | if "@" in url: |
| 656 | repo_part, branch = url.rsplit("@", 1) |
| 657 | else: |
| 658 | repo_part, branch = url, None |
| 659 | |
| 660 | parts = repo_part.split("/") |
| 661 | if len(parts) != 2: |
| 662 | raise PluginError(f"Invalid GitHub shorthand: {url}") |
| 663 | return parts[0], parts[1], branch |
| 664 | |
| 665 | # Handle owner/repo shorthand |
| 666 | if "/" in url and not url.startswith("http"): |
| 667 | parts = url.split("/") |
| 668 | if len(parts) == 2 and not url.startswith("."): |
| 669 | return parts[0], parts[1], None |
| 670 | |
| 671 | # Handle full URLs with @ref suffix |
| 672 | if "@" in url and url.startswith(("http://", "https://", "github.com/", "www.github.com/")): |
| 673 | url, branch = url.rsplit("@", 1) |
| 674 | |
| 675 | # Normalize URLs without scheme (github.com/owner/repo -> https://github.com/owner/repo) |
| 676 | if url.startswith("github.com/") or url.startswith("www.github.com/"): |
| 677 | url = "https://" + url |
| 678 | |
| 679 | # Handle full URLs |
| 680 | parsed = urlparse(url) |
| 681 | if parsed.netloc not in ("github.com", "www.github.com"): |
| 682 | raise PluginError(f"Not a GitHub URL: {url}") |
| 683 | |
| 684 | path_parts = parsed.path.strip("/").split("/") |
| 685 | if len(path_parts) < 2: |
| 686 | raise PluginError(f"Invalid GitHub URL: {url}") |
| 687 | |
| 688 | owner = path_parts[0] |
| 689 | repo = path_parts[1].removesuffix(".git") |
| 690 | |
| 691 | # Check for /tree/branch pattern |
| 692 | if len(path_parts) >= 4 and path_parts[2] == "tree": |
| 693 | branch = path_parts[3] |
| 694 | |
| 695 | return owner, repo, branch |