Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and Base versions are tracked in the repo-root `VERSION` file.

### Changed

- Suppressed pip self-upgrade notices during Base-managed pip installs so
setup output stays focused on Base actions and real install failures.
- Made live workflow docs and installer examples main-ready, using default-branch
URLs for raw GitHub install scripts and `main` for contributor branch
examples.
Expand Down
2 changes: 1 addition & 1 deletion cli/bash/commands/basectl/subcommands/setup_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ setup_install_base_python_package() {
python_bin="$(setup_base_venv_python_bin "$venv_dir")" || fatal_error "Base virtual environment Python was not found at '$venv_dir/bin/python'. $(setup_recovery_venv)"

log_info "Installing Python package '$package' in the Base virtual environment."
run "$python_bin" -m pip install "$package"
run "$python_bin" -m pip install --disable-pip-version-check "$package"
}

setup_install_pyyaml() {
Expand Down
39 changes: 37 additions & 2 deletions cli/bash/commands/basectl/tests/setup.bats
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" && "${4:-}" ==
[[ -f "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-installed" ]]
exit $?
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "$pyyaml_package" ]]; then
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "--disable-pip-version-check" && "${5:-}" == "$pyyaml_package" ]]; then
touch "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-install-ran"
touch "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-installed"
exit 0
Expand All @@ -70,7 +70,7 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" && "${4:-}" ==
[[ -f "${BASE_SETUP_TEST_STATE_DIR:?}/click-installed" ]]
exit $?
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "$click_package" ]]; then
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "--disable-pip-version-check" && "${5:-}" == "$click_package" ]]; then
touch "${BASE_SETUP_TEST_STATE_DIR:?}/click-install-ran"
touch "${BASE_SETUP_TEST_STATE_DIR:?}/click-installed"
exit 0
Expand Down Expand Up @@ -120,6 +120,41 @@ EOF
[[ "$(cat "$TEST_STATE_DIR/project-setup-python")" != *"$inherited_venv/bin/python"* ]]
}

@test "setup installs Base Python packages without pip self-version notices" {
local bash_libs_dir
local venv_dir="$TEST_HOME/.base.d/base/.venv"

bash_libs_dir="$(base_bash_libs_fixture_dir)"
mkdir -p "$venv_dir/bin"
: > "$venv_dir/pyvenv.cfg"
cat > "$venv_dir/bin/python" <<'EOF'
#!/usr/bin/env bash
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" ]]; then
exit 1
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" ]]; then
printf '%s\n' "$@" > "${BASE_SETUP_TEST_STATE_DIR:?}/pip-install-args"
exit 0
fi
printf 'unexpected venv python args: %s\n' "$*" >&2
exit 1
EOF
chmod +x "$venv_dir/bin/python"

run env \
HOME="$TEST_HOME" \
PATH="$TEST_MOCKBIN:$TEST_BASH_BIN_DIR:/usr/bin:/bin:/usr/sbin:/sbin" \
OSTYPE=darwin24 \
BASE_HOME="$BASE_REPO_ROOT" \
BASE_BASH_LIBS_DIR="$bash_libs_dir" \
BASE_SETUP_VENV_DIR="$venv_dir" \
BASE_SETUP_TEST_STATE_DIR="$TEST_STATE_DIR" \
bash -c 'source "$BASE_HOME/base_init.sh"; source "$BASE_HOME/cli/bash/commands/basectl/subcommands/setup_common.sh"; setup_install_base_python_package requests'

[ "$status" -eq 0 ]
grep -Fxq -- "--disable-pip-version-check" "$TEST_STATE_DIR/pip-install-args"
}

@test "basectl setup installs missing dependencies and creates the Base virtual environment" {
local installer
local venv_dir="$TEST_HOME/.base.d/base/.venv"
Expand Down
12 changes: 6 additions & 6 deletions cli/bash/commands/basectl/tests/setup_helpers.bash
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" && "${4:-}" ==
[[ -f "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-installed" ]]
exit $?
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "$pyyaml_package" ]]; then
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "--disable-pip-version-check" && "${5:-}" == "$pyyaml_package" ]]; then
touch "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-install-ran"
touch "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-installed"
exit 0
Expand All @@ -111,7 +111,7 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" && "${4:-}" ==
[[ -f "${BASE_SETUP_TEST_STATE_DIR:?}/click-installed" ]]
exit $?
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "$click_package" ]]; then
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "--disable-pip-version-check" && "${5:-}" == "$click_package" ]]; then
touch "${BASE_SETUP_TEST_STATE_DIR:?}/click-install-ran"
touch "${BASE_SETUP_TEST_STATE_DIR:?}/click-installed"
exit 0
Expand Down Expand Up @@ -198,7 +198,7 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" && "${4:-}" ==
[[ -f "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-installed" ]]
exit $?
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "$pyyaml_package" ]]; then
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "--disable-pip-version-check" && "${5:-}" == "$pyyaml_package" ]]; then
touch "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-install-ran"
touch "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-installed"
exit 0
Expand All @@ -207,7 +207,7 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" && "${4:-}" ==
[[ -f "${BASE_SETUP_TEST_STATE_DIR:?}/click-installed" ]]
exit $?
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "$click_package" ]]; then
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "--disable-pip-version-check" && "${5:-}" == "$click_package" ]]; then
touch "${BASE_SETUP_TEST_STATE_DIR:?}/click-install-ran"
touch "${BASE_SETUP_TEST_STATE_DIR:?}/click-installed"
exit 0
Expand Down Expand Up @@ -346,7 +346,7 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" && "${4:-}" ==
[[ -f "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-installed" ]]
exit $?
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "$pyyaml_package" ]]; then
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "--disable-pip-version-check" && "${5:-}" == "$pyyaml_package" ]]; then
touch "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-install-ran"
touch "${BASE_SETUP_TEST_STATE_DIR:?}/pyyaml-installed"
exit 0
Expand All @@ -355,7 +355,7 @@ if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "show" && "${4:-}" ==
[[ -f "${BASE_SETUP_TEST_STATE_DIR:?}/click-installed" ]]
exit $?
fi
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "$click_package" ]]; then
if [[ "${1:-}" == "-m" && "${2:-}" == "pip" && "${3:-}" == "install" && "${4:-}" == "--disable-pip-version-check" && "${5:-}" == "$click_package" ]]; then
touch "${BASE_SETUP_TEST_STATE_DIR:?}/click-install-ran"
touch "${BASE_SETUP_TEST_STATE_DIR:?}/click-installed"
exit 0
Expand Down
13 changes: 10 additions & 3 deletions cli/python/base_setup/artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import subprocess
import venv
from collections.abc import Iterable
from pathlib import Path

