From 4f09926fb0a6906c4ba9696634c3aa02d7811569 Mon Sep 17 00:00:00 2001 From: Sergio Schvezov Date: Fri, 1 Mar 2024 12:21:17 -0300 Subject: [PATCH] fix: use VersionStr in model and add write test Signed-off-by: Sergio Schvezov --- snapcraft/models/project.py | 6 +-- snapcraft/parts/update_metadata.py | 2 +- tests/unit/models/test_projects.py | 65 ++++++----------------------- tests/unit/services/test_package.py | 43 +++++++++++++++++-- 4 files changed, 55 insertions(+), 61 deletions(-) diff --git a/snapcraft/models/project.py b/snapcraft/models/project.py index 4ab62f55c4..abfa5a4033 100644 --- a/snapcraft/models/project.py +++ b/snapcraft/models/project.py @@ -22,7 +22,7 @@ import pydantic from craft_application import models -from craft_application.models import BuildInfo, UniqueStrList +from craft_application.models import BuildInfo, UniqueStrList, VersionStr from craft_cli import emit from craft_grammar.models import GrammarSingleEntryDictList, GrammarStr, GrammarStrList from craft_providers import bases @@ -45,10 +45,8 @@ # fmt: off if TYPE_CHECKING: ProjectName = str - ProjectVersion = str else: ProjectName = constr(max_length=40) - ProjectVersion = constr(max_length=32, strict=True) # fmt: on @@ -444,7 +442,7 @@ class Project(models.Project): name: ProjectName # type: ignore[assignment] build_base: Optional[str] compression: Literal["lzo", "xz"] = "xz" - version: Optional[ProjectVersion] # type: ignore[assignment] + version: Optional[VersionStr] # type: ignore[assignment] donation: Optional[Union[str, UniqueStrList]] # snapcraft's `source_code` is more general than craft-application source_code: Optional[str] # type: ignore[assignment] diff --git a/snapcraft/parts/update_metadata.py b/snapcraft/parts/update_metadata.py index 8652601fc9..7bd32b8482 100644 --- a/snapcraft/parts/update_metadata.py +++ b/snapcraft/parts/update_metadata.py @@ -89,7 +89,7 @@ def _update_project_variables(project: Project, project_vars: Dict[str, str]): """Update project fields with values set during lifecycle processing.""" try: if project_vars["version"]: - project.version = project_vars["version"] + project.version = cast(VersionStr, project_vars["version"]) if project_vars["grade"]: project.grade = project_vars["grade"] # type: ignore except pydantic.ValidationError as err: diff --git a/tests/unit/models/test_projects.py b/tests/unit/models/test_projects.py index b35390ae97..0770563cf3 100644 --- a/tests/unit/models/test_projects.py +++ b/tests/unit/models/test_projects.py @@ -258,59 +258,18 @@ def test_project_version_valid(self, version, project_yaml_data): project = Project.unmarshal(project_yaml_data(version=version)) assert project.version == version - @pytest.mark.parametrize( - "version,error", - [ - ( - "1_0", - "Invalid version '1_0': Snap versions consist of", - ), # _ is an invalid character - ( - "1=1", - "Invalid version '1=1': Snap versions consist of", - ), # = is an invalid character - ( - ".1", - "Invalid version '.1': Snap versions consist of", - ), # cannot start with period - ( - ":1", - "Invalid version ':1': Snap versions consist of", - ), # cannot start with colon - ( - "+1", - r"Invalid version '\+1': Snap versions consist of", - ), # cannot start with plus sign - # escaping + from the regex string to match. - ( - "~1", - "Invalid version '~1': Snap versions consist of", - ), # cannot start with tilde - ( - "-1", - "Invalid version '-1': Snap versions consist of", - ), # cannot start with hyphen - ( - "1.", - "Invalid version '1.': Snap versions consist of", - ), # cannot end with period - ( - "1:", - "Invalid version '1:': Snap versions consist of", - ), # cannot end with colon - ( - "1-", - "Invalid version '1-': Snap versions consist of", - ), # cannot end with hyphen - ( - "123456789012345678901234567890123", - "ensure this value has at most 32 characters", - ), # too large - ], - ) - def test_project_version_invalid(self, version, error, project_yaml_data): - with pytest.raises(errors.ProjectValidationError, match=error): - Project.unmarshal(project_yaml_data(version=version)) + def test_project_version_invalid(self, project_yaml_data): + # We only test one invalid version as this model is inherited + # from Craft Application. + with pytest.raises(errors.ProjectValidationError) as raised: + + Project.unmarshal(project_yaml_data(version="1=1")) + + assert str(raised.value) == ( + "Bad snapcraft.yaml content:\n- string does not match regex " + '"^[a-zA-Z0-9](?:[a-zA-Z0-9:.+~-]*[a-zA-Z0-9+~])?$" ' + "(in field 'version')" + ) @pytest.mark.parametrize( "snap_type", diff --git a/tests/unit/services/test_package.py b/tests/unit/services/test_package.py index c844649492..7716638463 100644 --- a/tests/unit/services/test_package.py +++ b/tests/unit/services/test_package.py @@ -17,14 +17,17 @@ """Tests for the Snapcraft Package service.""" from pathlib import Path +from textwrap import dedent -from craft_application.models import SummaryStr +import pytest +from craft_application.models import SummaryStr, VersionStr from snapcraft import linters, meta, pack, services from snapcraft.application import APP_METADATA -def test_pack(package_service, default_factory, mocker): +@pytest.mark.usefixtures("default_factory") +def test_pack(package_service, mocker): mock_pack_snap = mocker.patch.object(pack, "pack_snap") mocker.patch.object(linters, "run_linters") mocker.patch.object(linters, "report") @@ -72,7 +75,7 @@ def test_metadata(package_service, default_factory, default_build_plan, new_dir) assert package_service.metadata == meta.SnapMetadata( name="default", title=None, - version="1.0", + version=VersionStr("1.0"), summary=SummaryStr("default project"), description="default project", license="MIT", @@ -96,3 +99,37 @@ def test_metadata(package_service, default_factory, default_build_plan, new_dir) provenance=None, links=None, ) + + +def test_write_metadata( + package_service, + default_factory, + default_build_plan, + new_dir, +): + default_factory.set_kwargs( + "lifecycle", + work_dir=Path("work"), + cache_dir=new_dir, + build_plan=default_build_plan, + ) + + package_service.write_metadata(new_dir) + + assert (new_dir / "meta" / "snap.yaml").read_text() == dedent( + """\ + name: default + version: '1.0' + summary: default project + description: default project + license: MIT + architectures: + - amd64 + base: core24 + confinement: devmode + grade: devel + environment: + LD_LIBRARY_PATH: ${SNAP_LIBRARY_PATH}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} + PATH: $SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH + """ + )