diff --git a/.gitignore b/.gitignore index 4d45401b08..db83361816 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ docs/reference.md docs/reference/commands docs/.sphinx docs/_build +docs/common *.egg-info .eggs/ .envrc diff --git a/docs/common/.gitkeep b/docs/common/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/conf.py b/docs/conf.py index 812413e6a8..29a3726c58 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,6 +3,8 @@ import pathlib import sys +import craft_parts_docs + project_dir = pathlib.Path("..").resolve() sys.path.insert(0, str(project_dir.absolute())) @@ -60,7 +62,12 @@ myst_enable_extensions = ["substitution", "deflist"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "sphinx-resources"] +exclude_patterns = [ + "_build", + "Thumbs.db", + ".DS_Store", + "sphinx-resources", +] rst_epilog = """ .. include:: /reuse/links.txt @@ -161,6 +168,34 @@ # For example: "explanation/old-name.html": "../how-to/prettify.html", # redirects = {} +extensions.extend( + ( + "sphinx.ext.ifconfig", + "sphinxcontrib.details.directive", + ) +) + +exclude_patterns.extend( + ( + # Excluded because Snapcraft doesn't use overlays + "common/craft-parts/overlay_parameters.rst", + # Excluded here because they are included explicitly in other documents; + # if we don't exclude them, they generate "duplicate label" errors. + "common/craft-parts/dump_plugin.rst", + "common/craft-parts/part_properties.rst", + "common/craft-parts/python_plugin.rst", + "common/craft-parts/rust_plugin.rst", + "common/craft-parts/step_execution_environment.rst", + "common/craft-parts/step_output_directories.rst", + "common/craft-parts/explanation/filesets.rst", + "common/craft-parts/explanation/lifecycle.rst", + "common/craft-parts/explanation/parts.rst", + "common/craft-parts/explanation/how_parts_are_built.rst", + "common/craft-parts/reference/parts_steps.rst", + # Extra non-craft-parts exclusions can be added after this comment + ) +) + def generate_cli_docs(nil): gen_cli_docs_path = (project_dir / "tools" / "docs" / "gen_cli_docs.py").resolve() @@ -169,3 +204,12 @@ def generate_cli_docs(nil): def setup(app): app.connect("builder-inited", generate_cli_docs) + + +# Setup libraries documentation snippets for use in snapcraft docs. +common_docs_path = pathlib.Path(__file__).parent / "common" +craft_parts_docs_path = pathlib.Path(craft_parts_docs.__file__).parent +(common_docs_path / "craft-parts").unlink(missing_ok=True) +(common_docs_path / "craft-parts").symlink_to( + craft_parts_docs_path, target_is_directory=True +) diff --git a/docs/explanation/filesets.rst b/docs/explanation/filesets.rst new file mode 100644 index 0000000000..33d0c00db5 --- /dev/null +++ b/docs/explanation/filesets.rst @@ -0,0 +1,2 @@ + +.. include:: /common/craft-parts/explanation/filesets.rst diff --git a/docs/explanation/how_parts_are_built.rst b/docs/explanation/how_parts_are_built.rst new file mode 100644 index 0000000000..eab69291c4 --- /dev/null +++ b/docs/explanation/how_parts_are_built.rst @@ -0,0 +1,2 @@ + +.. include:: /common/craft-parts/explanation/how_parts_are_built.rst diff --git a/docs/explanation/index.rst b/docs/explanation/index.rst index ba25dd5754..affdb98bb7 100644 --- a/docs/explanation/index.rst +++ b/docs/explanation/index.rst @@ -7,3 +7,6 @@ Explanation :maxdepth: 1 architectures + filesets + parts + lifecycle diff --git a/docs/explanation/lifecycle.rst b/docs/explanation/lifecycle.rst new file mode 100644 index 0000000000..24e6f3f558 --- /dev/null +++ b/docs/explanation/lifecycle.rst @@ -0,0 +1,2 @@ + +.. include:: /common/craft-parts/explanation/lifecycle.rst diff --git a/docs/explanation/parts.rst b/docs/explanation/parts.rst new file mode 100644 index 0000000000..cc13a84b64 --- /dev/null +++ b/docs/explanation/parts.rst @@ -0,0 +1,2 @@ + +.. include:: /common/craft-parts/explanation/parts.rst diff --git a/docs/images/lifecycle_logic.png b/docs/images/lifecycle_logic.png new file mode 100644 index 0000000000..d3db34eb70 Binary files /dev/null and b/docs/images/lifecycle_logic.png differ diff --git a/docs/reference/index.rst b/docs/reference/index.rst index d3cfd3a7a3..bade44affb 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -8,6 +8,9 @@ Reference architectures commands + plugins + part_properties + parts_steps Indices and tables ================== diff --git a/docs/reference/part_properties.rst b/docs/reference/part_properties.rst new file mode 100644 index 0000000000..b381a524e4 --- /dev/null +++ b/docs/reference/part_properties.rst @@ -0,0 +1,6 @@ +.. _ref_parts: + +Part properties +=============== + +.. include:: /common/craft-parts/part_properties.rst diff --git a/docs/reference/parts_steps.rst b/docs/reference/parts_steps.rst new file mode 100644 index 0000000000..c5aacc3b13 --- /dev/null +++ b/docs/reference/parts_steps.rst @@ -0,0 +1,6 @@ + +.. include:: /common/craft-parts/reference/parts_steps.rst + +.. include:: /common/craft-parts/step_execution_environment.rst + +.. include:: /common/craft-parts/step_output_directories.rst diff --git a/docs/reference/plugins.rst b/docs/reference/plugins.rst new file mode 100644 index 0000000000..59eda54022 --- /dev/null +++ b/docs/reference/plugins.rst @@ -0,0 +1,15 @@ +.. _plugins: + +***************** +Snapcraft plugins +***************** + +This section contains an in-depth description of the plugins available in +Snapcraft. + +.. toctree:: + :maxdepth: 1 + + plugins/dump_plugin + plugins/python_plugin + plugins/rust_plugin diff --git a/docs/reference/plugins/dump_plugin.rst b/docs/reference/plugins/dump_plugin.rst new file mode 100644 index 0000000000..9e6b8ca751 --- /dev/null +++ b/docs/reference/plugins/dump_plugin.rst @@ -0,0 +1,2 @@ + +.. include:: /common/craft-parts/dump_plugin.rst diff --git a/docs/reference/plugins/python_plugin.rst b/docs/reference/plugins/python_plugin.rst new file mode 100644 index 0000000000..7fb9d22e07 --- /dev/null +++ b/docs/reference/plugins/python_plugin.rst @@ -0,0 +1,23 @@ + +.. include:: /common/craft-parts/python_plugin.rst + :end-before: .. _python-details-begin: + +Dependencies +------------ + +Whether the Python interpreter needs to be included in the snap depends on its +``confinement``. Specifically: + +- Projects with ``strict`` or ``devmode`` confinement can safely use the base + snap's interpreter, so they typically do **not** need to include Python. +- Projects with ``classic`` confinement **cannot** use the base snap's + interpreter and thus must always bundle it (typically via ``stage-packages``). +- In both cases, a specific/custom Python installation can always be included + in the snap. This can be useful, for example, when using a different Python + version or building an interpreter with custom flags. + +Snapcraft will prefer an included interpreter over the base's, even for projects +with ``strict`` and ``devmode`` confinement. + +.. include:: /common/craft-parts/python_plugin.rst + :start-after: .. _python-details-end: diff --git a/docs/reference/plugins/rust_plugin.rst b/docs/reference/plugins/rust_plugin.rst new file mode 100644 index 0000000000..c6fc9d2717 --- /dev/null +++ b/docs/reference/plugins/rust_plugin.rst @@ -0,0 +1,2 @@ + +.. include:: /common/craft-parts/rust_plugin.rst diff --git a/docs/requirements.txt b/docs/requirements.txt index 2e0e78bbdc..31c29baed7 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,10 +1,11 @@ attrs==23.1.0 catkin-pkg==0.5.2 click==8.1.7 +craft-application==1.2.1 craft-archives==1.1.3 craft-cli==2.5.1 craft-grammar==1.1.1 -craft-parts==1.26.2 +craft-parts==1.27.0 craft-providers==1.23.0 craft-store==2.5.0 Deprecated==1.2.14 @@ -40,6 +41,7 @@ simplejson==3.19.2 snap-helpers==0.4.2 spdx==2.5.1 spdx-lookup==0.3.3 +sphinxcontrib-details-directive==0.1.0 tabulate==0.8.10 types-Deprecated==1.2.9.2 typing_extensions==4.5.0 diff --git a/docs/reuse/links.txt b/docs/reuse/links.txt index bcc4554180..a299bf6a1f 100644 --- a/docs/reuse/links.txt +++ b/docs/reuse/links.txt @@ -1,6 +1,7 @@ .. _AppStream: https://www.freedesktop.org/software/appstream/docs/ .. _Canonical Documentation Style Guide: https://docs.ubuntu.com/styleguide/en .. _Canonical website: https://canonical.com/ +.. _`Charmcraft`: https://juju.is/docs/sdk/charmcraft .. _`Create a brand account`: https://snapcraft.io/docs/t/creating-snap-store-brand-accounts/6271 .. _`Kernel connector`: https://www.kernel.org/doc/Documentation/connector/connector.txt .. _managing-snap-configuration: https://snapcraft.io/docs/configuration-in-snaps @@ -8,6 +9,7 @@ .. _reStructuredText style guide: https://canonical-documentation-with-sphinx-and-readthedocscom.readthedocs-hosted.com/style-guide/ .. _ROS: https://www.ros.org/ .. _setuptools: https://setuptools.readthedocs.io/en/latest/ +.. _`Snapcraft`: https://snapcraft.io/docs/snapcraft .. _`snap-channels`: https://snapcraft.io/docs/channels .. _`Snap Store desktop app`: https://snapcraft.io/snap-store .. _`Snap Store`: https://snapcraft.io/store @@ -16,3 +18,4 @@ .. _`Ubuntu Core`: https://ubuntu.com/core/ .. _vscode: https://code.visualstudio.com/ .. _`YAML specification`: https://yaml.org/spec/ + diff --git a/requirements-devel.txt b/requirements-devel.txt index 3e57007027..f54c1e76b3 100644 --- a/requirements-devel.txt +++ b/requirements-devel.txt @@ -15,7 +15,7 @@ craft-application==1.2.1 craft-archives==1.1.3 craft-cli==2.5.1 craft-grammar==1.1.2 -craft-parts==1.26.2 +craft-parts==1.27.0 craft-providers==1.23.0 craft-store==2.6.0 cryptography==42.0.4 diff --git a/requirements.txt b/requirements.txt index 734893d058..a01d92a8d4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ craft-application==1.2.1 craft-archives==1.1.3 craft-cli==2.5.1 craft-grammar==1.1.2 -craft-parts==1.26.2 +craft-parts==1.27.0 craft-providers==1.23.0 craft-store==2.6.0 cryptography==42.0.4 diff --git a/snapcraft/extensions/_ros2_humble_meta.py b/snapcraft/extensions/_ros2_humble_meta.py index e4204d5f93..be3d3ecff8 100644 --- a/snapcraft/extensions/_ros2_humble_meta.py +++ b/snapcraft/extensions/_ros2_humble_meta.py @@ -54,9 +54,9 @@ def is_experimental(base: Optional[str]) -> bool: def get_root_snippet(self) -> Dict[str, Any]: root_snippet = super().get_root_snippet() root_snippet["plugs"] = { - "ros-humble": { + self.ros2_humble_snaps.content: { "interface": "content", - "content": "ros-humble", + "content": self.ros2_humble_snaps.content, "target": "$SNAP/opt/ros/underlay_ws", "default-provider": self.ros2_humble_snaps.content, } diff --git a/snapcraft/meta/appstream.py b/snapcraft/meta/appstream.py index de4074b5dc..86d5611ad3 100644 --- a/snapcraft/meta/appstream.py +++ b/snapcraft/meta/appstream.py @@ -100,6 +100,13 @@ def extract(relpath: str, *, workdir: str) -> Optional[ExtractedMetadata]: description = _get_value_from_xml_element(dom, "description") title = _get_value_from_xml_element(dom, "name") version = _get_latest_release_from_nodes(dom.findall("releases/release")) + project_license = _get_value_from_xml_element(dom, "project_license") + contact = _get_value_from_xml_element(dom, "update_contact") + + issues = _get_urls_from_xml_element(dom.findall("url"), "bugtracker") + donation = _get_urls_from_xml_element(dom.findall("url"), "donation") + website = _get_urls_from_xml_element(dom.findall("url"), "homepage") + source_code = _get_source_code_from_xml_element(dom.findall("url")) desktop_file_paths = [] desktop_file_ids = _get_desktop_file_ids_from_nodes(dom.findall("launchable")) @@ -125,6 +132,12 @@ def extract(relpath: str, *, workdir: str) -> Optional[ExtractedMetadata]: description=description, version=version, icon=icon, + license=project_license, + contact=contact, + issues=issues, + donation=donation, + website=website, + source_code=source_code, desktop_file_paths=desktop_file_paths, ) @@ -161,6 +174,23 @@ def _get_value_from_xml_element(tree, key) -> Optional[str]: return None +def _get_urls_from_xml_element(nodes, url_type) -> Optional[List[str]]: + urls = [] # type: List[str] + for node in nodes: + if node is not None and node.attrib["type"] == url_type: + urls.append(node.text.strip()) + if urls: + return urls + return None + + +def _get_source_code_from_xml_element(nodes) -> Optional[str]: + for node in nodes: + if node is not None and node.attrib["type"] == "vcs-browser": + return node.text.strip() + return None + + def _get_latest_release_from_nodes(nodes) -> Optional[str]: for node in nodes: if "version" in node.attrib: diff --git a/snapcraft/meta/extracted_metadata.py b/snapcraft/meta/extracted_metadata.py index 18823cfd45..a6eb48b8da 100644 --- a/snapcraft/meta/extracted_metadata.py +++ b/snapcraft/meta/extracted_metadata.py @@ -47,3 +47,21 @@ class ExtractedMetadata: desktop_file_paths: List[str] = field(default_factory=list) """The extracted application desktop file paths.""" + + license: Optional[str] = None + """The extracted package license""" + + contact: Optional[str] = None + """The extracted package contact""" + + donation: Optional[List[str]] = None + """The extracted package donation""" + + issues: Optional[List[str]] = None + """The extracted package issues""" + + source_code: Optional[str] = None + """The extracted package source code""" + + website: Optional[List[str]] = None + """The extracted package website""" diff --git a/snapcraft/models/project.py b/snapcraft/models/project.py index a05c76a40f..e72145a9b5 100644 --- a/snapcraft/models/project.py +++ b/snapcraft/models/project.py @@ -570,14 +570,14 @@ def _validate_grade_and_build_base(cls, values): raise ValueError("grade must be 'devel' when build-base is 'devel'") return values - @pydantic.validator("base", always=True) + @pydantic.root_validator() @classmethod - def _validate_base(cls, base, values): + def _validate_base(cls, values): """Not allowed to use unstable base without devel build-base.""" if values.get("base") == "core24" and values.get("build_base") != "devel": raise ValueError("build-base must be 'devel' when base is 'core24'") - return base + return values @pydantic.validator("build_base", always=True) @classmethod diff --git a/snapcraft_legacy/internal/project_loader/_extensions/_ros1_noetic_meta.py b/snapcraft_legacy/internal/project_loader/_extensions/_ros1_noetic_meta.py index d9fceafafb..21bc40638f 100644 --- a/snapcraft_legacy/internal/project_loader/_extensions/_ros1_noetic_meta.py +++ b/snapcraft_legacy/internal/project_loader/_extensions/_ros1_noetic_meta.py @@ -53,10 +53,10 @@ def __init__(self, *, extension_name: str, yaml_data: Dict[str, Any]) -> None: self.part_snippet_extra = dict() self.root_snippet["plugs"] = { - "ros-noetic": + self.ros_noetic_snaps.content: { "interface": "content", - "content": "ros-noetic", + "content": self.ros_noetic_snaps.content, "target": "$SNAP/opt/ros/underlay_ws", "default-provider": self.ros_noetic_snaps.content, } diff --git a/snapcraft_legacy/internal/project_loader/_extensions/_ros2_foxy_meta.py b/snapcraft_legacy/internal/project_loader/_extensions/_ros2_foxy_meta.py index 95390250ea..0d9086e83b 100644 --- a/snapcraft_legacy/internal/project_loader/_extensions/_ros2_foxy_meta.py +++ b/snapcraft_legacy/internal/project_loader/_extensions/_ros2_foxy_meta.py @@ -61,10 +61,10 @@ def __init__(self, *, extension_name: str, yaml_data: Dict[str, Any]) -> None: ] self.root_snippet["plugs"] = { - "ros-foxy": + self.ros2_foxy_snaps.content: { "interface": "content", - "content": "ros-foxy", + "content": self.ros2_foxy_snaps.content, "target": "$SNAP/opt/ros/underlay_ws", "default-provider": self.ros2_foxy_snaps.content, } diff --git a/tests/legacy/unit/project_loader/extensions/test_ros1_noetic_meta.py b/tests/legacy/unit/project_loader/extensions/test_ros1_noetic_meta.py index 78661abe69..a24c53a47b 100644 --- a/tests/legacy/unit/project_loader/extensions/test_ros1_noetic_meta.py +++ b/tests/legacy/unit/project_loader/extensions/test_ros1_noetic_meta.py @@ -92,9 +92,9 @@ def test_extension(self, extension_name, extension_class, meta, meta_dev): } ], "plugs": { - "ros-noetic": { + meta: { "interface": "content", - "content": "ros-noetic", + "content": meta, "target": "$SNAP/opt/ros/underlay_ws", "default-provider": meta, } diff --git a/tests/legacy/unit/project_loader/extensions/test_ros2_foxy_meta.py b/tests/legacy/unit/project_loader/extensions/test_ros2_foxy_meta.py index 57c1dfe3ed..c936c84a19 100644 --- a/tests/legacy/unit/project_loader/extensions/test_ros2_foxy_meta.py +++ b/tests/legacy/unit/project_loader/extensions/test_ros2_foxy_meta.py @@ -72,9 +72,9 @@ def test_extension(self, extension_name, extension_class, meta, meta_dev): } ], "plugs": { - "ros-foxy": { + meta: { "interface": "content", - "content": "ros-foxy", + "content": meta, "target": "$SNAP/opt/ros/underlay_ws", "default-provider": meta, } diff --git a/tests/spread/extensions/catkin-tools-noetic-meta-hello/task.yaml b/tests/spread/extensions/catkin-tools-noetic-meta-hello/task.yaml index 828112480d..1a1a7b1822 100644 --- a/tests/spread/extensions/catkin-tools-noetic-meta-hello/task.yaml +++ b/tests/spread/extensions/catkin-tools-noetic-meta-hello/task.yaml @@ -9,19 +9,21 @@ environment: SNAP: catkin-tools-noetic-hello SNAP_DIR: "../../plugins/v2/snaps/$SNAP" - INTERFACE: ros-noetic - META_SNAP/catkin_noetic_ros_core: ros-noetic-ros-core EXTENSION/catkin_noetic_ros_core: ros1-noetic-ros-core + INTERFACE/catkin_noetic_ros_core: ros-noetic-ros-core META_SNAP/catkin_noetic_ros_base: ros-noetic-ros-base EXTENSION/catkin_noetic_ros_base: ros1-noetic-ros-base + INTERFACE/catkin_noetic_ros_base: ros-noetic-ros-base META_SNAP/catkin_noetic_robot: ros-noetic-robot EXTENSION/catkin_noetic_robot: ros1-noetic-robot + INTERFACE/catkin_noetic_robot: ros-noetic-robot META_SNAP/catkin_noetic_desktop: ros-noetic-desktop EXTENSION/catkin_noetic_desktop: ros1-noetic-desktop + INTERFACE/catkin_noetic_desktop: ros-noetic-desktop # The content snap required for the test to succeed is only # available on a subset of all the architectures this testbed diff --git a/tests/spread/extensions/ros-noetic-meta-hello/task.yaml b/tests/spread/extensions/ros-noetic-meta-hello/task.yaml index fc1ce2d070..38de63a0fc 100644 --- a/tests/spread/extensions/ros-noetic-meta-hello/task.yaml +++ b/tests/spread/extensions/ros-noetic-meta-hello/task.yaml @@ -9,19 +9,21 @@ environment: SNAP: catkin-noetic-hello SNAP_DIR: "../../plugins/v2/snaps/$SNAP" - INTERFACE: ros-noetic - META_SNAP/catkin_noetic_ros_core: ros-noetic-ros-core EXTENSION/catkin_noetic_ros_core: ros1-noetic-ros-core + INTERFACE/catkin_noetic_ros_core: ros-noetic-ros-core META_SNAP/catkin_noetic_ros_base: ros-noetic-ros-base EXTENSION/catkin_noetic_ros_base: ros1-noetic-ros-base + INTERFACE/catkin_noetic_ros_base: ros-noetic-ros-base META_SNAP/catkin_noetic_robot: ros-noetic-robot EXTENSION/catkin_noetic_robot: ros1-noetic-robot + INTERFACE/catkin_noetic_robot: ros-noetic-robot META_SNAP/catkin_noetic_desktop: ros-noetic-desktop EXTENSION/catkin_noetic_desktop: ros1-noetic-desktop + INTERFACE/catkin_noetic_desktop: ros-noetic-desktop # The content snap required for the test to succeed is only # available on a subset of all the architectures this testbed diff --git a/tests/spread/extensions/ros-noetic-meta-talker-listener/task.yaml b/tests/spread/extensions/ros-noetic-meta-talker-listener/task.yaml index d702e84cb5..89f50c9e5b 100644 --- a/tests/spread/extensions/ros-noetic-meta-talker-listener/task.yaml +++ b/tests/spread/extensions/ros-noetic-meta-talker-listener/task.yaml @@ -10,19 +10,21 @@ environment: SNAP_DIR: "../../plugins/v2/snaps/$SNAP" - INTERFACE: ros-noetic - META_SNAP/catkin_noetic_ros_core: ros-noetic-ros-core EXTENSION/catkin_noetic_ros_core: ros1-noetic-ros-core + INTERFACE/catkin_noetic_ros_core: ros-noetic-ros-core META_SNAP/catkin_noetic_ros_base: ros-noetic-ros-base EXTENSION/catkin_noetic_ros_base: ros1-noetic-ros-base + INTERFACE/catkin_noetic_ros_base: ros-noetic-ros-base META_SNAP/catkin_noetic_robot: ros-noetic-robot EXTENSION/catkin_noetic_robot: ros1-noetic-robot + INTERFACE/catkin_noetic_robot: ros-noetic-robot META_SNAP/catkin_noetic_desktop: ros-noetic-desktop EXTENSION/catkin_noetic_desktop: ros1-noetic-desktop + INTERFACE/catkin_noetic_desktop: ros-noetic-desktop # The content snap required for the test to succeed is only # available on a subset of all the architectures this testbed diff --git a/tests/spread/extensions/ros2-foxy-meta-hello/task.yaml b/tests/spread/extensions/ros2-foxy-meta-hello/task.yaml index 095005808f..63c67f301d 100644 --- a/tests/spread/extensions/ros2-foxy-meta-hello/task.yaml +++ b/tests/spread/extensions/ros2-foxy-meta-hello/task.yaml @@ -8,16 +8,17 @@ environment: SNAP: colcon-ros2-wrapper SNAP_DIR: "../../plugins/v2/snaps/$SNAP" - INTERFACE: ros-foxy - META_SNAP/colcon_foxy_ros_core: ros-foxy-ros-core EXTENSION/colcon_foxy_ros_core: ros2-foxy-ros-core + INTERFACE/colcon_foxy_ros_core: ros-foxy-ros-core META_SNAP/colcon_foxy_ros_base: ros-foxy-ros-base EXTENSION/colcon_foxy_ros_base: ros2-foxy-ros-base + INTERFACE/colcon_foxy_ros_base: ros-foxy-ros-base META_SNAP/colcon_foxy_desktop: ros-foxy-desktop EXTENSION/colcon_foxy_desktop: ros2-foxy-desktop + INTERFACE/colcon_foxy_desktop: ros-foxy-desktop # The content snap required for the test to succeed is only # available on a subset of all the architectures this testbed diff --git a/tests/spread/extensions/ros2-foxy-meta-talker-listener/task.yaml b/tests/spread/extensions/ros2-foxy-meta-talker-listener/task.yaml index bba345e2b7..62381c45d5 100644 --- a/tests/spread/extensions/ros2-foxy-meta-talker-listener/task.yaml +++ b/tests/spread/extensions/ros2-foxy-meta-talker-listener/task.yaml @@ -8,16 +8,17 @@ environment: SNAP: colcon-ros2-talker-listener SNAP_DIR: "../../plugins/v2/snaps/$SNAP" - INTERFACE: ros-foxy - META_SNAP/colcon_foxy_ros_core: ros-foxy-ros-core EXTENSION/colcon_foxy_ros_core: ros2-foxy-ros-core + INTERFACE/colcon_foxy_ros_core: ros-foxy-ros-core META_SNAP/colcon_foxy_ros_base: ros-foxy-ros-base EXTENSION/colcon_foxy_ros_base: ros2-foxy-ros-base + INTERFACE/colcon_foxy_ros_base: ros-foxy-ros-base META_SNAP/colcon_foxy_desktop: ros-foxy-desktop EXTENSION/colcon_foxy_desktop: ros2-foxy-desktop + INTERFACE/colcon_foxy_desktop: ros-foxy-desktop # The content snap required for the test to succeed is only # available on a subset of all the architectures this testbed diff --git a/tests/spread/extensions/ros2-humble-meta-hello/task.yaml b/tests/spread/extensions/ros2-humble-meta-hello/task.yaml index 7a0af11f65..d841082f43 100644 --- a/tests/spread/extensions/ros2-humble-meta-hello/task.yaml +++ b/tests/spread/extensions/ros2-humble-meta-hello/task.yaml @@ -9,16 +9,17 @@ environment: SNAP: colcon-ros2-wrapper SNAP_DIR: "../../plugins/craft-parts/build-and-run-hello/$SNAP" - INTERFACE: ros-humble - META_SNAP/colcon_humble_ros_core: ros-humble-ros-core EXTENSION/colcon_humble_ros_core: ros2-humble-ros-core + INTERFACE/colcon_humble_ros_core: ros-humble-ros-core META_SNAP/colcon_humble_ros_base: ros-humble-ros-base EXTENSION/colcon_humble_ros_base: ros2-humble-ros-base + INTERFACE/colcon_humble_ros_base: ros-humble-ros-base META_SNAP/colcon_humble_desktop: ros-humble-desktop EXTENSION/colcon_humble_desktop: ros2-humble-desktop + INTERFACE/colcon_humble_desktop: ros-humble-desktop # The content snap required for the test to succeed is only # available on a subset of all the architectures this testbed diff --git a/tests/spread/extensions/ros2-humble-meta-talker-listener/task.yaml b/tests/spread/extensions/ros2-humble-meta-talker-listener/task.yaml index 7c594ad2f8..e11055ec47 100644 --- a/tests/spread/extensions/ros2-humble-meta-talker-listener/task.yaml +++ b/tests/spread/extensions/ros2-humble-meta-talker-listener/task.yaml @@ -8,16 +8,17 @@ environment: SNAP: colcon-talker-listener SNAP_DIR: "../../plugins/craft-parts/$SNAP/$SNAP" - INTERFACE: ros-humble - META_SNAP/colcon_humble_ros_core: ros-humble-ros-core EXTENSION/colcon_humble_ros_core: ros2-humble-ros-core + INTERFACE/colcon_humble_ros_core: ros-humble-ros-core META_SNAP/colcon_humble_ros_base: ros-humble-ros-base EXTENSION/colcon_humble_ros_base: ros2-humble-ros-base + INTERFACE/colcon_humble_ros_base: ros-humble-ros-base META_SNAP/colcon_humble_desktop: ros-humble-desktop EXTENSION/colcon_humble_desktop: ros2-humble-desktop + INTERFACE/colcon_humble_desktop: ros-humble-desktop # The content snap required for the test to succeed is only # available on a subset of all the architectures this testbed diff --git a/tests/spread/plugins/v2/ros1-hello/task.yaml b/tests/spread/plugins/v2/ros1-hello/task.yaml index 64cc610f52..14389e38af 100644 --- a/tests/spread/plugins/v2/ros1-hello/task.yaml +++ b/tests/spread/plugins/v2/ros1-hello/task.yaml @@ -58,7 +58,7 @@ execute: | done # Connect the content sharing snap - snap connect "${SNAP}":ros-noetic ros-noetic-ros-core + snap connect "${SNAP}":ros-noetic-ros-core ros-noetic-ros-core fi [ "$($SNAP)" = "hello world" ] diff --git a/tests/unit/commands/test_remote.py b/tests/unit/commands/test_remote.py index 2f485b0a88..20ace8c7d6 100644 --- a/tests/unit/commands/test_remote.py +++ b/tests/unit/commands/test_remote.py @@ -98,7 +98,7 @@ def mock_run_legacy(mocker): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_argv") def test_command_user_confirms_upload( @@ -115,7 +115,7 @@ def test_command_user_confirms_upload( @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_argv") def test_command_user_denies_upload( @@ -135,7 +135,7 @@ def test_command_user_denies_upload( @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml") def test_command_accept_upload( @@ -153,7 +153,7 @@ def test_command_accept_upload( @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "use_new_remote_build" @@ -173,7 +173,7 @@ def test_command_new_build_arguments_mutually_exclusive(capsys, mocker): @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm") def test_command_legacy_build_arguments_not_mutually_exclusive(mocker, mock_run_legacy): @@ -190,7 +190,7 @@ def test_command_legacy_build_arguments_not_mutually_exclusive(mocker, mock_run_ @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm") def test_command_build_on_warning( @@ -208,7 +208,7 @@ def test_command_build_on_warning( @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "fake_sudo", "mock_argv" @@ -236,7 +236,7 @@ def test_cannot_load_snapcraft_yaml(capsys): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "use_new_remote_build", "mock_argv" @@ -256,7 +256,7 @@ def test_launchpad_timeout_default(mock_remote_builder): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "use_new_remote_build" @@ -285,7 +285,7 @@ def test_launchpad_timeout(mocker, mock_remote_builder): @pytest.mark.usefixtures("mock_argv", "mock_confirm") -@pytest.mark.parametrize("base", CURRENT_BASES | LEGACY_BASES) +@pytest.mark.parametrize("base", sorted(CURRENT_BASES | LEGACY_BASES)) def test_get_effective_base( base, snapcraft_yaml, mock_run_new_or_fallback_remote_build ): @@ -321,7 +321,7 @@ def test_get_effective_base_with_build_base( @pytest.mark.usefixtures("mock_argv", "mock_confirm") -@pytest.mark.parametrize("base", CURRENT_BASES | LEGACY_BASES | ESM_BASES) +@pytest.mark.parametrize("base", sorted(CURRENT_BASES | LEGACY_BASES | ESM_BASES)) def test_get_effective_base_type( base, snapcraft_yaml, mock_run_new_or_fallback_remote_build ): @@ -395,7 +395,7 @@ def test_get_effective_base_core18_esm_warning( @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES - {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES - {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_newer_than_core_22(emitter, mock_run_new_remote_build): @@ -407,7 +407,7 @@ def test_run_newer_than_core_22(emitter, mock_run_new_remote_build): @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_core22_and_older(emitter, mock_run_legacy): @@ -419,7 +419,7 @@ def test_run_core22_and_older(emitter, mock_run_legacy): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES - {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES - {"core22"}), indirect=True ) @pytest.mark.parametrize( "envvar", ["force-fallback", "disable-fallback", "badvalue", None] @@ -441,7 +441,7 @@ def test_run_envvar_newer_than_core22( @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_envvar_disable_fallback(emitter, mock_run_new_remote_build, monkeypatch): @@ -458,7 +458,7 @@ def test_run_envvar_disable_fallback(emitter, mock_run_new_remote_build, monkeyp @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_envvar_force_fallback(emitter, mock_run_legacy, monkeypatch): @@ -475,7 +475,7 @@ def test_run_envvar_force_fallback(emitter, mock_run_legacy, monkeypatch): @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_envvar_force_fallback_unset(emitter, mock_run_legacy, monkeypatch): @@ -489,7 +489,7 @@ def test_run_envvar_force_fallback_unset(emitter, mock_run_legacy, monkeypatch): @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_envvar_force_fallback_empty(emitter, mock_run_legacy, monkeypatch): @@ -503,7 +503,7 @@ def test_run_envvar_force_fallback_empty(emitter, mock_run_legacy, monkeypatch): @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_envvar_invalid(capsys, emitter, mock_run_legacy, monkeypatch): @@ -521,7 +521,7 @@ def test_run_envvar_invalid(capsys, emitter, mock_run_legacy, monkeypatch): @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_in_repo(emitter, mock_run_new_remote_build, new_dir): @@ -538,7 +538,7 @@ def test_run_in_repo(emitter, mock_run_new_remote_build, new_dir): @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(LEGACY_BASES | {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_not_in_repo(emitter, mock_run_legacy): @@ -550,7 +550,7 @@ def test_run_not_in_repo(emitter, mock_run_legacy): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES - {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES - {"core22"}), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_in_repo_newer_than_core22( @@ -567,7 +567,7 @@ def test_run_in_repo_newer_than_core22( @pytest.mark.parametrize( - "create_snapcraft_yaml", LEGACY_BASES | {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(sorted(LEGACY_BASES | {"core22"})), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_confirm", "mock_argv") def test_run_in_shallow_repo(emitter, mock_run_legacy, new_dir): @@ -614,7 +614,7 @@ def test_run_in_shallow_repo(emitter, mock_run_legacy, new_dir): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES - {"core22"}, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES - {"core22"}), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "mock_argv", "use_new_remote_build" @@ -672,7 +672,7 @@ def test_run_in_shallow_repo_unsupported(capsys, new_dir): ###################### -@pytest.mark.parametrize("base", CURRENT_BASES | LEGACY_BASES) +@pytest.mark.parametrize("base", sorted(CURRENT_BASES | LEGACY_BASES)) @pytest.mark.parametrize( ["archs", "expected_archs"], [ @@ -730,7 +730,7 @@ def test_determine_architectures_from_snapcraft_yaml( @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_argv", "mock_confirm", "use_new_remote_build" @@ -763,7 +763,7 @@ def test_determine_architectures_host_arch(mocker, mock_remote_builder): ], ) @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "use_new_remote_build" @@ -806,7 +806,7 @@ def test_determine_architectures_provided_by_user_duplicate_arguments( ], ) @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "use_new_remote_build" @@ -829,7 +829,7 @@ def test_determine_architectures_provided_by_user( ) -@pytest.mark.parametrize("base", CURRENT_BASES | LEGACY_BASES) +@pytest.mark.parametrize("base", sorted(CURRENT_BASES | LEGACY_BASES)) @pytest.mark.usefixtures("mock_confirm", "use_new_remote_build") def test_determine_architectures_error(base, capsys, snapcraft_yaml, mocker): """Error if `--build-for` is provided and archs are in the snapcraft.yaml.""" @@ -855,7 +855,7 @@ def test_determine_architectures_error(base, capsys, snapcraft_yaml, mocker): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "use_new_remote_build" @@ -879,7 +879,7 @@ def test_build_id_provided(mocker, mock_remote_builder): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "mock_argv", "use_new_remote_build" @@ -899,7 +899,7 @@ def test_build_id_not_provided(mock_remote_builder): ) -@pytest.mark.parametrize("base", CURRENT_BASES | LEGACY_BASES) +@pytest.mark.parametrize("base", sorted(CURRENT_BASES | LEGACY_BASES)) @pytest.mark.usefixtures("mock_confirm", "mock_argv", "use_new_remote_build") def test_build_id_no_project_name_error(base, capsys): """Raise an error if there is no name in the snapcraft.yaml file.""" @@ -931,7 +931,7 @@ def test_build_id_no_project_name_error(base, capsys): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "use_new_remote_build" @@ -946,7 +946,7 @@ def test_status(mocker, mock_remote_builder): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", @@ -964,7 +964,7 @@ def test_recover_no_build(emitter, mocker): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_confirm", "use_new_remote_build" @@ -984,7 +984,7 @@ def test_recover_build(emitter, mocker, mock_remote_builder): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_argv", "mock_confirm", "use_new_remote_build" @@ -1003,7 +1003,7 @@ def test_recover_build_user_confirms(emitter, mocker, mock_remote_builder): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures("create_snapcraft_yaml", "mock_argv", "use_new_remote_build") def test_recover_build_user_denies(emitter, mocker, mock_remote_builder): @@ -1025,7 +1025,7 @@ def test_recover_build_user_denies(emitter, mocker, mock_remote_builder): @pytest.mark.parametrize( - "create_snapcraft_yaml", CURRENT_BASES | LEGACY_BASES, indirect=True + "create_snapcraft_yaml", sorted(CURRENT_BASES | LEGACY_BASES), indirect=True ) @pytest.mark.usefixtures( "create_snapcraft_yaml", "mock_argv", "mock_confirm", "use_new_remote_build" diff --git a/tests/unit/meta/test_appstream.py b/tests/unit/meta/test_appstream.py index 2acc27df9d..d8e6936455 100644 --- a/tests/unit/meta/test_appstream.py +++ b/tests/unit/meta/test_appstream.py @@ -49,6 +49,24 @@ class TestAppstreamData: ("icon", {"type": "local"}, "icon", "/icon.png", "/icon.png"), ("id", {}, "common_id", "test-id", "test-id"), ("name", {}, "title", "test-title", "test-title"), + ("project_license", {}, "license", "test-license", "test-license"), + ("update_contact", {}, "contact", "test-contact", "test-contact"), + ("url", {"type": "homepage"}, "website", "test-website", ["test-website"]), + ("url", {"type": "bugtracker"}, "issues", "test-issues", ["test-issues"]), + ( + "url", + {"type": "donation"}, + "donation", + "test-donation", + ["test-donation"], + ), + ( + "url", + {"type": "vcs-browser"}, + "source_code", + "test-source", + "test-source", + ), ], ) def test_entries(self, file_extension, key, attributes, param_name, value, expect): @@ -491,6 +509,7 @@ def test_appstream_em(self):
  • Publica snaps en la tienda.
  • + rrroschan@gmail.com """ ) @@ -514,6 +533,8 @@ def test_appstream_em(self): - _Build snaps_. - Publish snaps to the store.""" ) + assert metadata.license == "GPL-3.0-or-later" + assert metadata.contact == "rrroschan@gmail.com" def test_appstream_code_tags_not_swallowed(self): file_name = "foliate.appdata.xml" @@ -627,6 +648,107 @@ def test_appstream_with_comments(self): - Publish snaps to the store.""" ) + def test_appstream_links(self): + file_name = "foliate.appdata.xml" + content = textwrap.dedent( + """\ + + + com.github.maoschanz.drawing + CC0-1.0 + GPL-3.0-or-later + + Drawing + +

    Command Line Utility to create snaps quickly.

    +

    Aplicativo de lĂ­nea de comandos para crear snaps.

    +

    Ordered Features:

    +

    Funciones:

    +
      +
    1. Build snaps.
    2. +
    3. Construye snaps.
    4. +
    5. Publish snaps to the store.
    6. +
    7. Publica snaps en la tienda.
    8. +
    +

    Unordered Features:

    +
      +
    • Build snaps.
    • +
    • Construye snaps.
    • +
    • Publish snaps to the store.
    • +
    • Publica snaps en la tienda.
    • +
    +
    + https://johnfactotum.github.io/foliate/ + https://github.com/johnfactotum/foliate + https://github.com/johnfactotum/foliate/issues + https://github.com/johnfactotum/foliate/tree/gtk4/po + https://github.com/johnfactotum/foliate/blob/gtk4/docs/faq.md + https://www.buymeacoffee.com/johnfactotum +
    + """ + ) + Path(file_name).write_text(content) + + metadata = appstream.extract(file_name, workdir=".") + + assert metadata is not None + assert metadata.website == ["https://johnfactotum.github.io/foliate/"] + assert metadata.issues == ["https://github.com/johnfactotum/foliate/issues"] + assert metadata.donation == ["https://www.buymeacoffee.com/johnfactotum"] + assert metadata.source_code == "https://github.com/johnfactotum/foliate" + + def test_appstream_url(self): + file_name = "foliate.appdata.xml" + content = textwrap.dedent( + """\ + + + com.github.maoschanz.drawing + CC0-1.0 + GPL-3.0-or-later + + Drawing + https://johnfactotum.github.io/foliate/ + https://github.com/johnfactotum/foliate + + """ + ) + Path(file_name).write_text(content) + + metadata = appstream.extract(file_name, workdir=".") + assert metadata is not None + assert metadata.source_code == "https://github.com/johnfactotum/foliate" + + def test_appstream_with_multiple_lists(self): + file_name = "foliate.appdata.xml" + content = textwrap.dedent( + """\ + + + com.github.maoschanz.drawing + CC0-1.0 + GPL-3.0-or-later + + Drawing + https://johnfactotum.github.io/foliate/ + https://github.com/johnfactotum/foliate + https://github.com/alainm23/planify/issues + https://github.com/johnfactotum/foliate/issues + + """ + ) + Path(file_name).write_text(content) + + metadata = appstream.extract(file_name, workdir=".") + assert metadata is not None + assert metadata.issues == [ + "https://github.com/alainm23/planify/issues", + "https://github.com/johnfactotum/foliate/issues", + ] + assert metadata.source_code == "https://github.com/johnfactotum/foliate" + assert metadata.website == ["https://johnfactotum.github.io/foliate/"] + assert metadata.donation is None + def test_appstream_parse_error(self): file_name = "snapcraft_legacy.appdata.xml" content = textwrap.dedent( diff --git a/tests/unit/models/test_projects.py b/tests/unit/models/test_projects.py index deee80a103..0a8f62db82 100644 --- a/tests/unit/models/test_projects.py +++ b/tests/unit/models/test_projects.py @@ -593,7 +593,7 @@ def test_project_build_base_devel_grade_devel(self, project_yaml_data): assert project.grade == "devel" - @pytest.mark.parametrize("build_base", {"core22", "devel"}) + @pytest.mark.parametrize("build_base", ["core22", "devel"]) def test_project_grade_not_defined(self, build_base, project_yaml_data): """Do not validate the grade if it is not defined, regardless of build_base.""" data = project_yaml_data(build_base=build_base) @@ -614,6 +614,12 @@ def test_project_build_base_devel_grade_stable_error(self, project_yaml_data): with pytest.raises(errors.ProjectValidationError, match=error): Project.unmarshal(project_yaml_data(build_base="devel", grade="stable")) + def test_project_development_base_error(self, project_yaml_data): + error = "build-base must be 'devel' when base is 'core24'" + + with pytest.raises(errors.ProjectValidationError, match=error): + Project.unmarshal(project_yaml_data(base="core24")) + def test_project_global_plugs_warning(self, project_yaml_data, emitter): data = project_yaml_data(plugs={"desktop": None, "desktop-legacy": None}) Project.unmarshal(data) diff --git a/tests/unit/parts/extensions/test_ros2_humble_meta.py b/tests/unit/parts/extensions/test_ros2_humble_meta.py index 39b5e4827e..67a439be02 100644 --- a/tests/unit/parts/extensions/test_ros2_humble_meta.py +++ b/tests/unit/parts/extensions/test_ros2_humble_meta.py @@ -123,8 +123,8 @@ def test_get_root_snippet(self, extension_name, extension_class, meta, meta_dev) ] }, "plugs": { - "ros-humble": { - "content": "ros-humble", + meta: { + "content": meta, "default-provider": meta, "interface": "content", "target": "$SNAP/opt/ros/underlay_ws", diff --git a/tests/unit/remote/test_launchpad.py b/tests/unit/remote/test_launchpad.py index 16412b683d..91c89a4cac 100644 --- a/tests/unit/remote/test_launchpad.py +++ b/tests/unit/remote/test_launchpad.py @@ -236,17 +236,11 @@ def launchpad_client(mock_login_with): ) -def test_login(mock_login_with): - lpc = LaunchpadClient( - app_name="test-app", - build_id="id", - project_name="test-project", - architectures=[], - ) +def test_login(mock_login_with, launchpad_client): - assert lpc.user == "user" + assert launchpad_client.user == "user" - assert mock_login_with.called_with( + mock_login_with.assert_called_once_with( "test-app remote-build", "production", ANY, diff --git a/tox.ini b/tox.ini index 2bb58d93bc..bab2aab826 100644 --- a/tox.ini +++ b/tox.ini @@ -138,7 +138,7 @@ commands_pre = mypy: mkdir -p .mypy_cache commands = pyright: pyright {posargs} - mypy: mypy --install-types --non-interactive --exclude 'docs/sphinx-resources/conf.py' . + mypy: mypy --install-types --non-interactive --exclude 'docs/sphinx-resources/conf.py' --exclude 'docs/common' . [testenv:format-{black,ruff,codespell}] description = Automatically format source code