Compare commits

...

6 Commits

Author SHA1 Message Date
latest-changes[bot] 5b632d4f88 📝 Update release notes
[skip ci]
2026-09-01 10:43:36 +00:00
dependabot[bot] bbe269d382 ⬆ Bump the github-actions group with 4 updates (#2464)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-01 12:43:33 +02:00
latest-changes[bot] 486f054cc8 📝 Update release notes
[skip ci]
2026-08-28 11:53:12 +00:00
Sebastián Ramírez f8dd304eeb ♻️ Simplify database readiness checks (#2460) 2026-08-28 13:53:10 +02:00
latest-changes[bot] 2ccfa25845 📝 Update release notes
[skip ci]
2026-08-27 17:18:32 +00:00
Yurii Motov f8ba0b81cd ⬆️ Bump Typer min version to 0.26.1 (#2459) 2026-08-27 19:18:29 +02:00
16 changed files with 13 additions and 171 deletions
+2 -2
View File
@@ -28,7 +28,7 @@ jobs:
fetch-depth: 2
persist-credentials: false
# For pull requests it's not necessary to checkout the code but for the main branch it is
- uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
id: filter
with:
filters: |
@@ -132,7 +132,7 @@ jobs:
timeout-minutes: 5
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
uses: re-actors/alls-green@b5b5b37504aa4183270bd3d855c52a67f212be35 # v1.3.0
with:
jobs: ${{ toJSON(needs) }}
allowed-skips: test-playwright
+2 -2
View File
@@ -72,7 +72,7 @@ jobs:
- name: Get PR Push token
id: pr-push
if: env.CAN_PUSH == 'true' && steps.changes.outputs.changed == 'true'
uses: tiangolo/pr-push@ff4e51a433de4c22bbf90597e069e8247b9203d2 # 0.0.1
uses: tiangolo/pr-push@f336b3817f32ea9b8273a8c15f8ecb739ac38167 # 0.0.4
- name: Commit and push changes
if: env.CAN_PUSH == 'true' && steps.changes.outputs.changed == 'true'
env:
@@ -109,6 +109,6 @@ jobs:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
uses: re-actors/alls-green@b5b5b37504aa4183270bd3d855c52a67f212be35 # v1.3.0
with:
jobs: ${{ toJSON(needs) }}
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
with:
version: "latest-known"
- run: docker compose down -v --remove-orphans
- run: docker compose up -d db mailpit
- run: docker compose up -d --wait db mailpit
- name: Migrate DB
run: uv run bash scripts/prestart.sh
working-directory: backend
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
with:
persist-credentials: false
- name: Run zizmor
uses: zizmorcore/zizmor-action@6fc4b006235f201fdab3722e17240ab420d580e5 # v0.6.1
uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2
with:
advanced-security: ${{ github.repository_owner == 'fastapi' }}
annotations: ${{ github.repository_owner != 'fastapi' }}
+1 -1
View File
@@ -78,7 +78,7 @@ If your stack is already up and you just want to run the tests, you can use:
docker compose exec backend bash scripts/tests-start.sh
```
The `/app/backend/scripts/tests-start.sh` script calls `pytest` after making sure that the rest of the stack is running. If you need to pass extra arguments to `pytest`, you can pass them to that command and they will be forwarded.
The `/app/backend/scripts/tests-start.sh` script calls `pytest`. If you need to pass extra arguments to `pytest`, you can pass them to that command and they will be forwarded.
For example, to stop on first error:
-39
View File
@@ -1,39 +0,0 @@
import logging
from sqlalchemy import Engine
from sqlmodel import Session, select
from tenacity import after_log, before_log, retry, stop_after_attempt, wait_fixed
from app.core.db import engine
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
max_tries = 60 * 5 # 5 minutes
wait_seconds = 1
@retry(
stop=stop_after_attempt(max_tries),
wait=wait_fixed(wait_seconds),
before=before_log(logger, logging.INFO),
after=after_log(logger, logging.WARN),
)
def init(db_engine: Engine) -> None:
try:
with Session(db_engine) as session:
# Try to create session to check if DB is awake
session.exec(select(1))
except Exception as e:
logger.error(e)
raise e
def main() -> None:
logger.info("Initializing service")
init(engine)
logger.info("Service finished initializing")
if __name__ == "__main__":
main()
+1 -1
View File
@@ -4,7 +4,7 @@ from app import crud
from app.core.config import settings
from app.models import User, UserCreate
engine = create_engine(str(settings.DATABASE_URL))
engine = create_engine(str(settings.DATABASE_URL), pool_pre_ping=True)
# make sure all SQLModel models are imported (app.models) before initializing DB
-39
View File
@@ -1,39 +0,0 @@
import logging
from sqlalchemy import Engine
from sqlmodel import Session, select
from tenacity import after_log, before_log, retry, stop_after_attempt, wait_fixed
from app.core.db import engine
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
max_tries = 60 * 5 # 5 minutes
wait_seconds = 1
@retry(
stop=stop_after_attempt(max_tries),
wait=wait_fixed(wait_seconds),
before=before_log(logger, logging.INFO),
after=after_log(logger, logging.WARN),
)
def init(db_engine: Engine) -> None:
try:
# Try to create session to check if DB is awake
with Session(db_engine) as session:
session.exec(select(1))
except Exception as e:
logger.error(e)
raise e
def main() -> None:
logger.info("Initializing service")
init(engine)
logger.info("Service finished initializing")
if __name__ == "__main__":
main()
-1
View File
@@ -7,7 +7,6 @@ dependencies = [
"fastapi[standard]>=0.141.1,<1.0.0",
"python-multipart<1.0.0,>=0.0.27",
"email-validator<3.0.0.0,>=2.1.0.post1",
"tenacity<10.0.0,>=8.2.3",
"pydantic>2.0",
"emails>=1.1.2,<2.0",
"jinja2<4.0.0,>=3.1.4",
-3
View File
@@ -3,9 +3,6 @@
set -e
set -x
# Let the DB start
python app/backend_pre_start.py
# Run migrations
alembic upgrade head
-2
View File
@@ -2,6 +2,4 @@
set -e
set -x
python app/tests_pre_start.py
bash scripts/test.sh "$@"
@@ -1,33 +0,0 @@
from unittest.mock import MagicMock, patch
from sqlmodel import select
from app.backend_pre_start import init, logger
def test_init_successful_connection() -> None:
engine_mock = MagicMock()
session_mock = MagicMock()
session_mock.__enter__.return_value = session_mock
select1 = select(1)
with (
patch("app.backend_pre_start.Session", return_value=session_mock),
patch("app.backend_pre_start.select", return_value=select1),
patch.object(logger, "info"),
patch.object(logger, "error"),
patch.object(logger, "warn"),
):
try:
init(engine_mock)
connection_successful = True
except Exception:
connection_successful = False
assert connection_successful, (
"The database connection should be successful and not raise an exception."
)
session_mock.exec.assert_called_once_with(select1)
@@ -1,33 +0,0 @@
from unittest.mock import MagicMock, patch
from sqlmodel import select
from app.tests_pre_start import init, logger
def test_init_successful_connection() -> None:
engine_mock = MagicMock()
session_mock = MagicMock()
session_mock.__enter__.return_value = session_mock
select1 = select(1)
with (
patch("app.tests_pre_start.Session", return_value=session_mock),
patch("app.tests_pre_start.select", return_value=select1),
patch.object(logger, "info"),
patch.object(logger, "error"),
patch.object(logger, "warn"),
):
try:
init(engine_mock)
connection_successful = True
except Exception:
connection_successful = False
assert connection_successful, (
"The database connection should be successful and not raise an exception."
)
session_mock.exec.assert_called_once_with(select1)
+1 -1
View File
@@ -1,7 +1,7 @@
[dependency-groups]
dev = [
"prek>=0.4.11,<1.0.0",
"typer>=0.20.0,<1.0.0",
"typer>=0.26.1,<1.0.0",
"zizmor>=1.28.0",
]
+3
View File
@@ -9,6 +9,7 @@
### Refactors
* ♻️ Simplify database readiness checks. PR [#2460](https://github.com/fastapi/full-stack-fastapi-template/pull/2460) by [@tiangolo](https://github.com/tiangolo).
* ✅ Simplify password reset E2E tests. PR [#2453](https://github.com/fastapi/full-stack-fastapi-template/pull/2453) by [@alejsdev](https://github.com/alejsdev).
* 💄 Refactor email templates and components for improved styling. PR [#2451](https://github.com/fastapi/full-stack-fastapi-template/pull/2451) by [@alejsdev](https://github.com/alejsdev).
* ♻️ Replace Mailcatcher with Mailpit for local email testing. PR [#2436](https://github.com/fastapi/full-stack-fastapi-template/pull/2436) by [@alejsdev](https://github.com/alejsdev).
@@ -20,6 +21,8 @@
### Internal
* ⬆ Bump the github-actions group with 4 updates. PR [#2464](https://github.com/fastapi/full-stack-fastapi-template/pull/2464) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆️ Bump Typer min version to `0.26.1`. PR [#2459](https://github.com/fastapi/full-stack-fastapi-template/pull/2459) by [@YuriiMotov](https://github.com/YuriiMotov).
* ⬆️ Bump setup-uv action to 10.0.1. PR [#2458](https://github.com/fastapi/full-stack-fastapi-template/pull/2458) by [@YuriiMotov](https://github.com/YuriiMotov).
## 0.12.0 (2026-08-12)
Generated
+1 -12
View File
@@ -14,7 +14,7 @@ members = [
[manifest.dependency-groups]
dev = [
{ name = "prek", specifier = ">=0.4.11,<1.0.0" },
{ name = "typer", specifier = ">=0.20.0,<1.0.0" },
{ name = "typer", specifier = ">=0.26.1,<1.0.0" },
{ name = "zizmor", specifier = ">=1.28.0" },
]
github-actions = [{ name = "smokeshow", specifier = ">=0.5.0" }]
@@ -82,7 +82,6 @@ dependencies = [
{ name = "python-multipart" },
{ name = "sentry-sdk", extra = ["fastapi"] },
{ name = "sqlmodel" },
{ name = "tenacity" },
]
[package.dev-dependencies]
@@ -110,7 +109,6 @@ requires-dist = [
{ name = "python-multipart", specifier = ">=0.0.27,<1.0.0" },
{ name = "sentry-sdk", extras = ["fastapi"], specifier = ">=2.66.1,<3.0.0" },
{ name = "sqlmodel", specifier = ">=0.0.39,<1.0.0" },
{ name = "tenacity", specifier = ">=8.2.3,<10.0.0" },
]
[package.metadata.requires-dev]
@@ -1284,15 +1282,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" },
]
[[package]]
name = "tenacity"
version = "9.1.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" },
]
[[package]]
name = "ty"
version = "0.0.54"