Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions spec/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,16 @@ def owner_repos(owner):
page += 1


GITHUB_URL_RE = re.compile(r"^https://github\.com/([^/\s]+)/([^/\s]+?)(?:\.git)?/?$")
GITHUB_URL_RE = re.compile(r"^https://github\.com/([^/\s?#]+)/([^/\s?#]+?)(?:\.git)?/?$")


def repo_identity(url):
"""owner/repo, lowercased, parsed from a github.com URL, or None if it does not parse.

The canonical identity two repos are compared by, since a bare repo name collides across
owners and GitHub's own full_name field is already this exact shape (case-preserved). A
trailing .git is stripped so it still resolves to the same identity full_name would.
The canonical identity two repos are compared by, since a bare repo name collides across owners.
GitHub's own full_name field is already this exact shape (case-preserved).
A trailing .git is stripped so it still resolves to the same identity full_name would.
A query string or fragment is rejected outright rather than folded into the repo name.
spec/validate.py rejects a url that fails to parse here at all, kept in sync with this regex.
"""
if not isinstance(url, str):
Expand Down Expand Up @@ -4212,6 +4213,11 @@ def _selftest():
(" https://github.com/owner/Repo ", "owner/repo"),
("https://github.com/owner/Repo.git", "owner/repo"),
("https://github.com/owner/Repo.github", "owner/repo.github"),
("https://github.com/owner/Repo?tab=readme", None),
("https://github.com/owner/Repo#readme", None),
("https://github.com/owner/Repo.git?tab=readme", None),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
("https://github.com/owner?tab=readme/Repo", None),
("https://github.com/owner#readme/Repo", None),
("http://github.com/owner/Repo", None),
("https://gitlab.com/owner/Repo", None),
("not a url", None),
Expand Down
4 changes: 3 additions & 1 deletion spec/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
CONSUMER_MODELS = ("push", "pull")
# Parses owner/repo, lowercased, from a repo's url.
# A trailing .git is stripped so it still matches GitHub's own full_name.
# A query character or a fragment character is excluded from both groups too.
# Otherwise a query string or fragment folds into the repo name instead of failing to match.
# A duplicate identity here would let spec/audit.py's fleet membership check silently shadow one entry with the other.
GITHUB_URL_RE = re.compile(r"^https://github\.com/([^/\s]+)/([^/\s]+?)(?:\.git)?/?$")
GITHUB_URL_RE = re.compile(r"^https://github\.com/([^/\s?#]+)/([^/\s?#]+?)(?:\.git)?/?$")
# How faithfully a carried unit is checked, per spec/fidelity-model.md, defaulting to presence.
FIDELITIES = ("presence", "intent", "verbatim", "interface")
# The keys an interface unit's `contract` may carry (kept in sync with files.schema.json).
Expand Down