1
0
mirror of https://github.com/quay/quay.git synced 2025-04-18 10:44:06 +03:00

api: allow refining search with an organization (PROJQUAY-7244) (#2901)

This allows a more refined search than just the repo name. When two
organizations contain the same name repo, e.g: org1/python and
org2/python, you can now search via org1/python to get the specific
result instead of both.
This commit is contained in:
nmaloof 2024-08-09 11:19:55 -04:00 committed by GitHub
parent dde4dde03d
commit 4899ebd6c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 60 additions and 8 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
*.pyc
venv
.venv
screenshots/screenshots/
conf/stack
*/node_modules

View File

@ -491,6 +491,9 @@ def _get_sorted_matching_repositories(
"""
select_fields = [Repository.id] if ids_only else [Repository, Namespace]
# Used to make sure that the join to the Namespace table only occurs once
is_namespace_table_joined = False
if not lookup_value:
# This is a generic listing of repositories. Simply return the sorted repositories based
# on RepositorySearchScore.
@ -505,15 +508,19 @@ def _get_sorted_matching_repositories(
search_fields = set([SEARCH_FIELDS.description.name, SEARCH_FIELDS.name.name])
# Always search at least on name (init clause)
clause = Repository.name.match(lookup_value)
repo_name_value, user_name_value = lookup_value, None
if "/" in lookup_value:
user_name_value, repo_name_value = lookup_value.split("/", 1)
clause = Repository.name.match(repo_name_value)
computed_score = RepositorySearchScore.score.alias("score")
# If the description field is in the search fields, then we need to compute a synthetic score
# to discount the weight of the description more than the name.
if SEARCH_FIELDS.description.name in search_fields:
clause = Repository.description.match(lookup_value) | clause
clause = Repository.description.match(repo_name_value) | clause
cases = [
(Repository.name.match(lookup_value), 100 * RepositorySearchScore.score),
(Repository.name.match(repo_name_value), 100 * RepositorySearchScore.score),
]
computed_score = Case(None, cases, RepositorySearchScore.score).alias("score")
@ -526,16 +533,23 @@ def _get_sorted_matching_repositories(
.order_by(SQL("score").desc(), RepositorySearchScore.id)
)
# If an organization/user was found and it was not blank.
if user_name_value is not None and user_name_value != "":
query = (
query.switch(Repository)
.join(Namespace)
.where(Namespace.username == user_name_value)
)
is_namespace_table_joined = True
if repo_kind is not None:
query = query.where(Repository.kind == Repository.kind.get_id(repo_kind))
if not include_private:
query = query.where(Repository.visibility == _basequery.get_public_repo_visibility())
if not ids_only:
query = query.switch(Repository).join(
Namespace, on=(Namespace.id == Repository.namespace_user)
)
if not ids_only and not is_namespace_table_joined:
query = query.switch(Repository).join(Namespace)
return query

View File

@ -64,6 +64,43 @@ def test_search_pagination(query, authed_username, initialized_db):
assert repositories[1].id == next_repos[0].id
@pytest.mark.skipif(
os.environ.get("TEST_DATABASE_URI", "").find("mysql") >= 0,
reason="MySQL requires specialized indexing of newly created repos",
)
@pytest.mark.parametrize(
"query,repo_count",
[
("somenewrepo", 3),
("devtable/somenewrepo", 2),
("devtable/", 2),
("devtable/somenewrepo2", 1),
("doesnotexist/somenewrepo", 0),
("does/notexist/somenewrepo", 0),
("/somenewrepo", 3),
("repo/withslash", 0),
("/repo/withslash", 1),
],
)
def test_search_filtering_complex(query, repo_count, initialized_db):
# Create some public repos
repo1 = create_repository(
"devtable", "somenewrepo", None, repo_kind="image", visibility="public"
)
repo2 = create_repository(
"devtable", "somenewrepo2", None, repo_kind="image", visibility="public"
)
repo3 = create_repository(
"freshuser", "somenewrepo", None, repo_kind="image", visibility="public"
)
repo4 = create_repository(
"freshuser", "repo/withslash", None, repo_kind="image", visibility="public"
)
repositories = get_filtered_matching_repositories(query, filter_username=None)
assert len(repositories) == repo_count
def test_get_estimated_repository_count(initialized_db):
assert get_estimated_repository_count() >= Repository.select().count()

View File

@ -139,7 +139,7 @@ Quay is covered by tests using various approaches. Read our [testing guide](/TES
## Contributing
How great that you want to contribute to Quay! Before starting make sure to check our [contributing guidelines](.github/CONTRIBUTE.md).
How great that you want to contribute to Quay! Before starting make sure to check our [contributing guidelines](../.github/CONTRIBUTING.md).
# Using Quay