diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 082d0bb5f..26e4fbd77 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -2,8 +2,6 @@ // Configuration file for RenovateBot: https://docs.renovatebot.com/configuration-options extends: ["config:recommended", ":semanticCommitTypeAll(build)"], ignoreDeps: [ - "types-requests", // Don't update until we can support urllib3 >= 2.0 - "urllib3", // Can't update, see setup.py ], labels: ["dependencies"], // For convenient searching in GitHub baseBranches: ["$default", "/^hotfix\\/.*/"], diff --git a/craft_parts/packages/snaps.py b/craft_parts/packages/snaps.py index b8e01bfee..2e983851c 100644 --- a/craft_parts/packages/snaps.py +++ b/craft_parts/packages/snaps.py @@ -19,6 +19,7 @@ import contextlib import logging import os +import pathlib import subprocess import sys from collections.abc import Iterator, Sequence @@ -200,7 +201,7 @@ def is_valid(self) -> bool: store_channels = self._get_store_channels() return self.channel in store_channels - def download(self, *, directory: str | None = None) -> None: + def download(self, *, directory: str | pathlib.Path | None = None) -> None: """Download a given snap.""" # We use the `snap download` command here on recommendation # of the snapd team. @@ -270,7 +271,7 @@ def refresh(self) -> None: self._is_installed = None -def download_snaps(*, snaps_list: Sequence[str], directory: str) -> None: +def download_snaps(*, snaps_list: Sequence[str], directory: str | pathlib.Path) -> None: """Download snaps of the format / into directory. The target directory is created if it does not exist. diff --git a/docs/changelog.rst b/docs/changelog.rst index a6711eac3..4168d4b39 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,11 @@ Changelog ********* +X.Y.Z (2024-MM-DD) +------------------ + +- Replace the dependency on requests-unixsocket with requests-unixsocket2 + 2.1.1 (2024-09-13) ------------------ diff --git a/docs/common/craft-parts/craft-parts.wordlist.txt b/docs/common/craft-parts/craft-parts.wordlist.txt index 47491b1a2..776e41973 100644 --- a/docs/common/craft-parts/craft-parts.wordlist.txt +++ b/docs/common/craft-parts/craft-parts.wordlist.txt @@ -451,6 +451,7 @@ txt ubuntu umount unbuilt +unixsocket unmark unmarshal unmount diff --git a/setup.py b/setup.py index 5b5348aaa..c40018621 100644 --- a/setup.py +++ b/setup.py @@ -51,11 +51,8 @@ def is_rtd() -> bool: "PyYAML", "pydantic>=2.0.0", "pyxdg", - "requests<2.32.0", - "requests-unixsocket", - # See: https://github.com/msabramo/requests-unixsocket/pull/69 - # When updating to urllib3 v2, also remove the constraint on types-requests. - "urllib3<2", # keep compatible API + "requests>=2.32,<3.0", + "requests-unixsocket2>=0.4.0", ] dev_requires = [ @@ -81,7 +78,7 @@ def is_rtd() -> bool: "types-Pygments", "types-pytz", "types-PyYAML", - "types-requests<2.30", # When removing this constraint, remove from renovate's ignoreDeps + "types-requests", "types-setuptools", ] diff --git a/tests/conftest.py b/tests/conftest.py index b44e252c8..0c3f95b0d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -45,6 +45,12 @@ def new_dir(monkeypatch, tmpdir): return tmpdir +@pytest.fixture +def new_path(monkeypatch, tmp_path): + monkeypatch.chdir(tmp_path) + return tmp_path + + @pytest.fixture def tmp_homedir_path(): """A non-hidden temporary directory in the user's home directory. diff --git a/tests/integration/packages/test_snaps.py b/tests/integration/packages/test_snaps.py new file mode 100644 index 000000000..265ba3edd --- /dev/null +++ b/tests/integration/packages/test_snaps.py @@ -0,0 +1,57 @@ +# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- +# +# Copyright 2024 Canonical Ltd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 3 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +"""Integration tests for interacting with snapd.""" + +import pathlib +from collections.abc import Sequence + +import pytest +import pytest_check # type: ignore[import] +from craft_parts.packages import snaps + + +def test_get_installed_snaps_success(): + """Test that get_installed_snaps returns a list of snaps.""" + actual = snaps.get_installed_snaps() + + for snap in actual: + name, _, revision = snap.partition("=") + pytest_check.is_true(len(name) >= 1) + if revision.startswith("x"): + # Locally installed snaps should be of the form "x" + with pytest_check.check(): + int(revision[1:]) + else: + # Store-instaled snaps should simply have an integer revision. + with pytest_check.check(): + int(revision) + + +@pytest.mark.parametrize( + "snaps_list", + [ + {"snapcraft", "ruff"}, + {"snapcraft/7.x/stable"}, + ], +) +def test_download_snaps_success(new_path: pathlib.Path, snaps_list: Sequence[str]): + + snaps.download_snaps(snaps_list=snaps_list, directory=new_path) + + for snap in snaps_list: + snap_name, _, snap_channel = snap.partition("/") + assert len(list(new_path.glob(f"{snap_name}*.snap"))) == 1 + assert len(list(new_path.glob(f"{snap_name}*.assert"))) == 1