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
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: CI
on:
push:
branches: [main]
tags: ["v*"]
pull_request:

jobs:
Expand All @@ -18,3 +19,24 @@ jobs:
python-version: ${{ matrix.python-version }}
- run: pip install -e ".[dev]"
- run: pytest tests/ -v

# The package version and the git tag drifted for three releases: tags said 1.x
# while pyproject said 0.1.0. This fails the tag build rather than shipping a
# release that misreports itself.
version-matches-tag:
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Compare __version__ with the tag
run: |
tag="${GITHUB_REF_NAME#v}"
pkg=$(python -c "import sys; sys.path.insert(0, 'src'); import algolia_agent; print(algolia_agent.__version__)")
echo "tag=$tag __version__=$pkg"
if [ "$tag" != "$pkg" ]; then
echo "::error::tag ${GITHUB_REF_NAME} does not match __version__ ${pkg}"
exit 1
fi
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ algolia-agent delete <agent_id> --confirm
```

Add `--json` to any command except `init` for machine-readable output.
`algolia-agent --version` reports the installed version.

## Releasing

`src/algolia_agent/__init__.py` holds `__version__` and everything derives from it:
`pyproject.toml` reads it via `[tool.setuptools.dynamic]`, `--version` reports it, and
the client sends it in the `User-Agent`. To cut a release, bump that one value, merge,
then tag from `main`:

```bash
git checkout main && git pull
git tag vX.Y.Z && git push origin vX.Y.Z
```

CI fails the tag build if the tag and `__version__` disagree.

## Config formats

Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "algolia-agent"
version = "0.1.0"
dynamic = ["version"]
description = "CLI for Algolia Agent Studio"
readme = "README.md"
requires-python = ">=3.10"
Expand All @@ -23,6 +23,9 @@ dev = ["pytest>=7"]
[project.scripts]
algolia-agent = "algolia_agent.cli:main"

[tool.setuptools.dynamic]
version = { attr = "algolia_agent.__version__" }

[tool.setuptools.packages.find]
where = ["src"]

Expand Down
7 changes: 7 additions & 0 deletions src/algolia_agent/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""CLI for the Algolia Agent Studio REST API."""

# Single source of truth for the version. pyproject.toml reads it via
# [tool.setuptools.dynamic], the CLI reports it through --version, and the client
# sends it in the User-Agent — so a release cannot disagree with itself. CI checks
# this value against the git tag whenever a v* tag is pushed.
__version__ = "1.3.0"
3 changes: 3 additions & 0 deletions src/algolia_agent/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from InquirerPy import inquirer

from . import __version__
from .client import AgentAPIError, AlgoliaAgentClient
from .template import extract_variables, render

Expand Down Expand Up @@ -1180,6 +1181,8 @@ def build_parser() -> argparse.ArgumentParser:
prog="algolia-agent",
description="Algolia Agent Studio CLI",
)
parser.add_argument("--version", action="version",
version=f"algolia-agent {__version__}")
parser.add_argument("--app-id", help="Algolia Application ID (overrides env/dotenv)")
parser.add_argument("--api-key", help="Algolia API Key (overrides env/dotenv)")

Expand Down
9 changes: 7 additions & 2 deletions src/algolia_agent/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
_RETRY_BACKOFF = 1.0 # seconds; doubles each retry


from . import __version__

_USER_AGENT = f"algolia-agent-cli/{__version__}"


def _load_dotenv(path: Path) -> dict[str, str]:
"""Parse a .env file and return key/value pairs. Ignores comments and blank lines."""
result = {}
Expand Down Expand Up @@ -66,7 +71,7 @@ def _request(self, path: str, method: str = "GET", body: dict | None = None) ->
req.add_header("x-algolia-api-key", self.api_key)
req.add_header("Content-Type", "application/json")
req.add_header("Accept", "application/json")
req.add_header("User-Agent", "algolia-agent-cli/0.1.0")
req.add_header("User-Agent", _USER_AGENT)
delay = _RETRY_BACKOFF
for attempt in range(_MAX_RETRIES):
try:
Expand Down Expand Up @@ -151,7 +156,7 @@ def list_indices(self) -> list[str]:
req.add_header("x-algolia-application-id", self.app_id)
req.add_header("x-algolia-api-key", self.api_key)
req.add_header("Accept", "application/json")
req.add_header("User-Agent", "algolia-agent-cli/0.1.0")
req.add_header("User-Agent", _USER_AGENT)
try:
with urllib.request.urlopen(req, timeout=_TIMEOUT) as resp:
result = json.loads(resp.read())
Expand Down
35 changes: 35 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,38 @@ def test_timeout_error_retries_then_succeeds(client):
with patch("time.sleep"):
result = client.get_agent("abc")
assert result == agent


# ── version reporting ─────────────────────────────────────────────────────────

def test_user_agent_reports_the_package_version():
"""The User-Agent was frozen at 0.1.0 through three tagged releases."""
import re

import algolia_agent
from algolia_agent.client import _USER_AGENT

assert re.fullmatch(r"\d+\.\d+\.\d+", algolia_agent.__version__), algolia_agent.__version__
assert _USER_AGENT == f"algolia-agent-cli/{algolia_agent.__version__}"


def test_user_agent_header_is_actually_sent(client):
import algolia_agent

with patch("urllib.request.urlopen", return_value=_mock_response({"data": []})) as m:
client.list_agents()
req = m.call_args.args[0]
assert req.get_header("User-agent") == f"algolia-agent-cli/{algolia_agent.__version__}"


def test_installed_metadata_matches_dunder_version():
"""pyproject reads the version from the package, so these cannot diverge."""
from importlib.metadata import PackageNotFoundError, version

import algolia_agent

try:
installed = version("algolia-agent")
except PackageNotFoundError:
pytest.skip("package not installed")
assert installed == algolia_agent.__version__
Loading