Skip to content
Open
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
146 changes: 146 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
name: CI

on:
push:
branches:
- main
- master
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
lint:
name: Lint & docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-in-project: true

- name: Cache virtualenv
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-py3.12-${{ hashFiles('**/poetry.lock') }}

- name: Install dependencies
run: make install

- name: Lint
run: make lint

- name: Build docs
run: make docs

test:
name: Unit & integration (py${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-in-project: true

- name: Cache virtualenv
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }}

- name: Install dependencies
run: make install

- name: Unit tests
run: make test-unit

- name: Integration tests
run: make test-integration

- name: Coverage reports
if: always()
run: make coverage-report

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

functional:
name: Functional (LocalStack)
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-in-project: true

- name: Cache virtualenv
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-py3.12-${{ hashFiles('**/poetry.lock') }}

- name: Install dependencies
run: make install

# Log in to Docker Hub only when credentials are configured, to avoid
# anonymous pull rate limits when pulling the LocalStack image.
# The `secrets` context cannot be used in `if:`, so it is surfaced via
# `env` first and the env var is what the condition checks.
- name: Log in to Docker Hub
if: env.DOCKERHUB_USERNAME != ''
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Functional tests
run: make test-functional

- name: Coverage reports
if: always()
run: make coverage-report

- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-functional
path: |
coverage.xml
htmlcov/
if-no-files-found: ignore
104 changes: 104 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Release

# Publish a new version to PyPI when a version tag is pushed.
#
# git tag v0.7.0
# git push origin v0.7.0
#
# The tag must match the version in pyproject.toml (the "check-version" step
# enforces this). PyPI's proxy on JFrog picks the release up automatically, so
# downstream repos can then depend on the published version instead of a local
# path.

on:
push:
tags:
- "v*"

permissions:
contents: read

jobs:
test:
name: Lint & unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-in-project: true

- name: Install dependencies
run: poetry install --no-interaction

- name: Lint
run: make lint

# Functional/integration tests need a Docker daemon to run LocalStack and
# are intentionally left out of the release gate to keep it fast and
# deterministic. Run them in a separate CI workflow if desired.
- name: Unit tests
run: poetry run pytest tests/unit -ra --cov=pytest_localstack

publish:
name: Build & publish to PyPI
needs: test
runs-on: ubuntu-latest

# Trusted Publishing (OIDC) requires an environment and id-token permission.
# One-time setup on PyPI: project -> Settings -> Publishing -> add a
# "GitHub Actions" trusted publisher with:
# owner: mintel
# repository: pytest-localstack
# workflow: release.yml
# environment: pypi
# And in GitHub: Settings -> Environments -> create an environment named
# "pypi". No API token secret is needed with this approach.
environment:
name: pypi
url: https://pypi.org/p/pytest-localstack
permissions:
id-token: write # required for Trusted Publishing (OIDC)

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Poetry
uses: snok/install-poetry@v1

- name: Check tag matches package version
run: |
TAG_VERSION="${GITHUB_REF_NAME#v}"
PKG_VERSION="$(poetry version -s)"
echo "Tag version: $TAG_VERSION"
echo "Package version: $PKG_VERSION"
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "::error::Tag $GITHUB_REF_NAME does not match pyproject version $PKG_VERSION"
exit 1
fi

- name: Build sdist and wheel
run: poetry build

- name: Publish to PyPI (Trusted Publishing)
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/

# --- Alternative: API token instead of Trusted Publishing ---------------
# If you would rather use a token, delete the "environment"/"permissions"
# blocks and the step above, then add a PYPI_API_TOKEN repository secret
# (PyPI -> Account settings -> API tokens) and use:
#
# - name: Publish to PyPI (API token)
# run: poetry publish --no-interaction --username __token__ --password "${{ secrets.PYPI_API_TOKEN }}"
65 changes: 0 additions & 65 deletions .travis.yml

This file was deleted.

23 changes: 23 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
Change Log
==========

0.8.0 (2026-08-21)

- Drop support for Python 3.9
- Remove version contraint from Poetry in ci pipeline

0.7.0 (2026-08-13)
------------------

- Drop support for Python < 3.9.
- Add support for Python 3.12 and pytest >= 7.
- Require docker >= 7.0.0 and pluggy >= 1.0.0; remove urllib3 < 2 pin.
- Replace deprecated ``inspect.getcallargs`` with ``inspect.Signature.bind``.
- Switch build backend from setuptools to poetry-core.
- Add ``container_env`` parameter to ``LocalstackSession``.
- Default the LocalStack image to ``4.14`` instead of ``latest``. This is the
last free community release published before LocalStack consolidated to a
single image requiring an auth token (v2026.03.0, March 2026).
- Fix the ``RunningSession`` start retry loop so it always sleeps and increments
the retry counter; previously these only ran when the max delay was exceeded,
causing a busy loop.
- Increase the botocore service-check connect/read timeouts from 1s to 5s to
reduce flaky readiness checks on slower hosts.

0.6.1 (2023-06-06)
------------------

Expand Down
21 changes: 19 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ clean: ## remove all build, test, coverage and Python artifacts
lint: $(INSTALL_STAMP) ## check code style
$(POETRY) run isort --check-only ./tests/ $(NAME)
$(POETRY) run black --check ./tests/ $(NAME) --diff
$(POETRY) run pflake8 ./tests/ $(NAME)
$(POETRY) run flake8 ./tests/ $(NAME)
$(POETRY) run mypy ./tests/ $(NAME) --ignore-missing-imports
$(POETRY) run bandit -r $(NAME) -s B608

Expand All @@ -59,9 +59,26 @@ fmt: $(INSTALL_STAMP) ## apply code style formatting
$(POETRY) run black ./tests/ $(NAME)

.PHONY: test
test: $(INSTALL_STAMP) ## run tests
test: $(INSTALL_STAMP) ## run all tests
$(POETRY) run pytest

.PHONY: test-unit
test-unit: $(INSTALL_STAMP) ## run unit tests with coverage
$(POETRY) run pytest tests/unit -ra --cov=$(NAME) -n auto

.PHONY: test-integration
test-integration: $(INSTALL_STAMP) ## run integration tests with coverage (appended)
$(POETRY) run pytest tests/integration -ra --cov=$(NAME) --cov-append -n auto

.PHONY: test-functional
test-functional: $(INSTALL_STAMP) ## run functional tests with coverage (requires Docker)
$(POETRY) run pytest tests/functional -ra --cov=$(NAME)

.PHONY: coverage-report
coverage-report: $(INSTALL_STAMP) ## generate coverage.xml and htmlcov/ from collected coverage
$(POETRY) run coverage xml
$(POETRY) run coverage html

.PHONY: docs
docs: $(INSTALL_STAMP) ## build documentation
$(POETRY) run $(MAKE) -C docs html
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ via a Localstack_ Docker container.

**Requires:**

- pytest >= 3.3.0
- pytest >= 7
- Docker

Tested against Python >= 3.6.
Tested against Python >= 3.10.

.. _pytest: http://docs.pytest.org/
.. _AWS: https://aws.amazon.com/
Expand Down
Loading
Loading