diff --git a/.github/actions/setup-nats-server/action.yml b/.github/actions/setup-nats-server/action.yml new file mode 100644 index 00000000..9e2ad15a --- /dev/null +++ b/.github/actions/setup-nats-server/action.yml @@ -0,0 +1,34 @@ +name: Setup NATS Server +description: Install and cache NATS Server binary + +inputs: + version: + description: "NATS Server version (e.g., latest, v2.10.29, v2.11.8)" + required: false + default: "latest" + +runs: + using: composite + steps: + - name: Cache NATS Server + uses: actions/cache@v4 + id: cache-nats + with: + path: ~/nats-server + key: nats-server-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} + + - name: Install NATS Server + if: steps.cache-nats.outputs.cache-hit != 'true' + shell: bash + run: | + INSTALL_DIR="$HOME/nats-server" + mkdir -p "$INSTALL_DIR" + curl -fsSL https://binaries.nats.dev/nats-io/nats-server/v2@${{ inputs.version }} | PREFIX="$INSTALL_DIR" sh + + - name: Add NATS Server to PATH + shell: bash + run: echo "$HOME/nats-server" >> $GITHUB_PATH + + - name: Verify NATS Server + shell: bash + run: nats-server -v diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 165fc0d4..76f29541 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,10 +18,7 @@ jobs: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] - nats_version: ["v2.10.29", "v2.11.8", "main"] - include: - - nats_version: "main" - continue-on-error: true + nats_version: ["latest"] steps: - name: Check out repository @@ -35,17 +32,18 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v6 + - name: Setup NATS Server + uses: ./.github/actions/setup-nats-server + with: + version: ${{ matrix.nats_version }} + - name: Install dependencies and project - run: | - uv sync --dev - ./nats/scripts/install_nats.sh + run: uv sync --dev - name: Run tests run: | uv run flake8 --ignore="W391, W503, W504, E501" ./nats/src/nats/js/ uv run pytest -x -vv -s --continue-on-collection-errors ./nats/tests - env: - PATH: $HOME/nats-server:$PATH project: name: ${{ matrix.project }} (python-${{ matrix.python-version }}, nats-server-${{ matrix.nats-server-version }}, ${{ matrix.os }}) @@ -60,15 +58,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v5 - - name: Set up Go - uses: actions/setup-go@v6 + - name: Setup NATS Server + uses: ./.github/actions/setup-nats-server with: - go-version: "stable" - - - name: Install NATS Server - run: | - go install github.com/nats-io/nats-server/v2@${{ matrix.nats-server-version }} - shell: bash + version: ${{ matrix.nats-server-version }} - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 diff --git a/nats-server/src/nats/server/__init__.py b/nats-server/src/nats/server/__init__.py index b80fa79e..1274cf93 100644 --- a/nats-server/src/nats/server/__init__.py +++ b/nats-server/src/nats/server/__init__.py @@ -23,6 +23,7 @@ import logging import os import re +import shutil import socket import tempfile from typing import Self @@ -203,8 +204,18 @@ async def _create_server_process( Returns: The created subprocess. + + Raises: + ServerError: If nats-server executable is not found in PATH. """ - cmd = ["nats-server"] + nats_server_path = shutil.which("nats-server") + if not nats_server_path: + raise ServerError( + "nats-server executable not found in PATH. " + "Please install nats-server from https://github.com/nats-io/nats-server" + ) + + cmd = [nats_server_path] # Direct parameter to CLI flag mapping if host is not None: diff --git a/nats-server/tests/conftest.py b/nats-server/tests/conftest.py index 0d245df6..d63fb43c 100644 --- a/nats-server/tests/conftest.py +++ b/nats-server/tests/conftest.py @@ -5,6 +5,7 @@ particularly for verifying that the required nats-server executable is available. """ +import shutil import socket import subprocess @@ -13,14 +14,19 @@ def get_nats_server_version(): """Get the nats-server version or fail if not installed.""" + nats_server_path = shutil.which("nats-server") + if not nats_server_path: + pytest.fail("nats-server is not installed or not in PATH") + return None + try: - result = subprocess.run(["nats-server", "--version"], + result = subprocess.run([nats_server_path, "--version"], capture_output=True, check=True, text=True) return result.stdout.strip() or result.stderr.strip() - except (subprocess.SubprocessError, FileNotFoundError) as e: - pytest.fail(f"nats-server is not installed or not in PATH: {e}") + except subprocess.SubprocessError as e: + pytest.fail(f"Failed to run nats-server: {e}") return None diff --git a/nats/scripts/install_nats.sh b/nats/scripts/install_nats.sh deleted file mode 100755 index cce3dead..00000000 --- a/nats/scripts/install_nats.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -e - -export DEFAULT_NATS_SERVER_VERSION=v2.10.26 - -export NATS_SERVER_VERSION="${NATS_SERVER_VERSION:=$DEFAULT_NATS_SERVER_VERSION}" - -mkdir -p $HOME/nats-server -curl -sf https://binaries.nats.dev/nats-io/nats-server/v2@$NATS_SERVER_VERSION | PREFIX=$HOME/nats-server/ sh -$HOME/nats-server/nats-server -v diff --git a/nats/tests/utils.py b/nats/tests/utils.py index d200937a..0a61ae70 100644 --- a/nats/tests/utils.py +++ b/nats/tests/utils.py @@ -62,7 +62,7 @@ def start(self): # Default path if Path(self.bin_name).is_file(): self.bin_name = Path(self.bin_name).absolute() - # Path in `../scripts/install_nats.sh` + # Path installed via https://docs.nats.io/running-a-nats-service/introduction/installation elif Path.home().joinpath(SERVER_BIN_DIR_NAME, self.bin_name).is_file(): self.bin_name = str(