Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9357c4632e | ||
|
|
ca5d0d22f3 | ||
|
|
3875338fb7 | ||
|
|
196f55c58e |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,3 +1,13 @@
|
|||||||
|
## [0.7.7] - 2025-12-09
|
||||||
|
|
||||||
|
* Added TEST_PATTERN parameter to execute dedicated tests
|
||||||
|
|
||||||
|
|
||||||
|
## [0.7.6] - 2025-12-09
|
||||||
|
|
||||||
|
* Fixed pull --preview bug in e2e test
|
||||||
|
|
||||||
|
|
||||||
## [0.7.5] - 2025-12-09
|
## [0.7.5] - 2025-12-09
|
||||||
|
|
||||||
* Fixed wrong directory permissions for nix
|
* Fixed wrong directory permissions for nix
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -12,7 +12,7 @@ NIX_CACHE_VOLUME := pkgmgr_nix_cache
|
|||||||
# Distro list and base images
|
# Distro list and base images
|
||||||
# (kept for documentation/reference; actual build logic is in scripts/build)
|
# (kept for documentation/reference; actual build logic is in scripts/build)
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
DISTROS := arch debian ubuntu fedora centos
|
DISTROS := arch debian ubuntu fedora centos
|
||||||
BASE_IMAGE_ARCH := archlinux:latest
|
BASE_IMAGE_ARCH := archlinux:latest
|
||||||
BASE_IMAGE_DEBIAN := debian:stable-slim
|
BASE_IMAGE_DEBIAN := debian:stable-slim
|
||||||
BASE_IMAGE_UBUNTU := ubuntu:latest
|
BASE_IMAGE_UBUNTU := ubuntu:latest
|
||||||
@@ -27,6 +27,10 @@ export BASE_IMAGE_UBUNTU
|
|||||||
export BASE_IMAGE_FEDORA
|
export BASE_IMAGE_FEDORA
|
||||||
export BASE_IMAGE_CENTOS
|
export BASE_IMAGE_CENTOS
|
||||||
|
|
||||||
|
# PYthon Unittest Pattern
|
||||||
|
TEST_PATTERN := test_*.py
|
||||||
|
export TEST_PATTERN
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# PKGMGR setup (developer wrapper -> scripts/installation/main.sh)
|
# PKGMGR setup (developer wrapper -> scripts/installation/main.sh)
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
|
|||||||
2
PKGBUILD
2
PKGBUILD
@@ -1,7 +1,7 @@
|
|||||||
# Maintainer: Kevin Veen-Birkenbach <info@veen.world>
|
# Maintainer: Kevin Veen-Birkenbach <info@veen.world>
|
||||||
|
|
||||||
pkgname=package-manager
|
pkgname=package-manager
|
||||||
pkgver=0.7.5
|
pkgver=0.7.7
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Local-flake wrapper for Kevin's package-manager (Nix-based)."
|
pkgdesc="Local-flake wrapper for Kevin's package-manager (Nix-based)."
|
||||||
arch=('any')
|
arch=('any')
|
||||||
|
|||||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@@ -1,3 +1,15 @@
|
|||||||
|
package-manager (0.7.7-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Added TEST_PATTERN parameter to execute dedicated tests
|
||||||
|
|
||||||
|
-- Kevin Veen-Birkenbach <kevin@veen.world> Tue, 09 Dec 2025 17:54:38 +0100
|
||||||
|
|
||||||
|
package-manager (0.7.6-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Fixed pull --preview bug in e2e test
|
||||||
|
|
||||||
|
-- Kevin Veen-Birkenbach <kevin@veen.world> Tue, 09 Dec 2025 17:14:19 +0100
|
||||||
|
|
||||||
package-manager (0.7.5-1) unstable; urgency=medium
|
package-manager (0.7.5-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Fixed wrong directory permissions for nix
|
* Fixed wrong directory permissions for nix
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
rec {
|
rec {
|
||||||
pkgmgr = pyPkgs.buildPythonApplication {
|
pkgmgr = pyPkgs.buildPythonApplication {
|
||||||
pname = "package-manager";
|
pname = "package-manager";
|
||||||
version = "0.7.5";
|
version = "0.7.7";
|
||||||
|
|
||||||
# Use the git repo as source
|
# Use the git repo as source
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Name: package-manager
|
Name: package-manager
|
||||||
Version: 0.7.5
|
Version: 0.7.7
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: Wrapper that runs Kevin's package-manager via Nix flake
|
Summary: Wrapper that runs Kevin's package-manager via Nix flake
|
||||||
|
|
||||||
@@ -77,6 +77,12 @@ echo ">>> package-manager removed. Nix itself was not removed."
|
|||||||
/usr/lib/package-manager/
|
/usr/lib/package-manager/
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Dec 09 2025 Kevin Veen-Birkenbach <kevin@veen.world> - 0.7.7-1
|
||||||
|
- Added TEST_PATTERN parameter to execute dedicated tests
|
||||||
|
|
||||||
|
* Tue Dec 09 2025 Kevin Veen-Birkenbach <kevin@veen.world> - 0.7.6-1
|
||||||
|
- Fixed pull --preview bug in e2e test
|
||||||
|
|
||||||
* Tue Dec 09 2025 Kevin Veen-Birkenbach <kevin@veen.world> - 0.7.5-1
|
* Tue Dec 09 2025 Kevin Veen-Birkenbach <kevin@veen.world> - 0.7.5-1
|
||||||
- Fixed wrong directory permissions for nix
|
- Fixed wrong directory permissions for nix
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,57 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pkgmgr.core.repository.identifier import get_repo_identifier
|
from pkgmgr.core.repository.identifier import get_repo_identifier
|
||||||
from pkgmgr.core.repository.dir import get_repo_dir
|
from pkgmgr.core.repository.dir import get_repo_dir
|
||||||
from pkgmgr.core.repository.verify import verify_repository
|
from pkgmgr.core.repository.verify import verify_repository
|
||||||
|
|
||||||
|
|
||||||
def pull_with_verification(
|
def pull_with_verification(
|
||||||
selected_repos,
|
selected_repos,
|
||||||
repositories_base_dir,
|
repositories_base_dir,
|
||||||
all_repos,
|
all_repos,
|
||||||
extra_args,
|
extra_args,
|
||||||
no_verification,
|
no_verification,
|
||||||
preview:bool):
|
preview: bool,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Executes "git pull" for each repository with verification.
|
Execute `git pull` for each repository with verification.
|
||||||
|
|
||||||
Uses the verify_repository function in "pull" mode.
|
- Uses verify_repository() in "pull" mode.
|
||||||
If verification fails (and verification info is set) and --no-verification is not enabled,
|
- If verification fails (and verification info is set) and
|
||||||
the user is prompted to confirm the pull.
|
--no-verification is not enabled, the user is prompted to confirm
|
||||||
|
the pull.
|
||||||
|
- In preview mode, no interactive prompts are performed and no
|
||||||
|
Git commands are executed; only the would-be command is printed.
|
||||||
"""
|
"""
|
||||||
for repo in selected_repos:
|
for repo in selected_repos:
|
||||||
repo_identifier = get_repo_identifier(repo, all_repos)
|
repo_identifier = get_repo_identifier(repo, all_repos)
|
||||||
repo_dir = get_repo_dir(repositories_base_dir, repo)
|
repo_dir = get_repo_dir(repositories_base_dir, repo)
|
||||||
|
|
||||||
if not os.path.exists(repo_dir):
|
if not os.path.exists(repo_dir):
|
||||||
print(f"Repository directory '{repo_dir}' not found for {repo_identifier}.")
|
print(f"Repository directory '{repo_dir}' not found for {repo_identifier}.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
verified_info = repo.get("verified")
|
verified_info = repo.get("verified")
|
||||||
verified_ok, errors, commit_hash, signing_key = verify_repository(repo, repo_dir, mode="pull", no_verification=no_verification)
|
verified_ok, errors, commit_hash, signing_key = verify_repository(
|
||||||
|
repo,
|
||||||
|
repo_dir,
|
||||||
|
mode="pull",
|
||||||
|
no_verification=no_verification,
|
||||||
|
)
|
||||||
|
|
||||||
if not no_verification and verified_info and not verified_ok:
|
# Only prompt the user if:
|
||||||
|
# - we are NOT in preview mode
|
||||||
|
# - verification is enabled
|
||||||
|
# - the repo has verification info configured
|
||||||
|
# - verification failed
|
||||||
|
if (
|
||||||
|
not preview
|
||||||
|
and not no_verification
|
||||||
|
and verified_info
|
||||||
|
and not verified_ok
|
||||||
|
):
|
||||||
print(f"Warning: Verification failed for {repo_identifier}:")
|
print(f"Warning: Verification failed for {repo_identifier}:")
|
||||||
for err in errors:
|
for err in errors:
|
||||||
print(f" - {err}")
|
print(f" - {err}")
|
||||||
@@ -37,12 +59,19 @@ def pull_with_verification(
|
|||||||
if choice != "y":
|
if choice != "y":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
full_cmd = f"git pull {' '.join(extra_args)}"
|
# Build the git pull command (include extra args if present)
|
||||||
|
args_part = " ".join(extra_args) if extra_args else ""
|
||||||
|
full_cmd = f"git pull{(' ' + args_part) if args_part else ''}"
|
||||||
|
|
||||||
if preview:
|
if preview:
|
||||||
|
# Preview mode: only show the command, do not execute or prompt.
|
||||||
print(f"[Preview] In '{repo_dir}': {full_cmd}")
|
print(f"[Preview] In '{repo_dir}': {full_cmd}")
|
||||||
else:
|
else:
|
||||||
print(f"Running in '{repo_dir}': {full_cmd}")
|
print(f"Running in '{repo_dir}': {full_cmd}")
|
||||||
result = subprocess.run(full_cmd, cwd=repo_dir, shell=True)
|
result = subprocess.run(full_cmd, cwd=repo_dir, shell=True)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
print(f"'git pull' for {repo_identifier} failed with exit code {result.returncode}.")
|
print(
|
||||||
|
f"'git pull' for {repo_identifier} failed "
|
||||||
|
f"with exit code {result.returncode}."
|
||||||
|
)
|
||||||
sys.exit(result.returncode)
|
sys.exit(result.returncode)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "package-manager"
|
name = "package-manager"
|
||||||
version = "0.7.5"
|
version = "0.7.7"
|
||||||
description = "Kevin's package-manager tool (pkgmgr)"
|
description = "Kevin's package-manager tool (pkgmgr)"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ for distro in $DISTROS; do
|
|||||||
$MOUNT_NIX \
|
$MOUNT_NIX \
|
||||||
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
||||||
-e PKGMGR_DEV=1 \
|
-e PKGMGR_DEV=1 \
|
||||||
|
-e TEST_PATTERN="${TEST_PATTERN}" \
|
||||||
--workdir /src \
|
--workdir /src \
|
||||||
--entrypoint bash \
|
--entrypoint bash \
|
||||||
"package-manager-test-$distro" \
|
"package-manager-test-$distro" \
|
||||||
@@ -51,6 +52,6 @@ for distro in $DISTROS; do
|
|||||||
nix develop .#default --no-write-lock-file -c \
|
nix develop .#default --no-write-lock-file -c \
|
||||||
python3 -m unittest discover \
|
python3 -m unittest discover \
|
||||||
-s /src/tests/e2e \
|
-s /src/tests/e2e \
|
||||||
-p "test_*.py";
|
-p "$TEST_PATTERN";
|
||||||
'
|
'
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ docker run --rm \
|
|||||||
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
||||||
--workdir /src \
|
--workdir /src \
|
||||||
-e PKGMGR_DEV=1 \
|
-e PKGMGR_DEV=1 \
|
||||||
|
-e TEST_PATTERN="${TEST_PATTERN}" \
|
||||||
--entrypoint bash \
|
--entrypoint bash \
|
||||||
"package-manager-test-arch" \
|
"package-manager-test-arch" \
|
||||||
-c '
|
-c '
|
||||||
@@ -19,5 +20,5 @@ docker run --rm \
|
|||||||
python -m unittest discover \
|
python -m unittest discover \
|
||||||
-s tests/integration \
|
-s tests/integration \
|
||||||
-t /src \
|
-t /src \
|
||||||
-p "test_*.py";
|
-p "$TEST_PATTERN";
|
||||||
'
|
'
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ docker run --rm \
|
|||||||
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
-v "pkgmgr_nix_cache:/root/.cache/nix" \
|
||||||
--workdir /src \
|
--workdir /src \
|
||||||
-e PKGMGR_DEV=1 \
|
-e PKGMGR_DEV=1 \
|
||||||
|
-e TEST_PATTERN="${TEST_PATTERN}" \
|
||||||
--entrypoint bash \
|
--entrypoint bash \
|
||||||
"package-manager-test-arch" \
|
"package-manager-test-arch" \
|
||||||
-c '
|
-c '
|
||||||
@@ -19,5 +20,5 @@ docker run --rm \
|
|||||||
python -m unittest discover \
|
python -m unittest discover \
|
||||||
-s tests/unit \
|
-s tests/unit \
|
||||||
-t /src \
|
-t /src \
|
||||||
-p "test_*.py";
|
-p "$TEST_PATTERN";
|
||||||
'
|
'
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ def remove_pkgmgr_from_nix_profile() -> None:
|
|||||||
prints a descriptive format without an index column inside the container.
|
prints a descriptive format without an index column inside the container.
|
||||||
|
|
||||||
Instead, we directly try to remove possible names:
|
Instead, we directly try to remove possible names:
|
||||||
- 'pkgmgr' (the actual name shown in `nix profile list`)
|
- 'pkgmgr' (the actual name shown in `nix profile list`)
|
||||||
- 'package-manager' (the name mentioned in Nix's own error hints)
|
- 'package-manager' (the name mentioned in Nix's own error hints)
|
||||||
"""
|
"""
|
||||||
for spec in ("pkgmgr", "package-manager"):
|
for spec in ("pkgmgr", "package-manager"):
|
||||||
@@ -76,29 +76,47 @@ def pkgmgr_help_debug() -> None:
|
|||||||
print(f"returncode: {proc.returncode}")
|
print(f"returncode: {proc.returncode}")
|
||||||
print("--- END ---\n")
|
print("--- END ---\n")
|
||||||
|
|
||||||
if proc.returncode != 0:
|
# Important: this is **debug-only**. Do NOT fail the test here.
|
||||||
raise AssertionError(f"'pkgmgr --help' failed with exit code {proc.returncode}")
|
# If you ever want to hard-assert on this, you can add an explicit
|
||||||
|
# assertion in the test method instead of here.
|
||||||
# Wichtig: Hier KEIN AssertionError mehr – das ist reine Debug-Ausgabe.
|
|
||||||
# Falls du später hart testen willst, kannst du optional:
|
|
||||||
# if proc.returncode != 0:
|
|
||||||
# self.fail("...")
|
|
||||||
# aber aktuell nur Sichtprüfung.
|
|
||||||
|
|
||||||
|
|
||||||
class TestIntegrationInstalPKGMGRShallow(unittest.TestCase):
|
class TestIntegrationInstalPKGMGRShallow(unittest.TestCase):
|
||||||
def test_install_pkgmgr_self_install(self) -> None:
|
def test_install_pkgmgr_self_install(self) -> None:
|
||||||
# Debug before cleanup
|
"""
|
||||||
nix_profile_list_debug("BEFORE CLEANUP")
|
End-to-end test that runs "python main.py install pkgmgr ..." inside
|
||||||
|
the test container.
|
||||||
|
|
||||||
# Cleanup: aggressively try to drop any pkgmgr/profile entries
|
We isolate HOME into /tmp/pkgmgr-self-install so that:
|
||||||
remove_pkgmgr_from_nix_profile()
|
- ~/.config/pkgmgr points to an isolated test config area
|
||||||
|
- ~/Repositories is owned by the current user inside the container
|
||||||
# Debug after cleanup
|
(avoiding Nix's 'repository path is not owned by current user' error)
|
||||||
nix_profile_list_debug("AFTER CLEANUP")
|
"""
|
||||||
|
# Use a dedicated HOME for this test to avoid permission/ownership issues
|
||||||
|
temp_home = "/tmp/pkgmgr-self-install"
|
||||||
|
os.makedirs(temp_home, exist_ok=True)
|
||||||
|
|
||||||
original_argv = sys.argv
|
original_argv = sys.argv
|
||||||
|
original_environ = os.environ.copy()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Isolate HOME so that ~ expands to /tmp/pkgmgr-self-install
|
||||||
|
os.environ["HOME"] = temp_home
|
||||||
|
|
||||||
|
# Optional: ensure XDG_* also use the temp HOME for extra isolation
|
||||||
|
os.environ.setdefault("XDG_CONFIG_HOME", os.path.join(temp_home, ".config"))
|
||||||
|
os.environ.setdefault("XDG_CACHE_HOME", os.path.join(temp_home, ".cache"))
|
||||||
|
os.environ.setdefault("XDG_DATA_HOME", os.path.join(temp_home, ".local", "share"))
|
||||||
|
|
||||||
|
# Debug before cleanup
|
||||||
|
nix_profile_list_debug("BEFORE CLEANUP")
|
||||||
|
|
||||||
|
# Cleanup: aggressively try to drop any pkgmgr/profile entries
|
||||||
|
remove_pkgmgr_from_nix_profile()
|
||||||
|
|
||||||
|
# Debug after cleanup
|
||||||
|
nix_profile_list_debug("AFTER CLEANUP")
|
||||||
|
|
||||||
sys.argv = [
|
sys.argv = [
|
||||||
"python",
|
"python",
|
||||||
"install",
|
"install",
|
||||||
@@ -107,13 +125,18 @@ class TestIntegrationInstalPKGMGRShallow(unittest.TestCase):
|
|||||||
"shallow",
|
"shallow",
|
||||||
"--no-verification",
|
"--no-verification",
|
||||||
]
|
]
|
||||||
# Führt die Installation via main.py aus
|
|
||||||
|
# Run installation via main.py
|
||||||
runpy.run_module("main", run_name="__main__")
|
runpy.run_module("main", run_name="__main__")
|
||||||
|
|
||||||
# Nach erfolgreicher Installation: pkgmgr --help anzeigen (Debug)
|
# After successful installation: run `pkgmgr --help` for debug
|
||||||
pkgmgr_help_debug()
|
pkgmgr_help_debug()
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
sys.argv = original_argv
|
sys.argv = original_argv
|
||||||
|
# Restore full environment
|
||||||
|
os.environ.clear()
|
||||||
|
os.environ.update(original_environ)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
309
tests/unit/pkgmgr/actions/repos/test_pull_with_verification.py
Normal file
309
tests/unit/pkgmgr/actions/repos/test_pull_with_verification.py
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
import io
|
||||||
|
import unittest
|
||||||
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
|
from pkgmgr.actions.repository.pull import pull_with_verification
|
||||||
|
|
||||||
|
|
||||||
|
class TestPullWithVerification(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Comprehensive unit tests for pull_with_verification().
|
||||||
|
|
||||||
|
These tests verify:
|
||||||
|
- Preview mode behaviour
|
||||||
|
- Verification logic (prompting, bypassing, skipping)
|
||||||
|
- subprocess.run invocation
|
||||||
|
- Repository directory existence checks
|
||||||
|
- Handling of extra git pull arguments
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _setup_mocks(self, mock_exists, mock_get_repo_id, mock_get_repo_dir,
|
||||||
|
mock_verify, exists=True, verified_ok=True,
|
||||||
|
errors=None, verified_info=True):
|
||||||
|
"""Helper to configure repetitive mock behavior."""
|
||||||
|
repo = {
|
||||||
|
"name": "pkgmgr",
|
||||||
|
"verified": {"gpg_keys": ["ABCDEF"]} if verified_info else None,
|
||||||
|
}
|
||||||
|
mock_exists.return_value = exists
|
||||||
|
mock_get_repo_id.return_value = "pkgmgr"
|
||||||
|
mock_get_repo_dir.return_value = "/fake/base/pkgmgr"
|
||||||
|
mock_verify.return_value = (
|
||||||
|
verified_ok,
|
||||||
|
errors or [],
|
||||||
|
"deadbeef", # commit hash
|
||||||
|
"ABCDEF", # signing key
|
||||||
|
)
|
||||||
|
return repo
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
@patch("pkgmgr.actions.repository.pull.subprocess.run")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.verify_repository")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_dir")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_identifier")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.os.path.exists")
|
||||||
|
@patch("builtins.input")
|
||||||
|
def test_preview_mode_non_interactive(
|
||||||
|
self,
|
||||||
|
mock_input,
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
mock_subprocess,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Preview mode must NEVER request user input and must NEVER execute git.
|
||||||
|
It must only print the preview command.
|
||||||
|
"""
|
||||||
|
repo = self._setup_mocks(
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
exists=True,
|
||||||
|
verified_ok=False,
|
||||||
|
errors=["bad signature"],
|
||||||
|
verified_info=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
buf = io.StringIO()
|
||||||
|
with patch("sys.stdout", new=buf):
|
||||||
|
pull_with_verification(
|
||||||
|
selected_repos=[repo],
|
||||||
|
repositories_base_dir="/fake/base",
|
||||||
|
all_repos=[repo],
|
||||||
|
extra_args=["--ff-only"],
|
||||||
|
no_verification=False,
|
||||||
|
preview=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
output = buf.getvalue()
|
||||||
|
self.assertIn(
|
||||||
|
"[Preview] In '/fake/base/pkgmgr': git pull --ff-only",
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_input.assert_not_called()
|
||||||
|
mock_subprocess.assert_not_called()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
@patch("pkgmgr.actions.repository.pull.subprocess.run")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.verify_repository")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_dir")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_identifier")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.os.path.exists")
|
||||||
|
@patch("builtins.input")
|
||||||
|
def test_verification_failure_user_declines(
|
||||||
|
self,
|
||||||
|
mock_input,
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
mock_subprocess,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
If verification fails and preview=False, the user is prompted.
|
||||||
|
If the user declines ('n'), no git command is executed.
|
||||||
|
"""
|
||||||
|
repo = self._setup_mocks(
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
verified_ok=False,
|
||||||
|
errors=["signature invalid"],
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_input.return_value = "n"
|
||||||
|
|
||||||
|
buf = io.StringIO()
|
||||||
|
with patch("sys.stdout", new=buf):
|
||||||
|
pull_with_verification(
|
||||||
|
selected_repos=[repo],
|
||||||
|
repositories_base_dir="/fake/base",
|
||||||
|
all_repos=[repo],
|
||||||
|
extra_args=[],
|
||||||
|
no_verification=False,
|
||||||
|
preview=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_input.assert_called_once()
|
||||||
|
mock_subprocess.assert_not_called()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
@patch("pkgmgr.actions.repository.pull.subprocess.run")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.verify_repository")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_dir")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_identifier")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.os.path.exists")
|
||||||
|
@patch("builtins.input")
|
||||||
|
def test_verification_failure_user_accepts_runs_git(
|
||||||
|
self,
|
||||||
|
mock_input,
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
mock_subprocess,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
If verification fails and the user accepts ('y'),
|
||||||
|
then the git pull should be executed.
|
||||||
|
"""
|
||||||
|
repo = self._setup_mocks(
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
verified_ok=False,
|
||||||
|
errors=["invalid"],
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_input.return_value = "y"
|
||||||
|
mock_subprocess.return_value = MagicMock(returncode=0)
|
||||||
|
|
||||||
|
pull_with_verification(
|
||||||
|
selected_repos=[repo],
|
||||||
|
repositories_base_dir="/fake/base",
|
||||||
|
all_repos=[repo],
|
||||||
|
extra_args=[],
|
||||||
|
no_verification=False,
|
||||||
|
preview=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_subprocess.assert_called_once()
|
||||||
|
mock_input.assert_called_once()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
@patch("pkgmgr.actions.repository.pull.subprocess.run")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.verify_repository")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_dir")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_identifier")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.os.path.exists")
|
||||||
|
@patch("builtins.input")
|
||||||
|
def test_verification_success_no_prompt(
|
||||||
|
self,
|
||||||
|
mock_input,
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
mock_subprocess,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
If verification is successful, the user should NOT be prompted,
|
||||||
|
and git pull should run immediately.
|
||||||
|
"""
|
||||||
|
repo = self._setup_mocks(
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
verified_ok=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_subprocess.return_value = MagicMock(returncode=0)
|
||||||
|
|
||||||
|
pull_with_verification(
|
||||||
|
selected_repos=[repo],
|
||||||
|
repositories_base_dir="/fake/base",
|
||||||
|
all_repos=[repo],
|
||||||
|
extra_args=["--rebase"],
|
||||||
|
no_verification=False,
|
||||||
|
preview=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_input.assert_not_called()
|
||||||
|
mock_subprocess.assert_called_once()
|
||||||
|
cmd = mock_subprocess.call_args[0][0]
|
||||||
|
self.assertIn("git pull --rebase", cmd)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
@patch("pkgmgr.actions.repository.pull.subprocess.run")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.verify_repository")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_dir")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_identifier")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.os.path.exists")
|
||||||
|
@patch("builtins.input")
|
||||||
|
def test_directory_missing_skips_repo(
|
||||||
|
self,
|
||||||
|
mock_input,
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
mock_subprocess,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
If the repository directory does not exist, the repo must be skipped
|
||||||
|
silently and no git command executed.
|
||||||
|
"""
|
||||||
|
repo = self._setup_mocks(
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
exists=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
buf = io.StringIO()
|
||||||
|
with patch("sys.stdout", new=buf):
|
||||||
|
pull_with_verification(
|
||||||
|
selected_repos=[repo],
|
||||||
|
repositories_base_dir="/fake/base",
|
||||||
|
all_repos=[repo],
|
||||||
|
extra_args=[],
|
||||||
|
no_verification=False,
|
||||||
|
preview=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
output = buf.getvalue()
|
||||||
|
self.assertIn("not found", output)
|
||||||
|
|
||||||
|
mock_input.assert_not_called()
|
||||||
|
mock_subprocess.assert_not_called()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
@patch("pkgmgr.actions.repository.pull.subprocess.run")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.verify_repository")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_dir")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.get_repo_identifier")
|
||||||
|
@patch("pkgmgr.actions.repository.pull.os.path.exists")
|
||||||
|
@patch("builtins.input")
|
||||||
|
def test_no_verification_flag_skips_prompt(
|
||||||
|
self,
|
||||||
|
mock_input,
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
mock_subprocess,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
If no_verification=True, verification failures must NOT prompt.
|
||||||
|
Git pull should run directly.
|
||||||
|
"""
|
||||||
|
repo = self._setup_mocks(
|
||||||
|
mock_exists,
|
||||||
|
mock_get_repo_id,
|
||||||
|
mock_get_repo_dir,
|
||||||
|
mock_verify,
|
||||||
|
verified_ok=False,
|
||||||
|
errors=["invalid"],
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_subprocess.return_value = MagicMock(returncode=0)
|
||||||
|
|
||||||
|
pull_with_verification(
|
||||||
|
selected_repos=[repo],
|
||||||
|
repositories_base_dir="/fake/base",
|
||||||
|
all_repos=[repo],
|
||||||
|
extra_args=[],
|
||||||
|
no_verification=True,
|
||||||
|
preview=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_input.assert_not_called()
|
||||||
|
mock_subprocess.assert_called_once()
|
||||||
Reference in New Issue
Block a user