From e95696ff530d1ef5cc103a4c6f148f983f6a998d Mon Sep 17 00:00:00 2001 From: Anne Redulla Date: Wed, 16 Aug 2023 06:48:43 +0000 Subject: [PATCH] [ssci] Defined URL metadata field Bug: b:277147404 Change-Id: I4e1fb86afb991fd3b6bf59a2a96d620fc7eea469 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4776732 Reviewed-by: Rachael Newitt Commit-Queue: Anne Redulla --- metadata/fields/custom/url.py | 59 +++++++++++++++++++++++++++++++++++ metadata/fields/known.py | 3 ++ metadata/tests/fields_test.py | 19 +++++++++++ 3 files changed, 81 insertions(+) create mode 100644 metadata/fields/custom/url.py diff --git a/metadata/fields/custom/url.py b/metadata/fields/custom/url.py new file mode 100644 index 0000000000..90d7ea307e --- /dev/null +++ b/metadata/fields/custom/url.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# Copyright 2023 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import re +import sys +from typing import Union + +_THIS_DIR = os.path.abspath(os.path.dirname(__file__)) +# The repo's root directory. +_ROOT_DIR = os.path.abspath(os.path.join(_THIS_DIR, "..", "..", "..")) + +# Add the repo's root directory for clearer imports. +sys.path.insert(0, _ROOT_DIR) + +import metadata.fields.types as field_types +import metadata.fields.util as util +import metadata.validation_result as vr + +# The delimiter used to separate multiple URLs. +_VALUE_DELIMITER = "," + +_PATTERN_URL_ALLOWED = re.compile(r"^(https?|ftp|git):\/\/\S+$") +_PATTERN_URL_CANONICAL_REPO = re.compile( + r"^This is the canonical (public )?repo(sitory)?\.?$", re.IGNORECASE) + + +class URLField(field_types.MetadataField): + """Custom field for the package URL(s).""" + def __init__(self): + super().__init__(name="URL", one_liner=False) + + def validate(self, value: str) -> Union[vr.ValidationResult, None]: + """Checks the given value has acceptable URL values only. + + Note: this field supports multiple values. + """ + if util.matches(_PATTERN_URL_CANONICAL_REPO, value): + return None + + invalid_values = [] + for url in value.split(_VALUE_DELIMITER): + url = url.strip() + if not util.matches(_PATTERN_URL_ALLOWED, url): + invalid_values.append(url) + + if invalid_values: + template = ("{field_name} has invalid values. URLs must use a protocol " + "scheme in [http, https, ftp, git]. If there are multiple " + "URLs, separate them with a '{delim}'. Invalid values: " + "{values}.") + message = template.format(field_name=self._name, + delim=_VALUE_DELIMITER, + values=util.quoted(invalid_values)) + return vr.ValidationError(message) + + return None diff --git a/metadata/fields/known.py b/metadata/fields/known.py index 2ab88036f2..edb9460876 100644 --- a/metadata/fields/known.py +++ b/metadata/fields/known.py @@ -16,6 +16,7 @@ sys.path.insert(0, _ROOT_DIR) import metadata.fields.custom.cpe_prefix import metadata.fields.custom.date +import metadata.fields.custom.url import metadata.fields.custom.version import metadata.fields.types as field_types @@ -36,11 +37,13 @@ LICENSE_ANDROID_COMPATIBLE = field_types.YesNoField( # Custom fields. CPE_PREFIX = metadata.fields.custom.cpe_prefix.CPEPrefixField() DATE = metadata.fields.custom.date.DateField() +URL = metadata.fields.custom.url.URLField() VERSION = metadata.fields.custom.version.VersionField() ALL_FIELDS = ( NAME, SHORT_NAME, + URL, VERSION, DATE, REVISION, diff --git a/metadata/tests/fields_test.py b/metadata/tests/fields_test.py index 343dc1141f..409ce53fb6 100644 --- a/metadata/tests/fields_test.py +++ b/metadata/tests/fields_test.py @@ -82,6 +82,25 @@ class FieldValidationTest(unittest.TestCase): error_values=["", "\n", "April 3, 2012", "2012/03/04"], ) + def test_url_validation(self): + self._run_field_validation( + field=known_fields.URL, + valid_values=[ + "https://www.example.com/a", + "http://www.example.com/b", + "ftp://www.example.com/c,git://www.example.com/d", + "This is the canonical public repository", + ], + error_values=[ + "", + "\n", + "ghttps://www.example.com/e", + "https://www.example.com/ f", + "Https://www.example.com/g", + "This is an unrecognized message for the URL", + ], + ) + def test_version_validation(self): self._run_field_validation( field=known_fields.VERSION,