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
4 changes: 2 additions & 2 deletions .github/workflows/stage-2-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
- name: "Save the coverage check result"
uses: actions/upload-artifact@v4
with:
name: coverage
name: coverage.xml
path: coverage.xml
test-lint:
name: "Linting"
Expand Down Expand Up @@ -85,7 +85,7 @@ jobs:
- name: "Get the coverage report"
uses: actions/download-artifact@v4
with:
name: coverage
name: coverage.xml
- name: "Perform static analysis"
uses: ./.github/actions/perform-static-analysis
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stage-4-acceptance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ jobs:
needs: environment-set-up
timeout-minutes: 10
env:
LOCALSTACK_INTERNAL_DYNAMODB_ENDPOINT: http://localstack:4566/
LOCALSTACK_INTERNAL_ENDPOINT: http://localstack:4566/
steps:
- name: "Checkout code"
uses: actions/checkout@v4
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ make precommit

There are `make` tasks for you to configure to run your tests. Run `make test` to see how they work. You should be able to use the same entry points for local development as in your CI pipeline.

## Conflict with yanai

If you have previously built [yanai](https://nhsd-confluence.digital.nhs.uk/pages/viewpage.action?pageId=48826732), which is the platform we use to supply data to this project, that uses an old version of localstack that does not support our Python version. We have pinned the correct version here and yanai have their version pinned as well so it should work fine, but sometimes issues can arise - if so then removing the docker image can solve that, before then rebuilding.

```shell
docker rmi localstack/localstack
```

## Design

We'll be separating our [presentation](https://martinfowler.com/eaaDev/SeparatedPresentation.html) layer (where API logic lives, in [`views/`](src/eligibility_signposting_api/views)), [business services](https://martinfowler.com/eaaCatalog/serviceLayer.html) layer (where business logic lives, in [`services/`](src/eligibility_signposting_api/services)) and [repository](https://martinfowler.com/eaaCatalog/repository.html) layer (where database logic lives, [`repos/`](src/eligibility_signposting_api/repos)). We will be using [wireup](https://pypi.org/project/wireup/) for [dependency injection](https://pinboard.in/u:brunns/t:dependency-injection), so services get their dependencies given to them ("injection"), and wireup takes care of that. (We'll usually use the [`@service` annotation](https://maldoinc.github.io/wireup/latest/services/), but [factory functions](https://maldoinc.github.io/wireup/latest/factory_functions/) will be used where necessary, typically for creating resources from 3rd party libraries.) We'll be using [Pydantic](https://pypi.org/project/pydantic/) for both response models and database models.
Expand Down
14 changes: 3 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pytest-docker = "^3.2.0"
stamina = "^25.1.0"

[tool.poetry-plugin-lambda-build]
docker-image = "public.ecr.aws/sam/build-python3.13:latest-x86_64"
docker-image = "public.ecr.aws/sam/build-python3.13:1.135-x86_64"
docker-network = "host"
docker-platform = "linux/x86_64"
package-artifact-path = "dist/lambda.zip"
Expand Down Expand Up @@ -83,17 +83,9 @@ log_format = "%(asctime)s %(levelname)s %(message)s"
log_date_format = "%Y-%m-%d %H:%M:%S"

[tool.coverage.run]
relative_files = true
branch = true
source = ["src/eligibility_signposting_api"]
omit = [
"tests/*",
"*/__init__.py",
"*/migrations/*",
"*/settings/*",
"*/venv/*",
"*/.venv/*",
"*/site-packages/*",
]
source = ["src"]

[tool.coverage.report]
show_missing = true
Expand Down
7 changes: 2 additions & 5 deletions scripts/config/sonar-scanner.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ sonar.host.url=https://sonarcloud.io
sonar.qualitygate.wait=true
sonar.sourceEncoding=UTF-8

#sonar.python.coverage.reportPaths=.coverage/coverage.xml
#sonar.[javascript|typescript].lcov.reportPaths=.coverage/lcov.info

sonar.python.version=3.13

sonar.sources=src/
sonar.sources=src
sonar.exclusions=**/test_*.py

sonar.tests=tests/
sonar.tests=tests
sonar.test.inclusions=**/test_*.py

sonar.python.coverage.reportPaths=coverage.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ pyenv
colima
wireup
Pydantic
yanai
7 changes: 7 additions & 0 deletions scripts/tests/lint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

set -euo pipefail

cd "$(git rev-parse --show-toplevel)"

make dependencies install-python lint
3 changes: 1 addition & 2 deletions scripts/tests/unit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,4 @@ cd "$(git rev-parse --show-toplevel)"
# tasks in scripts/test.mk.

make dependencies install-python
poetry run pytest tests/unit/ --durations=10 --cov-report= --cov src/
poetry run python -m coverage xml
poetry run pytest tests/unit/ --durations=10 --cov-report=xml --cov=src/
9 changes: 5 additions & 4 deletions src/eligibility_signposting_api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
from eligibility_signposting_api.views.eligibility import eligibility
from eligibility_signposting_api.views.hello import hello

init_logging()
logger = logging.getLogger(__name__)


def main() -> None: # pragma: no cover
"""Run the Flask app as a local process."""
Expand All @@ -27,10 +30,8 @@ def lambda_handler(event: LambdaEvent, context: LambdaContext) -> dict[str, Any]


def create_app() -> Flask:
init_logging()

app = Flask(__name__)
app.logger.info("app created")
logger.info("app created")

# Register views & error handler
app.register_blueprint(eligibility, url_prefix="/eligibility")
Expand All @@ -41,7 +42,7 @@ def create_app() -> Flask:
container = wireup.create_container(service_modules=[services, repos], parameters=config())
wireup.integration.flask.setup(container, app, import_flask_config=True)

app.logger.info("app ready")
logger.info("app ready")
return app


Expand Down
22 changes: 2 additions & 20 deletions src/eligibility_signposting_api/config.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import logging
import os
from logging.config import dictConfig
from typing import Any, NewType

from yarl import URL

LOG_LEVEL = logging.DEBUG
LOG_LEVEL = logging.getLevelNamesMapping().get(os.getenv("LOG_LEVEL", ""), logging.WARNING)

AwsRegion = NewType("AwsRegion", str)
AwsAccessKey = NewType("AwsAccessKey", str)
Expand All @@ -22,22 +21,5 @@ def config() -> dict[str, Any]:


def init_logging() -> None:
level = logging.getLevelName(LOG_LEVEL)
log_format = "%(asctime)s %(levelname)-8s %(name)s %(module)s.py:%(funcName)s():%(lineno)d %(message)s"
dictConfig(
{
"version": 1,
"formatters": {
"default": {
"format": log_format,
}
},
"handlers": {
"wsgi": {"class": "logging.StreamHandler", "stream": "ext://sys.stdout", "formatter": "default"}
},
"root": {"level": level, "handlers": ["wsgi"]},
"loggers": {
"eligibility_signposting_api.app": {"level": level, "handlers": ["wsgi"], "propagate": False},
},
}
)
logging.basicConfig(level=LOG_LEVEL, format=log_format, handlers=[logging.StreamHandler()])
2 changes: 1 addition & 1 deletion tests/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
services:
localstack:
# container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}"
image: localstack/localstack
image: localstack/localstack:4.2.0
ports:
- "4566:4566" # LocalStack Gateway
- "4510-4559:4510-4559" # external services port range
Expand Down
4 changes: 1 addition & 3 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ def flask_function(lambda_client: BaseClient) -> str:
Timeout=180,
Environment={
"Variables": {
"DYNAMODB_ENDPOINT": os.getenv(
"LOCALSTACK_INTERNAL_DYNAMODB_ENDPOINT", "http://host.docker.internal:4566"
),
"DYNAMODB_ENDPOINT": os.getenv("LOCALSTACK_INTERNAL_ENDPOINT", "http://localstack:4566/"),
"AWS_REGION": AWS_REGION,
}
},
Expand Down
Loading