diff --git a/bin/base-test b/bin/base-test index 0aafb8d..b7dd86a 100755 --- a/bin/base-test +++ b/bin/base-test @@ -3,16 +3,47 @@ set -euo pipefail base_test_python="${BASE_TEST_PYTHON:-$HOME/.base.d/base/.venv/bin/python}" +base_test_home="${BASE_HOME:-$(pwd)}" +base_test_unset_env=( + -u BASE_HOME + -u BASE_BIN_DIR + -u BASE_CLI_DIR + -u BASE_BASH_DIR + -u BASE_BASH_COMMANDS_DIR + -u BASE_LIB_DIR + -u BASE_BASH_LIB_DIR + -u BASE_SHELL_DIR + -u BASE_OS + -u BASE_HOST + -u BASE_SHELL + -u BASE_PLATFORM_TOOLS_HOME + -u BASE_PLATFORM_TOOLS_BIN_DIR + -u BASE_PROFILE_VERSION + -u BASE_ENABLE_BASH_DEFAULTS + -u BASE_ENABLE_ZSH_DEFAULTS + -u BASE_DEBUG + -u BASE_BASH_COMMAND_NAME + -u BASE_BASH_COMMAND_DIR + -u BASE_BASH_COMMAND_SCRIPT + -u BASE_BASH_BOOTSTRAP_SOURCE + -u BASE_PROJECT + -u BASE_PROJECT_ROOT + -u BASE_PROJECT_MANIFEST + -u BASE_PROJECT_VENV_DIR + -u VIRTUAL_ENV +) if [[ ! -x "$base_test_python" ]]; then printf 'ERROR: Base test Python was not found at %s. Run basectl setup base first.\n' "$base_test_python" >&2 exit 1 fi -PYTHONPATH="${BASE_HOME:-$(pwd)}/lib/python:${BASE_HOME:-$(pwd)}/cli/python${PYTHONPATH:+:$PYTHONPATH}" \ +env "${base_test_unset_env[@]}" \ + PYTHONPATH="$base_test_home/lib/python:$base_test_home/cli/python${PYTHONPATH:+:$PYTHONPATH}" \ "$base_test_python" -m pytest -bats \ +env "${base_test_unset_env[@]}" \ + bats \ cli/bash/commands/basectl/tests/*.bats \ lib/bash/file/tests/lib_file.bats \ lib/bash/git/tests/lib_git.bats \ diff --git a/cli/bash/commands/basectl/subcommands/setup_common.sh b/cli/bash/commands/basectl/subcommands/setup_common.sh index 4f64e79..cdebb9f 100644 --- a/cli/bash/commands/basectl/subcommands/setup_common.sh +++ b/cli/bash/commands/basectl/subcommands/setup_common.sh @@ -524,14 +524,15 @@ setup_install_xcode_tools() { } setup_python_installed() { - local formula + local brew_bin formula formula="$(setup_python_formula)" - command -v brew >/dev/null 2>&1 && brew list "$formula" >/dev/null 2>&1 + brew_bin="$(setup_find_brew_bin)" || return 1 + "$brew_bin" list "$formula" >/dev/null 2>&1 } setup_install_python() { - local formula + local brew_bin formula formula="$(setup_python_formula)" @@ -545,14 +546,14 @@ setup_install_python() { return 0 fi - command -v brew >/dev/null 2>&1 || fatal_error "Homebrew is required to install Python formula '$formula'. $(setup_recovery_homebrew)" + brew_bin="$(setup_find_brew_bin)" || fatal_error "Homebrew is required to install Python formula '$formula'. $(setup_recovery_homebrew)" log_info "Installing Python formula '$formula' via Homebrew." - run brew install "$formula" + run "$brew_bin" install "$formula" } setup_find_python_bin() { - local formula prefix candidate + local brew_bin formula prefix candidate local candidates=() if [[ -n "${BASE_SETUP_PYTHON_BIN:-}" ]]; then @@ -574,8 +575,8 @@ setup_find_python_bin() { done candidates=() - if command -v brew >/dev/null 2>&1; then - prefix="$(brew --prefix "$formula" 2>/dev/null || true)" + if brew_bin="$(setup_find_brew_bin)"; then + prefix="$("$brew_bin" --prefix "$formula" 2>/dev/null || true)" if [[ -n "$prefix" ]]; then candidates+=("$prefix/bin/python3") candidates+=("$prefix/libexec/bin/python3") diff --git a/cli/bash/commands/basectl/tests/runtime-shell.bats b/cli/bash/commands/basectl/tests/runtime-shell.bats index 971b44a..770b76d 100644 --- a/cli/bash/commands/basectl/tests/runtime-shell.bats +++ b/cli/bash/commands/basectl/tests/runtime-shell.bats @@ -46,7 +46,13 @@ EOF @test "Base runtime shell activates project virtual environment" { local project_root="$TEST_TMPDIR/demo" local venv_dir="$TEST_TMPDIR/demo-venv" + local path_with_platform + local path_without_platform + local workspace_root + workspace_root="$(cd "$BASE_REPO_ROOT/.." && pwd -P)" + path_without_platform="PATH=$venv_dir/bin:$BASE_REPO_ROOT/bin:$project_root/bin:" + path_with_platform="PATH=$venv_dir/bin:$BASE_REPO_ROOT/bin:$workspace_root/base-platform-tools/bin:$project_root/bin:" mkdir -p "$project_root/bin" "$venv_dir/bin" cat > "$venv_dir/bin/activate" <<'EOF' VIRTUAL_ENV="$BASE_PROJECT_VENV_DIR" @@ -70,7 +76,7 @@ EOF [ "$status" -eq 0 ] [[ "$output" == *"BASE_PROJECT=demo"* ]] [[ "$output" == *"VIRTUAL_ENV=$venv_dir"* ]] - [[ "$output" == *"PATH=$venv_dir/bin:$BASE_REPO_ROOT/bin:$project_root/bin:"* ]] + [[ "$output" == *"$path_without_platform"* || "$output" == *"$path_with_platform"* ]] [[ "$output" == *'PS1=\T ${_BASE_RUNTIME_HOST_PROMPT:-unknown} ${BASE_PROJECT:+[$BASE_PROJECT] }$(_base_runtime_venv_prompt)$(_base_runtime_git_prompt)\w: '* ]] } diff --git a/cli/bash/commands/basectl/tests/update-profile.bats b/cli/bash/commands/basectl/tests/update-profile.bats index c030260..33693d9 100644 --- a/cli/bash/commands/basectl/tests/update-profile.bats +++ b/cli/bash/commands/basectl/tests/update-profile.bats @@ -170,6 +170,12 @@ EOF } @test "BASE_DEBUG traces Base-managed Bash startup" { + local base_only_trace + local platform_tools_trace + + base_only_trace="BASE_DEBUG bashrc: prepended '$BASE_REPO_ROOT/bin' to PATH" + platform_tools_trace="BASE_DEBUG bashrc: configured PATH with '$BASE_REPO_ROOT/bin' and " + run_base_command update-profile [ "$status" -eq 0 ] @@ -182,7 +188,7 @@ EOF [ "$status" -eq 0 ] [[ "$output" == *"BASE_DEBUG bashrc: loading"* ]] [[ "$output" == *"BASE_DEBUG bashrc: BASE_HOME=$BASE_REPO_ROOT"* ]] - [[ "$output" == *"BASE_DEBUG bashrc: prepended '$BASE_REPO_ROOT/bin' to PATH"* ]] + [[ "$output" == *"$base_only_trace"* || "$output" == *"$platform_tools_trace"* ]] [[ "$output" == *"BASE_DEBUG bashrc: complete"* ]] } diff --git a/cli/python/base_setup/tests/helpers.py b/cli/python/base_setup/tests/helpers.py index 992afbc..dd36e97 100644 --- a/cli/python/base_setup/tests/helpers.py +++ b/cli/python/base_setup/tests/helpers.py @@ -10,6 +10,14 @@ from base_setup.engine import main +PROJECT_RUNTIME_ENV_VARS = ( + "BASE_PROJECT", + "BASE_PROJECT_ROOT", + "BASE_PROJECT_MANIFEST", + "BASE_PROJECT_VENV_DIR", +) + + def run_engine(args: list[str]) -> tuple[int, str, str]: stdout = io.StringIO() stderr = io.StringIO() @@ -18,6 +26,8 @@ def run_engine(args: list[str]) -> tuple[int, str, str]: os.environ, {"HOME": home_dir, "BASE_HOME": str(Path(__file__).resolve().parents[4])}, ): + for name in PROJECT_RUNTIME_ENV_VARS: + os.environ.pop(name, None) with redirect_stdout(stdout), redirect_stderr(stderr): status = main(args) return status, stdout.getvalue(), stderr.getvalue() diff --git a/cli/python/base_setup/tests/test_artifacts.py b/cli/python/base_setup/tests/test_artifacts.py index fff91f7..8334e60 100644 --- a/cli/python/base_setup/tests/test_artifacts.py +++ b/cli/python/base_setup/tests/test_artifacts.py @@ -158,7 +158,41 @@ def test_unknown_python_package_artifact_dry_run_uses_pip(self) -> None: self.assertEqual(status, 0) self.assertIn("pip install click==8.4.1 PyYAML==6.0.3 rich", stderr) + @unittest.skipUnless(importlib.util.find_spec("click"), "Click is not installed") + def test_dry_run_ignores_inherited_project_runtime_environment(self) -> None: + with tempfile.TemporaryDirectory() as tmpdir: + repo_root = Path(__file__).resolve().parents[4] + inherited_venv_dir = Path(tmpdir) / "inherited-base-venv" + manifest_path = Path(tmpdir) / "base_manifest.yaml" + manifest_path.write_text( + "\n".join( + [ + "project:", + " name: demo", + "", + "artifacts:", + " - type: python-package", + " name: rich", + " version: latest", + ] + ), + encoding="utf-8", + ) + with mock.patch.dict( + os.environ, + { + "BASE_PROJECT": "base", + "BASE_PROJECT_ROOT": str(repo_root), + "BASE_PROJECT_MANIFEST": str(repo_root / "base_manifest.yaml"), + "BASE_PROJECT_VENV_DIR": str(inherited_venv_dir), + }, + ): + status, _stdout, stderr = run_engine(["--dry-run", "--manifest", str(manifest_path)]) + + self.assertEqual(status, 0) + self.assertNotIn(str(inherited_venv_dir), stderr) + self.assertIn("pip install click==8.4.1 PyYAML==6.0.3 rich", stderr) @unittest.skipUnless(importlib.util.find_spec("click"), "Click is not installed") def test_known_homebrew_artifact_dry_run_does_not_require_brew(self) -> None: diff --git a/lib/bash/tests/test_helper.sh b/lib/bash/tests/test_helper.sh index 62fb0f2..b3f8608 100644 --- a/lib/bash/tests/test_helper.sh +++ b/lib/bash/tests/test_helper.sh @@ -12,7 +12,42 @@ readonly BASE_REPO_ROOT="$(cd "$BASE_BASH_DIR/../.." && pwd -P)" readonly BASE_CLI_BASH_DIR="$BASE_REPO_ROOT/cli/bash" readonly BASE_TEST_ORIG_PATH="$PATH" +unset_base_runtime_env() { + local var_name + + for var_name in \ + BASE_HOME \ + BASE_BIN_DIR \ + BASE_CLI_DIR \ + BASE_BASH_DIR \ + BASE_BASH_COMMANDS_DIR \ + BASE_LIB_DIR \ + BASE_BASH_LIB_DIR \ + BASE_SHELL_DIR \ + BASE_OS \ + BASE_HOST \ + BASE_SHELL \ + BASE_PLATFORM_TOOLS_HOME \ + BASE_PLATFORM_TOOLS_BIN_DIR \ + BASE_PROFILE_VERSION \ + BASE_ENABLE_BASH_DEFAULTS \ + BASE_ENABLE_ZSH_DEFAULTS \ + BASE_DEBUG \ + BASE_BASH_COMMAND_NAME \ + BASE_BASH_COMMAND_DIR \ + BASE_BASH_COMMAND_SCRIPT \ + BASE_BASH_BOOTSTRAP_SOURCE \ + BASE_PROJECT \ + BASE_PROJECT_ROOT \ + BASE_PROJECT_MANIFEST \ + BASE_PROJECT_VENV_DIR \ + VIRTUAL_ENV; do + unset "$var_name" 2>/dev/null || true + done +} + setup_test_tmpdir() { + unset_base_runtime_env TEST_TMPDIR="${BATS_TEST_TMPDIR}/workspace" mkdir -p "$TEST_TMPDIR" }