diff --git a/.github/actions/install-llama-stack-client/action.yml b/.github/actions/install-llama-stack-client/action.yml index 553d82f01..3c1c77d9c 100644 --- a/.github/actions/install-llama-stack-client/action.yml +++ b/.github/actions/install-llama-stack-client/action.yml @@ -8,9 +8,6 @@ inputs: default: "" outputs: - uv-index-url: - description: 'UV_INDEX_URL to use (set for release branches)' - value: ${{ steps.configure.outputs.uv-index-url }} uv-extra-index-url: description: 'UV_EXTRA_INDEX_URL to use (set for release branches)' value: ${{ steps.configure.outputs.uv-extra-index-url }} @@ -46,9 +43,8 @@ runs: exit 1 fi - # Configure to use test.pypi for sync (to resolve RC versions) - echo "uv-index-url=https://test.pypi.org/simple/" >> $GITHUB_OUTPUT - echo "uv-extra-index-url=https://pypi.org/simple/" >> $GITHUB_OUTPUT + # Configure to use test.pypi as extra index (PyPI is primary) + echo "uv-extra-index-url=https://test.pypi.org/simple/" >> $GITHUB_OUTPUT echo "install-after-sync=true" >> $GITHUB_OUTPUT echo "install-source=git+https://github.com/llamastack/llama-stack-client-python.git@$BRANCH" >> $GITHUB_OUTPUT elif [ "${{ inputs.client-version }}" = "latest" ]; then diff --git a/.github/actions/setup-runner/action.yml b/.github/actions/setup-runner/action.yml index 52a3c4643..8e357fb96 100644 --- a/.github/actions/setup-runner/action.yml +++ b/.github/actions/setup-runner/action.yml @@ -27,9 +27,16 @@ runs: - name: Install dependencies shell: bash env: - UV_INDEX_URL: ${{ steps.client-config.outputs.uv-index-url }} UV_EXTRA_INDEX_URL: ${{ steps.client-config.outputs.uv-extra-index-url }} + UV_INDEX_STRATEGY: ${{ steps.client-config.outputs.uv-extra-index-url && 'unsafe-best-match' || '' }} run: | + # Export UV env vars to GITHUB_ENV so they persist across steps + if [ -n "$UV_EXTRA_INDEX_URL" ]; then + echo "UV_EXTRA_INDEX_URL=$UV_EXTRA_INDEX_URL" >> $GITHUB_ENV + echo "UV_INDEX_STRATEGY=$UV_INDEX_STRATEGY" >> $GITHUB_ENV + echo "Exported UV environment variables for subsequent steps" + fi + echo "Updating project dependencies via uv sync" uv sync --all-groups diff --git a/.github/workflows/install-script-ci.yml b/.github/workflows/install-script-ci.yml index 82aa56482..bbdaefb50 100644 --- a/.github/workflows/install-script-ci.yml +++ b/.github/workflows/install-script-ci.yml @@ -30,10 +30,16 @@ jobs: - name: Build a single provider run: | + BUILD_ARGS="--build-arg INSTALL_MODE=editable --build-arg DISTRO_NAME=starter" + if [ -n "${UV_EXTRA_INDEX_URL:-}" ]; then + BUILD_ARGS="$BUILD_ARGS --build-arg UV_EXTRA_INDEX_URL=$UV_EXTRA_INDEX_URL" + fi + if [ -n "${UV_INDEX_STRATEGY:-}" ]; then + BUILD_ARGS="$BUILD_ARGS --build-arg UV_INDEX_STRATEGY=$UV_INDEX_STRATEGY" + fi docker build . \ -f containers/Containerfile \ - --build-arg INSTALL_MODE=editable \ - --build-arg DISTRO_NAME=starter \ + $BUILD_ARGS \ --tag llama-stack:starter-ci - name: Run installer end-to-end diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 6d9f358d2..012a99894 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -43,43 +43,25 @@ jobs: with: node-version: '20' cache: 'npm' - cache-dependency-path: 'src/llama_stack/ui/' - - - name: Set up uv - uses: astral-sh/setup-uv@2ddd2b9cb38ad8efd50337e8ab201519a34c9f24 # v7.1.1 + cache-dependency-path: 'llama_stack/ui/' - name: Install npm dependencies run: npm ci - working-directory: src/llama_stack/ui - - - name: Install pre-commit - run: python -m pip install pre-commit - - - name: Cache pre-commit - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: ~/.cache/pre-commit - key: pre-commit-3|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }} + working-directory: llama_stack/ui - name: Run pre-commit id: precommit - run: | - set +e - pre-commit run --show-diff-on-failure --color=always --all-files 2>&1 | tee /tmp/precommit.log - status=${PIPESTATUS[0]} - echo "status=$status" >> $GITHUB_OUTPUT - exit 0 + uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 + continue-on-error: true env: - SKIP: no-commit-to-branch,mypy + SKIP: no-commit-to-branch RUFF_OUTPUT_FORMAT: github - name: Check pre-commit results - if: steps.precommit.outputs.status != '0' + if: steps.precommit.outcome == 'failure' run: | echo "::error::Pre-commit hooks failed. Please run 'pre-commit run --all-files' locally and commit the fixes." - echo "" - echo "Failed hooks output:" - cat /tmp/precommit.log + echo "::warning::Some pre-commit hooks failed. Check the output above for details." exit 1 - name: Debug @@ -130,16 +112,31 @@ jobs: exit 1 fi + - name: Install uv for mypy + uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 + with: + python-version: "3.12" + version: 0.7.6 + - name: Configure client installation id: client-config uses: ./.github/actions/install-llama-stack-client - - name: Sync dev + type_checking dependencies + - name: Sync dev dependencies for mypy env: - UV_INDEX_URL: ${{ steps.client-config.outputs.uv-index-url }} UV_EXTRA_INDEX_URL: ${{ steps.client-config.outputs.uv-extra-index-url }} + UV_INDEX_STRATEGY: ${{ steps.client-config.outputs.uv-extra-index-url && 'unsafe-best-match' || '' }} run: | - uv sync --group dev --group type_checking + # Check if type_checking group exists, otherwise just use dev + if grep -q "type.checking" pyproject.toml; then + echo "Found type_checking group, syncing with both groups" + uv sync --group dev --group type_checking + MYPY_CMD="uv run --group dev --group type_checking mypy" + else + echo "No type_checking group found, syncing with dev only" + uv sync --group dev + MYPY_CMD="uv run --group dev mypy" + fi # Install specific client version after sync if needed if [ "${{ steps.client-config.outputs.install-after-sync }}" = "true" ]; then @@ -147,11 +144,24 @@ jobs: uv pip install ${{ steps.client-config.outputs.install-source }} fi - - name: Run mypy (full type_checking) + echo "MYPY_CMD=$MYPY_CMD" >> $GITHUB_ENV + + - name: Run mypy (full type checking) + env: + UV_EXTRA_INDEX_URL: ${{ steps.client-config.outputs.uv-extra-index-url }} + UV_INDEX_STRATEGY: ${{ steps.client-config.outputs.uv-extra-index-url && 'unsafe-best-match' || '' }} run: | set +e - uv run --group dev --group type_checking mypy + output=$($MYPY_CMD 2>&1) status=$? + + # If mypy isn't available (common on older release branches), skip gracefully + if echo "$output" | grep -q "Failed to spawn.*mypy"; then + echo "::warning::mypy not available, skipping type checking (expected on release-0.3.x)" + exit 0 + fi + + echo "$output" if [ $status -ne 0 ]; then echo "::error::Full mypy failed. Reproduce locally with 'uv run pre-commit run mypy-full --hook-stage manual --all-files'." fi diff --git a/.github/workflows/providers-build.yml b/.github/workflows/providers-build.yml index 2b2ca6330..68b745da5 100644 --- a/.github/workflows/providers-build.yml +++ b/.github/workflows/providers-build.yml @@ -7,24 +7,24 @@ on: branches: - main paths: - - 'src/llama_stack/cli/stack/build.py' - - 'src/llama_stack/cli/stack/_build.py' - - 'src/llama_stack/core/build.*' - - 'src/llama_stack/core/*.sh' + - 'llama_stack/cli/stack/build.py' + - 'llama_stack/cli/stack/_build.py' + - 'llama_stack/core/build.*' + - 'llama_stack/core/*.sh' - '.github/workflows/providers-build.yml' - - 'src/llama_stack/distributions/**' + - 'llama_stack/distributions/**' - 'pyproject.toml' - 'containers/Containerfile' - '.dockerignore' pull_request: paths: - - 'src/llama_stack/cli/stack/build.py' - - 'src/llama_stack/cli/stack/_build.py' - - 'src/llama_stack/core/build.*' - - 'src/llama_stack/core/*.sh' + - 'llama_stack/cli/stack/build.py' + - 'llama_stack/cli/stack/_build.py' + - 'llama_stack/core/build.*' + - 'llama_stack/core/*.sh' - '.github/workflows/providers-build.yml' - - 'src/llama_stack/distributions/**' + - 'llama_stack/distributions/**' - 'pyproject.toml' - 'containers/Containerfile' - '.dockerignore' @@ -45,7 +45,7 @@ jobs: - name: Generate Distribution List id: set-matrix run: | - distros=$(ls src/llama_stack/distributions/*/*build.yaml | awk -F'/' '{print $(NF-1)}' | jq -R -s -c 'split("\n")[:-1]') + distros=$(ls llama_stack/distributions/*/*build.yaml | awk -F'/' '{print $(NF-1)}' | jq -R -s -c 'split("\n")[:-1]') echo "distros=$distros" >> "$GITHUB_OUTPUT" build: @@ -72,10 +72,16 @@ jobs: - name: Build container image if: matrix.image-type == 'container' run: | + BUILD_ARGS="--build-arg INSTALL_MODE=editable --build-arg DISTRO_NAME=${{ matrix.distro }}" + if [ -n "${UV_EXTRA_INDEX_URL:-}" ]; then + BUILD_ARGS="$BUILD_ARGS --build-arg UV_EXTRA_INDEX_URL=$UV_EXTRA_INDEX_URL" + fi + if [ -n "${UV_INDEX_STRATEGY:-}" ]; then + BUILD_ARGS="$BUILD_ARGS --build-arg UV_INDEX_STRATEGY=$UV_INDEX_STRATEGY" + fi docker build . \ -f containers/Containerfile \ - --build-arg INSTALL_MODE=editable \ - --build-arg DISTRO_NAME=${{ matrix.distro }} \ + $BUILD_ARGS \ --tag llama-stack:${{ matrix.distro }}-ci - name: Print dependencies in the image @@ -107,13 +113,19 @@ jobs: - name: Build container image run: | - BASE_IMAGE=$(yq -r '.distribution_spec.container_image // "python:3.12-slim"' src/llama_stack/distributions/ci-tests/build.yaml) + BASE_IMAGE=$(yq -r '.distribution_spec.container_image // "python:3.12-slim"' llama_stack/distributions/ci-tests/build.yaml) + BUILD_ARGS="--build-arg INSTALL_MODE=editable --build-arg DISTRO_NAME=ci-tests" + BUILD_ARGS="$BUILD_ARGS --build-arg BASE_IMAGE=$BASE_IMAGE" + BUILD_ARGS="$BUILD_ARGS --build-arg RUN_CONFIG_PATH=/workspace/llama_stack/distributions/ci-tests/run.yaml" + if [ -n "${UV_EXTRA_INDEX_URL:-}" ]; then + BUILD_ARGS="$BUILD_ARGS --build-arg UV_EXTRA_INDEX_URL=$UV_EXTRA_INDEX_URL" + fi + if [ -n "${UV_INDEX_STRATEGY:-}" ]; then + BUILD_ARGS="$BUILD_ARGS --build-arg UV_INDEX_STRATEGY=$UV_INDEX_STRATEGY" + fi docker build . \ -f containers/Containerfile \ - --build-arg INSTALL_MODE=editable \ - --build-arg DISTRO_NAME=ci-tests \ - --build-arg BASE_IMAGE="$BASE_IMAGE" \ - --build-arg RUN_CONFIG_PATH=/workspace/src/llama_stack/distributions/ci-tests/run.yaml \ + $BUILD_ARGS \ -t llama-stack:ci-tests - name: Inspect the container image entrypoint @@ -143,17 +155,23 @@ jobs: run: | yq -i ' .distribution_spec.container_image = "registry.access.redhat.com/ubi9:latest" - ' src/llama_stack/distributions/ci-tests/build.yaml + ' llama_stack/distributions/ci-tests/build.yaml - name: Build UBI9 container image run: | - BASE_IMAGE=$(yq -r '.distribution_spec.container_image // "registry.access.redhat.com/ubi9:latest"' src/llama_stack/distributions/ci-tests/build.yaml) + BASE_IMAGE=$(yq -r '.distribution_spec.container_image // "registry.access.redhat.com/ubi9:latest"' llama_stack/distributions/ci-tests/build.yaml) + BUILD_ARGS="--build-arg INSTALL_MODE=editable --build-arg DISTRO_NAME=ci-tests" + BUILD_ARGS="$BUILD_ARGS --build-arg BASE_IMAGE=$BASE_IMAGE" + BUILD_ARGS="$BUILD_ARGS --build-arg RUN_CONFIG_PATH=/workspace/llama_stack/distributions/ci-tests/run.yaml" + if [ -n "${UV_EXTRA_INDEX_URL:-}" ]; then + BUILD_ARGS="$BUILD_ARGS --build-arg UV_EXTRA_INDEX_URL=$UV_EXTRA_INDEX_URL" + fi + if [ -n "${UV_INDEX_STRATEGY:-}" ]; then + BUILD_ARGS="$BUILD_ARGS --build-arg UV_INDEX_STRATEGY=$UV_INDEX_STRATEGY" + fi docker build . \ -f containers/Containerfile \ - --build-arg INSTALL_MODE=editable \ - --build-arg DISTRO_NAME=ci-tests \ - --build-arg BASE_IMAGE="$BASE_IMAGE" \ - --build-arg RUN_CONFIG_PATH=/workspace/src/llama_stack/distributions/ci-tests/run.yaml \ + $BUILD_ARGS \ -t llama-stack:ci-tests-ubi9 - name: Inspect UBI9 image diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9990b6342..fe9f0c2b0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,7 +42,7 @@ repos: hooks: - id: ruff args: [ --fix ] - exclude: ^src/llama_stack/strong_typing/.*$ + exclude: ^llama_stack/strong_typing/.*$ - id: ruff-format - repo: https://github.com/adamchainz/blacken-docs @@ -52,33 +52,20 @@ repos: additional_dependencies: - black==24.3.0 -- repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.7.20 - hooks: - - id: uv-lock - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.18.2 + rev: v1.16.1 hooks: - id: mypy additional_dependencies: - uv==0.6.2 + - mypy - pytest - rich - types-requests - pydantic - - httpx pass_filenames: false -- repo: local - hooks: - - id: mypy-full - name: mypy (full type_checking) - entry: uv run --group dev --group type_checking mypy - language: system - pass_filenames: false - stages: [manual] - # - repo: https://github.com/tcort/markdown-link-check # rev: v3.11.2 # hooks: @@ -87,33 +74,42 @@ repos: - repo: local hooks: + - id: uv-lock + name: uv-lock + additional_dependencies: + - uv==0.7.20 + entry: ./scripts/uv-run-with-index.sh lock + language: python + pass_filenames: false + require_serial: true + files: ^(pyproject\.toml|uv\.lock)$ - id: distro-codegen name: Distribution Template Codegen additional_dependencies: - uv==0.7.8 - entry: uv run --group codegen ./scripts/distro_codegen.py + entry: ./scripts/uv-run-with-index.sh run --group codegen ./scripts/distro_codegen.py language: python pass_filenames: false require_serial: true - files: ^src/llama_stack/distributions/.*$|^src/llama_stack/providers/.*/inference/.*/models\.py$ + files: ^llama_stack/distributions/.*$|^llama_stack/providers/.*/inference/.*/models\.py$ - id: provider-codegen name: Provider Codegen additional_dependencies: - uv==0.7.8 - entry: uv run --group codegen ./scripts/provider_codegen.py + entry: ./scripts/uv-run-with-index.sh run --group codegen ./scripts/provider_codegen.py language: python pass_filenames: false require_serial: true - files: ^src/llama_stack/providers/.*$ + files: ^llama_stack/providers/.*$ - id: openapi-codegen name: API Spec Codegen additional_dependencies: - uv==0.7.8 - entry: sh -c 'uv run ./docs/openapi_generator/run_openapi_generator.sh > /dev/null' + entry: sh -c './scripts/uv-run-with-index.sh run ./docs/openapi_generator/run_openapi_generator.sh > /dev/null' language: python pass_filenames: false require_serial: true - files: ^src/llama_stack/apis/|^docs/openapi_generator/ + files: ^llama_stack/apis/|^docs/openapi_generator/ - id: check-workflows-use-hashes name: Check GitHub Actions use SHA-pinned actions entry: ./scripts/check-workflows-use-hashes.sh @@ -129,7 +125,7 @@ repos: pass_filenames: false require_serial: true always_run: true - files: ^src/llama_stack/.*$ + files: ^llama_stack/.*$ - id: forbid-pytest-asyncio name: Block @pytest.mark.asyncio and @pytest_asyncio.fixture entry: bash @@ -150,7 +146,7 @@ repos: name: Generate CI documentation additional_dependencies: - uv==0.7.8 - entry: uv run ./scripts/gen-ci-docs.py + entry: ./scripts/uv-run-with-index.sh run ./scripts/gen-ci-docs.py language: python pass_filenames: false require_serial: true @@ -159,9 +155,10 @@ repos: name: Format & Lint UI entry: bash ./scripts/run-ui-linter.sh language: system - files: ^src/llama_stack/ui/.*\.(ts|tsx)$ + files: ^llama_stack/ui/.*\.(ts|tsx)$ pass_filenames: false require_serial: true + - id: check-log-usage name: Ensure 'llama_stack.log' usage for logging entry: bash @@ -180,23 +177,7 @@ repos: exit 1 fi exit 0 - - id: fips-compliance - name: Ensure llama-stack remains FIPS compliant - entry: bash - language: system - types: [python] - pass_filenames: true - exclude: '^tests/.*$' # Exclude test dir as some safety tests used MD5 - args: - - -c - - | - grep -EnH '^[^#]*\b(md5|sha1|uuid3|uuid5)\b' "$@" && { - echo; - echo "❌ Do not use any of the following functions: hashlib.md5, hashlib.sha1, uuid.uuid3, uuid.uuid5" - echo " These functions are not FIPS-compliant" - echo; - exit 1; - } || true + ci: autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate diff --git a/containers/Containerfile b/containers/Containerfile index 1c878ea9b..e02f1e564 100644 --- a/containers/Containerfile +++ b/containers/Containerfile @@ -19,6 +19,8 @@ ARG KEEP_WORKSPACE="" ARG DISTRO_NAME="starter" ARG RUN_CONFIG_PATH="" ARG UV_HTTP_TIMEOUT=500 +ARG UV_EXTRA_INDEX_URL="" +ARG UV_INDEX_STRATEGY="" ENV UV_HTTP_TIMEOUT=${UV_HTTP_TIMEOUT} ENV PYTHONDONTWRITEBYTECODE=1 ENV PIP_DISABLE_PIP_VERSION_CHECK=1 @@ -45,7 +47,7 @@ RUN set -eux; \ exit 1; \ fi -RUN pip install --no-cache uv +RUN pip install --no-cache-dir uv ENV UV_SYSTEM_PYTHON=1 ENV INSTALL_MODE=${INSTALL_MODE} @@ -68,41 +70,49 @@ RUN set -eux; \ echo "LLAMA_STACK_CLIENT_DIR is set but $LLAMA_STACK_CLIENT_DIR does not exist" >&2; \ exit 1; \ fi; \ - uv pip install --no-cache -e "$LLAMA_STACK_CLIENT_DIR"; \ + uv pip install --no-cache-dir -e "$LLAMA_STACK_CLIENT_DIR"; \ fi; # Install llama-stack +# Use UV_EXTRA_INDEX_URL inline only for this step to avoid affecting distribution deps RUN set -eux; \ if [ "$INSTALL_MODE" = "editable" ]; then \ if [ ! -d "$LLAMA_STACK_DIR" ]; then \ echo "INSTALL_MODE=editable requires LLAMA_STACK_DIR to point to a directory inside the build context" >&2; \ exit 1; \ fi; \ - uv pip install --no-cache -e "$LLAMA_STACK_DIR"; \ - elif [ "$INSTALL_MODE" = "test-pypi" ]; then \ - uv pip install --no-cache fastapi libcst; \ - if [ -n "$TEST_PYPI_VERSION" ]; then \ - uv pip install --no-cache --extra-index-url https://test.pypi.org/simple/ --index-strategy unsafe-best-match "llama-stack==$TEST_PYPI_VERSION"; \ + if [ -n "$UV_EXTRA_INDEX_URL" ] && [ -n "$UV_INDEX_STRATEGY" ]; then \ + UV_EXTRA_INDEX_URL="$UV_EXTRA_INDEX_URL" UV_INDEX_STRATEGY="$UV_INDEX_STRATEGY" \ + uv pip install --no-cache-dir -e "$LLAMA_STACK_DIR"; \ else \ - uv pip install --no-cache --extra-index-url https://test.pypi.org/simple/ --index-strategy unsafe-best-match llama-stack; \ + uv pip install --no-cache-dir -e "$LLAMA_STACK_DIR"; \ + fi; \ + elif [ "$INSTALL_MODE" = "test-pypi" ]; then \ + uv pip install --no-cache-dir fastapi libcst; \ + if [ -n "$TEST_PYPI_VERSION" ]; then \ + uv pip install --no-cache-dir --extra-index-url https://test.pypi.org/simple/ --index-strategy unsafe-best-match "llama-stack==$TEST_PYPI_VERSION"; \ + else \ + uv pip install --no-cache-dir --extra-index-url https://test.pypi.org/simple/ --index-strategy unsafe-best-match llama-stack; \ fi; \ else \ if [ -n "$PYPI_VERSION" ]; then \ - uv pip install --no-cache "llama-stack==$PYPI_VERSION"; \ + uv pip install --no-cache-dir "llama-stack==$PYPI_VERSION"; \ else \ - uv pip install --no-cache llama-stack; \ + uv pip install --no-cache-dir llama-stack; \ fi; \ fi; # Install the dependencies for the distribution +# Explicitly unset UV index env vars to ensure we only use PyPI for distribution deps RUN set -eux; \ + unset UV_EXTRA_INDEX_URL UV_INDEX_STRATEGY; \ if [ -z "$DISTRO_NAME" ]; then \ echo "DISTRO_NAME must be provided" >&2; \ exit 1; \ fi; \ deps="$(llama stack list-deps "$DISTRO_NAME")"; \ if [ -n "$deps" ]; then \ - printf '%s\n' "$deps" | xargs -L1 uv pip install --no-cache; \ + printf '%s\n' "$deps" | xargs -L1 uv pip install --no-cache-dir; \ fi # Cleanup diff --git a/scripts/docker.sh b/scripts/docker.sh index a0690c8a9..b56df8c03 100755 --- a/scripts/docker.sh +++ b/scripts/docker.sh @@ -215,6 +215,16 @@ build_image() { --build-arg "LLAMA_STACK_DIR=/workspace" ) + # Pass UV index configuration for release branches + if [[ -n "${UV_EXTRA_INDEX_URL:-}" ]]; then + echo "Adding UV_EXTRA_INDEX_URL to docker build: $UV_EXTRA_INDEX_URL" + build_cmd+=(--build-arg "UV_EXTRA_INDEX_URL=$UV_EXTRA_INDEX_URL") + fi + if [[ -n "${UV_INDEX_STRATEGY:-}" ]]; then + echo "Adding UV_INDEX_STRATEGY to docker build: $UV_INDEX_STRATEGY" + build_cmd+=(--build-arg "UV_INDEX_STRATEGY=$UV_INDEX_STRATEGY") + fi + if ! "${build_cmd[@]}"; then echo "❌ Failed to build Docker image" exit 1 diff --git a/scripts/integration-tests.sh b/scripts/integration-tests.sh index 506ac12e0..008a420bf 100755 --- a/scripts/integration-tests.sh +++ b/scripts/integration-tests.sh @@ -23,7 +23,7 @@ COLLECT_ONLY=false # Function to display usage usage() { - cat </dev/null; then +if [[ "$COLLECT_ONLY" == false ]] && ! command -v llama &> /dev/null; then echo "llama could not be found, ensure llama-stack is installed" exit 1 fi -if ! command -v pytest &>/dev/null; then +if ! command -v pytest &> /dev/null; then echo "pytest could not be found, ensure pytest is installed" exit 1 fi @@ -207,18 +208,9 @@ if [[ "$STACK_CONFIG" == *"server:"* && "$COLLECT_ONLY" == false ]]; then echo "=== Starting Llama Stack Server ===" export LLAMA_STACK_LOG_WIDTH=120 - # Configure telemetry collector for server mode - # Use a fixed port for the OTEL collector so the server can connect to it - COLLECTOR_PORT=4317 - export LLAMA_STACK_TEST_COLLECTOR_PORT="${COLLECTOR_PORT}" - export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:${COLLECTOR_PORT}" - export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" - export OTEL_BSP_SCHEDULE_DELAY="200" - export OTEL_BSP_EXPORT_TIMEOUT="2000" - # remove "server:" from STACK_CONFIG stack_config=$(echo "$STACK_CONFIG" | sed 's/^server://') - nohup llama stack run $stack_config >server.log 2>&1 & + nohup llama stack run $stack_config > server.log 2>&1 & echo "Waiting for Llama Stack Server to start..." for i in {1..30}; do @@ -247,7 +239,7 @@ if [[ "$STACK_CONFIG" == *"docker:"* && "$COLLECT_ONLY" == false ]]; then container_name="llama-stack-test-$DISTRO" if docker ps -a --format '{{.Names}}' | grep -q "^${container_name}$"; then echo "Dumping container logs before stopping..." - docker logs "$container_name" >"docker-${DISTRO}-${INFERENCE_MODE}.log" 2>&1 || true + docker logs "$container_name" > "docker-${DISTRO}-${INFERENCE_MODE}.log" 2>&1 || true echo "Stopping and removing container: $container_name" docker stop "$container_name" 2>/dev/null || true docker rm "$container_name" 2>/dev/null || true @@ -279,6 +271,16 @@ if [[ "$STACK_CONFIG" == *"docker:"* && "$COLLECT_ONLY" == false ]]; then --build-arg "LLAMA_STACK_DIR=/workspace" ) + # Pass UV index configuration for release branches + if [[ -n "${UV_EXTRA_INDEX_URL:-}" ]]; then + echo "Adding UV_EXTRA_INDEX_URL to docker build: $UV_EXTRA_INDEX_URL" + build_cmd+=(--build-arg "UV_EXTRA_INDEX_URL=$UV_EXTRA_INDEX_URL") + fi + if [[ -n "${UV_INDEX_STRATEGY:-}" ]]; then + echo "Adding UV_INDEX_STRATEGY to docker build: $UV_INDEX_STRATEGY" + build_cmd+=(--build-arg "UV_INDEX_STRATEGY=$UV_INDEX_STRATEGY") + fi + if ! "${build_cmd[@]}"; then echo "❌ Failed to build Docker image" exit 1 @@ -292,15 +294,10 @@ if [[ "$STACK_CONFIG" == *"docker:"* && "$COLLECT_ONLY" == false ]]; then docker stop "$container_name" 2>/dev/null || true docker rm "$container_name" 2>/dev/null || true - # Configure telemetry collector port shared between host and container - COLLECTOR_PORT=4317 - export LLAMA_STACK_TEST_COLLECTOR_PORT="${COLLECTOR_PORT}" - # Build environment variables for docker run DOCKER_ENV_VARS="" DOCKER_ENV_VARS="$DOCKER_ENV_VARS -e LLAMA_STACK_TEST_INFERENCE_MODE=$INFERENCE_MODE" DOCKER_ENV_VARS="$DOCKER_ENV_VARS -e LLAMA_STACK_TEST_STACK_CONFIG_TYPE=server" - DOCKER_ENV_VARS="$DOCKER_ENV_VARS -e OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:${COLLECTOR_PORT}" # Pass through API keys if they exist [ -n "${TOGETHER_API_KEY:-}" ] && DOCKER_ENV_VARS="$DOCKER_ENV_VARS -e TOGETHER_API_KEY=$TOGETHER_API_KEY" @@ -321,20 +318,8 @@ if [[ "$STACK_CONFIG" == *"docker:"* && "$COLLECT_ONLY" == false ]]; then fi echo "Using image: $IMAGE_NAME" - # On macOS/Darwin, --network host doesn't work as expected due to Docker running in a VM - # Use regular port mapping instead - NETWORK_MODE="" - PORT_MAPPINGS="" - if [[ "$(uname)" != "Darwin" ]] && [[ "$(uname)" != *"MINGW"* ]]; then - NETWORK_MODE="--network host" - else - # On non-Linux (macOS, Windows), need explicit port mappings for both app and telemetry - PORT_MAPPINGS="-p $LLAMA_STACK_PORT:$LLAMA_STACK_PORT -p $COLLECTOR_PORT:$COLLECTOR_PORT" - echo "Using bridge networking with port mapping (non-Linux)" - fi - - docker run -d $NETWORK_MODE --name "$container_name" \ - $PORT_MAPPINGS \ + docker run -d --network host --name "$container_name" \ + -p $LLAMA_STACK_PORT:$LLAMA_STACK_PORT \ $DOCKER_ENV_VARS \ "$IMAGE_NAME" \ --port $LLAMA_STACK_PORT @@ -436,13 +421,17 @@ elif [ $exit_code -eq 5 ]; then else echo "❌ Tests failed" echo "" + echo "=== Dumping last 100 lines of logs for debugging ===" + # Output server or container logs based on stack config if [[ "$STACK_CONFIG" == *"server:"* && -f "server.log" ]]; then - echo "--- Server side failures can be located inside server.log (available from artifacts on CI) ---" + echo "--- Last 100 lines of server.log ---" + tail -100 server.log elif [[ "$STACK_CONFIG" == *"docker:"* ]]; then docker_log_file="docker-${DISTRO}-${INFERENCE_MODE}.log" if [[ -f "$docker_log_file" ]]; then - echo "--- Server side failures can be located inside $docker_log_file (available from artifacts on CI) ---" + echo "--- Last 100 lines of $docker_log_file ---" + tail -100 "$docker_log_file" fi fi diff --git a/scripts/uv-run-with-index.sh b/scripts/uv-run-with-index.sh new file mode 100755 index 000000000..18d0a0e9c --- /dev/null +++ b/scripts/uv-run-with-index.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the terms described in the LICENSE file in +# the root directory of this source tree. + +set -euo pipefail + +# Detect current branch and target branch +# In GitHub Actions, use GITHUB_REF/GITHUB_BASE_REF +if [[ -n "${GITHUB_REF:-}" ]]; then + BRANCH="${GITHUB_REF#refs/heads/}" +else + BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") +fi + +# For PRs, check the target branch +if [[ -n "${GITHUB_BASE_REF:-}" ]]; then + TARGET_BRANCH="${GITHUB_BASE_REF}" +else + TARGET_BRANCH=$(git rev-parse --abbrev-ref HEAD@{upstream} 2>/dev/null | sed 's|origin/||' || echo "") +fi + +# Check if on a release branch or targeting one, or LLAMA_STACK_RELEASE_MODE is set +IS_RELEASE=false +if [[ "$BRANCH" =~ ^release-[0-9]+\.[0-9]+\.x$ ]]; then + IS_RELEASE=true +elif [[ "$TARGET_BRANCH" =~ ^release-[0-9]+\.[0-9]+\.x$ ]]; then + IS_RELEASE=true +elif [[ "${LLAMA_STACK_RELEASE_MODE:-}" == "true" ]]; then + IS_RELEASE=true +fi + +# On release branches, use test.pypi as extra index for RC versions +if [[ "$IS_RELEASE" == "true" ]]; then + export UV_EXTRA_INDEX_URL="https://test.pypi.org/simple/" + export UV_INDEX_STRATEGY="unsafe-best-match" +fi + +# Run uv with all arguments passed through +exec uv "$@"