import base_cli
Expand All @@ -13,6 +14,8 @@
from .manifest import ArtifactRequest
from .registry import ArtifactDefinition, get_artifact_definition

PIP_INSTALL_COMMAND_PREFIX = ("-m", "pip", "install", "--disable-pip-version-check")


def homebrew_no_auto_update_env() -> dict[str, str]:
env = os.environ.copy()
Expand Down Expand Up @@ -309,7 +312,7 @@ def reconcile_python_artifacts(
if dry_run:
if not python_bin.exists():
ctx.log.info("[DRY-RUN] Would create project virtual environment at '%s'.", venv_dir)
process.dry_run_command(ctx, [str(python_bin), "-m", "pip", "install", *requirements])
process.dry_run_command(ctx, pip_install_command(python_bin, requirements))
return

if not python_bin.exists():
Expand All @@ -318,7 +321,7 @@ def reconcile_python_artifacts(

names = ", ".join(definition.name for definition, _version, _requirement in missing)
ctx.log.info("Installing Python artifacts into project virtual environment: %s.", names)
command = [str(python_bin), "-m", "pip", "install", *requirements]
command = pip_install_command(python_bin, requirements)
try:
process.run_command(ctx, command)
except ArtifactError as exc:
Expand All @@ -342,13 +345,17 @@ def reconcile_python_artifacts_sequential(
)
continue
ctx.log.info("Installing Python artifact '%s' into project virtual environment.", definition.name)
process.run_command(ctx, [str(python_bin), "-m", "pip", "install", requirement])
process.run_command(ctx, pip_install_command(python_bin, (requirement,)))


def python_requirement(definition: ArtifactDefinition, version: str) -> str:
return f"{definition.package}=={version}" if version != "latest" else definition.package


def pip_install_command(python_bin: Path, requirements: Iterable[str]) -> list[str]:
return [str(python_bin), *PIP_INSTALL_COMMAND_PREFIX, *requirements]


def project_venv_dir(project: str) -> Path:
override = os.environ.get("BASE_PROJECT_VENV_DIR")
if override:
Expand Down
53 changes: 46 additions & 7 deletions cli/python/base_setup/tests/test_artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def test_unknown_python_package_artifact_dry_run_uses_pip(self) -> None:
status, _stdout, stderr = run_engine(["--dry-run", "--manifest", str(manifest_path)])

self.assertEqual(status, 0)
self.assertIn("pip install click==8.4.1 PyYAML==6.0.3 rich", stderr)
self.assertIn("pip install --disable-pip-version-check 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:
Expand Down Expand Up @@ -217,7 +217,7 @@ def test_dry_run_ignores_inherited_project_runtime_environment(self) -> None:

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)
self.assertIn("pip install --disable-pip-version-check 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:
Expand Down Expand Up @@ -392,7 +392,7 @@ def test_python_artifact_honors_project_venv_dir_override(self) -> None:
info_messages,
)
self.assertIn(
f"[DRY-RUN] Would run: {venv_dir}/bin/python -m pip install requests",
f"[DRY-RUN] Would run: {venv_dir}/bin/python -m pip install --disable-pip-version-check requests",
info_messages,
)

Expand Down Expand Up @@ -444,7 +444,15 @@ def test_reconcile_artifacts_batches_python_installs(self) -> None:

run_command.assert_called_once_with(
ctx,
[str(python_bin), "-m", "pip", "install", "click==8.4.1", "requests"],
[
str(python_bin),
"-m",
"pip",
"install",
"--disable-pip-version-check",
"click==8.4.1",
"requests",
],
)

def test_reconcile_artifacts_retries_python_installs_sequentially_after_batch_failure(self) -> None:
Expand Down Expand Up @@ -480,9 +488,40 @@ def test_reconcile_artifacts_retries_python_installs_sequentially_after_batch_fa
self.assertEqual(
run_command.call_args_list,
[
mock.call(ctx, [str(python_bin), "-m", "pip", "install", "click==8.4.1", "requests"]),
mock.call(ctx, [str(python_bin), "-m", "pip", "install", "click==8.4.1"]),
mock.call(ctx, [str(python_bin), "-m", "pip", "install", "requests"]),
mock.call(
ctx,
[
str(python_bin),
"-m",
"pip",
"install",
"--disable-pip-version-check",
"click==8.4.1",
"requests",
],
),
mock.call(
ctx,
[
str(python_bin),
"-m",
"pip",
"install",
"--disable-pip-version-check",
"click==8.4.1",
],
),
mock.call(
ctx,
[
str(python_bin),
"-m",
"pip",
"install",
"--disable-pip-version-check",
"requests",
],
),
],
)
ctx.log.warning.assert_called_once_with(
Expand Down
Loading