Something went wrong. Try again.
Maps Linux distribution source packages to their upstream repositories, and through them to each other
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260package repourl
import "testing"
func TestParse(t *testing.T) { cases := []struct { in string key string kind Kind hint string ref string }{ {"https://github.com/curl/curl", "github.com/curl/curl", KindRepo, "", ""}, {"https://github.com/Curl/Curl.git/", "github.com/curl/curl", KindRepo, "", ""}, {"git://github.com/curl/curl.git", "github.com/curl/curl", KindRepo, "", ""}, {"git@github.com:curl/curl.git", "github.com/curl/curl", KindRepo, "", ""}, {"ssh://git@github.com/curl/curl.git", "github.com/curl/curl", KindRepo, "", ""}, {"git+https://github.com/curl/curl.git#tag=curl-8_0_0", "github.com/curl/curl", KindRepo, "", "curl-8_0_0"}, {"curl::git+https://github.com/curl/curl.git#commit=abc123", "github.com/curl/curl", KindRepo, "", "abc123"}, {"https://github.com/curl/curl/tree/master/lib", "github.com/curl/curl", KindRepo, "", ""}, {"https://github.com/curl/curl/blob/master/README", "github.com/curl/curl", KindRepo, "", ""}, {"https://github.com/curl/curl/commit/deadbeef", "github.com/curl/curl", KindRepo, "", ""}, {"https://github.com/curl/curl/releases/download/curl-8_0_0/curl-8.0.0.tar.xz", "github.com/curl/curl", KindTarball, "github.com/curl/curl", ""}, {"https://github.com/curl/curl/archive/refs/tags/v1.tar.gz", "github.com/curl/curl", KindTarball, "github.com/curl/curl", ""}, {"https://codeload.github.com/curl/curl/tar.gz/v1.0", "github.com/curl/curl", KindTarball, "github.com/curl/curl", ""}, {"https://api.github.com/repos/curl/curl", "github.com/curl/curl", KindRepo, "", ""}, {"https://www.github.com/curl/curl", "github.com/curl/curl", KindRepo, "", ""}, {"https://gitlab.com/gnutls/gnutls.git", "gitlab.com/gnutls/gnutls", KindRepo, "", ""}, {"https://ftp.gnu.org/gnu/dejagnu-1.6.3.tar.gz", "ftp.gnu.org/gnu/dejagnu-1.6.3.tar.gz", KindTarball, "git.savannah.gnu.org/dejagnu", ""}, {"https://git.kernel.org/cgit/linux/kernel/git/jaegeuk/f2fs-tools.git/snapshot/f2fs-tools-1.16.0.tar.gz", "git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools", KindRepo, "", ""}, {"https://git.joeyh.name/index.cgi/etckeeper.git/snapshot/etckeeper-1.18.23.tar.gz", "git.joeyh.name/etckeeper", KindRepo, "", ""}, {"https://pagure.io/certmonger/archive/0.79.21/certmonger-0.79.21.tar.gz", "pagure.io/certmonger", KindRepo, "", ""}, // GitLab API and upload URLs carry a numeric project id. {"https://gitlab.gnome.org/api/v4/projects/20183/repository/archive.tar.gz?sha=v1", "gitlab.gnome.org/-/project/20183", KindRepo, "", ""}, {"https://gitlab.com/-/project/6865053/uploads/4f51/appmenu-gtk-module-25.04.tar.xz", "gitlab.com/-/project/6865053", KindRepo, "", ""}, {"https://web.git.kernel.org/pub/scm/linux/kernel/git/superm1/amd-debug-tools.git", "git.kernel.org/pub/scm/linux/kernel/git/superm1/amd-debug-tools", KindRepo, "", ""}, {"https://www.kernel.org/pub/linux/kernel/people/kdave/btrfs-progs/btrfs-progs-v6.9.tar.xz", "kernel.org/pub/linux/kernel/people/kdave/btrfs-progs/btrfs-progs-v6.9.tar.xz", KindTarball, "", ""}, // Arch spells SourceForge downloads with a /sourceforge/ segment. {"https://downloads.sourceforge.net/sourceforge/acpid2/acpid-2.0.34.tar.xz", "sourceforge.net/acpid2", KindRepo, "", ""}, // kernel.org hosts many projects under /pub/; only the kernel's own tarballs hint at it. {"https://www.kernel.org/pub/linux/utils/nfs-utils/2.6.4/nfs-utils-2.6.4.tar.xz", "kernel.org/pub/linux/utils/nfs-utils/2.6.4/nfs-utils-2.6.4.tar.xz", KindTarball, "", ""}, {"https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.tar.xz", "cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.tar.xz", KindTarball, "git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux", ""}, // Project sites on kernel.org subdomains are not the kernel. {"https://iwd.wiki.kernel.org/", "iwd.wiki.kernel.org", KindOther, "", ""}, {"https://b4.docs.kernel.org/", "b4.docs.kernel.org", KindOther, "", ""}, // samba.org hosts rsync, ppp, cifs-utils and cwrap next to Samba. {"https://download.samba.org/pub/rsync/rsync-3.5.0.tar.gz", "download.samba.org/pub/rsync/rsync-3.5.0.tar.gz", KindTarball, "", ""}, {"https://ftp.samba.org/pub/cwrap/nss_wrapper-1.1.16.tar.gz", "ftp.samba.org/pub/cwrap/nss_wrapper-1.1.16.tar.gz", KindTarball, "", ""}, {"https://dbench.samba.org/", "dbench.samba.org", KindOther, "", ""}, {"https://download.samba.org/pub/samba/stable/samba-4.23.1.tar.gz", "download.samba.org/pub/samba/stable/samba-4.23.1.tar.gz", KindTarball, "git.samba.org/samba", ""}, {"https://download.samba.org/pub/talloc/talloc-2.4.3.tar.gz", "download.samba.org/pub/talloc/talloc-2.4.3.tar.gz", KindTarball, "git.samba.org/samba", ""}, {"https://rsync.samba.org/", "rsync.samba.org", KindOther, "github.com/rsyncproject/rsync", ""}, // KDE application pages name the project; the group comes from KDE's project list. {"https://apps.kde.org/kasts/", "apps.kde.org/kasts", KindOther, "invent.kde.org/kasts", ""}, {"https://apps.kde.org/de/kate/", "apps.kde.org/de/kate", KindOther, "invent.kde.org/kate", ""}, {"https://kde.org/applications/utilities/org.kde.kmousetool", "kde.org/applications/utilities/org.kde.kmousetool", KindOther, "invent.kde.org/kmousetool", ""}, // python.org serves CPython, but its subdomains serve PyPI-era pages and PyPy. {"https://packages.python.org/WSME/", "pypi.org/wsme", KindRegistry, "", ""}, {"http://cheeseshop.python.org/pypi/simplegeneric", "pypi.org/simplegeneric", KindRegistry, "", ""}, {"https://downloads.python.org/pypy/pypy3.11-v8.0.0-src.tar.gz", "downloads.python.org/pypy/pypy3.11-v8.0.0-src.tar.gz", KindTarball, "", ""}, {"https://www.python.org/ftp/python/3.13.1/Python-3.13.1.tar.xz", "python.org/ftp/python/3.13.1/Python-3.13.1.tar.xz", KindTarball, "github.com/python/cpython", ""}, {"https://wiki.python.org/moin/X", "wiki.python.org/moin/X", KindOther, "", ""}, // Catalogue sites list many projects; a page names none of their repositories. {"https://octave.sourceforge.net/geometry/", "octave.sourceforge.net/geometry", KindOther, "", ""}, {"https://pear.php.net/package/Mail_Mime", "pear.php.net/package/Mail_Mime", KindOther, "", ""}, {"https://downloads.sourceforge.net/octave/geometry-4.1.0.tar.gz", "sourceforge.net/octave/geometry-4.1.0.tar.gz", KindOther, "", ""}, {"https://sourceforge.net/p/octave/geometry/", "sourceforge.net/octave/geometry", KindRepo, "", ""}, {"https://git.code.sf.net/p/octave/geometry", "sourceforge.net/octave/geometry", KindRepo, "", ""}, {"https://sourceforge.net/p/net-snmp/code/", "sourceforge.net/net-snmp", KindRepo, "", ""}, {"https://sourceforge.net/p/mingw-w64/mingw-w64/", "sourceforge.net/mingw-w64", KindRepo, "", ""}, {"https://sourceforge.net/p/gnuplot/gnuplot-main/", "sourceforge.net/gnuplot", KindRepo, "", ""}, {"https://sourceforge.net/p/foo/tickets/12/", "sourceforge.net/foo", KindRepo, "", ""}, // gnupg.org's sibling projects are not GnuPG. {"https://gnupg.org/software/gpa/index.html", "gnupg.org/software/gpa/index.html", KindOther, "", ""}, {"https://gnupg.org/ftp/gcrypt/gnupg/gnupg-2.4.8.tar.bz2", "gnupg.org/ftp/gcrypt/gnupg/gnupg-2.4.8.tar.bz2", KindTarball, "git.gnupg.org/gnupg", ""}, {"https://opendev.org/openstack/python-barbicanclient", "opendev.org/openstack/python-barbicanclient", KindRepo, "", ""}, // GitLab API routes that name the project by path. {"https://gitlab.com/api/v4/projects/orcus%2Forcus/packages/generic/source/0.21.0/liborcus-0.21.0.tar.xz", "gitlab.com/orcus/orcus", KindTarball, "gitlab.com/orcus/orcus", ""}, // Packaging fields append refs and branches after the URL. {"https://git.sr.ht/~rjarry/aerc refs/tags/v0.20.0", "git.sr.ht/~rjarry/aerc", KindRepo, "", ""}, {"https://gitlab.inria.fr/ngs/altree.git refs/tags/v1.3.2", "gitlab.inria.fr/ngs/altree", KindRepo, "", ""}, // Savannah trackers name their project in ?group=; without one they are not a repo. {"https://savannah.gnu.org/bugs/?group=aldo", "git.savannah.gnu.org/aldo", KindRepo, "", ""}, {"https://savannah.nongnu.org/support/?group=aldo", "git.savannah.gnu.org/aldo", KindRepo, "", ""}, {"https://savannah.gnu.org/bugs/", "git.savannah.gnu.org/bugs", KindOther, "", ""}, {"https://savannah.gnu.org/cvs/?group=gnubg", "git.savannah.gnu.org/gnubg", KindRepo, "", ""}, {"https://savannah.gnu.org/git/?group=gnubg", "git.savannah.gnu.org/gnubg", KindRepo, "", ""}, // Redmine project pages are trackers. {"https://redmine.audacious-media-player.org/projects/audacious/issues", "redmine.audacious-media-player.org/projects/audacious/issues", KindOther, "", ""}, // Pagure: namespaced, forked and browsing URLs; paths keep their case. {"https://code.opensuse.org/microos/libdnf-plugin-txnupd", "code.opensuse.org/microos/libdnf-plugin-txnupd", KindRepo, "", ""}, {"https://code.opensuse.org/xfce/openSUSE-xfce-icon-theme.git", "code.opensuse.org/xfce/openSUSE-xfce-icon-theme", KindRepo, "", ""}, {"https://code.opensuse.org/package/texlive/blob/d820a867/f/texlive.spec", "code.opensuse.org/package/texlive", KindRepo, "", ""}, {"https://code.opensuse.org/fork/someone/microos/foo/c/abc123", "code.opensuse.org/fork/someone/microos/foo", KindRepo, "", ""}, {"https://pagure.io/pagure/pull-request/12", "pagure.io/pagure", KindRepo, "", ""}, {"https://src.fedoraproject.org/rpms/rpm", "src.fedoraproject.org/rpms/rpm", KindRepo, "", ""}, {"https://code.opensuse.org/users", "code.opensuse.org/users", KindOther, "", ""}, {"https://gitlab.com/a/b/c/-/tree/main", "gitlab.com/a/b/c", KindRepo, "", ""}, {"https://gitlab.com/a/b/c/-/archive/v1/c-v1.tar.gz", "gitlab.com/a/b/c", KindRepo, "", ""}, {"https://salsa.debian.org/debian/curl", "salsa.debian.org/debian/curl", KindRepo, "", ""}, {"https://gitlab.gnome.org/GNOME/glib/-/blob/main/README", "gitlab.gnome.org/gnome/glib", KindRepo, "", ""}, {"https://gitlab.freedesktop.org/xorg/lib/libx11.git", "gitlab.freedesktop.org/xorg/lib/libx11", KindRepo, "", ""}, {"https://sourceforge.net/projects/libpng/", "sourceforge.net/libpng", KindRepo, "", ""}, {"https://git.code.sf.net/p/libpng/code", "sourceforge.net/libpng", KindRepo, "", ""}, {"https://downloads.sourceforge.net/project/libpng/libpng16/1.6.40/libpng-1.6.40.tar.xz", "sourceforge.net/libpng", KindRepo, "", ""}, {"http://libpng.sourceforge.net/", "sourceforge.net/libpng", KindRepo, "", ""}, {"https://git.savannah.gnu.org/git/tar.git", "git.savannah.gnu.org/tar", KindRepo, "", ""}, {"https://git.savannah.gnu.org/cgit/tar.git/tree/src", "git.savannah.gnu.org/tar", KindRepo, "", ""}, {"git://git.sv.gnu.org/tar.git", "git.savannah.gnu.org/tar", KindRepo, "", ""}, {"https://savannah.gnu.org/projects/tar", "git.savannah.gnu.org/tar", KindRepo, "", ""}, {"https://ftp.gnu.org/gnu/tar/tar-1.35.tar.xz", "ftp.gnu.org/gnu/tar/tar-1.35.tar.xz", KindTarball, "git.savannah.gnu.org/tar", ""}, {"https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git", "git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux", KindRepo, "", ""}, {"https://git.kernel.org/pub/scm/utils/util-linux/util-linux.git/tree/README", "git.kernel.org/pub/scm/utils/util-linux/util-linux", KindRepo, "", ""}, {"https://launchpad.net/pyflakes", "launchpad.net/pyflakes", KindRepo, "", ""}, {"https://git.launchpad.net/ubuntu-dev-tools", "launchpad.net/ubuntu-dev-tools", KindRepo, "", ""}, {"https://code.launchpad.net/~someone/foo/+git/foo", "launchpad.net/foo", KindRepo, "", ""}, {"https://codeberg.org/dnkl/foot/src/branch/master", "codeberg.org/dnkl/foot", KindRepo, "", ""}, {"https://src.opensuse.org/pool/curl", "src.opensuse.org/pool/curl", KindRepo, "", ""}, {"https://git.sr.ht/~sircmpwn/scdoc", "git.sr.ht/~sircmpwn/scdoc", KindRepo, "", ""}, {"https://bitbucket.org/multicoreware/x265_git/src/master/", "bitbucket.org/multicoreware/x265_git", KindRepo, "", ""}, {"https://android.googlesource.com/platform/external/zlib/+/refs/heads/main", "android.googlesource.com/platform/external/zlib", KindRepo, "", ""}, {"https://pypi.org/project/Requests/", "pypi.org/requests", KindRegistry, "", ""}, {"https://files.pythonhosted.org/packages/source/r/requests/requests-2.31.0.tar.gz", "pypi.org/requests", KindTarball, "pypi.org/requests", ""}, {"https://crates.io/api/v1/crates/serde/1.0.0/download", "crates.io/serde", KindTarball, "crates.io/serde", ""}, {"https://crates.io/crates/serde", "crates.io/serde", KindRegistry, "", ""}, {"https://registry.npmjs.org/@types/node/-/node-1.0.0.tgz", "npmjs.com/@types/node", KindRegistry, "", ""}, {"https://hackage.haskell.org/package/pandoc-3.1.2/pandoc-3.1.2.tar.gz", "hackage.haskell.org/pandoc", KindRegistry, "", ""}, {"https://rubygems.org/gems/rake", "rubygems.org/rake", KindRegistry, "", ""}, {"https://cpan.metacpan.org/authors/id/T/TO/TODDR/YAML-Syck-1.34.tar.gz", "metacpan.org/YAML-Syck", KindRegistry, "", ""}, {"https://download.gnome.org/sources/glib/2.78/glib-2.78.0.tar.xz", "download.gnome.org/sources/glib/2.78/glib-2.78.0.tar.xz", KindTarball, "gitlab.gnome.org/gnome/glib", ""}, {"https://download.kde.org/stable/frameworks/5.110/kconfig-5.110.0.tar.xz", "download.kde.org/stable/frameworks/5.110/kconfig-5.110.0.tar.xz", KindTarball, "invent.kde.org/kconfig", ""}, {"https://xorg.freedesktop.org/releases/individual/lib/libX11-1.8.7.tar.xz", "xorg.freedesktop.org/releases/individual/lib/libX11-1.8.7.tar.xz", KindTarball, "gitlab.freedesktop.org/xorg/lib/libx11", ""}, {"https://sourceware.org/git/glibc.git", "sourceware.org/glibc", KindRepo, "", ""}, {"https://forge.sourceware.org/gcc/gcc", "forge.sourceware.org/gcc/gcc", KindRepo, "", ""}, {"git+https://github.com/systemd/systemd#tag=v262?signed", "github.com/systemd/systemd", KindRepo, "", "v262"}, {"https://sourceware.org/git/?p=binutils-gdb.git;a=summary", "sourceware.org/binutils-gdb", KindRepo, "", ""}, {"https://git.zx2c4.com/wireguard-tools/", "git.zx2c4.com/wireguard-tools", KindRepo, "", ""}, {"https://git.musl-libc.org/cgit/musl/log/", "git.musl-libc.org/musl", KindRepo, "", ""}, // Forge verbs and cgit mounts on hosts repourl does not know. {"https://git.enlightenment.org/enlightenment/efl/pulls/133", "git.enlightenment.org/enlightenment/efl", KindRepo, "", ""}, {"https://git.enlightenment.org/enlightenment/efl/issues/41", "git.enlightenment.org/enlightenment/efl", KindRepo, "", ""}, {"https://git.enlightenment.org/enlightenment/efl", "git.enlightenment.org/enlightenment/efl", KindRepo, "", ""}, {"https://git.gnome.org/browse/goffice", "git.gnome.org/goffice", KindRepo, "", ""}, {"https://git.gnome.org/browse/goffice/commit/?id=abc", "git.gnome.org/goffice", KindRepo, "", ""}, {"https://code.qt.io/cgit/qt/qtbase.git/commit/?id=1ffcca4", "code.qt.io/qt/qtbase", KindRepo, "", ""}, {"https://code.qt.io/cgit/qt/qtbase.git", "code.qt.io/qt/qtbase", KindRepo, "", ""}, {"https://git.sr.ht/~user/repo/commit/abc", "git.sr.ht/~user/repo", KindRepo, "", ""}, {"https://gitea.example.org/o/r/pulls/3", "gitea.example.org/o/r", KindRepo, "", ""}, {"https://gitea.example.org/o/r/src/branch/main/README", "gitea.example.org/o/r", KindRepo, "", ""}, {"https://gitlab.example.org/group/sub/proj/-/merge_requests/1", "gitlab.example.org/group/sub/proj", KindRepo, "", ""}, {"https://git.ligo.org/lscsoft/lalsuite/merge_requests/1452", "git.ligo.org/lscsoft/lalsuite", KindRepo, "", ""}, {"https://cgit.example.org/cgit/proj.git/log/", "cgit.example.org/proj", KindRepo, "", ""}, {"https://git.cgsecurity.org/cgit/testdisk", "git.cgsecurity.org/testdisk", KindRepo, "", ""}, {"https://example.org/gitweb/?p=proj.git;a=commit;h=abc", "example.org/proj", KindRepo, "", ""}, {"https://git.postgresql.org/gitweb/?p=postgresql.git;a=summary", "git.postgresql.org/postgresql", KindRepo, "", ""}, {"https://git.example.org/foo/bar.git/tree/README", "git.example.org/foo/bar", KindRepo, "", ""}, // A bare owner/repo on an unknown host is still just a web page. {"https://gitea.example.org/o/r", "gitea.example.org/o/r", KindOther, "", ""}, {"https://example.org/o/r/releases/r-1.0.tar.gz", "example.org/o/r/releases/r-1.0.tar.gz", KindTarball, "", ""}, {"https://curl.se/download/curl-8.4.0.tar.xz", "curl.se/download/curl-8.4.0.tar.xz", KindTarball, "github.com/curl/curl", ""}, {"https://curl.se/", "curl.se", KindOther, "github.com/curl/curl", ""}, {"https://www.zlib.net/", "zlib.net", KindOther, "github.com/madler/zlib", ""}, {"https://docs.python.org/3/", "docs.python.org/3", KindOther, "github.com/python/cpython", ""}, {"https://musl.libc.org", "musl.libc.org", KindOther, "git.musl-libc.org/musl", ""}, {"https://www.doxygen.nl/index.html", "doxygen.nl/index.html", KindOther, "github.com/doxygen/doxygen", ""}, {"https://www.gnu.org/software/gzip/", "gnu.org/software/gzip", KindOther, "", ""}, {"https://savannah.nongnu.org/download/atool/atool-0.39.0.tar.gz", "git.savannah.gnu.org/download/atool/atool-0.39.0.tar.gz", KindTarball, "git.savannah.gnu.org/atool", ""}, {"https://savannah.gnu.org/projects/tar", "git.savannah.gnu.org/tar", KindRepo, "", ""}, {"https://example.org/foo.git", "example.org/foo", KindRepo, "", ""}, {"https://git.example.org/gitweb/?p=foo.git;a=summary", "git.example.org/foo", KindRepo, "", ""}, } for _, tc := range cases { c, err := Parse(tc.in) if err != nil { t.Errorf("%q: unexpected error %v", tc.in, err) continue } if c.Key != tc.key { t.Errorf("%q: key = %q, want %q", tc.in, c.Key, tc.key) } if c.Kind != tc.kind { t.Errorf("%q: kind = %q, want %q", tc.in, c.Kind, tc.kind) } if c.Hint != tc.hint { t.Errorf("%q: hint = %q, want %q", tc.in, c.Hint, tc.hint) } if c.Ref != tc.ref { t.Errorf("%q: ref = %q, want %q", tc.in, c.Ref, tc.ref) } }}
func TestParseErrors(t *testing.T) { for _, in := range []string{"", " ", "not a url", "mailto:foo@bar.com"} { if _, err := Parse(in); err == nil { t.Errorf("%q: expected error", in) } }}
func TestSameRepo(t *testing.T) { if !SameRepo("git@github.com:curl/curl.git", "https://github.com/Curl/Curl/tree/master") { t.Fatal("expected same repo") } if SameRepo("https://github.com/curl/curl", "https://curl.se/download/curl-8.4.0.tar.xz") { t.Fatal("tarball should not equal repo") }}
func TestCanonicalURL(t *testing.T) { cases := map[string]string{ "git://git.sv.gnu.org/tar.git": "https://git.savannah.gnu.org/git/tar.git", "https://sourceforge.net/projects/libpng": "https://git.code.sf.net/p/libpng/code", "https://GitHub.com/Curl/Curl.git": "https://github.com/curl/curl", "https://git.example.org/gitweb/?p=foo.git": "https://git.example.org/?p=foo.git", } for in, want := range cases { c, err := Parse(in) if err != nil { t.Fatalf("%q: %v", in, err) } if c.URL != want { t.Errorf("%q: URL = %q, want %q", in, c.URL, want) } }}
// TestGenericForge pins the Kind and Forge of repositories recognised on hosts repourl does// not know: a cgit mount or ".git/" marks cgit, a forge verb alone leaves Forge unknown.func TestGenericForge(t *testing.T) { cases := []struct { in string kind Kind forge string }{ {"https://code.qt.io/cgit/qt/qtbase.git/commit/?id=x", KindRepo, "cgit"}, {"https://cgit.example.org/cgit/proj.git/log/", KindRepo, "cgit"}, {"https://git.cgsecurity.org/cgit/testdisk", KindRepo, "cgit"}, {"https://git.example.org/foo/bar.git/tree/README", KindRepo, "cgit"}, {"https://git.example.org/foo/bar.git/info/refs", KindRepo, ""}, {"https://example.org/gitweb/?p=proj.git;a=commit;h=abc", KindRepo, "gitweb"}, {"https://gitea.example.org/o/r/pulls/3", KindRepo, ""}, {"https://gitlab.example.org/group/sub/proj/-/merge_requests/1", KindRepo, ""}, {"https://git.enlightenment.org/enlightenment/efl/pulls/133", KindRepo, "gitea"}, {"https://git.gnome.org/browse/goffice", KindRepo, "cgit"}, {"https://git.sr.ht/~user/repo/commit/abc", KindRepo, "sourcehut"}, {"https://gitea.example.org/o/r", KindOther, ""}, } for _, tc := range cases { c, err := Parse(tc.in) if err != nil { t.Errorf("%q: %v", tc.in, err) continue } if c.Kind != tc.kind || c.Forge != tc.forge { t.Errorf("%q: kind/forge = %q/%q, want %q/%q", tc.in, c.Kind, c.Forge, tc.kind, tc.forge) } }}