diff --git a/metadata/fields/custom/version.py b/metadata/fields/custom/version.py new file mode 100644 index 000000000..2b51901a7 --- /dev/null +++ b/metadata/fields/custom/version.py @@ -0,0 +1,51 @@ +#!/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 + +_PATTERN_NOT_APPLICABLE = re.compile(r"^N ?\/ ?A$", re.IGNORECASE) + + +def is_version_unknown(value: str) -> bool: + """Returns whether the value denotes the version being unknown.""" + return (value == "0" or util.matches(_PATTERN_NOT_APPLICABLE, value) + or util.is_unknown(value)) + + +class VersionField(field_types.MetadataField): + """Custom field for the package version.""" + def __init__(self): + super().__init__(name="Version", one_liner=True) + + def validate(self, value: str) -> Union[vr.ValidationResult, None]: + """Checks the given value is acceptable - there must be at least one + non-whitespace character, and "N/A" is preferred over "0" if the version is + unknown. + """ + if value == "0" or util.is_unknown(value): + return vr.ValidationWarning( + f"{self._name} is '{value}' - use 'N/A' if this package does not " + "version or is versioned by date or revision.") + + if util.is_empty(value): + return vr.ValidationError( + f"{self._name} is empty - use 'N/A' if this package is versioned by " + "date or revision.") + + return None diff --git a/metadata/fields/known.py b/metadata/fields/known.py index abddf2b75..2ab88036f 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.version import metadata.fields.types as field_types # Freeform text fields. @@ -35,10 +36,12 @@ LICENSE_ANDROID_COMPATIBLE = field_types.YesNoField( # Custom fields. CPE_PREFIX = metadata.fields.custom.cpe_prefix.CPEPrefixField() DATE = metadata.fields.custom.date.DateField() +VERSION = metadata.fields.custom.version.VersionField() ALL_FIELDS = ( NAME, SHORT_NAME, + VERSION, DATE, REVISION, SECURITY_CRITICAL, diff --git a/metadata/tests/fields_test.py b/metadata/tests/fields_test.py index ddd99d1cb..343dc1141 100644 --- a/metadata/tests/fields_test.py +++ b/metadata/tests/fields_test.py @@ -82,6 +82,14 @@ class FieldValidationTest(unittest.TestCase): error_values=["", "\n", "April 3, 2012", "2012/03/04"], ) + def test_version_validation(self): + self._run_field_validation( + field=known_fields.VERSION, + valid_values=["n / a", "123abc", "unknown forked version"], + error_values=["", "\n"], + warning_values=["0", "unknown"], + ) + if __name__ == "__main__": unittest.main()