|
11 | 11 | from comfy_cli.command.install import ( |
12 | 12 | GitHubRateLimitError, |
13 | 13 | PRInfo, |
| 14 | + _parse_github_owner_repo, |
14 | 15 | _resolve_latest_tag_from_local, |
15 | 16 | checkout_stable_comfyui, |
16 | 17 | fetch_pr_info, |
@@ -626,6 +627,57 @@ def test_tag_with_v_prefix_normalized(self, tmp_path): |
626 | 627 | assert tag == "0.20.1" |
627 | 628 |
|
628 | 629 |
|
| 630 | +class TestParseGithubOwnerRepo: |
| 631 | + """Cover the URL parser used by the API fallback to query the same repo |
| 632 | + we cloned from (forks included), instead of always asking upstream.""" |
| 633 | + |
| 634 | + @pytest.mark.parametrize( |
| 635 | + "url,expected", |
| 636 | + [ |
| 637 | + # The default URL the install command uses |
| 638 | + ("https://github.com/comfyanonymous/ComfyUI", ("comfyanonymous", "ComfyUI")), |
| 639 | + # With .git suffix |
| 640 | + ("https://github.com/comfyanonymous/ComfyUI.git", ("comfyanonymous", "ComfyUI")), |
| 641 | + # With trailing slash |
| 642 | + ("https://github.com/comfyanonymous/ComfyUI/", ("comfyanonymous", "ComfyUI")), |
| 643 | + # setuptools-style @branch suffix that clone_comfyui supports |
| 644 | + ("https://github.com/comfyanonymous/ComfyUI@master", ("comfyanonymous", "ComfyUI")), |
| 645 | + ("https://github.com/comfyanonymous/ComfyUI.git@release/1.0", ("comfyanonymous", "ComfyUI")), |
| 646 | + # Forks |
| 647 | + ("https://github.com/myfork/ComfyUI", ("myfork", "ComfyUI")), |
| 648 | + ("https://github.com/some-user/some-repo.git", ("some-user", "some-repo")), |
| 649 | + # SSH forms |
| 650 | + ("git@github.com:comfyanonymous/ComfyUI", ("comfyanonymous", "ComfyUI")), |
| 651 | + ("git@github.com:comfyanonymous/ComfyUI.git", ("comfyanonymous", "ComfyUI")), |
| 652 | + ], |
| 653 | + ) |
| 654 | + def test_parses_github_urls(self, url, expected): |
| 655 | + assert _parse_github_owner_repo(url) == expected |
| 656 | + |
| 657 | + @pytest.mark.parametrize( |
| 658 | + "url", |
| 659 | + [ |
| 660 | + None, |
| 661 | + "", |
| 662 | + "/local/path/to/comfyui", # local path |
| 663 | + "https://gitlab.com/foo/bar", # not GitHub |
| 664 | + "https://example.com/owner/repo", # not GitHub |
| 665 | + "https://github.com/owner/repo/pull/123", # not a repo URL |
| 666 | + "ftp://github.com/owner/repo", # exotic scheme — still parses since regex matches `github.com/...` |
| 667 | + ], |
| 668 | + ) |
| 669 | + def test_returns_none_for_non_github_urls(self, url): |
| 670 | + # The PR URL form (last case) intentionally doesn't match — `[^/@]+?` excludes `/` |
| 671 | + # so `repo/pull/123` cannot be the second capture; we want this to fall through |
| 672 | + # to the upstream default in the caller. |
| 673 | + if url == "ftp://github.com/owner/repo": |
| 674 | + # Edge-case: this DOES match because we don't anchor on the scheme. |
| 675 | + # That's fine — owner/repo is what matters; the API call uses HTTPS regardless. |
| 676 | + assert _parse_github_owner_repo(url) == ("owner", "repo") |
| 677 | + else: |
| 678 | + assert _parse_github_owner_repo(url) is None |
| 679 | + |
| 680 | + |
629 | 681 | class TestCheckoutStableComfyUI: |
630 | 682 | """Verify checkout_stable_comfyui prefers local tag resolution over the |
631 | 683 | GitHub API for `--version latest` (issue #440), and falls back when local |
@@ -685,6 +737,58 @@ def test_latest_falls_back_to_api_when_local_empty(self, mock_local, mock_api, m |
685 | 737 | mock_api.assert_called_once_with("comfyanonymous", "ComfyUI") |
686 | 738 | mock_co.assert_called_once_with("/repo", "v0.20.1") |
687 | 739 |
|
| 740 | + @patch("comfy_cli.command.install.git_checkout_tag", return_value=True) |
| 741 | + @patch("comfy_cli.command.install.get_latest_release") |
| 742 | + @patch("comfy_cli.command.install._resolve_latest_tag_from_local", return_value=(None, True)) |
| 743 | + def test_latest_fallback_uses_fork_owner_repo_from_url(self, mock_local, mock_api, mock_co): |
| 744 | + """Fork case: API fallback must query the FORK's releases/latest, not upstream's. |
| 745 | +
|
| 746 | + Otherwise we'd ask GitHub for `comfyanonymous/ComfyUI`'s latest tag and |
| 747 | + try to check it out in a fork that may not have it. |
| 748 | + """ |
| 749 | + mock_api.return_value = {"tag": "v0.20.1-myfork", "version": None, "download_url": "u"} |
| 750 | + |
| 751 | + checkout_stable_comfyui("latest", "/repo", url="https://github.com/myfork/ComfyUI") |
| 752 | + |
| 753 | + mock_api.assert_called_once_with("myfork", "ComfyUI") |
| 754 | + mock_co.assert_called_once_with("/repo", "v0.20.1-myfork") |
| 755 | + |
| 756 | + @patch("comfy_cli.command.install.git_checkout_tag", return_value=True) |
| 757 | + @patch("comfy_cli.command.install.get_latest_release") |
| 758 | + @patch("comfy_cli.command.install._resolve_latest_tag_from_local", return_value=(None, True)) |
| 759 | + def test_latest_fallback_strips_branch_suffix_from_url(self, mock_local, mock_api, mock_co): |
| 760 | + """The setuptools-style `@branch` suffix in the install URL must not leak |
| 761 | + into the API call. `clone_comfyui` already strips it before cloning.""" |
| 762 | + mock_api.return_value = {"tag": "v0.20.1", "version": None, "download_url": "u"} |
| 763 | + |
| 764 | + checkout_stable_comfyui("latest", "/repo", url="https://github.com/myfork/ComfyUI.git@some-branch") |
| 765 | + |
| 766 | + mock_api.assert_called_once_with("myfork", "ComfyUI") |
| 767 | + |
| 768 | + @patch("comfy_cli.command.install.git_checkout_tag", return_value=True) |
| 769 | + @patch("comfy_cli.command.install.get_latest_release") |
| 770 | + @patch("comfy_cli.command.install._resolve_latest_tag_from_local", return_value=(None, True)) |
| 771 | + def test_latest_fallback_defaults_to_upstream_for_non_github_url(self, mock_local, mock_api, mock_co): |
| 772 | + """Non-GitHub URLs (local paths, GitLab, etc.) fall back to upstream defaults |
| 773 | + — preserves prior behavior for users whose URL we can't parse.""" |
| 774 | + mock_api.return_value = {"tag": "v0.20.1", "version": None, "download_url": "u"} |
| 775 | + |
| 776 | + checkout_stable_comfyui("latest", "/repo", url="/local/path/to/comfyui") |
| 777 | + |
| 778 | + mock_api.assert_called_once_with("comfyanonymous", "ComfyUI") |
| 779 | + |
| 780 | + @patch("comfy_cli.command.install.git_checkout_tag", return_value=True) |
| 781 | + @patch("comfy_cli.command.install.get_latest_release") |
| 782 | + @patch("comfy_cli.command.install._resolve_latest_tag_from_local", return_value=(None, True)) |
| 783 | + def test_latest_fallback_defaults_to_upstream_when_url_omitted(self, mock_local, mock_api, mock_co): |
| 784 | + """Backward compat: omitting the new `url` kwarg yields the prior behavior |
| 785 | + (querying upstream).""" |
| 786 | + mock_api.return_value = {"tag": "v0.20.1", "version": None, "download_url": "u"} |
| 787 | + |
| 788 | + checkout_stable_comfyui("latest", "/repo") # no url= |
| 789 | + |
| 790 | + mock_api.assert_called_once_with("comfyanonymous", "ComfyUI") |
| 791 | + |
688 | 792 | @patch("comfy_cli.command.install.git_checkout_tag", return_value=True) |
689 | 793 | @patch("comfy_cli.command.install.get_latest_release") |
690 | 794 | @patch("comfy_cli.command.install._resolve_latest_tag_from_local", return_value=(None, False)) |
|
0 commit comments