Beispiel #1
0
def parse_semver(version, operator) -> Optional[SemverFilter]:
    """
    Attempts to parse a release version using our semver syntax. version should be in
    format `<package_name>@<version>` or `<version>`, where package_name is a string and
    version is a version string matching semver format (https://semver.org/). We've
    slightly extended this format to allow up to 4 integers. EG
     - [email protected]
     - [email protected]
     - 1.2.3.4
     - 1.2.3.4-alpha
     - 1.*
    """
    (operator, negated) = handle_operator_negation(operator)
    operator = OPERATOR_TO_DJANGO[operator]
    version = version if "@" in version else f"{SEMVER_FAKE_PACKAGE}@{version}"
    parsed = parse_release_relay(version)
    parsed_version = parsed.get("version_parsed")
    if parsed_version:
        # Convert `pre` to always be a string
        prerelease = parsed_version["pre"] if parsed_version["pre"] else ""
        semver_filter = SemverFilter(
            operator,
            [
                parsed_version["major"],
                parsed_version["minor"],
                parsed_version["patch"],
                parsed_version["revision"],
                0 if prerelease else 1,
                prerelease,
            ],
            negated=negated,
        )
        if parsed["package"] and parsed["package"] != SEMVER_FAKE_PACKAGE:
            semver_filter.package = parsed["package"]
        return semver_filter
    else:
        # Try to parse as a wildcard match
        package, version = version.split("@", 1)
        version_parts = []
        if version:
            for part in version.split(".", 3):
                if part in SEMVER_WILDCARDS:
                    break
                try:
                    # We assume all ints for a wildcard match - not handling prerelease as
                    # part of these
                    version_parts.append(int(part))
                except ValueError:
                    raise InvalidSearchQuery(INVALID_SEMVER_MESSAGE)

        package = package if package and package != SEMVER_FAKE_PACKAGE else None
        return SemverFilter("exact", version_parts, package, negated)
Beispiel #2
0
def _semver_package_filter_converter(
    search_filter: SearchFilter,
    name: str,
    params: Optional[Mapping[str, Union[int, str, datetime]]],
) -> Tuple[str, str, Sequence[str]]:
    """
    Applies a semver package filter to the search. Note that if the query returns more than
    `MAX_SEARCH_RELEASES` here we arbitrarily return a subset of the releases.
    """
    if not params or "organization_id" not in params:
        raise ValueError("organization_id is a required param")

    organization_id: int = params["organization_id"]
    project_ids: Optional[list[int]] = params.get("project_id")
    package: str = search_filter.value.raw_value

    versions = list(
        Release.objects.filter_by_semver(
            organization_id,
            SemverFilter("exact", [], package),
            project_ids=project_ids,
        ).values_list("version", flat=True)[:MAX_SEARCH_RELEASES])

    if not versions:
        # XXX: Just return a filter that will return no results if we have no versions
        versions = [SEMVER_EMPTY_RELEASE]

    return ["release", "IN", versions]
Beispiel #3
0
def _filter_releases_by_query(queryset, organization, query, filter_params):
    search_filters = parse_search_query(query)
    for search_filter in search_filters:
        if search_filter.key.name == RELEASE_FREE_TEXT_KEY:
            query_q = Q(version__icontains=query)
            suffix_match = _release_suffix.match(query)
            if suffix_match is not None:
                query_q |= Q(version__icontains="%s+%s" % suffix_match.groups())

            queryset = queryset.filter(query_q)

        if search_filter.key.name == RELEASE_ALIAS:
            if search_filter.value.is_wildcard():
                raw_value = search_filter.value.raw_value
                if raw_value.endswith("*") and raw_value.startswith("*"):
                    query_q = Q(version__contains=raw_value[1:-1])
                elif raw_value.endswith("*"):
                    query_q = Q(version__startswith=raw_value[:-1])
                elif raw_value.startswith("*"):
                    query_q = Q(version__endswith=raw_value[1:])
            elif search_filter.operator == "!=":
                query_q = ~Q(version=search_filter.value.value)
            else:
                query_q = Q(version=search_filter.value.value)

            queryset = queryset.filter(query_q)

        if search_filter.key.name == SEMVER_ALIAS:
            queryset = queryset.filter_by_semver(
                organization.id, parse_semver(search_filter.value.raw_value, search_filter.operator)
            )

        if search_filter.key.name == SEMVER_PACKAGE_ALIAS:
            negated = True if search_filter.operator == "!=" else False
            queryset = queryset.filter_by_semver(
                organization.id,
                SemverFilter("exact", [], search_filter.value.raw_value, negated),
            )

        if search_filter.key.name == RELEASE_STAGE_ALIAS:
            queryset = queryset.filter_by_stage(
                organization.id,
                search_filter.operator,
                search_filter.value.value,
                project_ids=filter_params["project_id"],
                environments=filter_params.get("environment"),
            )

        if search_filter.key.name == SEMVER_BUILD_ALIAS:
            (operator, negated) = handle_operator_negation(search_filter.operator)
            queryset = queryset.filter_by_semver_build(
                organization.id,
                OPERATOR_TO_DJANGO[operator],
                search_filter.value.raw_value,
                negated=negated,
            )

    return queryset
Beispiel #4
0
def _filter_releases_by_query(queryset, organization, query):
    search_filters = parse_search_query(query)
    for search_filter in search_filters:
        if search_filter.key.name == RELEASE_FREE_TEXT_KEY:
            query_q = Q(version__icontains=query)
            suffix_match = _release_suffix.match(query)
            if suffix_match is not None:
                query_q |= Q(version__icontains="%s+%s" % suffix_match.groups())

            queryset = queryset.filter(query_q)

        if search_filter.key.name == RELEASE_ALIAS:
            if search_filter.value.is_wildcard():
                raw_value = search_filter.value.raw_value
                if raw_value.endswith("*") and raw_value.startswith("*"):
                    query_q = Q(version__contains=raw_value[1:-1])
                elif raw_value.endswith("*"):
                    query_q = Q(version__startswith=raw_value[:-1])
                elif raw_value.startswith("*"):
                    query_q = Q(version__endswith=raw_value[1:])
            else:
                query_q = Q(version=search_filter.value.value)

            queryset = queryset.filter(query_q)

        if search_filter.key.name == SEMVER_ALIAS:
            queryset = queryset.filter_by_semver(
                organization.id,
                parse_semver(search_filter.value.raw_value, search_filter.operator),
            )

        if search_filter.key.name == SEMVER_PACKAGE_ALIAS:
            queryset = queryset.filter_by_semver(
                organization.id,
                SemverFilter("exact", [], search_filter.value.raw_value),
            )

        if search_filter.key.name == RELEASE_STAGE_ALIAS:
            queryset = queryset.filter_by_stage(
                organization.id, search_filter.operator, search_filter.value.value
            )

        if search_filter.key.name == SEMVER_BUILD_ALIAS:
            queryset = queryset.filter_by_semver_build(
                organization.id,
                OPERATOR_TO_DJANGO[search_filter.operator],
                search_filter.value.raw_value,
            )

    return queryset