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
80 changes: 80 additions & 0 deletions .github/workflows/_lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: lint

on:
workflow_call:

permissions:
contents: read

env:
# Inline annotations on PR diffs when ruff complains.
RUFF_OUTPUT_FORMAT: github

jobs:
ruff:
name: "ruff #${{ matrix.python-version }}"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Min + max supported Pythons only; intermediates almost never surface
# a lint issue that doesn't show up on the boundaries.
python-version: ["3.11", "3.13"]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml

- name: Install ruff
run: pip install 'ruff>=0.15,<0.16'

- name: ruff check
run: ruff check azure/ tests/ function_app/

- name: ruff format --check
run: ruff format --check azure/ tests/ function_app/

wheel-namespace-guard:
name: "wheel namespace guard"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
cache-dependency-path: pyproject.toml

- name: Install build
run: pip install build

- name: Build wheel
run: python -m build --wheel

- name: Assert wheel does NOT ship azure/ or azure/cosmos/ __init__.py
# azure.cosmos.* is a PEP 420 implicit namespace package owned by the
# official azure-cosmos SDK. Shipping azure/__init__.py or
# azure/cosmos/__init__.py from this wheel would shadow the SDK and
# break every consumer of azure-cosmos at import time.
run: |
set -eo pipefail
BAD=$(python -m zipfile -l dist/*.whl | awk '{print $1}' | \
grep -E '^(azure/__init__\.py|azure/cosmos/__init__\.py)$' || true)
if [ -n "$BAD" ]; then
echo "::error::Wheel contains forbidden namespace __init__.py files:"
echo "$BAD"
exit 1
fi
echo "✓ Wheel does not ship azure/ or azure/cosmos/ __init__.py"

- name: Assert wheel DOES ship azure/cosmos/agent_memory/__init__.py
run: |
set -eo pipefail
python -m zipfile -l dist/*.whl | awk '{print $1}' | \
grep -qE '^azure/cosmos/agent_memory/__init__\.py$'
echo "✓ Wheel ships azure/cosmos/agent_memory/__init__.py"
56 changes: 56 additions & 0 deletions .github/workflows/_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: test

on:
workflow_call:

permissions:
contents: read

jobs:
unit:
name: "pytest #${{ matrix.python-version }}"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml

- name: Install package with dev extras
run: pip install -e ".[dev]"

- name: Run unit tests with coverage
run: |
pytest tests/unit/ \
--cov=azure.cosmos.agent_memory \
--cov-report=xml \
--cov-report=term-missing \
-v

- name: Upload coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report-${{ matrix.python-version }}
path: coverage.xml
if-no-files-found: ignore

- name: Ensure tests did not write to the working tree
# Catches tests that accidentally leave files behind (e.g. .cache
# directories, downloaded fixtures, or local Cosmos emulator state).
run: |
set -eu
STATUS="$(git status --porcelain)"
if [ -n "$STATUS" ]; then
echo "::error::Tests modified the working tree:"
echo "$STATUS"
exit 1
fi
echo "✓ Working tree clean"
93 changes: 93 additions & 0 deletions .github/workflows/_test_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: test-release

# Builds the wheel + sdist, uploads to TestPyPI (sanity check only).
# Called by release.yml before the real PyPI publish.

on:
workflow_call:
outputs:
pkg-name:
description: "Distribution name from pyproject.toml"
value: ${{ jobs.build.outputs.pkg-name }}
version:
description: "Version from pyproject.toml"
value: ${{ jobs.build.outputs.version }}

permissions: {}

env:
PYTHON_VERSION: "3.11"

jobs:
build:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read

outputs:
pkg-name: ${{ steps.check-version.outputs.pkg-name }}
version: ${{ steps.check-version.outputs.version }}

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: pip
cache-dependency-path: pyproject.toml

- name: Install build tooling
run: pip install build

# We keep the build job *separate* from the publish job so a compromised
# build-time dependency cannot reach the trusted-publishing OIDC token.
# https://github.com/pypa/gh-action-pypi-publish#non-goals
- name: Build wheel + sdist
run: python -m build

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: test-dist
path: dist/

- name: Extract pkg-name + version
id: check-version
run: |
python -m pip install --quiet tomli
PKG=$(python -c "import tomli; print(tomli.load(open('pyproject.toml','rb'))['project']['name'])")
VER=$(python -c "import tomli; print(tomli.load(open('pyproject.toml','rb'))['project']['version'])")
echo "pkg-name=$PKG" >> "$GITHUB_OUTPUT"
echo "version=$VER" >> "$GITHUB_OUTPUT"

publish:
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
# Required for PyPI trusted publishing (OIDC token).
# Configure the trusted publisher at:
# https://test.pypi.org/manage/account/publishing/
id-token: write

steps:
- uses: actions/download-artifact@v4
with:
name: test-dist
path: dist/

- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/
verbose: true
print-hash: true
repository-url: https://test.pypi.org/legacy/
# CI-only — overwrites a same-version file if a re-run is needed.
# https://github.com/pypa/gh-action-pypi-publish#tolerating-release-package-file-duplicates
skip-existing: true
# Attestations default-on in v1.11.0+ and require additional
# trusted-publisher config; disable until we opt in deliberately.
attestations: false
62 changes: 30 additions & 32 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,42 @@ on:
pull_request:
branches: [main]

# Cancel in-progress runs on the same PR / branch when a new push arrives.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: pip install 'ruff>=0.15,<0.16'
- name: Ruff check
run: ruff check agent_memory_toolkit/ tests/
- name: Ruff format check
run: ruff format --check agent_memory_toolkit/ tests/
uses: ./.github/workflows/_lint.yml
permissions:
contents: read

test:
uses: ./.github/workflows/_test.yml
permissions:
contents: read

ci-success:
# Single required-status-check target. Branch protection should require
# only this job; it summarizes lint + test matrix results so a failure
# in any matrix cell blocks merge.
name: "CI Success"
needs: [lint, test]
if: always()
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
env:
JOBS_JSON: ${{ toJSON(needs) }}
RESULTS_JSON: ${{ toJSON(needs.*.result) }}
EXIT_CODE: ${{!contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && '0' || '1'}}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install package with dev dependencies
run: pip install -e ".[dev]"
- name: Run unit tests with coverage
run: pytest tests/unit/ --cov=agent_memory_toolkit --cov-report=xml --cov-report=term-missing -v
- name: Upload coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report-${{ matrix.python-version }}
path: coverage.xml
- name: Aggregate matrix results
run: |
echo "$JOBS_JSON"
echo "$RESULTS_JSON"
echo "Exiting with $EXIT_CODE"
exit $EXIT_CODE

Loading
Loading